Various fixes and improvements to Maps API

This commit is contained in:
Marvin W 2019-07-01 00:25:24 +02:00
parent 73fd85a8c7
commit 73aca6ea10
No known key found for this signature in database
GPG Key ID: 072E9235DB996F2A
17 changed files with 843 additions and 201 deletions

2
extern/GmsApi vendored

@ -1 +1 @@
Subproject commit 7197b8320b4e6d55d15b76d4faf05adaba36bf72 Subproject commit bfe649fc36a40e2498f1ecf123edfb9278fe0a1d

View File

@ -16,18 +16,20 @@
package org.microg.gms.maps.mapbox package org.microg.gms.maps.mapbox
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.location.Location import android.location.Location
import android.os.Bundle import android.os.Bundle
import android.os.Parcel import android.os.Parcel
import android.os.RemoteException
import android.support.annotation.IdRes import android.support.annotation.IdRes
import android.support.annotation.Keep import android.support.annotation.Keep
import android.support.v4.util.LongSparseArray import android.support.v4.util.LongSparseArray
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.Gravity
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.RelativeLayout
import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.maps.GoogleMapOptions import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.* 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.Mapbox
import com.mapbox.mapboxsdk.R import com.mapbox.mapboxsdk.R
import com.mapbox.mapboxsdk.camera.CameraUpdate import com.mapbox.mapboxsdk.camera.CameraUpdate
import com.mapbox.mapboxsdk.constants.MapboxConstants
import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style 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.toGms
import org.microg.gms.maps.mapbox.utils.toMapbox import org.microg.gms.maps.mapbox.utils.toMapbox
fun <T : Any> LongSparseArray<T>.values() = (0..size()).map { valueAt(it) }.mapNotNull { it } private fun <T : Any> LongSparseArray<T>.values() = (0..size()).map { valueAt(it) }.mapNotNull { it }
class GoogleMapImpl(private val context: Context, private val options: GoogleMapOptions) : IGoogleMapDelegate.Stub() { class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) : IGoogleMapDelegate.Stub() {
val view: FrameLayout val view: FrameLayout
var map: MapboxMap? = null 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 get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT
private var mapView: MapView? private var mapView: MapView?
private var created = false
private var initialized = false private var initialized = false
private val initializedCallbackList = mutableListOf<IOnMapReadyCallback>() private val initializedCallbackList = mutableListOf<IOnMapReadyCallback>()
private val mapLock = Object() private val mapLock = Object()
val markers = mutableMapOf<Long, MarkerImpl>()
private var cameraChangeListener: IOnCameraChangeListener? = null private var cameraChangeListener: IOnCameraChangeListener? = null
private var cameraMoveListener: IOnCameraMoveListener? = 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 markerClickListener: IOnMarkerClickListener? = null
private var markerDragListener: IOnMarkerDragListener? = null private var markerDragListener: IOnMarkerDragListener? = null
var circleManager: CircleManager? = null
var lineManager: LineManager? = null var lineManager: LineManager? = null
var fillManager: FillManager? = null var fillManager: FillManager? = null
var circleManager: CircleManager? = null
val pendingCircles = mutableSetOf<CircleImpl>()
var circleId = 0L
var symbolManager: SymbolManager? = null var symbolManager: SymbolManager? = null
var storedMapType: Int = MAP_TYPE_NORMAL val pendingMarkers = mutableSetOf<MarkerImpl>()
val markers = mutableMapOf<Long, MarkerImpl>()
var markerId = 0L
var storedMapType: Int = options.mapType
val waitingCameraUpdates = mutableListOf<CameraUpdate>()
init { init {
val mapContext = MapContext(context) val mapContext = MapContext(context)
LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context)) LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context))
Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY) 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) { this.view = object : FrameLayout(mapContext) {
@Keep @Keep
fun <T : View> findViewTraversal(@IdRes id: Int): T? { fun <T : View> findViewTraversal(@IdRes id: Int): T? {
return null return null
} }
@Keep
fun <T : View> 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.mapView = MapView(mapContext)
this.view.addView(this.mapView) this.view.addView(this.mapView)
} }
override fun getCameraPosition(): CameraPosition? = map?.cameraPosition?.toGms() override fun getCameraPosition(): CameraPosition? = map?.cameraPosition?.toGms()
override fun getMaxZoomLevel(): Float = map?.maxZoomLevel?.toFloat() ?: 20f override fun getMaxZoomLevel(): Float = (map?.maxZoomLevel?.toFloat() ?: 20f) + 1f
override fun getMinZoomLevel(): Float = map?.minZoomLevel?.toFloat() ?: 1f override fun getMinZoomLevel(): Float = (map?.minZoomLevel?.toFloat() ?: 0f) + 1f
override fun moveCamera(cameraUpdate: IObjectWrapper?) = override fun moveCamera(cameraUpdate: IObjectWrapper?) {
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.moveCamera(it) } ?: Unit val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
val map = this.map
if (map != null) {
map.moveCamera(update)
} else {
waitingCameraUpdates.add(update)
}
}
override fun animateCamera(cameraUpdate: IObjectWrapper?) = override fun animateCamera(cameraUpdate: IObjectWrapper?) {
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it) } ?: Unit val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
val map = this.map
if (map != null) {
map.animateCamera(update)
} else {
waitingCameraUpdates.add(update)
}
}
override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) = override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) {
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it, callback?.toMapbox()) } val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
?: Unit 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?) = override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) {
cameraUpdate.unwrap<CameraUpdate>()?.let { map?.animateCamera(it, duration, callback?.toMapbox()) } val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
?: Unit 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 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? { override fun addPolyline(options: PolylineOptions): IPolylineDelegate? {
val lineOptions = LineOptions() val lineOptions = LineOptions()
.withLatLngs(options.points.map { it.toMapbox() }) .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? { override fun addPolygon(options: PolygonOptions): IPolygonDelegate? {
Log.d(TAG, "unimplemented Method: addPolygon") val fillOptions = FillOptions()
return null .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? { override fun addMarker(options: MarkerOptions): IMarkerDelegate? {
var intBits = java.lang.Float.floatToIntBits(options.zIndex) val marker = MarkerImpl(this, "m${markerId++}", options)
if (intBits < 0) intBits = intBits xor 0x7fffffff synchronized(this) {
val symbolManager = symbolManager
val symbolOptions = SymbolOptions() if (symbolManager == null) {
.withIconOpacity(if (options.isVisible) options.alpha else 0f) pendingMarkers.add(marker)
.withIconRotate(options.rotation) } else {
.withZIndex(intBits) marker.update(symbolManager)
.withDraggable(options.isDraggable) }
}
options.position?.let { symbolOptions.withLatLng(it.toMapbox()) }
options.icon?.remoteObject.unwrap<BitmapDescriptorImpl>()?.applyTo(symbolOptions, floatArrayOf(options.anchorU, options.anchorV), dpiFactor)
val symbol = symbolManager?.create(symbolOptions) ?: return null
val marker = MarkerImpl(this, symbol, floatArrayOf(options.anchorU, options.anchorV), options.icon?.remoteObject.unwrap<BitmapDescriptorImpl>(), options.alpha, options.title, options.snippet)
markers.put(symbol.id, marker)
return marker return marker
} }
@ -165,16 +248,16 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
} }
override fun addCircle(options: CircleOptions): ICircleDelegate? { override fun addCircle(options: CircleOptions): ICircleDelegate? {
val circleOptions = com.mapbox.mapboxsdk.plugins.annotation.CircleOptions() val circle = CircleImpl(this, "c${circleId++}", options)
.withLatLng(options.center.toMapbox()) synchronized(this) {
.withCircleColor(ColorUtils.colorToRgbaString(options.fillColor)) val circleManager = circleManager
.withCircleRadius(options.radius.toFloat()) if (circleManager == null) {
.withCircleStrokeColor(ColorUtils.colorToRgbaString(options.strokeColor)) pendingCircles.add(circle)
.withCircleStrokeWidth(options.strokeWidth / dpiFactor) } else {
.withCircleOpacity(if (options.isVisible) 1f else 0f) circle.update(circleManager)
.withCircleStrokeOpacity(if (options.isVisible) 1f else 0f) }
}
return circleManager?.let { CircleImpl(this, it.create(circleOptions)) } return circle
} }
override fun clear() { override fun clear() {
@ -208,20 +291,27 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
val fills = fillManager?.annotations?.values() val fills = fillManager?.annotations?.values()
val symbols = symbolManager?.annotations?.values() val symbols = symbolManager?.annotations?.values()
val update: (Style) -> Unit = { val update: (Style) -> Unit = {
circles?.let { circleManager?.update(it) } circles?.let { runCatching { circleManager?.update(it) } }
lines?.let { lineManager?.update(it) } lines?.let { runCatching { lineManager?.update(it) } }
fills?.let { fillManager?.update(it) } fills?.let { runCatching { fillManager?.update(it) } }
symbols?.let { symbolManager?.update(it) } symbols?.let { runCatching { symbolManager?.update(it) } }
} }
// TODO: Serve map styles locally
when (storedMapType) { when (storedMapType) {
MAP_TYPE_NORMAL -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"), update) MAP_TYPE_SATELLITE -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update)
MAP_TYPE_SATELLITE -> map?.setStyle(Style.SATELLITE, update)
MAP_TYPE_TERRAIN -> map?.setStyle(Style.OUTDOORS, update) MAP_TYPE_TERRAIN -> map?.setStyle(Style.OUTDOORS, update)
MAP_TYPE_HYBRID -> map?.setStyle(Style.SATELLITE_STREETS, update) MAP_TYPE_HYBRID -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update)
else -> map?.setStyle(Style.LIGHT, 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 { override fun isTrafficEnabled(): Boolean {
@ -261,7 +351,10 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
override fun setLocationSource(locationSource: ILocationSourceDelegate) { override fun setLocationSource(locationSource: ILocationSourceDelegate) {
Log.d(TAG, "unimplemented Method: setLocationSource") Log.d(TAG, "unimplemented Method: setLocationSource")
}
override fun setContentDescription(desc: String?) {
mapView?.contentDescription = desc
} }
override fun getUiSettings(): IUiSettingsDelegate? = map?.uiSettings?.let { UiSettingsImpl(it) } 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 cameraIdleListener = listener
} }
fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
mapView?.onCreate(savedInstanceState?.toMapbox()) if (!created) {
mapView?.getMapAsync(this::initMap) mapView?.onCreate(savedInstanceState?.toMapbox())
mapView?.getMapAsync(this::initMap)
created = true
}
} }
private fun hasSymbolAt(latlng: com.mapbox.mapboxsdk.geometry.LatLng): Boolean { private fun hasSymbolAt(latlng: com.mapbox.mapboxsdk.geometry.LatLng): Boolean {
val point = map?.projection?.toScreenLocation(latlng) ?: return false val point = map?.projection?.toScreenLocation(latlng) ?: return false
val features = map?.queryRenderedFeatures(point, SymbolManager.ID_GEOJSON_LAYER) val features = map?.queryRenderedFeatures(point, SymbolManager.ID_GEOJSON_LAYER)
?: return false ?: return false
return !features.isEmpty() return features.isNotEmpty()
} }
private fun initMap(map: MapboxMap) { private fun initMap(map: MapboxMap) {
if (this.map != null) return if (this.map != null) return
this.map = map 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() 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 { map.getStyle {
mapView?.let { view -> mapView?.let { view ->
BitmapDescriptorFactoryImpl.registerMap(map)
circleManager = CircleManager(view, map, it) circleManager = CircleManager(view, map, it)
lineManager = LineManager(view, map, it) lineManager = LineManager(view, map, it)
lineManager?.lineCap = LINE_CAP_ROUND
fillManager = FillManager(view, map, it) 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?.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 { symbolManager?.addDragListener(object : OnSymbolDragListener {
override fun onAnnotationDragStarted(annotation: Symbol?) { 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 { try {
callback.onMapReady(this) markers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) }
} catch (e: RemoteException) { } catch (e: Exception) {
Log.w(TAG, e) 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() override fun useViewLifecycleWhenInFragment(): Boolean {
fun onPause() = mapView?.onPause() Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment")
fun onDestroy() { return false
}
override fun onResume() = mapView?.onResume() ?: Unit
override fun onPause() = mapView?.onPause() ?: Unit
override fun onDestroy() {
circleManager?.onDestroy() circleManager?.onDestroy()
circleManager = null circleManager = null
lineManager?.onDestroy() lineManager?.onDestroy()
@ -442,6 +614,8 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
fillManager = null fillManager = null
symbolManager?.onDestroy() symbolManager?.onDestroy()
symbolManager = null symbolManager = null
pendingMarkers.clear()
markers.clear()
BitmapDescriptorFactoryImpl.unregisterMap(map) BitmapDescriptorFactoryImpl.unregisterMap(map)
view.removeView(mapView) view.removeView(mapView)
// TODO can crash? // TODO can crash?
@ -449,8 +623,24 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
mapView = null mapView = null
} }
fun onLowMemory() = mapView?.onLowMemory() override fun onStart() {
fun onSaveInstanceState(outState: Bundle) { 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() val newBundle = Bundle()
mapView?.onSaveInstanceState(newBundle) mapView?.onSaveInstanceState(newBundle)
outState.putAll(newBundle.toGms()) outState.putAll(newBundle.toGms())
@ -459,8 +649,14 @@ class GoogleMapImpl(private val context: Context, private val options: GoogleMap
fun getMapAsync(callback: IOnMapReadyCallback) { fun getMapAsync(callback: IOnMapReadyCallback) {
synchronized(mapLock) { synchronized(mapLock) {
if (initialized) { 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 { } else {
Log.d(TAG, "Delay callback invocation, as map is not yet initialized")
initializedCallbackList.add(callback) initializedCallbackList.add(callback)
} }
} }

View File

@ -19,7 +19,9 @@ package org.microg.gms.maps.mapbox
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
import android.os.Parcel import android.os.Parcel
import android.util.Base64
import android.util.Log import android.util.Log
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper import com.google.android.gms.dynamic.ObjectWrapper
@ -34,32 +36,42 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu
private var options: GoogleMapOptions? = null private var options: GoogleMapOptions? = null
override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle) { override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle) {
Log.d(TAG, "onInflate: ${options.camera.target}")
this.options = options this.options = options
map?.options = options
} }
override fun onCreate(savedInstanceState: Bundle) { override fun onCreate(savedInstanceState: Bundle?) {
if (options == null) { if (options == null) {
options = savedInstanceState.getParcelable("MapOptions") options = savedInstanceState?.getParcelable("MapOptions")
} }
if (options == null) { if (options == null) {
options = GoogleMapOptions() options = GoogleMapOptions()
} }
Log.d(TAG, "onCreate: ${options?.camera?.target}")
map = GoogleMapImpl(activity, options ?: GoogleMapOptions())
} }
override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper { 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) { if (map == null) {
map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) 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 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 onResume() = map?.onResume() ?: Unit
override fun onPause() = map?.onPause() ?: Unit override fun onPause() = map?.onPause() ?: Unit
override fun onLowMemory() = map?.onLowMemory() ?: Unit override fun onLowMemory() = map?.onLowMemory() ?: Unit
@ -84,12 +96,14 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu
map?.onSaveInstanceState(outState) map?.onSaveInstanceState(outState)
} }
override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean = override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean {
if (super.onTransact(code, data, reply, flags)) { if (super.onTransact(code, data, reply, flags)) {
true return true
} else { } else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false Log.d(TAG, "onTransact [unknown]: $code, $data, $flags")
} return false
}
}
companion object { companion object {
private val TAG = "GmsMapFragment" private val TAG = "GmsMapFragment"

View File

@ -28,25 +28,28 @@ import com.google.android.gms.maps.internal.IMapViewDelegate
import com.google.android.gms.maps.internal.IOnMapReadyCallback import com.google.android.gms.maps.internal.IOnMapReadyCallback
class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() { 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 private var map: GoogleMapImpl? = null
init {
this.options = options ?: GoogleMapOptions()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate: ${options?.camera?.target}")
map = GoogleMapImpl(context, options) map = GoogleMapImpl(context, options)
map?.onCreate(savedInstanceState) map!!.onCreate(savedInstanceState)
} }
override fun getMap(): IGoogleMapDelegate? = map 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 onResume() = map?.onResume() ?: Unit
override fun onPause() = map?.onPause() ?: Unit override fun onPause() = map?.onPause() ?: Unit
override fun onDestroy() { override fun onDestroy() {
map?.onDestroy() map?.onDestroy()
map = null map = null
} }
override fun onLowMemory() = map?.onLowMemory() ?: Unit override fun onLowMemory() = map?.onLowMemory() ?: Unit
override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit
override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view) override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view)

View File

@ -30,16 +30,21 @@ import org.microg.gms.maps.mapbox.utils.toGms
import org.microg.gms.maps.mapbox.utils.toMapbox import org.microg.gms.maps.mapbox.utils.toMapbox
class ProjectionImpl(private val projection: Projection) : IProjectionDelegate.Stub() { 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? = override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? =
obj.unwrap<Point>()?.let { projection.fromScreenLocation(PointF(it)) }?.toGms() obj.unwrap<Point>()?.let { projection.fromScreenLocation(PointF(it)) }?.toGms()
override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try {
ObjectWrapper.wrap(latLng?.toMapbox()?.let { projection.toScreenLocation(it) }?.let { Point(it.x.toInt(), it.y.toInt()) }) 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) { } 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()
} }

View File

@ -78,6 +78,33 @@ class UiSettingsImpl(private val uiSettings: UiSettings) : IUiSettingsDelegate.S
override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled 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 = override fun onTransact(code: Int, data: Parcel?, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) { if (super.onTransact(code, data, reply, flags)) {
true true

View File

@ -37,10 +37,13 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {
} }
fun registerMap(map: MapboxMap) { fun registerMap(map: MapboxMap) {
Log.d(TAG, "registerMap")
map.getStyle { map.getStyle {
it.addImages(bitmaps) synchronized(bitmaps) {
maps.add(map) it.addImages(bitmaps)
}
} }
maps.add(map)
} }
fun unregisterMap(map: MapboxMap?) { fun unregisterMap(map: MapboxMap?) {
@ -53,9 +56,12 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {
?: floatArrayOf(0f, 0f) ?: floatArrayOf(0f, 0f)
private fun registerBitmap(id: String, bitmapCreator: () -> Bitmap?) { private fun registerBitmap(id: String, bitmapCreator: () -> Bitmap?) {
if (bitmaps.contains(id)) return val bitmap = synchronized(bitmaps) {
val bitmap = bitmapCreator() ?: return if (bitmaps.contains(id)) return
bitmaps[id] = bitmap val bitmap = bitmapCreator() ?: return
bitmaps[id] = bitmap
bitmap
}
for (map in maps) { for (map in maps) {
map.getStyle { it.addImage(id, bitmap) } map.getStyle { it.addImage(id, bitmap) }
} }

View File

@ -21,51 +21,78 @@ import android.util.Log
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.internal.ICircleDelegate import com.google.android.gms.maps.model.internal.ICircleDelegate
import com.mapbox.mapboxsdk.plugins.annotation.Circle 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.GoogleMapImpl
import org.microg.gms.maps.mapbox.utils.toGms
import org.microg.gms.maps.mapbox.utils.toMapbox 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<Circle, CircleOptions> {
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() { 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) { override fun setCenter(center: LatLng) {
circle.latLng = center.toMapbox() this.center = center
map.circleManager?.update(circle) 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) { override fun setRadius(radius: Double) {
circle.circleRadius = radius.toFloat() this.radius = radius
map.circleManager?.update(circle) 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) { override fun setStrokeWidth(width: Float) {
circle.circleStrokeWidth = width / map.dpiFactor this.strokeWidth = width
map.circleManager?.update(circle) 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) { override fun setStrokeColor(color: Int) {
circle.setCircleStrokeColor(color) this.strokeColor = color
map.circleManager?.update(circle) annotation?.setCircleStrokeColor(color)
map.circleManager?.let { update(it) }
} }
override fun getStrokeColor(): Int = circle.circleStrokeColorAsInt override fun getStrokeColor(): Int = strokeColor
override fun setFillColor(color: Int) { override fun setFillColor(color: Int) {
circle.setCircleColor(color) this.fillColor = color
map.circleManager?.update(circle) annotation?.setCircleColor(color)
map.circleManager?.let { update(it) }
} }
override fun getFillColor(): Int = circle.circleColorAsInt override fun getFillColor(): Int = fillColor
override fun setZIndex(zIndex: Float) { override fun setZIndex(zIndex: Float) {
Log.d(TAG, "unimplemented Method: setZIndex") 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) { override fun setVisible(visible: Boolean) {
circle.circleOpacity = if (visible) 1f else 0f this.visible = visible
circle.circleStrokeOpacity = if (visible) 1f else 0f annotation?.circleOpacity = if (visible) 1f else 0f
map.circleManager?.update(circle) 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) 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 { override fun equals(other: Any?): Boolean {
if (other is CircleImpl) { if (other is CircleImpl) {
return other.circle == circle return other.id == id
} }
return false return false
} }

View File

@ -19,35 +19,74 @@ package org.microg.gms.maps.mapbox.model
import android.util.Log import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.maps.model.LatLng 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.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.Symbol
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import org.microg.gms.kotlin.unwrap import org.microg.gms.kotlin.unwrap
import org.microg.gms.maps.mapbox.GoogleMapImpl import org.microg.gms.maps.mapbox.GoogleMapImpl
import org.microg.gms.maps.mapbox.utils.toGms
import org.microg.gms.maps.mapbox.utils.toMapbox import org.microg.gms.maps.mapbox.utils.toMapbox
class MarkerImpl(private val map: GoogleMapImpl, class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) : IMarkerDelegate.Stub(), Markup<Symbol, SymbolOptions> {
private val symbol: Symbol, private var position: LatLng = options.position
private var anchor: FloatArray, private var visible: Boolean = options.isVisible
private var icon: BitmapDescriptorImpl?, private var rotation: Float = options.rotation
private var alpha: Float = symbol.iconOpacity, private var anchor: FloatArray = floatArrayOf(options.anchorU, options.anchorV)
private var title: String? = null, private var icon: BitmapDescriptorImpl? = options.icon?.remoteObject.unwrap()
private var snippet: String? = null) : IMarkerDelegate.Stub() { 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 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() { override fun remove() {
map.symbolManager?.delete(symbol) removed = true
map.markers.remove(symbol.id) map.symbolManager?.let { update(it) }
} }
override fun getId(): String = "m" + symbol.id.toString() override fun update(manager: AnnotationManager<*, Symbol, SymbolOptions, *, *, *>) {
synchronized(this) {
override fun setPosition(pos: LatLng?) { val id = annotation?.id
pos?.let { symbol.latLng = it.toMapbox() } if (removed && id != null) {
map.symbolManager?.update(symbol) 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?) { override fun setTitle(title: String?) {
this.title = title this.title = title
@ -61,12 +100,13 @@ class MarkerImpl(private val map: GoogleMapImpl,
override fun getSnippet(): String? = snippet override fun getSnippet(): String? = snippet
override fun setDraggable(drag: Boolean) { override fun setDraggable(draggable: Boolean) {
symbol.isDraggable = drag this.draggable = draggable
map.symbolManager?.update(symbol) annotation?.isDraggable = draggable
map.symbolManager?.let { update(it) }
} }
override fun isDraggable(): Boolean = symbol.isDraggable override fun isDraggable(): Boolean = draggable
override fun showInfoWindow() { override fun showInfoWindow() {
Log.d(TAG, "unimplemented Method: showInfoWindow") Log.d(TAG, "unimplemented Method: showInfoWindow")
@ -82,11 +122,12 @@ class MarkerImpl(private val map: GoogleMapImpl,
} }
override fun setVisible(visible: Boolean) { override fun setVisible(visible: Boolean) {
symbol.iconOpacity = if (visible) 0f else alpha this.visible = visible
map.symbolManager?.update(symbol) 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
@ -107,15 +148,17 @@ class MarkerImpl(private val map: GoogleMapImpl,
override fun hashCodeRemote(): Int = hashCode() override fun hashCodeRemote(): Int = hashCode()
override fun setIcon(obj: IObjectWrapper?) { override fun setIcon(obj: IObjectWrapper?) {
obj.unwrap<BitmapDescriptorImpl>()?.let { icon = it } obj.unwrap<BitmapDescriptorImpl>()?.let { icon ->
icon?.applyTo(symbol, anchor, map.dpiFactor) this.icon = icon
map.symbolManager?.update(symbol) annotation?.let { icon.applyTo(it, anchor, map.dpiFactor) }
}
map.symbolManager?.let { update(it) }
} }
override fun setAnchor(x: Float, y: Float) { override fun setAnchor(x: Float, y: Float) {
anchor = floatArrayOf(x, y) anchor = floatArrayOf(x, y)
icon?.applyTo(symbol, anchor, map.dpiFactor) annotation?.let { icon?.applyTo(it, anchor, map.dpiFactor) }
map.symbolManager?.update(symbol) map.symbolManager?.let { update(it) }
} }
override fun setFlat(flat: Boolean) { override fun setFlat(flat: Boolean) {
@ -128,11 +171,12 @@ class MarkerImpl(private val map: GoogleMapImpl,
} }
override fun setRotation(rotation: Float) { override fun setRotation(rotation: Float) {
symbol.iconRotate = rotation this.rotation = rotation
map.symbolManager?.update(symbol) 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) { override fun setInfoWindowAnchor(x: Float, y: Float) {
Log.d(TAG, "unimplemented Method: setInfoWindowAnchor") Log.d(TAG, "unimplemented Method: setInfoWindowAnchor")
@ -140,24 +184,21 @@ class MarkerImpl(private val map: GoogleMapImpl,
override fun setAlpha(alpha: Float) { override fun setAlpha(alpha: Float) {
this.alpha = alpha this.alpha = alpha
symbol.iconOpacity = alpha annotation?.iconOpacity = if (visible) alpha else 0f
map.symbolManager?.update(symbol) map.symbolManager?.let { update(it) }
} }
override fun getAlpha(): Float = alpha override fun getAlpha(): Float = alpha
override fun setZIndex(zIndex: Float) { override fun setZIndex(zIndex: Float) {
this.zIndex = zIndex
var intBits = java.lang.Float.floatToIntBits(zIndex) var intBits = java.lang.Float.floatToIntBits(zIndex)
if (intBits < 0) intBits = intBits xor 0x7fffffff if (intBits < 0) intBits = intBits xor 0x7fffffff
symbol.zIndex = intBits annotation?.zIndex = intBits
map.symbolManager?.update(symbol) map.symbolManager?.let { update(it) }
} }
override fun getZIndex(): Float { override fun getZIndex(): Float = zIndex
var intBits = symbol.zIndex
if (intBits < 0) intBits = intBits xor 0x7fffffff
return java.lang.Float.intBitsToFloat(intBits)
}
override fun setTag(obj: IObjectWrapper?) { override fun setTag(obj: IObjectWrapper?) {
this.tag = obj this.tag = obj

View File

@ -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<T : Annotation<*>, S : Options<T>> {
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)
}
}
}
}

View File

@ -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<LatLng>) {
fill.latLngs = listOf(points.map { it.toMapbox() })
map.fillManager?.update(fill)
}
override fun getPoints(): List<LatLng> = fill.latLngs[0]?.map { it.toGms() } ?: emptyList()
override fun setHoles(holes: List<Any?>?) {
Log.d(TAG, "unimplemented Method: setHoles")
}
override fun getHoles(): List<Any?> {
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"
}
}

View File

@ -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 getId(): String = "l" + line.id.toString()
override fun setPoints(points: MutableList<LatLng>) { override fun setPoints(points: List<LatLng>) {
line.latLngs = points.map { it.toMapbox() } line.latLngs = points.map { it.toMapbox() }
map.lineManager?.update(line) map.lineManager?.update(line)
} }

View File

@ -17,6 +17,7 @@
package org.microg.gms.maps.mapbox.utils package org.microg.gms.maps.mapbox.utils
import android.os.Bundle import android.os.Bundle
import android.util.Log
import com.google.android.gms.maps.internal.ICancelableCallback import com.google.android.gms.maps.internal.ICancelableCallback
import com.google.android.gms.maps.model.CircleOptions import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.maps.model.MarkerOptions

View File

@ -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.CameraPosition;
import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.GroundOverlayOptions; 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.MarkerOptions;
import com.google.android.gms.maps.model.PolygonOptions; import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions; import com.google.android.gms.maps.model.PolylineOptions;
@ -155,7 +156,7 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
private void initFromOptions() { private void initFromOptions() {
try { try {
uiSettings.setCompassEnabled(options.isCompassEnabled()); uiSettings.setCompassEnabled(options.getCompassEnabled());
uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled()); uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled());
uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled()); uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled());
uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled()); uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled());
@ -173,6 +174,66 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
backendMap.destroy(); 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() { public void onResume() {
backendMap.onResume(); backendMap.onResume();
} }
@ -556,6 +617,18 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
}, 5000); }, 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 @Override
public void setCameraMoveStartedListener(IOnCameraMoveStartedListener listener) throws RemoteException { public void setCameraMoveStartedListener(IOnCameraMoveStartedListener listener) throws RemoteException {
Log.d(TAG, "unimplemented Method: setCameraMoveStartedListener"); Log.d(TAG, "unimplemented Method: setCameraMoveStartedListener");
@ -579,6 +652,18 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
Log.d(TAG, "unimplemented Method: setCameraIdleListener"); 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 Misc

View File

@ -125,6 +125,26 @@ public class MapFragmentImpl extends IMapFragmentDelegate.Stub {
Log.d(TAG, "onLowMemory"); 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 @Override
public void onSaveInstanceState(Bundle outState) throws RemoteException { public void onSaveInstanceState(Bundle outState) throws RemoteException {
Log.d(TAG, "onSaveInstanceState: " + outState); Log.d(TAG, "onSaveInstanceState: " + outState);

View File

@ -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 @Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (super.onTransact(code, data, reply, flags)) return true; if (super.onTransact(code, data, reply, flags)) return true;

View File

@ -28,6 +28,9 @@ public class UiSettingsImpl extends IUiSettingsDelegate.Stub {
private boolean tiltGesturesEnabled = true; private boolean tiltGesturesEnabled = true;
private boolean rotateGesturesEnabled = true; private boolean rotateGesturesEnabled = true;
private boolean allGesturesEnabled = true; private boolean allGesturesEnabled = true;
private boolean indoorLevelPickerEnabled = false;
private boolean mapToolbarEnabled = false;
private boolean scrollGesturesEnabledDuringRotateOrZoom = true;
private UiSettingsListener listener; private UiSettingsListener listener;
@ -127,7 +130,40 @@ public class UiSettingsImpl extends IUiSettingsDelegate.Stub {
public boolean isRotateGesturesEnabled() throws RemoteException { public boolean isRotateGesturesEnabled() throws RemoteException {
return rotateGesturesEnabled; 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 { public static interface UiSettingsListener {
void onUiSettingsChanged(UiSettingsImpl settings) throws RemoteException; void onUiSettingsChanged(UiSettingsImpl settings) throws RemoteException;
} }