mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-12-11 13:17:45 +01:00
Initial mapbox based maps implementation
This commit is contained in:
parent
2a01e6cb74
commit
6174997cb7
@ -9,7 +9,7 @@ microG GmsCore is a FLOSS (Free/Libre Open Source Software) framework to allow a
|
||||
|
||||
License
|
||||
-------
|
||||
Copyright 2014-2016 microG Project Team
|
||||
Copyright 2013-2019 microG Project Team
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,12 @@
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
def useMapbox() {
|
||||
Properties properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
return properties.getProperty("mapbox.enabled", "false") == "true"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.android.support:support-v4:$supportLibraryVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
@ -39,7 +45,11 @@ dependencies {
|
||||
implementation project(':wearable-lib')
|
||||
|
||||
implementation project(':remote-droid-guard-lib')
|
||||
implementation project(':play-services-maps-core-vtm')
|
||||
if (useMapbox()) {
|
||||
implementation project(':play-services-maps-core-mapbox')
|
||||
} else {
|
||||
implementation project(':play-services-maps-core-vtm')
|
||||
}
|
||||
}
|
||||
|
||||
def execResult(...args) {
|
||||
@ -60,7 +70,7 @@ def gitDirty = execResult('git', 'status', '--porcelain').size() > 0
|
||||
def ourVersionBase = gitVersionBase.substring(0, gitVersionBase.lastIndexOf('.'))
|
||||
def ourVersionMinor = Integer.parseInt(ourVersionBase.substring(ourVersionBase.lastIndexOf('.') + 1))
|
||||
def ourVersionCode = gmsVersionCode * 1000 + ourVersionMinor * 2 + (gitCommitCount > 0 || gitDirty ? 1 : 0)
|
||||
def ourVersionName = "$ourVersionBase.$gmsVersionCode" + (gitCommitCount > 0 && !gitDirty ? "-$gitCommitCount" : "") + (gitDirty ? "-dirty" : "") + (gitCommitCount > 0 && !gitDirty ? " ($gitCommitId)" : "")
|
||||
def ourVersionName = "$ourVersionBase.$gmsVersionCode" + (gitCommitCount > 0 && !gitDirty ? "-$gitCommitCount" : "") + (gitDirty ? "-dirty" : "") + (useMapbox() ? "-mapbox" : "") + (gitCommitCount > 0 && !gitDirty ? " ($gitCommitId)" : "")
|
||||
logger.lifecycle('Starting build for version {} ({})...', ourVersionName, ourVersionCode)
|
||||
|
||||
android {
|
||||
|
83
play-services-maps-core-mapbox/build.gradle
Normal file
83
play-services-maps-core-mapbox/build.gradle
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013-2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
dependencies {
|
||||
implementation project(':play-services-api')
|
||||
implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:7.3.0"
|
||||
implementation "com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v7:0.6.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
def execResult(...args) {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine args
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
def mapboxKey() {
|
||||
Properties properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
return properties.getProperty("mapbox.key", "invalid")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdk()
|
||||
buildToolsVersion "$androidBuildVersionTools"
|
||||
|
||||
defaultConfig {
|
||||
versionName "temp"
|
||||
versionCode 1
|
||||
|
||||
minSdkVersion androidMinSdk()
|
||||
targetSdkVersion androidTargetSdk()
|
||||
buildConfigField "String", "MAPBOX_KEY", "\"${mapboxKey()}\""
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'GradleCompatible'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
if (file('user.gradle').exists()) {
|
||||
apply from: 'user.gradle'
|
||||
}
|
34
play-services-maps-core-mapbox/src/main/AndroidManifest.xml
Normal file
34
play-services-maps-core-mapbox/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2013-2019 microG Project Team
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<manifest package="org.microg.gms.maps.mapbox"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<application />
|
||||
|
||||
</manifest>
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2017 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.maps.internal;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.Keep;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
import com.google.android.gms.maps.GoogleMapOptions;
|
||||
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;
|
||||
|
||||
import org.microg.gms.maps.mapbox.CameraUpdateFactoryImpl;
|
||||
import org.microg.gms.maps.mapbox.MapFragmentImpl;
|
||||
import org.microg.gms.maps.mapbox.MapViewImpl;
|
||||
import org.microg.gms.maps.mapbox.model.BitmapDescriptorFactoryImpl;
|
||||
|
||||
@Keep
|
||||
public class CreatorImpl extends ICreator.Stub {
|
||||
private static final String TAG = "GmsMapCreator";
|
||||
|
||||
@Override
|
||||
public void init(IObjectWrapper resources) {
|
||||
initV2(resources, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) {
|
||||
return new MapFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) {
|
||||
return new MapViewImpl(ObjectWrapper.unwrapTyped(context, Context.class), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() {
|
||||
return new CameraUpdateFactoryImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() {
|
||||
return BitmapDescriptorFactoryImpl.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initV2(IObjectWrapper resources, int flags) {
|
||||
BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class));
|
||||
//ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));
|
||||
Log.d(TAG, "initV2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||
if (super.onTransact(code, data, reply, flags)) return true;
|
||||
Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
import java.util.*
|
||||
|
||||
internal class CameraBoundsWithSizeUpdate(val bounds: LatLngBounds, val width: Int, val height: Int, val padding: IntArray) : CameraUpdate {
|
||||
|
||||
constructor(bounds: LatLngBounds, width: Int, height: Int, paddingLeft: Int, paddingTop: Int = paddingLeft, paddingRight: Int = paddingLeft, paddingBottom: Int = paddingTop) : this(bounds, width, height, intArrayOf(paddingLeft, paddingTop, paddingRight, paddingBottom)) {}
|
||||
|
||||
override fun getCameraPosition(map: MapboxMap): CameraPosition? {
|
||||
val padding = this.padding.clone()
|
||||
val widthPad = (map.padding[0] + map.padding[2])/2
|
||||
val heightPad = (map.padding[1] + map.padding[3])/2
|
||||
padding[0] += widthPad
|
||||
padding[1] += heightPad
|
||||
padding[2] += widthPad
|
||||
padding[3] += heightPad
|
||||
return map.getCameraForLatLngBounds(bounds, padding)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
if (other == null || other !is CameraBoundsWithSizeUpdate?) {
|
||||
return false
|
||||
}
|
||||
|
||||
val that = other as CameraBoundsWithSizeUpdate? ?: return false
|
||||
|
||||
if (bounds != that.bounds) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (Arrays.equals(padding, that.padding)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (height != that.height || width != that.width) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bounds.hashCode()
|
||||
result = 31 * result + Arrays.hashCode(padding)
|
||||
result = 31 * result + height.hashCode()
|
||||
result = 31 * result + width.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return ("CameraBoundsWithSizeUpdate{"
|
||||
+ "bounds=" + bounds
|
||||
+ ", padding=" + Arrays.toString(padding)
|
||||
+ '}'.toString())
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = "GmsCameraBounds"
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.graphics.Point
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.dynamic.ObjectWrapper
|
||||
import com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate
|
||||
import com.google.android.gms.maps.model.CameraPosition
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.LatLngBounds
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() {
|
||||
|
||||
override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomIn())
|
||||
override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomOut())
|
||||
|
||||
override fun zoomTo(zoom: Float): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.zoomTo(zoom.toDouble() - 1.0))
|
||||
|
||||
override fun zoomBy(zoomDelta: Float): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta.toDouble()))
|
||||
|
||||
override fun zoomByWithFocus(zoomDelta: Float, x: Int, y: Int): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta.toDouble(), Point(x, y)))
|
||||
|
||||
override fun newCameraPosition(cameraPosition: CameraPosition): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.newCameraPosition(cameraPosition.toMapbox()))
|
||||
|
||||
override fun newLatLng(latLng: LatLng): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.newLatLng(latLng.toMapbox()))
|
||||
|
||||
override fun newLatLngZoom(latLng: LatLng, zoom: Float): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.newLatLngZoom(latLng.toMapbox(), zoom.toDouble() - 1.0))
|
||||
|
||||
override fun newLatLngBounds(bounds: LatLngBounds, padding: Int): IObjectWrapper =
|
||||
ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toMapbox(), padding))
|
||||
|
||||
override fun scrollBy(x: Float, y: Float): IObjectWrapper {
|
||||
Log.d(TAG, "unimplemented Method: scrollBy")
|
||||
return ObjectWrapper.wrap(NoCameraUpdate())
|
||||
}
|
||||
|
||||
override fun newLatLngBoundsWithSize(bounds: LatLngBounds, width: Int, height: Int, padding: Int): IObjectWrapper {
|
||||
Log.d(TAG, "unimplemented Method: newLatLngBoundsWithSize")
|
||||
|
||||
return ObjectWrapper.wrap(CameraBoundsWithSizeUpdate(bounds.toMapbox(), width, height, padding))
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
private inner class NoCameraUpdate : CameraUpdate {
|
||||
override fun getCameraPosition(mapboxMap: MapboxMap): com.mapbox.mapboxsdk.camera.CameraPosition? =
|
||||
mapboxMap.cameraPosition
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsCameraUpdate"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.os.RemoteException
|
||||
import android.support.annotation.IdRes
|
||||
import android.support.annotation.Keep
|
||||
import android.support.v4.util.LongSparseArray
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.maps.GoogleMapOptions
|
||||
import com.google.android.gms.maps.internal.*
|
||||
import com.google.android.gms.maps.model.*
|
||||
import com.google.android.gms.maps.model.CircleOptions
|
||||
import com.google.android.gms.maps.model.internal.*
|
||||
import com.mapbox.mapboxsdk.LibraryLoader
|
||||
import com.mapbox.mapboxsdk.Mapbox
|
||||
import com.mapbox.mapboxsdk.R
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate
|
||||
import com.mapbox.mapboxsdk.maps.MapView
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
import com.mapbox.mapboxsdk.maps.Style
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.*
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.Annotation
|
||||
import com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_ROUND
|
||||
import com.mapbox.mapboxsdk.utils.ColorUtils
|
||||
import org.microg.gms.kotlin.unwrap
|
||||
import org.microg.gms.maps.MapsConstants.*
|
||||
import org.microg.gms.maps.mapbox.model.*
|
||||
import org.microg.gms.maps.mapbox.utils.MapContext
|
||||
import org.microg.gms.maps.mapbox.utils.MultiArchLoader
|
||||
import org.microg.gms.maps.mapbox.utils.toGms
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
fun <T : Any> LongSparseArray<T>.values() = (0..size()).map { valueAt(it) }.mapNotNull { it }
|
||||
|
||||
class GoogleMapImpl(private val context: Context, private val options: GoogleMapOptions) : IGoogleMapDelegate.Stub() {
|
||||
|
||||
val view: FrameLayout
|
||||
var map: MapboxMap? = null
|
||||
private set
|
||||
val dpiFactor: Float
|
||||
get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT
|
||||
|
||||
private var mapView: MapView?
|
||||
private var initialized = false
|
||||
private val initializedCallbackList = mutableListOf<IOnMapReadyCallback>()
|
||||
private val mapLock = Object()
|
||||
val markers = mutableMapOf<Long, MarkerImpl>()
|
||||
|
||||
private var cameraChangeListener: IOnCameraChangeListener? = null
|
||||
private var cameraMoveListener: IOnCameraMoveListener? = null
|
||||
private var cameraMoveCanceledListener: IOnCameraMoveCanceledListener? = null
|
||||
private var cameraMoveStartedListener: IOnCameraMoveStartedListener? = null
|
||||
private var cameraIdleListener: IOnCameraIdleListener? = null
|
||||
private var mapClickListener: IOnMapClickListener? = null
|
||||
private var mapLongClickListener: IOnMapLongClickListener? = null
|
||||
private var markerClickListener: IOnMarkerClickListener? = null
|
||||
private var markerDragListener: IOnMarkerDragListener? = null
|
||||
|
||||
var circleManager: CircleManager? = null
|
||||
var lineManager: LineManager? = null
|
||||
var fillManager: FillManager? = null
|
||||
var symbolManager: SymbolManager? = null
|
||||
var storedMapType: Int = MAP_TYPE_NORMAL
|
||||
|
||||
init {
|
||||
val mapContext = MapContext(context)
|
||||
LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context))
|
||||
Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY)
|
||||
|
||||
this.view = object : FrameLayout(mapContext) {
|
||||
@Keep
|
||||
fun <T : View> findViewTraversal(@IdRes id: Int): T? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
this.mapView = MapView(mapContext)
|
||||
this.view.addView(this.mapView)
|
||||
}
|
||||
|
||||
override fun getCameraPosition(): CameraPosition? = map?.cameraPosition?.toGms()
|
||||
override fun getMaxZoomLevel(): Float = map?.maxZoomLevel?.toFloat() ?: 20f
|
||||
override fun getMinZoomLevel(): Float = map?.minZoomLevel?.toFloat() ?: 1f
|
||||
|
||||
override fun moveCamera(cameraUpdate: IObjectWrapper?) =
|
||||
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.moveCamera(it) } ?: Unit
|
||||
|
||||
override fun animateCamera(cameraUpdate: IObjectWrapper?) =
|
||||
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it) } ?: Unit
|
||||
|
||||
override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) =
|
||||
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it, callback?.toMapbox()) }
|
||||
?: Unit
|
||||
|
||||
override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) =
|
||||
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it, duration, callback?.toMapbox()) }
|
||||
?: Unit
|
||||
|
||||
override fun stopAnimation() = map?.cancelTransitions() ?: Unit
|
||||
|
||||
override fun addPolyline(options: PolylineOptions): IPolylineDelegate? {
|
||||
val lineOptions = LineOptions()
|
||||
.withLatLngs(options.points.map { it.toMapbox() })
|
||||
.withLineWidth(options.width / dpiFactor)
|
||||
.withLineColor(ColorUtils.colorToRgbaString(options.color))
|
||||
.withLineOpacity(if (options.isVisible) 1f else 0f)
|
||||
return lineManager?.let { PolylineImpl(this, it.create(lineOptions)) }
|
||||
}
|
||||
|
||||
|
||||
override fun addPolygon(options: PolygonOptions): IPolygonDelegate? {
|
||||
Log.d(TAG, "unimplemented Method: addPolygon")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun addMarker(options: MarkerOptions): IMarkerDelegate? {
|
||||
var intBits = java.lang.Float.floatToIntBits(options.zIndex)
|
||||
if (intBits < 0) intBits = intBits xor 0x7fffffff
|
||||
|
||||
val symbolOptions = SymbolOptions()
|
||||
.withIconOpacity(if (options.isVisible) options.alpha else 0f)
|
||||
.withIconRotate(options.rotation)
|
||||
.withZIndex(intBits)
|
||||
.withDraggable(options.isDraggable)
|
||||
|
||||
options.position?.let { symbolOptions.withLatLng(it.toMapbox()) }
|
||||
options.icon?.remoteObject.unwrap<BitmapDescriptorImpl>()?.applyTo(symbolOptions, floatArrayOf(options.anchorU, options.anchorV), dpiFactor)
|
||||
|
||||
val symbol = symbolManager?.create(symbolOptions) ?: return null
|
||||
val marker = MarkerImpl(this, symbol, floatArrayOf(options.anchorU, options.anchorV), options.icon?.remoteObject.unwrap<BitmapDescriptorImpl>(), options.alpha, options.title, options.snippet)
|
||||
markers.put(symbol.id, marker)
|
||||
return marker
|
||||
}
|
||||
|
||||
override fun addGroundOverlay(options: GroundOverlayOptions): IGroundOverlayDelegate? {
|
||||
Log.d(TAG, "unimplemented Method: addGroundOverlay")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun addTileOverlay(options: TileOverlayOptions): ITileOverlayDelegate? {
|
||||
Log.d(TAG, "unimplemented Method: addTileOverlay")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun addCircle(options: CircleOptions): ICircleDelegate? {
|
||||
val circleOptions = com.mapbox.mapboxsdk.plugins.annotation.CircleOptions()
|
||||
.withLatLng(options.center.toMapbox())
|
||||
.withCircleColor(ColorUtils.colorToRgbaString(options.fillColor))
|
||||
.withCircleRadius(options.radius.toFloat())
|
||||
.withCircleStrokeColor(ColorUtils.colorToRgbaString(options.strokeColor))
|
||||
.withCircleStrokeWidth(options.strokeWidth / dpiFactor)
|
||||
.withCircleOpacity(if (options.isVisible) 1f else 0f)
|
||||
.withCircleStrokeOpacity(if (options.isVisible) 1f else 0f)
|
||||
|
||||
return circleManager?.let { CircleImpl(this, it.create(circleOptions)) }
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
circleManager?.let { clear(it) }
|
||||
lineManager?.let { clear(it) }
|
||||
fillManager?.let { clear(it) }
|
||||
symbolManager?.let { clear(it) }
|
||||
}
|
||||
|
||||
fun <T : Annotation<*>> clear(manager: AnnotationManager<*, T, *, *, *, *>) {
|
||||
val annotations = manager.getAnnotations()
|
||||
for (i in 0..annotations.size()) {
|
||||
val key = annotations.keyAt(i)
|
||||
val value = annotations[key];
|
||||
if (value is T) manager.delete(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMapType(): Int {
|
||||
return storedMapType
|
||||
}
|
||||
|
||||
override fun setMapType(type: Int) {
|
||||
storedMapType = type
|
||||
applyMapType()
|
||||
}
|
||||
|
||||
fun applyMapType() {
|
||||
val circles = circleManager?.annotations?.values()
|
||||
val lines = lineManager?.annotations?.values()
|
||||
val fills = fillManager?.annotations?.values()
|
||||
val symbols = symbolManager?.annotations?.values()
|
||||
val update: (Style) -> Unit = {
|
||||
circles?.let { circleManager?.update(it) }
|
||||
lines?.let { lineManager?.update(it) }
|
||||
fills?.let { fillManager?.update(it) }
|
||||
symbols?.let { symbolManager?.update(it) }
|
||||
}
|
||||
|
||||
when (storedMapType) {
|
||||
MAP_TYPE_NORMAL -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"), update)
|
||||
MAP_TYPE_SATELLITE -> map?.setStyle(Style.SATELLITE, update)
|
||||
MAP_TYPE_TERRAIN -> map?.setStyle(Style.OUTDOORS, update)
|
||||
MAP_TYPE_HYBRID -> map?.setStyle(Style.SATELLITE_STREETS, update)
|
||||
else -> map?.setStyle(Style.LIGHT, update)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun isTrafficEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isTrafficEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setTrafficEnabled(traffic: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setTrafficEnabled")
|
||||
|
||||
}
|
||||
|
||||
override fun isIndoorEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isIndoorEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setIndoorEnabled(indoor: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setIndoorEnabled")
|
||||
|
||||
}
|
||||
|
||||
override fun isMyLocationEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isMyLocationEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setMyLocationEnabled(myLocation: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setMyLocationEnabled")
|
||||
|
||||
}
|
||||
|
||||
override fun getMyLocation(): Location? {
|
||||
Log.d(TAG, "unimplemented Method: getMyLocation")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun setLocationSource(locationSource: ILocationSourceDelegate) {
|
||||
Log.d(TAG, "unimplemented Method: setLocationSource")
|
||||
|
||||
}
|
||||
|
||||
override fun getUiSettings(): IUiSettingsDelegate? = map?.uiSettings?.let { UiSettingsImpl(it) }
|
||||
|
||||
override fun getProjection(): IProjectionDelegate? = map?.projection?.let { ProjectionImpl(it) }
|
||||
|
||||
override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) {
|
||||
cameraChangeListener = listener
|
||||
}
|
||||
|
||||
override fun setOnMapClickListener(listener: IOnMapClickListener?) {
|
||||
mapClickListener = listener
|
||||
}
|
||||
|
||||
override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) {
|
||||
mapLongClickListener = listener
|
||||
}
|
||||
|
||||
override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) {
|
||||
markerClickListener = listener
|
||||
}
|
||||
|
||||
override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) {
|
||||
markerDragListener = listener
|
||||
}
|
||||
|
||||
override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) {
|
||||
Log.d(TAG, "unimplemented Method: setOnInfoWindowClickListener")
|
||||
|
||||
}
|
||||
|
||||
override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) {
|
||||
Log.d(TAG, "unimplemented Method: setInfoWindowAdapter")
|
||||
|
||||
}
|
||||
|
||||
override fun getTestingHelper(): IObjectWrapper? {
|
||||
Log.d(TAG, "unimplemented Method: getTestingHelper")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) {
|
||||
Log.d(TAG, "unimplemented Method: setOnMyLocationChangeListener")
|
||||
|
||||
}
|
||||
|
||||
override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) {
|
||||
Log.d(TAG, "unimplemented Method: setOnMyLocationButtonClickListener")
|
||||
|
||||
}
|
||||
|
||||
override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper) {
|
||||
Log.d(TAG, "unimplemented Method: snapshot")
|
||||
|
||||
}
|
||||
|
||||
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
|
||||
Log.d(TAG, "padding: $left, $top, $right, $bottom")
|
||||
map?.setPadding(left, top, right, bottom)
|
||||
val fourDp = mapView?.context?.resources?.getDimension(R.dimen.mapbox_four_dp)?.toInt() ?: 0
|
||||
val ninetyTwoDp = mapView?.context?.resources?.getDimension(R.dimen.mapbox_ninety_two_dp)?.toInt()
|
||||
?: 0
|
||||
map?.uiSettings?.setLogoMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp)
|
||||
map?.uiSettings?.setCompassMargins(left + fourDp, top + fourDp, right + fourDp, bottom + fourDp)
|
||||
map?.uiSettings?.setAttributionMargins(left + ninetyTwoDp, top + fourDp, right + fourDp, bottom + fourDp)
|
||||
}
|
||||
|
||||
override fun isBuildingsEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isBuildingsEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setBuildingsEnabled(buildings: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setBuildingsEnabled")
|
||||
|
||||
}
|
||||
|
||||
override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) {
|
||||
Log.d(TAG, "unimplemented Method: setOnMapLoadedCallback")
|
||||
|
||||
}
|
||||
|
||||
override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) {
|
||||
cameraMoveStartedListener = listener
|
||||
}
|
||||
|
||||
override fun setCameraMoveListener(listener: IOnCameraMoveListener?) {
|
||||
cameraMoveListener = listener
|
||||
}
|
||||
|
||||
override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) {
|
||||
cameraMoveCanceledListener = listener
|
||||
}
|
||||
|
||||
override fun setCameraIdleListener(listener: IOnCameraIdleListener?) {
|
||||
cameraIdleListener = listener
|
||||
}
|
||||
|
||||
fun onCreate(savedInstanceState: Bundle) {
|
||||
mapView?.onCreate(savedInstanceState.toMapbox())
|
||||
mapView?.getMapAsync(this::initMap)
|
||||
}
|
||||
|
||||
private fun hasSymbolAt(latlng: com.mapbox.mapboxsdk.geometry.LatLng): Boolean {
|
||||
val point = map?.projection?.toScreenLocation(latlng) ?: return false
|
||||
val features = map?.queryRenderedFeatures(point, SymbolManager.ID_GEOJSON_LAYER)
|
||||
?: return false
|
||||
return !features.isEmpty()
|
||||
}
|
||||
|
||||
private fun initMap(map: MapboxMap) {
|
||||
if (this.map != null) return
|
||||
this.map = map
|
||||
|
||||
applyMapType()
|
||||
map.getStyle {
|
||||
mapView?.let { view ->
|
||||
BitmapDescriptorFactoryImpl.registerMap(map)
|
||||
circleManager = CircleManager(view, map, it)
|
||||
lineManager = LineManager(view, map, it)
|
||||
lineManager?.lineCap = LINE_CAP_ROUND
|
||||
fillManager = FillManager(view, map, it)
|
||||
symbolManager = SymbolManager(view, map, it)
|
||||
symbolManager?.iconAllowOverlap = true
|
||||
symbolManager?.addClickListener { markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } }
|
||||
symbolManager?.addDragListener(object : OnSymbolDragListener {
|
||||
override fun onAnnotationDragStarted(annotation: Symbol?) {
|
||||
markers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) }
|
||||
}
|
||||
|
||||
override fun onAnnotationDrag(annotation: Symbol?) {
|
||||
markers[annotation?.id]?.let { markerDragListener?.onMarkerDrag(it) }
|
||||
}
|
||||
|
||||
override fun onAnnotationDragFinished(annotation: Symbol?) {
|
||||
markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) }
|
||||
}
|
||||
|
||||
})
|
||||
map.addOnCameraIdleListener { cameraChangeListener?.onCameraChange(map.cameraPosition.toGms()) }
|
||||
map.addOnCameraIdleListener { cameraIdleListener?.onCameraIdle() }
|
||||
map.addOnCameraMoveListener { cameraMoveListener?.onCameraMove() }
|
||||
map.addOnCameraMoveStartedListener { cameraMoveStartedListener?.onCameraMoveStarted(it) }
|
||||
map.addOnCameraMoveCancelListener { cameraMoveCanceledListener?.onCameraMoveCanceled() }
|
||||
map.addOnMapClickListener {
|
||||
val latlng = it
|
||||
mapClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapClick(latlng.toGms()); }
|
||||
false
|
||||
}
|
||||
map.addOnMapLongClickListener {
|
||||
val latlng = it
|
||||
mapLongClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapLongClick(latlng.toGms()); }
|
||||
false
|
||||
}
|
||||
|
||||
synchronized(mapLock) {
|
||||
for (callback in initializedCallbackList) {
|
||||
try {
|
||||
callback.onMapReady(this)
|
||||
} catch (e: RemoteException) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
}
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onResume() = mapView?.onResume()
|
||||
fun onPause() = mapView?.onPause()
|
||||
fun onDestroy() {
|
||||
circleManager?.onDestroy()
|
||||
circleManager = null
|
||||
lineManager?.onDestroy()
|
||||
lineManager = null
|
||||
fillManager?.onDestroy()
|
||||
fillManager = null
|
||||
symbolManager?.onDestroy()
|
||||
symbolManager = null
|
||||
BitmapDescriptorFactoryImpl.unregisterMap(map)
|
||||
view.removeView(mapView)
|
||||
// TODO can crash?
|
||||
mapView?.onDestroy()
|
||||
mapView = null
|
||||
}
|
||||
|
||||
fun onLowMemory() = mapView?.onLowMemory()
|
||||
fun onSaveInstanceState(outState: Bundle) {
|
||||
val newBundle = Bundle()
|
||||
mapView?.onSaveInstanceState(newBundle)
|
||||
outState.putAll(newBundle.toGms())
|
||||
}
|
||||
|
||||
fun getMapAsync(callback: IOnMapReadyCallback) {
|
||||
synchronized(mapLock) {
|
||||
if (initialized) {
|
||||
callback.onMapReady(this)
|
||||
} else {
|
||||
initializedCallbackList.add(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMap"
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.dynamic.ObjectWrapper
|
||||
import com.google.android.gms.maps.GoogleMapOptions
|
||||
import com.google.android.gms.maps.internal.IGoogleMapDelegate
|
||||
import com.google.android.gms.maps.internal.IMapFragmentDelegate
|
||||
import com.google.android.gms.maps.internal.IOnMapReadyCallback
|
||||
|
||||
class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stub() {
|
||||
|
||||
private var map: GoogleMapImpl? = null
|
||||
private var options: GoogleMapOptions? = null
|
||||
|
||||
override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle) {
|
||||
this.options = options
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle) {
|
||||
if (options == null) {
|
||||
options = savedInstanceState.getParcelable("MapOptions")
|
||||
}
|
||||
if (options == null) {
|
||||
options = GoogleMapOptions()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle): IObjectWrapper {
|
||||
if (map == null) {
|
||||
map = GoogleMapImpl(activity, options ?: GoogleMapOptions())
|
||||
map!!.onCreate(savedInstanceState)
|
||||
return ObjectWrapper.wrap(map!!.view)
|
||||
} else {
|
||||
val view = map!!.view
|
||||
val parent = view?.parent as ViewGroup
|
||||
parent.removeView(view)
|
||||
return ObjectWrapper.wrap(view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMap(): IGoogleMapDelegate? = map
|
||||
override fun onResume() = map?.onResume() ?: Unit
|
||||
override fun onPause() = map?.onPause() ?: Unit
|
||||
override fun onLowMemory() = map?.onLowMemory() ?: Unit
|
||||
override fun isReady(): Boolean = this.map != null
|
||||
override fun getMapAsync(callback: IOnMapReadyCallback) = map?.getMapAsync(callback) ?: Unit
|
||||
|
||||
override fun onDestroyView() {
|
||||
map?.onDestroy()
|
||||
map = null
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
map?.onDestroy()
|
||||
map = null
|
||||
options = null
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
if (options != null) {
|
||||
outState.putParcelable("MapOptions", options)
|
||||
}
|
||||
map?.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMapFragment"
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.dynamic.ObjectWrapper
|
||||
import com.google.android.gms.maps.GoogleMapOptions
|
||||
import com.google.android.gms.maps.internal.IGoogleMapDelegate
|
||||
import com.google.android.gms.maps.internal.IMapViewDelegate
|
||||
import com.google.android.gms.maps.internal.IOnMapReadyCallback
|
||||
|
||||
class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() {
|
||||
private val options: GoogleMapOptions
|
||||
private var map: GoogleMapImpl? = null
|
||||
|
||||
init {
|
||||
this.options = options ?: GoogleMapOptions()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle) {
|
||||
map = GoogleMapImpl(context, options)
|
||||
map?.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getMap(): IGoogleMapDelegate? = map
|
||||
override fun onResume() = map?.onResume() ?: Unit
|
||||
override fun onPause() = map?.onPause() ?: Unit
|
||||
override fun onDestroy() {
|
||||
map?.onDestroy()
|
||||
map = null
|
||||
}
|
||||
override fun onLowMemory() = map?.onLowMemory() ?: Unit
|
||||
override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit
|
||||
override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view)
|
||||
override fun getMapAsync(callback: IOnMapReadyCallback) = map?.getMapAsync(callback) ?: Unit
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMapView"
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.dynamic.ObjectWrapper
|
||||
import com.google.android.gms.maps.internal.IProjectionDelegate
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.LatLngBounds
|
||||
import com.google.android.gms.maps.model.VisibleRegion
|
||||
import com.mapbox.mapboxsdk.maps.Projection
|
||||
import org.microg.gms.kotlin.unwrap
|
||||
import org.microg.gms.maps.mapbox.utils.toGms
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
class ProjectionImpl(private val projection: Projection) : IProjectionDelegate.Stub() {
|
||||
override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? =
|
||||
obj.unwrap<Point>()?.let { projection.fromScreenLocation(PointF(it)) }?.toGms()
|
||||
|
||||
override fun toScreenLocation(latLng: LatLng?): IObjectWrapper =
|
||||
ObjectWrapper.wrap(latLng?.toMapbox()?.let { projection.toScreenLocation(it) }?.let { Point(it.x.toInt(), it.y.toInt()) })
|
||||
|
||||
override fun getVisibleRegion(): VisibleRegion = try {
|
||||
projection.visibleRegion.toGms()
|
||||
} catch (e: Exception) {
|
||||
VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0)))
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
|
||||
import com.google.android.gms.maps.internal.IUiSettingsDelegate
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings
|
||||
|
||||
class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.Stub() {
|
||||
|
||||
override fun setZoomControlsEnabled(zoom: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setZoomControlsEnabled")
|
||||
}
|
||||
|
||||
override fun setCompassEnabled(compass: Boolean) {
|
||||
uiSettings.isCompassEnabled = compass
|
||||
}
|
||||
|
||||
override fun setMyLocationButtonEnabled(locationButton: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setMyLocationButtonEnabled")
|
||||
|
||||
}
|
||||
|
||||
override fun setScrollGesturesEnabled(scrollGestures: Boolean) {
|
||||
uiSettings.isScrollGesturesEnabled = scrollGestures
|
||||
}
|
||||
|
||||
override fun setZoomGesturesEnabled(zoomGestures: Boolean) {
|
||||
uiSettings.isZoomGesturesEnabled = zoomGestures
|
||||
}
|
||||
|
||||
override fun setTiltGesturesEnabled(tiltGestures: Boolean) {
|
||||
uiSettings.isTiltGesturesEnabled = tiltGestures
|
||||
}
|
||||
|
||||
override fun setRotateGesturesEnabled(rotateGestures: Boolean) {
|
||||
uiSettings.isRotateGesturesEnabled = rotateGestures
|
||||
}
|
||||
|
||||
override fun setAllGesturesEnabled(gestures: Boolean) {
|
||||
uiSettings.setAllGesturesEnabled(gestures)
|
||||
}
|
||||
|
||||
override fun isZoomControlsEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isZoomControlsEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled
|
||||
|
||||
override fun isMyLocationButtonEnabled(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isMyLocationButtonEnabled")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled
|
||||
|
||||
override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled
|
||||
|
||||
override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled
|
||||
|
||||
override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMapsUi"
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.model
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.PointF
|
||||
import android.util.Log
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.Symbol
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
|
||||
import com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_TOP_LEFT
|
||||
import com.mapbox.mapboxsdk.utils.ColorUtils
|
||||
|
||||
open class BitmapDescriptorImpl(private val id: String, private val size: FloatArray) {
|
||||
open fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions {
|
||||
return options.withIconImage(id).withIconAnchor(ICON_ANCHOR_TOP_LEFT).withIconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor))
|
||||
}
|
||||
|
||||
open fun applyTo(symbol: Symbol, anchor: FloatArray, dpiFactor: Float) {
|
||||
symbol.iconAnchor = ICON_ANCHOR_TOP_LEFT
|
||||
symbol.iconOffset = PointF(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)
|
||||
symbol.iconImage = id
|
||||
}
|
||||
}
|
||||
|
||||
class ColorBitmapDescriptorImpl(id: String, size: FloatArray, val hue: Float) : BitmapDescriptorImpl(id, size) {
|
||||
override fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions = super.applyTo(options, anchor, dpiFactor).withIconColor(ColorUtils.colorToRgbaString(Color.HSVToColor(floatArrayOf(hue, 1.0f, 0.5f))))
|
||||
override fun applyTo(symbol: Symbol, anchor: FloatArray, dpiFactor: Float) {
|
||||
super.applyTo(symbol, anchor, dpiFactor)
|
||||
symbol.setIconColor(Color.HSVToColor(floatArrayOf(hue, 1.0f, 0.5f)))
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.model
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.dynamic.ObjectWrapper
|
||||
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
|
||||
object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {
|
||||
private val TAG = "GmsMapBitmap"
|
||||
private var resources: Resources? = null
|
||||
private val maps = hashSetOf<MapboxMap>()
|
||||
private val bitmaps = hashMapOf<String, Bitmap>()
|
||||
|
||||
fun initialize(resources: Resources) {
|
||||
BitmapDescriptorFactoryImpl.resources = resources
|
||||
}
|
||||
|
||||
fun registerMap(map: MapboxMap) {
|
||||
map.getStyle {
|
||||
it.addImages(bitmaps)
|
||||
maps.add(map)
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterMap(map: MapboxMap?) {
|
||||
maps.remove(map)
|
||||
// TODO: cleanup bitmaps?
|
||||
}
|
||||
|
||||
fun bitmapSize(id: String): FloatArray =
|
||||
bitmaps[id]?.let { floatArrayOf(it.width.toFloat(), it.height.toFloat()) }
|
||||
?: floatArrayOf(0f, 0f)
|
||||
|
||||
private fun registerBitmap(id: String, bitmapCreator: () -> Bitmap?) {
|
||||
if (bitmaps.contains(id)) return
|
||||
val bitmap = bitmapCreator() ?: return
|
||||
bitmaps[id] = bitmap
|
||||
for (map in maps) {
|
||||
map.getStyle { it.addImage(id, bitmap) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun fromResource(resourceId: Int): IObjectWrapper? {
|
||||
val id = "resource-$resourceId"
|
||||
registerBitmap(id) { BitmapFactory.decodeResource(resources, resourceId) }
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl(id, bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun fromAsset(assetName: String): IObjectWrapper? {
|
||||
val id = "asset-$assetName"
|
||||
registerBitmap(id) { resources?.assets?.open(assetName)?.let { BitmapFactory.decodeStream(it) } }
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl(id, bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun fromFile(fileName: String): IObjectWrapper? {
|
||||
val id = "file-$fileName"
|
||||
registerBitmap(id) { BitmapFactory.decodeFile(fileName) }
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl(id, bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun defaultMarker(): IObjectWrapper? {
|
||||
Log.d(TAG, "unimplemented Method: defaultMarker")
|
||||
val id = "marker"
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl("marker", bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun defaultMarkerWithHue(hue: Float): IObjectWrapper? {
|
||||
val id = "marker"
|
||||
Log.d(TAG, "unimplemented Method: defaultMarkerWithHue")
|
||||
return ObjectWrapper.wrap(ColorBitmapDescriptorImpl("marker", bitmapSize(id), hue))
|
||||
}
|
||||
|
||||
override fun fromBitmap(bitmap: Bitmap): IObjectWrapper? {
|
||||
val id = "bitmap-${bitmap.hashCode()}"
|
||||
registerBitmap(id) { bitmap }
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl(id, bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun fromPath(absolutePath: String): IObjectWrapper? {
|
||||
val id = "path-$absolutePath"
|
||||
registerBitmap(id) { BitmapFactory.decodeFile(absolutePath) }
|
||||
return ObjectWrapper.wrap(BitmapDescriptorImpl(id, bitmapSize(id)))
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.internal.ICircleDelegate
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.Circle
|
||||
import org.microg.gms.maps.mapbox.GoogleMapImpl
|
||||
import org.microg.gms.maps.mapbox.utils.toGms
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
class CircleImpl(private val map: GoogleMapImpl, private val circle: Circle) : ICircleDelegate.Stub() {
|
||||
override fun remove() {
|
||||
map.circleManager?.delete(circle)
|
||||
}
|
||||
|
||||
override fun getId(): String = "c" + circle.id.toString()
|
||||
|
||||
override fun setCenter(center: LatLng) {
|
||||
circle.latLng = center.toMapbox()
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun getCenter(): LatLng = circle.latLng.toGms()
|
||||
|
||||
override fun setRadius(radius: Double) {
|
||||
circle.circleRadius = radius.toFloat()
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun getRadius(): Double = circle.circleRadius.toDouble()
|
||||
|
||||
override fun setStrokeWidth(width: Float) {
|
||||
circle.circleStrokeWidth = width / map.dpiFactor
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun getStrokeWidth(): Float = circle.circleStrokeWidth * map.dpiFactor
|
||||
|
||||
override fun setStrokeColor(color: Int) {
|
||||
circle.setCircleStrokeColor(color)
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun getStrokeColor(): Int = circle.circleStrokeColorAsInt
|
||||
|
||||
override fun setFillColor(color: Int) {
|
||||
circle.setCircleColor(color)
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun getFillColor(): Int = circle.circleColorAsInt
|
||||
|
||||
override fun setZIndex(zIndex: Float) {
|
||||
Log.d(TAG, "unimplemented Method: setZIndex")
|
||||
}
|
||||
|
||||
override fun getZIndex(): Float {
|
||||
Log.d(TAG, "unimplemented Method: getZIndex")
|
||||
return 0f
|
||||
}
|
||||
|
||||
override fun setVisible(visible: Boolean) {
|
||||
circle.circleOpacity = if (visible) 1f else 0f
|
||||
circle.circleStrokeOpacity = if (visible) 1f else 0f
|
||||
map.circleManager?.update(circle)
|
||||
}
|
||||
|
||||
override fun isVisible(): Boolean = circle.circleOpacity != 0f || circle.circleStrokeOpacity != 0f
|
||||
|
||||
override fun equalsRemote(other: ICircleDelegate?): Boolean = equals(other)
|
||||
|
||||
override fun hashCodeRemote(): Int = hashCode()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is CircleImpl) {
|
||||
return other.circle == circle
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = "GmsMapCircle"
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.model
|
||||
|
||||
import android.util.Log
|
||||
import com.google.android.gms.dynamic.IObjectWrapper
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.internal.IMarkerDelegate
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.Symbol
|
||||
import org.microg.gms.kotlin.unwrap
|
||||
import org.microg.gms.maps.mapbox.GoogleMapImpl
|
||||
import org.microg.gms.maps.mapbox.utils.toGms
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
class MarkerImpl(private val map: GoogleMapImpl,
|
||||
private val symbol: Symbol,
|
||||
private var anchor: FloatArray,
|
||||
private var icon: BitmapDescriptorImpl?,
|
||||
private var alpha: Float = symbol.iconOpacity,
|
||||
private var title: String? = null,
|
||||
private var snippet: String? = null) : IMarkerDelegate.Stub() {
|
||||
private var tag: IObjectWrapper? = null
|
||||
|
||||
override fun remove() {
|
||||
map.symbolManager?.delete(symbol)
|
||||
map.markers.remove(symbol.id)
|
||||
}
|
||||
|
||||
override fun getId(): String = "m" + symbol.id.toString()
|
||||
|
||||
override fun setPosition(pos: LatLng?) {
|
||||
pos?.let { symbol.latLng = it.toMapbox() }
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun getPosition(): LatLng = symbol.latLng.toGms()
|
||||
|
||||
override fun setTitle(title: String?) {
|
||||
this.title = title
|
||||
}
|
||||
|
||||
override fun getTitle(): String? = title
|
||||
|
||||
override fun setSnippet(snippet: String?) {
|
||||
this.snippet = snippet
|
||||
}
|
||||
|
||||
override fun getSnippet(): String? = snippet
|
||||
|
||||
override fun setDraggable(drag: Boolean) {
|
||||
symbol.isDraggable = drag
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun isDraggable(): Boolean = symbol.isDraggable
|
||||
|
||||
override fun showInfoWindow() {
|
||||
Log.d(TAG, "unimplemented Method: showInfoWindow")
|
||||
}
|
||||
|
||||
override fun hideInfoWindow() {
|
||||
Log.d(TAG, "unimplemented Method: hideInfoWindow")
|
||||
}
|
||||
|
||||
override fun isInfoWindowShown(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isInfoWindowShow")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setVisible(visible: Boolean) {
|
||||
symbol.iconOpacity = if (visible) 0f else alpha
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun isVisible(): Boolean = symbol.iconOpacity != 0f
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is IMarkerDelegate) return other.id == id
|
||||
return false
|
||||
}
|
||||
|
||||
override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other)
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$id ($title)"
|
||||
}
|
||||
|
||||
override fun hashCodeRemote(): Int = hashCode()
|
||||
|
||||
override fun setIcon(obj: IObjectWrapper?) {
|
||||
obj.unwrap<BitmapDescriptorImpl>()?.let { icon = it }
|
||||
icon?.applyTo(symbol, anchor, map.dpiFactor)
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun setAnchor(x: Float, y: Float) {
|
||||
anchor = floatArrayOf(x, y)
|
||||
icon?.applyTo(symbol, anchor, map.dpiFactor)
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun setFlat(flat: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setFlat")
|
||||
}
|
||||
|
||||
override fun isFlat(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isFlat")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRotation(rotation: Float) {
|
||||
symbol.iconRotate = rotation
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun getRotation(): Float = symbol.iconRotate
|
||||
|
||||
override fun setInfoWindowAnchor(x: Float, y: Float) {
|
||||
Log.d(TAG, "unimplemented Method: setInfoWindowAnchor")
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Float) {
|
||||
this.alpha = alpha
|
||||
symbol.iconOpacity = alpha
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun getAlpha(): Float = alpha
|
||||
|
||||
override fun setZIndex(zIndex: Float) {
|
||||
var intBits = java.lang.Float.floatToIntBits(zIndex)
|
||||
if (intBits < 0) intBits = intBits xor 0x7fffffff
|
||||
symbol.zIndex = intBits
|
||||
map.symbolManager?.update(symbol)
|
||||
}
|
||||
|
||||
override fun getZIndex(): Float {
|
||||
var intBits = symbol.zIndex
|
||||
if (intBits < 0) intBits = intBits xor 0x7fffffff
|
||||
return java.lang.Float.intBitsToFloat(intBits)
|
||||
}
|
||||
|
||||
override fun setTag(obj: IObjectWrapper?) {
|
||||
this.tag = obj
|
||||
}
|
||||
|
||||
override fun getTag(): IObjectWrapper? = tag
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMapMarker"
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.util.Log
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.internal.IPolylineDelegate
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.Line
|
||||
import org.microg.gms.maps.mapbox.GoogleMapImpl
|
||||
import org.microg.gms.maps.mapbox.utils.toGms
|
||||
import org.microg.gms.maps.mapbox.utils.toMapbox
|
||||
|
||||
class PolylineImpl(private val map: GoogleMapImpl, private val line: Line) : IPolylineDelegate.Stub() {
|
||||
override fun remove() {
|
||||
map.lineManager?.delete(line)
|
||||
}
|
||||
|
||||
override fun getId(): String = "l" + line.id.toString()
|
||||
|
||||
override fun setPoints(points: MutableList<LatLng>) {
|
||||
line.latLngs = points.map { it.toMapbox() }
|
||||
map.lineManager?.update(line)
|
||||
}
|
||||
|
||||
override fun getPoints(): List<LatLng> = line.latLngs.map { it.toGms() }
|
||||
|
||||
override fun setWidth(width: Float) {
|
||||
line.lineWidth = width / map.dpiFactor
|
||||
map.lineManager?.update(line)
|
||||
}
|
||||
|
||||
override fun getWidth(): Float = line.lineWidth * map.dpiFactor
|
||||
|
||||
override fun setColor(color: Int) {
|
||||
line.setLineColor(color)
|
||||
map.lineManager?.update(line)
|
||||
}
|
||||
|
||||
override fun getColor(): Int = line.lineColorAsInt
|
||||
|
||||
override fun setZIndex(zIndex: Float) {
|
||||
Log.d(TAG, "unimplemented Method: setZIndex")
|
||||
}
|
||||
|
||||
override fun getZIndex(): Float {
|
||||
Log.d(TAG, "unimplemented Method: getZIndex")
|
||||
return 0f
|
||||
}
|
||||
|
||||
override fun setVisible(visible: Boolean) {
|
||||
line.lineOpacity = if (visible) 1f else 0f
|
||||
map.lineManager?.update(line)
|
||||
}
|
||||
|
||||
override fun isVisible(): Boolean = line.lineOpacity != 0f
|
||||
|
||||
override fun setGeodesic(geod: Boolean) {
|
||||
Log.d(TAG, "unimplemented Method: setGeodesic")
|
||||
}
|
||||
|
||||
override fun isGeodesic(): Boolean {
|
||||
Log.d(TAG, "unimplemented Method: isGeodesic")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun equalsRemote(other: IPolylineDelegate?): Boolean = equals(other)
|
||||
|
||||
override fun hashCodeRemote(): Int = hashCode()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is PolylineImpl) {
|
||||
return other.line == line
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
|
||||
if (super.onTransact(code, data, reply, flags)) {
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMapPolyline"
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.view.LayoutInflater
|
||||
import org.microg.gms.common.Constants
|
||||
import java.io.File
|
||||
|
||||
class MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE and Context.CONTEXT_IGNORE_SECURITY)) {
|
||||
private var layoutInflater: LayoutInflater? = null
|
||||
private val appContext: Context
|
||||
get() = context.applicationContext ?: context
|
||||
|
||||
override fun getApplicationContext(): Context {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getCacheDir(): File {
|
||||
val cacheDir = File(appContext.cacheDir, "com.google.android.gms")
|
||||
cacheDir.mkdirs()
|
||||
return cacheDir
|
||||
}
|
||||
|
||||
override fun getFilesDir(): File {
|
||||
val filesDir = File(appContext.filesDir, "com.google.android.gms")
|
||||
filesDir.mkdirs()
|
||||
return filesDir
|
||||
}
|
||||
|
||||
override fun getPackageName(): String {
|
||||
return appContext.packageName
|
||||
}
|
||||
|
||||
override fun getClassLoader(): ClassLoader {
|
||||
return MapContext::class.java.classLoader
|
||||
}
|
||||
|
||||
override fun getSharedPreferences(name: String?, mode: Int): SharedPreferences {
|
||||
return appContext.getSharedPreferences("com.google.android.gms_$name", mode)
|
||||
}
|
||||
|
||||
override fun getSystemService(name: String): Any? {
|
||||
if (name == Context.LAYOUT_INFLATER_SERVICE) {
|
||||
if (layoutInflater == null) {
|
||||
layoutInflater = super.getSystemService(name) as LayoutInflater
|
||||
layoutInflater?.cloneInContext(this)?.let { layoutInflater = it }
|
||||
}
|
||||
if (layoutInflater != null) {
|
||||
return layoutInflater
|
||||
}
|
||||
}
|
||||
return context.getSystemService(name)
|
||||
}
|
||||
|
||||
override fun startActivity(intent: Intent?) {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = "GmsMapContext"
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.util.Log
|
||||
import com.mapbox.mapboxsdk.LibraryLoader
|
||||
import java.io.*
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
class MultiArchLoader(private val mapContext: Context, private val appContext: Context) : LibraryLoader() {
|
||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||
override fun load(name: String) {
|
||||
try {
|
||||
val otherAppInfo = mapContext.packageManager.getApplicationInfo(appContext.packageName, 0)
|
||||
val primaryCpuAbi = ApplicationInfo::class.java.getField("primaryCpuAbi").get(otherAppInfo) as String?
|
||||
if (primaryCpuAbi != null) {
|
||||
val path = "lib/$primaryCpuAbi/lib$name.so"
|
||||
val cacheFile = File("${appContext.cacheDir.absolutePath}/.gmscore/$path")
|
||||
cacheFile.parentFile.mkdirs()
|
||||
val apkFile = File(mapContext.packageCodePath)
|
||||
if (!cacheFile.exists() || cacheFile.lastModified() < apkFile.lastModified()) {
|
||||
val zipFile = ZipFile(apkFile)
|
||||
val entry = zipFile.getEntry(path)
|
||||
if (entry != null) {
|
||||
copyInputStream(zipFile.getInputStream(entry), FileOutputStream(cacheFile))
|
||||
} else {
|
||||
Log.d(TAG, "Can't load native library: $path does not exist in $apkFile")
|
||||
val entries = zipFile.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
Log.d(TAG, "but: ${entries.nextElement()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Loading $name from ${cacheFile.getPath()}")
|
||||
System.load(cacheFile.absolutePath)
|
||||
return
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
Log.d(TAG, "Loading native $name")
|
||||
System.loadLibrary(name)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun copyInputStream(inp: InputStream, out: OutputStream) {
|
||||
val buffer = ByteArray(1024)
|
||||
var len: Int = inp.read(buffer)
|
||||
while (len >= 0) {
|
||||
out.write(buffer, 0, len)
|
||||
len = inp.read(buffer)
|
||||
}
|
||||
|
||||
inp.close()
|
||||
out.close()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "GmsMultiArchLoader"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2019 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.maps.mapbox.utils
|
||||
|
||||
import android.os.Bundle
|
||||
import com.google.android.gms.maps.internal.ICancelableCallback
|
||||
import com.google.android.gms.maps.model.CircleOptions
|
||||
import com.google.android.gms.maps.model.MarkerOptions
|
||||
import com.google.android.gms.maps.model.PolylineOptions
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds
|
||||
import com.mapbox.mapboxsdk.geometry.VisibleRegion
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.LineOptions
|
||||
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
|
||||
import com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_TOP_LEFT
|
||||
import com.mapbox.mapboxsdk.utils.ColorUtils
|
||||
import org.microg.gms.kotlin.unwrap
|
||||
import org.microg.gms.maps.mapbox.model.BitmapDescriptorImpl
|
||||
|
||||
fun com.google.android.gms.maps.model.LatLng.toMapbox(): LatLng =
|
||||
LatLng(latitude, longitude)
|
||||
|
||||
fun com.google.android.gms.maps.model.LatLngBounds.toMapbox(): LatLngBounds =
|
||||
LatLngBounds.from(this.northeast.latitude, this.northeast.longitude, this.southwest.latitude, this.southwest.longitude)
|
||||
|
||||
fun com.google.android.gms.maps.model.CameraPosition.toMapbox(): CameraPosition =
|
||||
CameraPosition.Builder()
|
||||
.target(target.toMapbox())
|
||||
.zoom(zoom.toDouble() - 1.0)
|
||||
.tilt(tilt.toDouble())
|
||||
.bearing(bearing.toDouble())
|
||||
.build()
|
||||
|
||||
fun ICancelableCallback.toMapbox(): MapboxMap.CancelableCallback =
|
||||
object : MapboxMap.CancelableCallback {
|
||||
override fun onFinish() = this@toMapbox.onFinish()
|
||||
override fun onCancel() = this@toMapbox.onCancel()
|
||||
}
|
||||
|
||||
|
||||
fun Bundle.toMapbox(): Bundle {
|
||||
val newBundle = Bundle(this)
|
||||
for (key in newBundle.keySet()) {
|
||||
val value = newBundle.get(key)
|
||||
when (value) {
|
||||
is com.google.android.gms.maps.model.CameraPosition -> newBundle.putParcelable(key, value.toMapbox())
|
||||
is com.google.android.gms.maps.model.LatLng -> newBundle.putParcelable(key, value.toMapbox())
|
||||
is com.google.android.gms.maps.model.LatLngBounds -> newBundle.putParcelable(key, value.toMapbox())
|
||||
is Bundle -> newBundle.putBundle(key, value.toMapbox())
|
||||
}
|
||||
}
|
||||
return newBundle
|
||||
}
|
||||
|
||||
fun LatLng.toGms(): com.google.android.gms.maps.model.LatLng =
|
||||
com.google.android.gms.maps.model.LatLng(latitude, longitude)
|
||||
|
||||
fun LatLngBounds.toGms(): com.google.android.gms.maps.model.LatLngBounds =
|
||||
com.google.android.gms.maps.model.LatLngBounds(southWest.toGms(), northEast.toGms())
|
||||
|
||||
fun CameraPosition.toGms(): com.google.android.gms.maps.model.CameraPosition =
|
||||
com.google.android.gms.maps.model.CameraPosition(target.toGms(), zoom.toFloat() + 1.0f, tilt.toFloat(), bearing.toFloat())
|
||||
|
||||
fun Bundle.toGms(): Bundle {
|
||||
val newBundle = Bundle(this)
|
||||
for (key in newBundle.keySet()) {
|
||||
val value = newBundle.get(key)
|
||||
when (value) {
|
||||
is CameraPosition -> newBundle.putParcelable(key, value.toGms())
|
||||
is LatLng -> newBundle.putParcelable(key, value.toGms())
|
||||
is LatLngBounds -> newBundle.putParcelable(key, value.toGms())
|
||||
is Bundle -> newBundle.putBundle(key, value.toGms())
|
||||
}
|
||||
}
|
||||
return newBundle
|
||||
}
|
||||
|
||||
fun VisibleRegion.toGms(): com.google.android.gms.maps.model.VisibleRegion =
|
||||
com.google.android.gms.maps.model.VisibleRegion(nearLeft.toGms(), nearRight.toGms(), farLeft.toGms(), farRight.toGms(), latLngBounds.toGms())
|
@ -17,6 +17,7 @@ include ':play-services-base'
|
||||
include ':play-services-tasks'
|
||||
include ':play-services-wearable'
|
||||
|
||||
include ':play-services-maps-core-mapbox'
|
||||
include ':play-services-maps-core-vtm'
|
||||
include ':play-services-core'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user