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'