From 73aca6ea10fb476ccc5bfd130460ee5a1babf8c6 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Mon, 1 Jul 2019 00:25:24 +0200 Subject: [PATCH] Various fixes and improvements to Maps API --- extern/GmsApi | 2 +- .../org/microg/gms/maps/mapbox/GoogleMap.kt | 398 +++++++++++++----- .../org/microg/gms/maps/mapbox/MapFragment.kt | 44 +- .../org/microg/gms/maps/mapbox/MapView.kt | 15 +- .../org/microg/gms/maps/mapbox/Projection.kt | 17 +- .../org/microg/gms/maps/mapbox/UiSettings.kt | 27 ++ .../mapbox/model/BitmapDescriptorFactory.kt | 16 +- .../microg/gms/maps/mapbox/model/Circle.kt | 76 ++-- .../microg/gms/maps/mapbox/model/Marker.kt | 121 ++++-- .../microg/gms/maps/mapbox/model/Markup.kt | 40 ++ .../microg/gms/maps/mapbox/model/Polygon.kt | 120 ++++++ .../microg/gms/maps/mapbox/model/Polyline.kt | 2 +- .../gms/maps/mapbox/utils/typeConverter.kt | 1 + .../microg/gms/maps/vtm/GoogleMapImpl.java | 87 +++- .../microg/gms/maps/vtm/MapFragmentImpl.java | 20 + .../org/microg/gms/maps/vtm/MapViewImpl.java | 20 + .../microg/gms/maps/vtm/UiSettingsImpl.java | 38 +- 17 files changed, 843 insertions(+), 201 deletions(-) create mode 100644 play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt create mode 100644 play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt diff --git a/extern/GmsApi b/extern/GmsApi index 7197b832..bfe649fc 160000 --- a/extern/GmsApi +++ b/extern/GmsApi @@ -1 +1 @@ -Subproject commit 7197b8320b4e6d55d15b76d4faf05adaba36bf72 +Subproject commit bfe649fc36a40e2498f1ecf123edfb9278fe0a1d 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 index c89e41aa..f809b4f4 100644 --- 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 @@ -16,18 +16,20 @@ package org.microg.gms.maps.mapbox +import android.annotation.SuppressLint 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.Gravity import android.view.View import android.widget.FrameLayout +import android.widget.RelativeLayout import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.maps.GoogleMapOptions import com.google.android.gms.maps.internal.* @@ -38,6 +40,7 @@ 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.constants.MapboxConstants import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Style @@ -53,9 +56,9 @@ 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 } +private fun LongSparseArray.values() = (0..size()).map { valueAt(it) }.mapNotNull { it } -class GoogleMapImpl(private val context: Context, private val options: GoogleMapOptions) : IGoogleMapDelegate.Stub() { +class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) : IGoogleMapDelegate.Stub() { val view: FrameLayout var map: MapboxMap? = null @@ -64,10 +67,10 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT private var mapView: MapView? + private var created = false 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 @@ -79,47 +82,130 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap private var markerClickListener: IOnMarkerClickListener? = null private var markerDragListener: IOnMarkerDragListener? = null - var circleManager: CircleManager? = null var lineManager: LineManager? = null var fillManager: FillManager? = null + + var circleManager: CircleManager? = null + val pendingCircles = mutableSetOf() + var circleId = 0L + var symbolManager: SymbolManager? = null - var storedMapType: Int = MAP_TYPE_NORMAL + val pendingMarkers = mutableSetOf() + val markers = mutableMapOf() + var markerId = 0L + + var storedMapType: Int = options.mapType + val waitingCameraUpdates = mutableListOf() init { val mapContext = MapContext(context) LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context)) Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY) + val fakeWatermark = View(mapContext) + fakeWatermark.layoutParams = object : RelativeLayout.LayoutParams(0, 0) { + @SuppressLint("RtlHardcoded") + override fun addRule(verb: Int, subject: Int) { + super.addRule(verb, subject) + val rules = this.rules + var gravity = 0 + if (rules[RelativeLayout.ALIGN_PARENT_BOTTOM] == RelativeLayout.TRUE) gravity = gravity or Gravity.BOTTOM + if (rules[RelativeLayout.ALIGN_PARENT_TOP] == RelativeLayout.TRUE) gravity = gravity or Gravity.TOP + if (rules[RelativeLayout.ALIGN_PARENT_LEFT] == RelativeLayout.TRUE) gravity = gravity or Gravity.LEFT + if (rules[RelativeLayout.ALIGN_PARENT_RIGHT] == RelativeLayout.TRUE) gravity = gravity or Gravity.RIGHT + if (rules[RelativeLayout.ALIGN_PARENT_START] == RelativeLayout.TRUE) gravity = gravity or Gravity.START + if (rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE) gravity = gravity or Gravity.END + map?.uiSettings?.logoGravity = gravity + } + } this.view = object : FrameLayout(mapContext) { @Keep fun findViewTraversal(@IdRes id: Int): T? { return null } + + @Keep + fun findViewWithTagTraversal(tag: Any): T? { + if ("GoogleWatermark" == tag) { + return try { + @Suppress("UNCHECKED_CAST") + fakeWatermark as T + } catch (e: ClassCastException) { + null + } + } + 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 getMaxZoomLevel(): Float = (map?.maxZoomLevel?.toFloat() ?: 20f) + 1f + override fun getMinZoomLevel(): Float = (map?.minZoomLevel?.toFloat() ?: 0f) + 1f - override fun moveCamera(cameraUpdate: IObjectWrapper?) = - cameraUpdate.unwrap()?.let { map?.moveCamera(it) } ?: Unit + override fun moveCamera(cameraUpdate: IObjectWrapper?) { + val update = cameraUpdate.unwrap() ?: return + val map = this.map + if (map != null) { + map.moveCamera(update) + } else { + waitingCameraUpdates.add(update) + } + } - override fun animateCamera(cameraUpdate: IObjectWrapper?) = - cameraUpdate.unwrap()?.let { map?.animateCamera(it) } ?: Unit + override fun animateCamera(cameraUpdate: IObjectWrapper?) { + val update = cameraUpdate.unwrap() ?: return + val map = this.map + if (map != null) { + map.animateCamera(update) + } else { + waitingCameraUpdates.add(update) + } + } - override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) = - cameraUpdate.unwrap()?.let { map?.animateCamera(it, callback?.toMapbox()) } - ?: Unit + override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) { + val update = cameraUpdate.unwrap() ?: return + val map = this.map + if (map != null) { + map.animateCamera(update, callback?.toMapbox()) + } else { + waitingCameraUpdates.add(update) + callback?.onFinish() + } + } - override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) = - cameraUpdate.unwrap()?.let { map?.animateCamera(it, duration, callback?.toMapbox()) } - ?: Unit + override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) { + val update = cameraUpdate.unwrap() ?: return + val map = this.map + if (map != null) { + map.animateCamera(update, duration, callback?.toMapbox()) + } else { + waitingCameraUpdates.add(update) + callback?.onFinish() + } + } override fun stopAnimation() = map?.cancelTransitions() ?: Unit + override fun setMinZoomPreference(minZoom: Float) { + map?.setMinZoomPreference(minZoom.toDouble() - 1) + } + + override fun setMaxZoomPreference(maxZoom: Float) { + map?.setMaxZoomPreference(maxZoom.toDouble() - 1) + } + + override fun resetMinMaxZoomPreference() { + map?.setMinZoomPreference(MapboxConstants.MINIMUM_ZOOM.toDouble()) + map?.setMaxZoomPreference(MapboxConstants.MAXIMUM_ZOOM.toDouble()) + } + + override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) { + map?.setLatLngBoundsForCameraTarget(bounds?.toMapbox()) + } + override fun addPolyline(options: PolylineOptions): IPolylineDelegate? { val lineOptions = LineOptions() .withLatLngs(options.points.map { it.toMapbox() }) @@ -131,26 +217,23 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap override fun addPolygon(options: PolygonOptions): IPolygonDelegate? { - Log.d(TAG, "unimplemented Method: addPolygon") - return null + val fillOptions = FillOptions() + .withLatLngs(listOf(options.points.map { it.toMapbox() })) + .withFillColor(ColorUtils.colorToRgbaString(options.fillColor)) + .withFillOpacity(if (options.isVisible) 1f else 0f) + return fillManager?.let { PolygonImpl(this, it.create(fillOptions)) } } 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) + val marker = MarkerImpl(this, "m${markerId++}", options) + synchronized(this) { + val symbolManager = symbolManager + if (symbolManager == null) { + pendingMarkers.add(marker) + } else { + marker.update(symbolManager) + } + } return marker } @@ -165,16 +248,16 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap } 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)) } + val circle = CircleImpl(this, "c${circleId++}", options) + synchronized(this) { + val circleManager = circleManager + if (circleManager == null) { + pendingCircles.add(circle) + } else { + circle.update(circleManager) + } + } + return circle } override fun clear() { @@ -208,20 +291,27 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap 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) } + circles?.let { runCatching { circleManager?.update(it) } } + lines?.let { runCatching { lineManager?.update(it) } } + fills?.let { runCatching { fillManager?.update(it) } } + symbols?.let { runCatching { symbolManager?.update(it) } } } + // TODO: Serve map styles locally 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_SATELLITE -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update) MAP_TYPE_TERRAIN -> map?.setStyle(Style.OUTDOORS, update) - MAP_TYPE_HYBRID -> map?.setStyle(Style.SATELLITE_STREETS, update) - else -> map?.setStyle(Style.LIGHT, update) + MAP_TYPE_HYBRID -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update) + //MAP_TYPE_NONE, MAP_TYPE_NORMAL, + else -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"), update) } + map?.let { BitmapDescriptorFactoryImpl.registerMap(it) } + + } + + override fun setWatermarkEnabled(watermark: Boolean) { + map?.uiSettings?.isLogoEnabled = watermark } override fun isTrafficEnabled(): Boolean { @@ -261,7 +351,10 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap override fun setLocationSource(locationSource: ILocationSourceDelegate) { Log.d(TAG, "unimplemented Method: setLocationSource") + } + override fun setContentDescription(desc: String?) { + mapView?.contentDescription = desc } override fun getUiSettings(): IUiSettingsDelegate? = map?.uiSettings?.let { UiSettingsImpl(it) } @@ -360,80 +453,159 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap cameraIdleListener = listener } - fun onCreate(savedInstanceState: Bundle?) { - mapView?.onCreate(savedInstanceState?.toMapbox()) - mapView?.getMapAsync(this::initMap) + override fun onCreate(savedInstanceState: Bundle?) { + if (!created) { + mapView?.onCreate(savedInstanceState?.toMapbox()) + mapView?.getMapAsync(this::initMap) + created = true + } } 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() + return features.isNotEmpty() } private fun initMap(map: MapboxMap) { if (this.map != null) return this.map = map + map.addOnCameraIdleListener { + try { + cameraChangeListener?.onCameraChange(map.cameraPosition.toGms()) + } catch (e: Exception) { + Log.w(TAG, e) + } + } + map.addOnCameraIdleListener { + try { + cameraIdleListener?.onCameraIdle() + } catch (e: Exception) { + Log.w(TAG, e) + } + } + map.addOnCameraMoveListener { + try { + cameraMoveListener?.onCameraMove() + } catch (e: Exception) { + Log.w(TAG, e) + } + } + map.addOnCameraMoveStartedListener { + try { + cameraMoveStartedListener?.onCameraMoveStarted(it) + } catch (e: Exception) { + Log.w(TAG, e) + } + } + map.addOnCameraMoveCancelListener { + try { + cameraMoveCanceledListener?.onCameraMoveCanceled() + } catch (e: Exception) { + Log.w(TAG, e) + } + } + map.addOnMapClickListener { latlng -> + try { + mapClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapClick(latlng.toGms()); } + } catch (e: Exception) { + Log.w(TAG, e) + } + false + } + map.addOnMapLongClickListener { latlng -> + try { + mapLongClickListener?.let { if (!hasSymbolAt(latlng)) it.onMapLongClick(latlng.toGms()); } + } catch (e: Exception) { + Log.w(TAG, e) + } + false + } + applyMapType() + options.minZoomPreference?.let { if (it != 0f) map.setMinZoomPreference(it.toDouble()) } + options.maxZoomPreference?.let { if (it != 0f) map.setMaxZoomPreference(it.toDouble()) } + options.latLngBoundsForCameraTarget?.let { map.setLatLngBoundsForCameraTarget(it.toMapbox()) } + options.compassEnabled?.let { map.uiSettings.isCompassEnabled = it } + options.rotateGesturesEnabled?.let { map.uiSettings.isRotateGesturesEnabled = it } + options.scrollGesturesEnabled?.let { map.uiSettings.isScrollGesturesEnabled = it } + options.tiltGesturesEnabled?.let { map.uiSettings.isTiltGesturesEnabled = it } + options.camera?.let { map.cameraPosition = it.toMapbox() } + waitingCameraUpdates.forEach { map.moveCamera(it) } + + synchronized(mapLock) { + Log.d(TAG, "Invoking ${initializedCallbackList.size} callbacks delayed, as map is initialized") + for (callback in initializedCallbackList) { + try { + callback.onMapReady(this) + } catch (e: Exception) { + Log.w(TAG, e) + } + } + initialized = true + } + 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) + lineManager?.lineCap = LINE_CAP_ROUND + synchronized(this) { + val symbolManager = SymbolManager(view, map, it) + pendingMarkers.forEach { it.update(symbolManager) } + pendingMarkers.clear() + this.symbolManager = symbolManager + } symbolManager?.iconAllowOverlap = true - symbolManager?.addClickListener { markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } } + symbolManager?.addClickListener { + try { + markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } + } catch (e: Exception) { + Log.w(TAG, e) + } + } 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) { + markers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) } + } catch (e: Exception) { Log.w(TAG, e) } } - initialized = true - } + + override fun onAnnotationDrag(annotation: Symbol?) { + try { + markers[annotation?.id]?.let { markerDragListener?.onMarkerDrag(it) } + } catch (e: Exception) { + Log.w(TAG, e) + } + } + + override fun onAnnotationDragFinished(annotation: Symbol?) { + try { + markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) } + } catch (e: Exception) { + Log.w(TAG, e) + } + } + + }) + } } } - fun onResume() = mapView?.onResume() - fun onPause() = mapView?.onPause() - fun onDestroy() { + override fun useViewLifecycleWhenInFragment(): Boolean { + Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment") + return false + } + + override fun onResume() = mapView?.onResume() ?: Unit + override fun onPause() = mapView?.onPause() ?: Unit + override fun onDestroy() { circleManager?.onDestroy() circleManager = null lineManager?.onDestroy() @@ -442,6 +614,8 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap fillManager = null symbolManager?.onDestroy() symbolManager = null + pendingMarkers.clear() + markers.clear() BitmapDescriptorFactoryImpl.unregisterMap(map) view.removeView(mapView) // TODO can crash? @@ -449,8 +623,24 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap mapView = null } - fun onLowMemory() = mapView?.onLowMemory() - fun onSaveInstanceState(outState: Bundle) { + override fun onStart() { + Log.d(TAG, "unimplemented Method: onStart") + } + + override fun onStop() { + Log.d(TAG, "unimplemented Method: onStop") + } + + override fun onEnterAmbient(bundle: Bundle?) { + Log.d(TAG, "unimplemented Method: onEnterAmbient") + } + + override fun onExitAmbient() { + Log.d(TAG, "unimplemented Method: onExitAmbient") + } + + override fun onLowMemory() = mapView?.onLowMemory() ?: Unit + override fun onSaveInstanceState(outState: Bundle) { val newBundle = Bundle() mapView?.onSaveInstanceState(newBundle) outState.putAll(newBundle.toGms()) @@ -459,8 +649,14 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap fun getMapAsync(callback: IOnMapReadyCallback) { synchronized(mapLock) { if (initialized) { - callback.onMapReady(this) + Log.d(TAG, "Invoking callback instantly, as map is initialized") + try { + callback.onMapReady(this) + } catch (e: Exception) { + Log.w(TAG, e) + } } else { + Log.d(TAG, "Delay callback invocation, as map is not yet initialized") initializedCallbackList.add(callback) } } 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 index 2c9b7dab..78636e93 100644 --- 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 @@ -19,7 +19,9 @@ package org.microg.gms.maps.mapbox import android.app.Activity import android.os.Bundle import android.os.Parcel +import android.util.Base64 import android.util.Log +import android.view.View import android.view.ViewGroup import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.ObjectWrapper @@ -34,32 +36,42 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu private var options: GoogleMapOptions? = null override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle) { + Log.d(TAG, "onInflate: ${options.camera.target}") this.options = options + map?.options = options } - override fun onCreate(savedInstanceState: Bundle) { + override fun onCreate(savedInstanceState: Bundle?) { if (options == null) { - options = savedInstanceState.getParcelable("MapOptions") + options = savedInstanceState?.getParcelable("MapOptions") } if (options == null) { options = GoogleMapOptions() } + Log.d(TAG, "onCreate: ${options?.camera?.target}") + map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) } override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper { + if (options == null) { + options = savedInstanceState?.getParcelable("MapOptions") + } + Log.d(TAG, "onCreateView: ${options?.camera?.target}") 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) } + map!!.onCreate(savedInstanceState) + val view = map!!.view + val parent = view.parent as ViewGroup? + parent?.removeView(view) + return ObjectWrapper.wrap(view) } override fun getMap(): IGoogleMapDelegate? = map + override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit + override fun onExitAmbient() = map?.onExitAmbient() ?: Unit + override fun onStart() = map?.onStart() ?: Unit + override fun onStop() = map?.onStop() ?: Unit override fun onResume() = map?.onResume() ?: Unit override fun onPause() = map?.onPause() ?: Unit override fun onLowMemory() = map?.onLowMemory() ?: Unit @@ -84,12 +96,14 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu 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 - } + override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean { + if (super.onTransact(code, data, reply, flags)) { + return true + } else { + Log.d(TAG, "onTransact [unknown]: $code, $data, $flags") + return 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 index 70d1b831..572eba6f 100644 --- 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 @@ -28,25 +28,28 @@ 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 val options: GoogleMapOptions = options ?: GoogleMapOptions() private var map: GoogleMapImpl? = null - init { - this.options = options ?: GoogleMapOptions() - } - override fun onCreate(savedInstanceState: Bundle?) { + Log.d(TAG, "onCreate: ${options?.camera?.target}") map = GoogleMapImpl(context, options) - map?.onCreate(savedInstanceState) + map!!.onCreate(savedInstanceState) } override fun getMap(): IGoogleMapDelegate? = map + override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit + override fun onExitAmbient() = map?.onExitAmbient() ?: Unit + override fun onStart() = map?.onStart() ?: Unit + override fun onStop() = map?.onStop() ?: Unit 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) 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 index 11415456..e27be03a 100644 --- 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 @@ -30,16 +30,21 @@ import org.microg.gms.maps.mapbox.utils.toGms import org.microg.gms.maps.mapbox.utils.toMapbox class ProjectionImpl(private val projection: Projection) : IProjectionDelegate.Stub() { + private val visibleRegion = projection.visibleRegion + private val farLeft = projection.toScreenLocation(visibleRegion.farLeft) + private val farRight = projection.toScreenLocation(visibleRegion.farRight) + private val nearLeft = projection.toScreenLocation(visibleRegion.nearLeft) + private val nearRight = projection.toScreenLocation(visibleRegion.nearRight) + 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() + override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try { + ObjectWrapper.wrap(latLng?.toMapbox()?.let { projection.toScreenLocation(it) }?.let { Point(it.x.toInt(), it.y.toInt()) }) } catch (e: Exception) { - VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0))) + ObjectWrapper.wrap(Point(0, 0)) } + override fun getVisibleRegion(): VisibleRegion = visibleRegion.toGms() + } \ 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 index 68e77c3d..abc1ddab 100644 --- 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 @@ -78,6 +78,33 @@ class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.S override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled + override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) { + Log.d(TAG, "unimplemented Method: setIndoorLevelPickerEnabled") + } + + override fun isIndoorLevelPickerEnabled(): Boolean { + Log.d(TAG, "unimplemented Method: isIndoorLevelPickerEnabled") + return false + } + + override fun setMapToolbarEnabled(mapToolbar: Boolean) { + Log.d(TAG, "unimplemented Method: setMapToolbarEnabled") + } + + override fun isMapToolbarEnabled(): Boolean { + Log.d(TAG, "unimplemented Method: isMapToolbarEnabled") + return false + } + + override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) { + Log.d(TAG, "unimplemented Method: setScrollGesturesEnabledDuringRotateOrZoom") + } + + override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean { + Log.d(TAG, "unimplemented Method: isScrollGesturesEnabledDuringRotateOrZoom") + return true + } + override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean = if (super.onTransact(code, data, reply, flags)) { true 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 index 39334ae8..bf5cf153 100644 --- 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 @@ -37,10 +37,13 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() { } fun registerMap(map: MapboxMap) { + Log.d(TAG, "registerMap") map.getStyle { - it.addImages(bitmaps) - maps.add(map) + synchronized(bitmaps) { + it.addImages(bitmaps) + } } + maps.add(map) } fun unregisterMap(map: MapboxMap?) { @@ -53,9 +56,12 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() { ?: floatArrayOf(0f, 0f) private fun registerBitmap(id: String, bitmapCreator: () -> Bitmap?) { - if (bitmaps.contains(id)) return - val bitmap = bitmapCreator() ?: return - bitmaps[id] = bitmap + val bitmap = synchronized(bitmaps) { + if (bitmaps.contains(id)) return + val bitmap = bitmapCreator() ?: return + bitmaps[id] = bitmap + bitmap + } for (map in maps) { map.getStyle { it.addImage(id, bitmap) } } 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 index b37cd9f8..90c4309e 100644 --- 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 @@ -21,51 +21,78 @@ 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 com.mapbox.mapboxsdk.plugins.annotation.CircleOptions +import com.mapbox.mapboxsdk.utils.ColorUtils import org.microg.gms.maps.mapbox.GoogleMapImpl -import org.microg.gms.maps.mapbox.utils.toGms import org.microg.gms.maps.mapbox.utils.toMapbox +import com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions + +class CircleImpl(private val map: GoogleMapImpl, private val id: String, options: GmsCircleOptions) : ICircleDelegate.Stub(), Markup { + private var center: LatLng = options.center + private var radius: Double = options.radius + private var strokeWidth: Float = options.strokeWidth + private var strokeColor: Int = options.strokeColor + private var fillColor: Int = options.fillColor + private var visible: Boolean = options.isVisible + + override var annotation: Circle? = null + override var removed: Boolean = false + override val annotationOptions: CircleOptions + get() = CircleOptions() + .withLatLng(center.toMapbox()) + .withCircleColor(ColorUtils.colorToRgbaString(fillColor)) + .withCircleRadius(radius.toFloat()) + .withCircleStrokeColor(ColorUtils.colorToRgbaString(strokeColor)) + .withCircleStrokeWidth(strokeWidth / map.dpiFactor) + .withCircleOpacity(if (visible) 1f else 0f) + .withCircleStrokeOpacity(if (visible) 1f else 0f) -class CircleImpl(private val map: GoogleMapImpl, private val circle: Circle) : ICircleDelegate.Stub() { override fun remove() { - map.circleManager?.delete(circle) + removed = true + map.circleManager?.let { update(it) } } - override fun getId(): String = "c" + circle.id.toString() + override fun getId(): String = id override fun setCenter(center: LatLng) { - circle.latLng = center.toMapbox() - map.circleManager?.update(circle) + this.center = center + annotation?.latLng = center.toMapbox() + map.circleManager?.let { update(it) } } - override fun getCenter(): LatLng = circle.latLng.toGms() + override fun getCenter(): LatLng = center override fun setRadius(radius: Double) { - circle.circleRadius = radius.toFloat() - map.circleManager?.update(circle) + this.radius = radius + annotation?.circleRadius = radius.toFloat() + map.circleManager?.let { update(it) } } - override fun getRadius(): Double = circle.circleRadius.toDouble() + override fun getRadius(): Double = radius override fun setStrokeWidth(width: Float) { - circle.circleStrokeWidth = width / map.dpiFactor - map.circleManager?.update(circle) + this.strokeWidth = width + annotation?.circleStrokeWidth = width / map.dpiFactor + map.circleManager?.let { update(it) } } - override fun getStrokeWidth(): Float = circle.circleStrokeWidth * map.dpiFactor + override fun getStrokeWidth(): Float = strokeWidth override fun setStrokeColor(color: Int) { - circle.setCircleStrokeColor(color) - map.circleManager?.update(circle) + this.strokeColor = color + annotation?.setCircleStrokeColor(color) + map.circleManager?.let { update(it) } } - override fun getStrokeColor(): Int = circle.circleStrokeColorAsInt + override fun getStrokeColor(): Int = strokeColor override fun setFillColor(color: Int) { - circle.setCircleColor(color) - map.circleManager?.update(circle) + this.fillColor = color + annotation?.setCircleColor(color) + map.circleManager?.let { update(it) } } - override fun getFillColor(): Int = circle.circleColorAsInt + override fun getFillColor(): Int = fillColor override fun setZIndex(zIndex: Float) { Log.d(TAG, "unimplemented Method: setZIndex") @@ -77,12 +104,13 @@ class CircleImpl(private val map: GoogleMapImpl, private val circle: Circle) : I } override fun setVisible(visible: Boolean) { - circle.circleOpacity = if (visible) 1f else 0f - circle.circleStrokeOpacity = if (visible) 1f else 0f - map.circleManager?.update(circle) + this.visible = visible + annotation?.circleOpacity = if (visible) 1f else 0f + annotation?.circleStrokeOpacity = if (visible) 1f else 0f + map.circleManager?.let { update(it) } } - override fun isVisible(): Boolean = circle.circleOpacity != 0f || circle.circleStrokeOpacity != 0f + override fun isVisible(): Boolean = visible override fun equalsRemote(other: ICircleDelegate?): Boolean = equals(other) @@ -90,7 +118,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val circle: Circle) : I override fun equals(other: Any?): Boolean { if (other is CircleImpl) { - return other.circle == circle + return other.id == id } return false } 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 index 3132137e..40fd3554 100644 --- 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 @@ -19,35 +19,74 @@ 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.MarkerOptions import com.google.android.gms.maps.model.internal.IMarkerDelegate +import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager import com.mapbox.mapboxsdk.plugins.annotation.Symbol +import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions 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() { +class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) : IMarkerDelegate.Stub(), Markup { + private var position: LatLng = options.position + private var visible: Boolean = options.isVisible + private var rotation: Float = options.rotation + private var anchor: FloatArray = floatArrayOf(options.anchorU, options.anchorV) + private var icon: BitmapDescriptorImpl? = options.icon?.remoteObject.unwrap() + private var alpha: Float = options.alpha + private var title: String? = options.title + private var snippet: String? = options.snippet + private var zIndex: Float = options.zIndex + private var draggable: Boolean = options.isDraggable private var tag: IObjectWrapper? = null + override var annotation: Symbol? = null + override var removed: Boolean = false + override val annotationOptions: SymbolOptions + get() { + var intBits = java.lang.Float.floatToIntBits(zIndex) + if (intBits < 0) intBits = intBits xor 0x7fffffff + + val symbolOptions = SymbolOptions() + .withIconOpacity(if (visible) alpha else 0f) + .withIconRotate(rotation) + .withZIndex(intBits) + .withDraggable(draggable) + + position.let { symbolOptions.withLatLng(it.toMapbox()) } + icon?.applyTo(symbolOptions, anchor, map.dpiFactor) + return symbolOptions + } + override fun remove() { - map.symbolManager?.delete(symbol) - map.markers.remove(symbol.id) + removed = true + map.symbolManager?.let { update(it) } } - 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 update(manager: AnnotationManager<*, Symbol, SymbolOptions, *, *, *>) { + synchronized(this) { + val id = annotation?.id + if (removed && id != null) { + map.markers.remove(id) + } + super.update(manager) + val annotation = annotation + if (annotation != null && id == null) { + map.markers[annotation.id] = this + } + } } - override fun getPosition(): LatLng = symbol.latLng.toGms() + override fun getId(): String = id + + override fun setPosition(position: LatLng?) { + this.position = position ?: return + annotation?.latLng = position.toMapbox() + map.symbolManager?.let { update(it) } + } + + override fun getPosition(): LatLng = position override fun setTitle(title: String?) { this.title = title @@ -61,12 +100,13 @@ class MarkerImpl(private val map: GoogleMapImpl, override fun getSnippet(): String? = snippet - override fun setDraggable(drag: Boolean) { - symbol.isDraggable = drag - map.symbolManager?.update(symbol) + override fun setDraggable(draggable: Boolean) { + this.draggable = draggable + annotation?.isDraggable = draggable + map.symbolManager?.let { update(it) } } - override fun isDraggable(): Boolean = symbol.isDraggable + override fun isDraggable(): Boolean = draggable override fun showInfoWindow() { Log.d(TAG, "unimplemented Method: showInfoWindow") @@ -82,11 +122,12 @@ class MarkerImpl(private val map: GoogleMapImpl, } override fun setVisible(visible: Boolean) { - symbol.iconOpacity = if (visible) 0f else alpha - map.symbolManager?.update(symbol) + this.visible = visible + annotation?.iconOpacity = if (visible) alpha else 0f + map.symbolManager?.let { update(it) } } - override fun isVisible(): Boolean = symbol.iconOpacity != 0f + override fun isVisible(): Boolean = visible override fun equals(other: Any?): Boolean { if (this === other) return true @@ -107,15 +148,17 @@ class MarkerImpl(private val map: GoogleMapImpl, 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) + obj.unwrap()?.let { icon -> + this.icon = icon + annotation?.let { icon.applyTo(it, anchor, map.dpiFactor) } + } + map.symbolManager?.let { update(it) } } override fun setAnchor(x: Float, y: Float) { anchor = floatArrayOf(x, y) - icon?.applyTo(symbol, anchor, map.dpiFactor) - map.symbolManager?.update(symbol) + annotation?.let { icon?.applyTo(it, anchor, map.dpiFactor) } + map.symbolManager?.let { update(it) } } override fun setFlat(flat: Boolean) { @@ -128,11 +171,12 @@ class MarkerImpl(private val map: GoogleMapImpl, } override fun setRotation(rotation: Float) { - symbol.iconRotate = rotation - map.symbolManager?.update(symbol) + this.rotation = rotation + annotation?.iconRotate = rotation + map.symbolManager?.let { update(it) } } - override fun getRotation(): Float = symbol.iconRotate + override fun getRotation(): Float = rotation override fun setInfoWindowAnchor(x: Float, y: Float) { Log.d(TAG, "unimplemented Method: setInfoWindowAnchor") @@ -140,24 +184,21 @@ class MarkerImpl(private val map: GoogleMapImpl, override fun setAlpha(alpha: Float) { this.alpha = alpha - symbol.iconOpacity = alpha - map.symbolManager?.update(symbol) + annotation?.iconOpacity = if (visible) alpha else 0f + map.symbolManager?.let { update(it) } } override fun getAlpha(): Float = alpha override fun setZIndex(zIndex: Float) { + this.zIndex = zIndex var intBits = java.lang.Float.floatToIntBits(zIndex) if (intBits < 0) intBits = intBits xor 0x7fffffff - symbol.zIndex = intBits - map.symbolManager?.update(symbol) + annotation?.zIndex = intBits + map.symbolManager?.let { update(it) } } - override fun getZIndex(): Float { - var intBits = symbol.zIndex - if (intBits < 0) intBits = intBits xor 0x7fffffff - return java.lang.Float.intBitsToFloat(intBits) - } + override fun getZIndex(): Float = zIndex override fun setTag(obj: IObjectWrapper?) { this.tag = obj diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt new file mode 100644 index 00000000..f0994173 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Markup.kt @@ -0,0 +1,40 @@ +/* + * 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 com.mapbox.mapboxsdk.plugins.annotation.Annotation +import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager +import com.mapbox.mapboxsdk.plugins.annotation.Options + +interface Markup, S : Options> { + var annotation: T? + val annotationOptions: S + val removed: Boolean + + fun update(manager: AnnotationManager<*, T, S, *, *, *>) { + synchronized(this) { + if (removed && annotation != null) { + manager.delete(annotation) + annotation = null + } else if (annotation != null) { + manager.update(annotation) + } else if (!removed) { + annotation = manager.create(annotationOptions) + } + } + } +} \ No newline at end of file diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt new file mode 100644 index 00000000..9e5ca9f5 --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt @@ -0,0 +1,120 @@ +/* + * 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.IPolygonDelegate +import com.mapbox.mapboxsdk.plugins.annotation.Fill +import org.microg.gms.maps.mapbox.GoogleMapImpl +import org.microg.gms.maps.mapbox.utils.toGms +import org.microg.gms.maps.mapbox.utils.toMapbox + +class PolygonImpl(private val map: GoogleMapImpl, private val fill: Fill) : IPolygonDelegate.Stub() { + override fun remove() { + map.fillManager?.delete(fill) + } + + override fun getId(): String = "p" + fill.id.toString() + + override fun setPoints(points: List) { + fill.latLngs = listOf(points.map { it.toMapbox() }) + map.fillManager?.update(fill) + } + + override fun getPoints(): List = fill.latLngs[0]?.map { it.toGms() } ?: emptyList() + + override fun setHoles(holes: List?) { + Log.d(TAG, "unimplemented Method: setHoles") + } + + override fun getHoles(): List { + Log.d(TAG, "unimplemented Method: getHoles") + return emptyList() + } + + override fun setStrokeWidth(width: Float) { + Log.d(TAG, "unimplemented Method: setStrokeWidth") + } + + override fun getStrokeWidth(): Float { + Log.d(TAG, "unimplemented Method: getStrokeWidth") + return 0f + } + + override fun setStrokeColor(color: Int) { + fill.setFillOutlineColor(color) + map.fillManager?.update(fill) + } + + override fun getStrokeColor(): Int = fill.fillOutlineColorAsInt + + override fun setFillColor(color: Int) { + fill.setFillColor(color) + map.fillManager?.update(fill) + } + + override fun getFillColor(): Int = fill.fillColorAsInt + + 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) { + fill.fillOpacity = if (visible) 1f else 0f + map.fillManager?.update(fill) + } + + override fun isVisible(): Boolean = fill.fillOpacity != 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: IPolygonDelegate?): Boolean = equals(other) + + override fun hashCodeRemote(): Int = hashCode() + + override fun equals(other: Any?): Boolean { + if (other is PolygonImpl) { + return other.fill == fill + } + 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 = "GmsMapPolygon" + } +} \ 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 index 46db6fcf..75ee0736 100644 --- 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 @@ -32,7 +32,7 @@ class PolylineImpl(private val map: GoogleMapImpl, private val line: Line) : IPo override fun getId(): String = "l" + line.id.toString() - override fun setPoints(points: MutableList) { + override fun setPoints(points: List) { line.latLngs = points.map { it.toMapbox() } map.lineManager?.update(line) } 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 index c37e9709..7cb5e5be 100644 --- 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 @@ -17,6 +17,7 @@ package org.microg.gms.maps.mapbox.utils import android.os.Bundle +import android.util.Log import com.google.android.gms.maps.internal.ICancelableCallback import com.google.android.gms.maps.model.CircleOptions import com.google.android.gms.maps.model.MarkerOptions diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java index 6b342e70..b18189a4 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/GoogleMapImpl.java @@ -57,6 +57,7 @@ import com.google.android.gms.maps.internal.IUiSettingsDelegate; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.GroundOverlayOptions; +import com.google.android.gms.maps.model.LatLngBounds; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.PolygonOptions; import com.google.android.gms.maps.model.PolylineOptions; @@ -155,7 +156,7 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub private void initFromOptions() { try { - uiSettings.setCompassEnabled(options.isCompassEnabled()); + uiSettings.setCompassEnabled(options.getCompassEnabled()); uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled()); uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled()); uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled()); @@ -173,6 +174,66 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub backendMap.destroy(); } + @Override + public void onLowMemory() throws RemoteException { + Log.d(TAG, "unimplemented Method: onLowMemory"); + + } + + @Override + public boolean useViewLifecycleWhenInFragment() throws RemoteException { + Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment"); + return false; + } + + @Override + public void onSaveInstanceState(Bundle outState) throws RemoteException { + Log.d(TAG, "unimplemented Method: onSaveInstanceState"); + + } + + @Override + public void setContentDescription(String desc) throws RemoteException { + Log.d(TAG, "unimplemented Method: setContentDescription"); + + } + + @Override + public void onEnterAmbient(Bundle bundle) throws RemoteException { + Log.d(TAG, "unimplemented Method: onEnterAmbient"); + + } + + @Override + public void onExitAmbient() throws RemoteException { + Log.d(TAG, "unimplemented Method: onExitAmbient"); + + } + + @Override + public void setMinZoomPreference(float minZoom) throws RemoteException { + Log.d(TAG, "unimplemented Method: setMinZoomPreference"); + + } + + @Override + public void setMaxZoomPreference(float maxZoom) throws RemoteException { + Log.d(TAG, "unimplemented Method: setMaxZoomPreference"); + + } + + @Override + public void resetMinMaxZoomPreference() throws RemoteException { + Log.d(TAG, "unimplemented Method: resetMinMaxZoomPreference"); + + } + + @Override + public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) throws RemoteException { + Log.d(TAG, "unimplemented Method: setLatLngBoundsForCameraTarget"); + + } + public void onResume() { backendMap.onResume(); } @@ -556,6 +617,18 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub }, 5000); } + @Override + public void setWatermarkEnabled(boolean watermark) throws RemoteException { + Log.d(TAG, "unimplemented Method: setWatermarkEnabled"); + + } + + @Override + public void onCreate(Bundle savedInstanceState) throws RemoteException { + Log.d(TAG, "unimplemented Method: onCreate"); + + } + @Override public void setCameraMoveStartedListener(IOnCameraMoveStartedListener listener) throws RemoteException { Log.d(TAG, "unimplemented Method: setCameraMoveStartedListener"); @@ -579,6 +652,18 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub Log.d(TAG, "unimplemented Method: setCameraIdleListener"); } + + @Override + public void onStart() throws RemoteException { + Log.d(TAG, "unimplemented Method: onStart"); + + } + + @Override + public void onStop() throws RemoteException { + Log.d(TAG, "unimplemented Method: onStop"); + + } /* Misc diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapFragmentImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapFragmentImpl.java index 403d3157..44521532 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapFragmentImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapFragmentImpl.java @@ -125,6 +125,26 @@ public class MapFragmentImpl extends IMapFragmentDelegate.Stub { Log.d(TAG, "onLowMemory"); } + @Override + public void onEnterAmbient(Bundle bundle) throws RemoteException { + map.onEnterAmbient(bundle); + } + + @Override + public void onExitAmbient() throws RemoteException { + map.onExitAmbient(); + } + + @Override + public void onStart() throws RemoteException { + map.onStart(); + } + + @Override + public void onStop() throws RemoteException { + map.onStop(); + } + @Override public void onSaveInstanceState(Bundle outState) throws RemoteException { Log.d(TAG, "onSaveInstanceState: " + outState); diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapViewImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapViewImpl.java index 6f713a90..c24ea52e 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapViewImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/MapViewImpl.java @@ -122,6 +122,26 @@ public class MapViewImpl extends IMapViewDelegate.Stub { }); } + @Override + public void onEnterAmbient(Bundle bundle) throws RemoteException { + map.onEnterAmbient(bundle); + } + + @Override + public void onExitAmbient() throws RemoteException { + map.onExitAmbient(); + } + + @Override + public void onStart() throws RemoteException { + map.onStart(); + } + + @Override + public void onStop() throws RemoteException { + map.onStop(); + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (super.onTransact(code, data, reply, flags)) return true; diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/UiSettingsImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/UiSettingsImpl.java index 1bc296fd..cb24de3c 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/UiSettingsImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/UiSettingsImpl.java @@ -28,6 +28,9 @@ public class UiSettingsImpl extends IUiSettingsDelegate.Stub { private boolean tiltGesturesEnabled = true; private boolean rotateGesturesEnabled = true; private boolean allGesturesEnabled = true; + private boolean indoorLevelPickerEnabled = false; + private boolean mapToolbarEnabled = false; + private boolean scrollGesturesEnabledDuringRotateOrZoom = true; private UiSettingsListener listener; @@ -127,7 +130,40 @@ public class UiSettingsImpl extends IUiSettingsDelegate.Stub { public boolean isRotateGesturesEnabled() throws RemoteException { return rotateGesturesEnabled; } - + + @Override + public void setIndoorLevelPickerEnabled(boolean indoorLevelPicker) throws RemoteException { + this.indoorLevelPickerEnabled = indoorLevelPicker; + listener.onUiSettingsChanged(this); + } + + @Override + public boolean isIndoorLevelPickerEnabled() throws RemoteException { + return indoorLevelPickerEnabled; + } + + @Override + public void setMapToolbarEnabled(boolean mapToolbar) throws RemoteException { + this.mapToolbarEnabled = mapToolbar; + listener.onUiSettingsChanged(this); + } + + @Override + public boolean isMapToolbarEnabled() throws RemoteException { + return mapToolbarEnabled; + } + + @Override + public void setScrollGesturesEnabledDuringRotateOrZoom(boolean scrollDuringZoom) throws RemoteException { + this.scrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom; + listener.onUiSettingsChanged(this); + } + + @Override + public boolean isScrollGesturesEnabledDuringRotateOrZoom() throws RemoteException { + return scrollGesturesEnabledDuringRotateOrZoom; + } + public static interface UiSettingsListener { void onUiSettingsChanged(UiSettingsImpl settings) throws RemoteException; }