diff --git a/README.md b/README.md
index 4edd7774..b378765f 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle
index 33ba7e75..10fda962 100644
--- a/play-services-core/build.gradle
+++ b/play-services-core/build.gradle
@@ -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 {
diff --git a/play-services-maps-core-mapbox/build.gradle b/play-services-maps-core-mapbox/build.gradle
new file mode 100644
index 00000000..3bc8c6d0
--- /dev/null
+++ b/play-services-maps-core-mapbox/build.gradle
@@ -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'
+}
diff --git a/play-services-maps-core-mapbox/src/main/AndroidManifest.xml b/play-services-maps-core-mapbox/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..eef94459
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/play-services-maps-core-mapbox/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java b/play-services-maps-core-mapbox/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java
new file mode 100644
index 00000000..df0fb3e9
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java
@@ -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;
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt
new file mode 100644
index 00000000..654feca6
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraBoundsWithSizeUpdate.kt
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt
new file mode 100644
index 00000000..03e92de2
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/CameraUpdateFactory.kt
@@ -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"
+ }
+}
+
+
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt
new file mode 100644
index 00000000..2dd285a3
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt
@@ -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 LongSparseArray.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()
+ private val mapLock = Object()
+ val markers = mutableMapOf()
+
+ 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 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()?.let { map?.moveCamera(it) } ?: Unit
+
+ override fun animateCamera(cameraUpdate: IObjectWrapper?) =
+ cameraUpdate.unwrap()?.let { map?.animateCamera(it) } ?: Unit
+
+ override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) =
+ cameraUpdate.unwrap()?.let { map?.animateCamera(it, callback?.toMapbox()) }
+ ?: Unit
+
+ override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) =
+ cameraUpdate.unwrap()?.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()?.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(), 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 > 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"
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt
new file mode 100644
index 00000000..2ff4b485
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt
@@ -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"
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt
new file mode 100644
index 00000000..fe00f687
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt
@@ -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"
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt
new file mode 100644
index 00000000..11415456
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Projection.kt
@@ -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()?.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)))
+ }
+
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt
new file mode 100644
index 00000000..68e77c3d
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/UiSettings.kt
@@ -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"
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt
new file mode 100644
index 00000000..e228387d
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptor.kt
@@ -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)))
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt
new file mode 100644
index 00000000..39334ae8
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/BitmapDescriptorFactory.kt
@@ -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()
+ private val bitmaps = hashMapOf()
+
+ 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
+ }
+}
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt
new file mode 100644
index 00000000..b37cd9f8
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt
new file mode 100644
index 00000000..3132137e
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Marker.kt
@@ -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()?.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"
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt
new file mode 100644
index 00000000..46db6fcf
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt
@@ -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) {
+ line.latLngs = points.map { it.toMapbox() }
+ map.lineManager?.update(line)
+ }
+
+ override fun getPoints(): List = 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"
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt
new file mode 100644
index 00000000..0c454fbd
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MultiArchLoader.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MultiArchLoader.kt
new file mode 100644
index 00000000..a4882883
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MultiArchLoader.kt
@@ -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"
+ }
+
+}
\ No newline at end of file
diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt
new file mode 100644
index 00000000..c37e9709
--- /dev/null
+++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/typeConverter.kt
@@ -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())
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 70e7de8c..cf94adba 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -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'