From 68d2d2c8f3ff32ff802b184a55f3b6fddb50a074 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 10:13:33 +0100 Subject: [PATCH 1/6] Approximate circles using a polygon and a line --- play-services-maps-core-mapbox/build.gradle | 2 + .../org/microg/gms/maps/mapbox/GoogleMap.kt | 36 ++-- .../microg/gms/maps/mapbox/model/Circle.kt | 158 ++++++++++++++---- 3 files changed, 146 insertions(+), 50 deletions(-) diff --git a/play-services-maps-core-mapbox/build.gradle b/play-services-maps-core-mapbox/build.gradle index 56883ed04..cd11c1ff1 100644 --- a/play-services-maps-core-mapbox/build.gradle +++ b/play-services-maps-core-mapbox/build.gradle @@ -26,6 +26,8 @@ dependencies { implementation("org.maplibre.gl:android-plugin-annotation-v9:1.0.0") { exclude group: 'com.google.android.gms' } + implementation 'org.maplibre.gl:android-sdk-turf:5.9.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" } 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 1ca155ec4..7c0638ef9 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 @@ -98,17 +98,13 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) private var markerDragListener: IOnMarkerDragListener? = null var lineManager: LineManager? = null - val pendingLines = mutableSetOf() + val pendingLines = mutableSetOf>() var lineId = 0L var fillManager: FillManager? = null - val pendingFills = mutableSetOf() + val pendingFills = mutableSetOf>() var fillId = 0L - var circleManager: CircleManager? = null - val pendingCircles = mutableSetOf() - var circleId = 0L - var symbolManager: SymbolManager? = null val pendingMarkers = mutableSetOf() val markers = mutableMapOf() @@ -302,20 +298,25 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } override fun addCircle(options: CircleOptions): ICircleDelegate? { - val circle = CircleImpl(this, "c${circleId++}", options) + val circle = CircleImpl(this, "c${fillId++}", options) synchronized(this) { - val circleManager = circleManager - if (circleManager == null) { - pendingCircles.add(circle) + val fillManager = fillManager + if (fillManager == null) { + pendingFills.add(circle) + } else { + circle.update(fillManager) + } + val lineManager = lineManager + if (lineManager == null) { + pendingLines.add(circle.line) } else { - circle.update(circleManager) + circle.line.update(lineManager) } } return circle } override fun clear() { - circleManager?.let { clear(it) } lineManager?.let { clear(it) } fillManager?.let { clear(it) } symbolManager?.let { clear(it) } @@ -342,12 +343,10 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } fun applyMapType() { - val circles = circleManager?.annotations?.values() val lines = lineManager?.annotations?.values() val fills = fillManager?.annotations?.values() val symbols = symbolManager?.annotations?.values() val update: (Style) -> Unit = { - circles?.let { runCatching { circleManager?.update(it) } } lines?.let { runCatching { lineManager?.update(it) } } fills?.let { runCatching { fillManager?.update(it) } } symbols?.let { runCatching { symbolManager?.update(it) } } @@ -649,11 +648,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) if (loaded) return@let val symbolManager: SymbolManager val lineManager: LineManager - val circleManager: CircleManager val fillManager: FillManager synchronized(mapLock) { - circleManager = CircleManager(view, map, it) fillManager = FillManager(view, map, it) symbolManager = SymbolManager(view, map, it) lineManager = LineManager(view, map, it) @@ -661,7 +658,6 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) this.symbolManager = symbolManager this.lineManager = lineManager - this.circleManager = circleManager this.fillManager = fillManager } symbolManager.iconAllowOverlap = true @@ -691,15 +687,15 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } override fun onAnnotationDragFinished(annotation: Symbol?) { + mapView?.post { try { markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) } } catch (e: Exception) { Log.w(TAG, e) } + } } }) - pendingCircles.forEach { it.update(circleManager) } - pendingCircles.clear() pendingFills.forEach { it.update(fillManager) } pendingFills.clear() pendingLines.forEach { it.update(lineManager) } @@ -743,8 +739,6 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun onPause() = mapView?.onPause() ?: Unit override fun onDestroy() { Log.d(TAG, "destroy") - circleManager?.onDestroy() - circleManager = null lineManager?.onDestroy() lineManager = null 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 aa016ea80..b20e2fe1b 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 @@ -20,76 +20,177 @@ import android.os.Parcel import android.util.Log import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.internal.ICircleDelegate -import com.mapbox.mapboxsdk.plugins.annotation.Circle -import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions +import com.mapbox.geojson.LineString +import com.mapbox.geojson.Point +import com.mapbox.mapboxsdk.plugins.annotation.* import com.mapbox.mapboxsdk.utils.ColorUtils +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement +import com.mapbox.turf.TurfMeta +import com.mapbox.turf.TurfTransformation import org.microg.gms.maps.mapbox.GoogleMapImpl -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 { +val NORTH_POLE = Point.fromLngLat(0.0, 90.0) +val SOUTH_POLE = Point.fromLngLat(0.0, -90.0) + +/** + * Amount of points to be used in the polygon that approximates the circle. + */ +const val CIRCLE_POLYGON_STEPS = 256 + + +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 radius: Double = options.radius // in meters 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 + internal val line: Markup = object : Markup { + override var annotation: Line? = null + override val annotationOptions: LineOptions + get() = LineOptions() + .withGeometry( + LineString.fromLngLats( + makeOutlineLatLngs() + ) + ).withLineWidth(strokeWidth / map.dpiFactor) + .withLineColor(ColorUtils.colorToRgbaString(strokeColor)) + .withLineOpacity(if (visible) 1f else 0f) + + override val removed: Boolean = false + } + + override var annotation: Fill? = 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) + override val annotationOptions: FillOptions + get() = + FillOptions() + .withGeometry(makePolygon()) + .withFillColor(ColorUtils.colorToRgbaString(fillColor)) + .withFillOutlineColor(ColorUtils.colorToRgbaString(strokeColor)) + .withFillOpacity(if (visible && !wrapsAroundPoles()) 1f else 0f) + + private fun makePolygon() = TurfTransformation.circle( + Point.fromLngLat(center.longitude, center.latitude), radius, CIRCLE_POLYGON_STEPS, TurfConstants.UNIT_METERS + ) + + /** + * Google's "map renderer is unable to draw the circle fill if + * the circle encompasses either the North or South pole". + */ + private fun wrapsAroundPoles() = Point.fromLngLat(center.longitude, center.latitude).let { + TurfMeasurement.distance( + it, NORTH_POLE + ) * 1000 < radius || TurfMeasurement.distance( + it, SOUTH_POLE + ) * 1000 < radius + } + + private fun makeOutlineLatLngs() = + TurfMeta.coordAll( + makePolygon(), wrapsAroundPoles() + ).let { + // Circles around the poles are tricky to draw (https://github.com/mapbox/mapbox-gl-js/issues/11235). + // We modify our lines such to match the way Mapbox / MapLibre draws them. + // This results in a small gap somewhere in the line, but avoids an incorrect horizontal line. + + val centerPoint = Point.fromLngLat(center.longitude, center.latitude) + + if (!centerPoint.equals(NORTH_POLE) && TurfMeasurement.distance(centerPoint, NORTH_POLE) * 1000 < radius) { + // Wraps around North Pole + for (i in 0 until it.size) { + // We want to have the north-most points at the start and end + if (it[0].latitude() > it[1].latitude() && it[it.size-1].latitude() > it[it.size-2].latitude()) { + return@let it + } else { + // Cycle point list + val zero = it.removeFirst() + it.add(zero) + } + } + } + + if (!centerPoint.equals(SOUTH_POLE) && TurfMeasurement.distance(centerPoint, SOUTH_POLE) * 1000 < radius) { + // Wraps around South Pole + for (i in 0 until it.size) { + // We want to have the south-most points at the start and end + if (it[0].latitude() < it[1].latitude() && it[it.size-1].latitude() < it[it.size-2].latitude()) { + return@let it + } else { + // Cycle point list + val last = it.removeAt(it.size - 1) + it.add(0, last) + } + } + } + + it + } + + private fun updateLatLngs() { + val polygon = makePolygon() + + // Extracts points from generated polygon in expected format + annotation?.latLngs = FillOptions().withGeometry(polygon).latLngs + + line.annotation?.latLngs = makeOutlineLatLngs().map { point -> + com.mapbox.mapboxsdk.geometry.LatLng( + point.latitude(), + point.longitude() + ) + } + + if (wrapsAroundPoles()) { + annotation?.fillOpacity = 0f + } + } override fun remove() { removed = true - map.circleManager?.let { update(it) } + map.fillManager?.let { update(it) } } override fun getId(): String = id override fun setCenter(center: LatLng) { this.center = center - annotation?.latLng = center.toMapbox() - map.circleManager?.let { update(it) } + updateLatLngs() + map.fillManager?.let { update(it) } } override fun getCenter(): LatLng = center override fun setRadius(radius: Double) { this.radius = radius - annotation?.circleRadius = radius.toFloat() - map.circleManager?.let { update(it) } + updateLatLngs() + map.fillManager?.let { update(it) } } override fun getRadius(): Double = radius override fun setStrokeWidth(width: Float) { this.strokeWidth = width - annotation?.circleStrokeWidth = width / map.dpiFactor - map.circleManager?.let { update(it) } + line.annotation?.lineWidth = width / map.dpiFactor + map.lineManager?.let { line.update(it) } } override fun getStrokeWidth(): Float = strokeWidth override fun setStrokeColor(color: Int) { this.strokeColor = color - annotation?.setCircleStrokeColor(color) - map.circleManager?.let { update(it) } + line.annotation?.setLineColor(color) + map.lineManager?.let { line.update(it) } } override fun getStrokeColor(): Int = strokeColor override fun setFillColor(color: Int) { this.fillColor = color - annotation?.setCircleColor(color) - map.circleManager?.let { update(it) } + annotation?.setFillColor(color) + map.fillManager?.let { update(it) } } override fun getFillColor(): Int = fillColor @@ -105,9 +206,8 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun setVisible(visible: Boolean) { this.visible = visible - annotation?.circleOpacity = if (visible) 1f else 0f - annotation?.circleStrokeOpacity = if (visible) 1f else 0f - map.circleManager?.let { update(it) } + annotation?.fillOpacity = if (visible && !wrapsAroundPoles()) 1f else 0f + map.fillManager?.let { update(it) } } override fun isVisible(): Boolean = visible -- GitLab From 861f830f09ef270d3f3a57a0ce7b2f7dd0b9485d Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 10:42:11 +0100 Subject: [PATCH 2/6] Clickable circles --- .../gms/maps/internal/IGoogleMapDelegate.aidl | 3 ++- .../maps/internal/IOnCircleClickListener.aidl | 7 ++++++ .../maps/model/internal/ICircleDelegate.aidl | 2 ++ .../android/gms/maps/model/CircleOptions.java | 22 ++++++++++++++++++ .../org/microg/gms/maps/mapbox/GoogleMap.kt | 22 ++++++++++++++++++ .../microg/gms/maps/mapbox/model/Circle.kt | 23 +++++++++++++++++++ .../microg/gms/maps/vtm/GoogleMapImpl.java | 6 +++++ .../gms/maps/vtm/markup/CircleImpl.java | 13 +++++++++++ 8 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl index af44f1c50..556c2872c 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IGoogleMapDelegate.aidl @@ -13,6 +13,7 @@ import com.google.android.gms.maps.internal.IOnCameraIdleListener; import com.google.android.gms.maps.internal.IOnCameraMoveCanceledListener; import com.google.android.gms.maps.internal.IOnCameraMoveListener; import com.google.android.gms.maps.internal.IOnCameraMoveStartedListener; +import com.google.android.gms.maps.internal.IOnCircleClickListener; import com.google.android.gms.maps.internal.IOnMapClickListener; import com.google.android.gms.maps.internal.IOnMapLongClickListener; import com.google.android.gms.maps.internal.IOnMarkerClickListener; @@ -124,7 +125,7 @@ interface IGoogleMapDelegate { //void setPolygonClickListener(IOnPolygonClickListener listener) = 84; //void setInfoWindowCloseListener(IOnInfoWindowCloseListener listener) = 85; //void setPolylineClickListener(IOnPolylineClickListener listener) = 86; - //void setCircleClickListener(IOnCircleClickListener listener) = 88; + void setCircleClickListener(IOnCircleClickListener listener) = 88; boolean setMapStyle(in MapStyleOptions options) = 90; void setMinZoomPreference(float minZoom) = 91; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl new file mode 100644 index 000000000..cd7ad60e6 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnCircleClickListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.maps.internal; + +import com.google.android.gms.maps.model.internal.ICircleDelegate; + +interface IOnCircleClickListener { + void onCircleClick(ICircleDelegate circle); +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl index 719d8eab6..7582804c5 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl @@ -21,4 +21,6 @@ interface ICircleDelegate { boolean isVisible(); boolean equalsRemote(ICircleDelegate other); int hashCodeRemote(); + void setClickable(boolean clickable); + boolean isClickable(); } diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/CircleOptions.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/CircleOptions.java index 9f6110602..cb14f525d 100644 --- a/play-services-api/src/main/java/com/google/android/gms/maps/model/CircleOptions.java +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/CircleOptions.java @@ -43,6 +43,8 @@ public class CircleOptions extends AutoSafeParcelable { private float zIndex = 0; @SafeParceled(8) private boolean visible = true; + @SafeParceled(9) + private boolean clickable = false; /** * Creates circle options. @@ -144,6 +146,15 @@ public class CircleOptions extends AutoSafeParcelable { return visible; } + /** + * Gets the clickability setting for the circle. + * + * @return {@code true} if the circle is clickable; {@code false} if it is not. + */ + public boolean isClickable() { + return clickable; + } + /** * Sets the radius in meters. *

@@ -217,5 +228,16 @@ public class CircleOptions extends AutoSafeParcelable { return this; } + /** + * Specifies whether this circle is clickable. The default setting is {@code false}. + * + * @param clickable + * @return this {@code CircleOptions} object with a new clickability setting. + */ + public CircleOptions clickable(boolean clickable) { + this.clickable = clickable; + return this; + } + public static Creator CREATOR = new AutoCreator(CircleOptions.class); } 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 7c0638ef9..e1cca36d1 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 @@ -96,6 +96,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) private var mapLongClickListener: IOnMapLongClickListener? = null private var markerClickListener: IOnMarkerClickListener? = null private var markerDragListener: IOnMarkerDragListener? = null + private var circleClickListener: IOnCircleClickListener? = null var lineManager: LineManager? = null val pendingLines = mutableSetOf>() @@ -103,6 +104,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) var fillManager: FillManager? = null val pendingFills = mutableSetOf>() + val circles = mutableMapOf() var fillId = 0L var symbolManager: SymbolManager? = null @@ -454,6 +456,10 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) markerDragListener = listener } + override fun setCircleClickListener(listener: IOnCircleClickListener?) { + circleClickListener = listener + } + override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) { Log.d(TAG, "unimplemented Method: setOnInfoWindowClickListener") @@ -696,6 +702,21 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } } }) + fillManager.addClickListener { fill -> + try { + circles[fill.id]?.let { circle -> + if (circle.isClickable) { + circleClickListener?.let { + it.onCircleClick(circle) + return@addClickListener true + } + } + } + } catch (e: Exception) { + Log.w(TAG, e) + } + false + } pendingFills.forEach { it.update(fillManager) } pendingFills.clear() pendingLines.forEach { it.update(lineManager) } @@ -745,6 +766,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) fillManager?.onDestroy() fillManager = null + circles.clear() symbolManager?.onDestroy() symbolManager = null 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 b20e2fe1b..c904c777f 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 @@ -47,6 +47,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options private var strokeColor: Int = options.strokeColor private var fillColor: Int = options.fillColor private var visible: Boolean = options.isVisible + private var clickable: Boolean = options.isClickable internal val line: Markup = object : Markup { override var annotation: Line? = null @@ -216,6 +217,28 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun hashCodeRemote(): Int = hashCode() + override fun setClickable(clickable: Boolean) { + this.clickable = clickable + } + + override fun isClickable(): Boolean { + return clickable + } + + override fun update(manager: AnnotationManager<*, Fill, FillOptions, *, *, *>) { + synchronized(this) { + val id = annotation?.id + if (removed && id != null) { + map.circles.remove(id) + } + super.update(manager) + val annotation = annotation + if (annotation != null && id == null) { + map.circles[annotation.id] = this + } + } + } + override fun hashCode(): Int { return id.hashCode() } 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 87a512091..5a8bebbfd 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 @@ -44,6 +44,7 @@ import com.google.android.gms.maps.internal.IOnCameraIdleListener; import com.google.android.gms.maps.internal.IOnCameraMoveCanceledListener; import com.google.android.gms.maps.internal.IOnCameraMoveListener; import com.google.android.gms.maps.internal.IOnCameraMoveStartedListener; +import com.google.android.gms.maps.internal.IOnCircleClickListener; import com.google.android.gms.maps.internal.IOnInfoWindowClickListener; import com.google.android.gms.maps.internal.IOnMapClickListener; import com.google.android.gms.maps.internal.IOnMapLoadedCallback; @@ -212,6 +213,11 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub } + @Override + public void setCircleClickListener(IOnCircleClickListener listener) throws RemoteException { + Log.d(TAG, "unimplemented Method: setCircleClickListener"); + } + @Override public boolean setMapStyle(MapStyleOptions options) throws RemoteException { Log.d(TAG, "unimplemented Method: setMapStyle"); diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java index 18b4a9994..04c12d3cf 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java @@ -18,6 +18,7 @@ package org.microg.gms.maps.vtm.markup; import android.os.RemoteException; +import android.util.Log; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.internal.ICircleDelegate; @@ -30,6 +31,8 @@ import org.oscim.map.Map; public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { + private static final String TAG = "GmsMapCircle"; + private final String id; private final CircleOptions options; private final MarkupListener listener; @@ -139,6 +142,16 @@ public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { return id.hashCode(); } + @Override + public void setClickable(boolean clickable) throws RemoteException { + Log.d(TAG, "unimplemented method: setClickable"); + } + + @Override + public boolean isClickable() throws RemoteException { + return false; + } + @Override public boolean onClick() { return listener.onClick(this); -- GitLab From c70e589cf98e688ec66e7f1cf8306e040147edf7 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 11:01:18 +0100 Subject: [PATCH 3/6] Implement circle tag --- .../maps/model/internal/ICircleDelegate.aidl | 5 +++++ .../microg/gms/maps/mapbox/model/Circle.kt | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl index 7582804c5..8f2277e9e 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/ICircleDelegate.aidl @@ -1,5 +1,6 @@ package com.google.android.gms.maps.model.internal; +import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.maps.model.LatLng; interface ICircleDelegate { @@ -23,4 +24,8 @@ interface ICircleDelegate { int hashCodeRemote(); void setClickable(boolean clickable); boolean isClickable(); + void setStrokePattern(IObjectWrapper object); + IObjectWrapper getStrokePattern(); + void setTag(IObjectWrapper object); + IObjectWrapper getTag(); } 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 c904c777f..6908c6525 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 @@ -18,6 +18,9 @@ package org.microg.gms.maps.mapbox.model import android.os.Parcel import android.util.Log +import com.google.android.gms.dynamic.IObjectWrapper +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.dynamic.unwrap import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.internal.ICircleDelegate import com.mapbox.geojson.LineString @@ -48,6 +51,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options private var fillColor: Int = options.fillColor private var visible: Boolean = options.isVisible private var clickable: Boolean = options.isClickable + private var tag: Any? = null internal val line: Markup = object : Markup { override var annotation: Line? = null @@ -239,6 +243,21 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options } } + override fun setStrokePattern(pattern: IObjectWrapper) { + Log.d(TAG, "unimplemented method: set stroke pattern") + } + + override fun getStrokePattern(): IObjectWrapper { + Log.d(TAG, "unimplemented method: getStrokePattern") + return ObjectWrapper.wrap(null) + } + + override fun setTag(o: IObjectWrapper) { + this.tag = o.unwrap() + } + + override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(tag) + override fun hashCode(): Int { return id.hashCode() } -- GitLab From a278b3d2f9f93203d6fbeb3b5bda0837f76196d1 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 11:21:35 +0100 Subject: [PATCH 4/6] Fill in missing methods in vtm implementation --- .../gms/maps/vtm/markup/CircleImpl.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java index 04c12d3cf..9fe9a05ff 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/CircleImpl.java @@ -19,6 +19,8 @@ package org.microg.gms.maps.vtm.markup; import android.os.RemoteException; import android.util.Log; +import com.google.android.gms.dynamic.IObjectWrapper; +import com.google.android.gms.dynamic.ObjectWrapper; import com.google.android.gms.maps.model.CircleOptions; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.internal.ICircleDelegate; @@ -152,6 +154,28 @@ public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { return false; } + @Override + public void setStrokePattern(IObjectWrapper object) throws RemoteException { + Log.d(TAG, "unimplemented method: setStrokePattern"); + } + + @Override + public IObjectWrapper getStrokePattern() throws RemoteException { + Log.d(TAG, "unimplemented method: getStrokePattern"); + return ObjectWrapper.wrap(null); + } + + @Override + public void setTag(IObjectWrapper object) throws RemoteException { + Log.d(TAG, "unimplemented method: setTag"); + } + + @Override + public IObjectWrapper getTag() throws RemoteException { + Log.d(TAG, "unimplemented method: getTag"); + return ObjectWrapper.wrap(null); + } + @Override public boolean onClick() { return listener.onClick(this); -- GitLab From 2e624ae90c49f852448ae16c3e6840bf96525098 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 18:57:02 +0100 Subject: [PATCH 5/6] Apply review --- .../microg/gms/maps/mapbox/model/Circle.kt | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) 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 6908c6525..38cd1f3b9 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 @@ -34,15 +34,14 @@ import com.mapbox.turf.TurfTransformation import org.microg.gms.maps.mapbox.GoogleMapImpl import com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions -val NORTH_POLE = Point.fromLngLat(0.0, 90.0) -val SOUTH_POLE = Point.fromLngLat(0.0, -90.0) +val NORTH_POLE: Point = Point.fromLngLat(0.0, 90.0) +val SOUTH_POLE: Point = Point.fromLngLat(0.0, -90.0) /** * Amount of points to be used in the polygon that approximates the circle. */ const val CIRCLE_POLYGON_STEPS = 256 - 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 // in meters @@ -94,47 +93,48 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options ) * 1000 < radius } - private fun makeOutlineLatLngs() = - TurfMeta.coordAll( + private fun makeOutlineLatLngs(): MutableList { + val pointList = TurfMeta.coordAll( makePolygon(), wrapsAroundPoles() - ).let { - // Circles around the poles are tricky to draw (https://github.com/mapbox/mapbox-gl-js/issues/11235). - // We modify our lines such to match the way Mapbox / MapLibre draws them. - // This results in a small gap somewhere in the line, but avoids an incorrect horizontal line. - - val centerPoint = Point.fromLngLat(center.longitude, center.latitude) - - if (!centerPoint.equals(NORTH_POLE) && TurfMeasurement.distance(centerPoint, NORTH_POLE) * 1000 < radius) { - // Wraps around North Pole - for (i in 0 until it.size) { - // We want to have the north-most points at the start and end - if (it[0].latitude() > it[1].latitude() && it[it.size-1].latitude() > it[it.size-2].latitude()) { - return@let it - } else { - // Cycle point list - val zero = it.removeFirst() - it.add(zero) - } + ) + // Circles around the poles are tricky to draw (https://github.com/mapbox/mapbox-gl-js/issues/11235). + // We modify our lines such to match the way Mapbox / MapLibre draws them. + // This results in a small gap somewhere in the line, but avoids an incorrect horizontal line. + + val centerPoint = Point.fromLngLat(center.longitude, center.latitude) + + if (!centerPoint.equals(NORTH_POLE) && TurfMeasurement.distance(centerPoint, NORTH_POLE) * 1000 < radius) { + // Wraps around North Pole + for (i in 0 until pointList.size) { + // We want to have the north-most points at the start and end + if (pointList[0].latitude() > pointList[1].latitude() && pointList[pointList.size - 1].latitude() > pointList[pointList.size - 2].latitude()) { + return pointList + } else { + // Cycle point list + val zero = pointList.removeFirst() + pointList.add(zero) } } + } - if (!centerPoint.equals(SOUTH_POLE) && TurfMeasurement.distance(centerPoint, SOUTH_POLE) * 1000 < radius) { - // Wraps around South Pole - for (i in 0 until it.size) { - // We want to have the south-most points at the start and end - if (it[0].latitude() < it[1].latitude() && it[it.size-1].latitude() < it[it.size-2].latitude()) { - return@let it - } else { - // Cycle point list - val last = it.removeAt(it.size - 1) - it.add(0, last) - } + if (!centerPoint.equals(SOUTH_POLE) && TurfMeasurement.distance(centerPoint, SOUTH_POLE) * 1000 < radius) { + // Wraps around South Pole + for (i in 0 until pointList.size) { + // We want to have the south-most points at the start and end + if (pointList[0].latitude() < pointList[1].latitude() && pointList[pointList.size - 1].latitude() < pointList[pointList.size - 2].latitude()) { + return pointList + } else { + // Cycle point list + val last = pointList.removeAt(pointList.size - 1) + pointList.add(0, last) } } - - it } + // In this case no changes were made + return pointList + } + private fun updateLatLngs() { val polygon = makePolygon() -- GitLab From 40ed6a3ce4510b76493909da352c9ece73e263ed Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Mon, 23 Jan 2023 10:29:32 +0100 Subject: [PATCH 6/6] Fix crash with unimplemented method --- .../src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 38cd1f3b9..d0aa04dab 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 @@ -243,7 +243,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options } } - override fun setStrokePattern(pattern: IObjectWrapper) { + override fun setStrokePattern(pattern: IObjectWrapper?) { Log.d(TAG, "unimplemented method: set stroke pattern") } -- GitLab