From 68d2d2c8f3ff32ff802b184a55f3b6fddb50a074 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Wed, 18 Jan 2023 10:13:33 +0100 Subject: [PATCH 1/9] 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/9] 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/9] 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/9] 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/9] 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/9] 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 From e763a60a600757be45f35110f96969744c587fb4 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Sat, 24 Dec 2022 21:02:19 +0100 Subject: [PATCH 7/9] Maps: Add a few missing parts --- .../gms/maps/internal/IGoogleMapDelegate.aidl | 7 ++- .../internal/ILocationSourceDelegate.aidl | 4 ++ .../IOnIndoorStateChangeListener.aidl | 6 ++ .../internal/IOnLocationChangeListener.aidl | 7 +++ .../google/android/gms/maps/model/Cap.aidl | 3 + .../android/gms/maps/model/StyleSpan.aidl | 3 + .../internal/IIndoorBuildingDelegate.aidl | 10 ++++ .../model/internal/IIndoorLevelDelegate.aidl | 9 +++ .../maps/model/internal/IPolygonDelegate.aidl | 1 + .../model/internal/IPolylineDelegate.aidl | 49 ++++++++++----- .../google/android/gms/maps/model/Cap.java | 21 +++++++ .../android/gms/maps/model/PatternItem.java | 24 +++++++- .../gms/maps/model/PolylineOptions.java | 59 ++++++++++++------- .../android/gms/maps/model/StampStyle.java | 18 ++++++ .../android/gms/maps/model/StrokeStyle.java | 23 ++++++++ .../android/gms/maps/model/StyleSpan.java | 25 ++++++++ .../org/microg/gms/maps/mapbox/GoogleMap.kt | 42 +++++++++---- .../microg/gms/maps/mapbox/model/Polygon.kt | 5 +- .../microg/gms/maps/mapbox/model/Polyline.kt | 33 ++++++++++- .../gms/maps/mapbox/utils/MapContext.kt | 4 +- .../gms/maps/vtm/markup/PolygonImpl.java | 5 ++ .../gms/maps/vtm/markup/PolylineImpl.java | 43 ++++++++++++++ 22 files changed, 345 insertions(+), 56 deletions(-) create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnIndoorStateChangeListener.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnLocationChangeListener.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/Cap.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/StyleSpan.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorBuildingDelegate.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorLevelDelegate.aidl create mode 100644 play-services-api/src/main/java/com/google/android/gms/maps/model/Cap.java create mode 100644 play-services-api/src/main/java/com/google/android/gms/maps/model/StampStyle.java create mode 100644 play-services-api/src/main/java/com/google/android/gms/maps/model/StrokeStyle.java create mode 100644 play-services-api/src/main/java/com/google/android/gms/maps/model/StyleSpan.java 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 bcb27314f..6759dbbd9 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 @@ -34,11 +34,12 @@ import com.google.android.gms.maps.model.MapStyleOptions; import com.google.android.gms.maps.model.PolygonOptions; import com.google.android.gms.maps.model.PolylineOptions; import com.google.android.gms.maps.model.TileOverlayOptions; -import com.google.android.gms.maps.model.internal.IPolylineDelegate; -import com.google.android.gms.maps.model.internal.IPolygonDelegate; -import com.google.android.gms.maps.model.internal.IMarkerDelegate; import com.google.android.gms.maps.model.internal.ICircleDelegate; import com.google.android.gms.maps.model.internal.IGroundOverlayDelegate; +import com.google.android.gms.maps.model.internal.IIndoorBuildingDelegate; +import com.google.android.gms.maps.model.internal.IMarkerDelegate; +import com.google.android.gms.maps.model.internal.IPolygonDelegate; +import com.google.android.gms.maps.model.internal.IPolylineDelegate; import com.google.android.gms.maps.model.internal.ITileOverlayDelegate; interface IGoogleMapDelegate { diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/ILocationSourceDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/ILocationSourceDelegate.aidl index 203ec69f1..3f1ed56fb 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/ILocationSourceDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/ILocationSourceDelegate.aidl @@ -1,4 +1,8 @@ package com.google.android.gms.maps.internal; +import com.google.android.gms.maps.internal.IOnLocationChangeListener; + interface ILocationSourceDelegate { + void activate(IOnLocationChangeListener listener) = 0; + void deactivate() = 1; } diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnIndoorStateChangeListener.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnIndoorStateChangeListener.aidl new file mode 100644 index 000000000..c224c58e2 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnIndoorStateChangeListener.aidl @@ -0,0 +1,6 @@ +package com.google.android.gms.maps.internal; + +interface IOnIndoorStateChangeListener { + void onIndoorBuildingFocused() = 0; + void onIndoorLevelActivated() = 1; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnLocationChangeListener.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnLocationChangeListener.aidl new file mode 100644 index 000000000..7d3897dcf --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/internal/IOnLocationChangeListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.maps.internal; + +import android.location.Location; + +interface IOnLocationChangeListener { + void onLocationChanged(in Location location) = 1; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Cap.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Cap.aidl new file mode 100644 index 000000000..802366f61 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Cap.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Cap; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/StyleSpan.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/StyleSpan.aidl new file mode 100644 index 000000000..3dd85466b --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/StyleSpan.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable StyleSpan; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorBuildingDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorBuildingDelegate.aidl new file mode 100644 index 000000000..3ec555d78 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorBuildingDelegate.aidl @@ -0,0 +1,10 @@ +package com.google.android.gms.maps.model.internal; + +interface IIndoorBuildingDelegate { + int getActiveLevelIndex() = 0; + int getDefaultLevelIndex() = 1; + List getLevels() = 2; // IIndoorLevelDelegate's + boolean isUnderground() = 3; + boolean equalsRemote(IIndoorBuildingDelegate other) = 4; + int hashCodeRemote() = 5; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorLevelDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorLevelDelegate.aidl new file mode 100644 index 000000000..8c48348e0 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IIndoorLevelDelegate.aidl @@ -0,0 +1,9 @@ +package com.google.android.gms.maps.model.internal; + +interface IIndoorLevelDelegate { + String getName() = 0; + String getShortName() = 1; + void activate() = 2; + boolean equalsRemote(IIndoorLevelDelegate other) = 3; + int hashCodeRemote() = 4; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolygonDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolygonDelegate.aidl index 79292fc7a..ef1d273ab 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolygonDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolygonDelegate.aidl @@ -31,6 +31,7 @@ interface IPolygonDelegate { boolean equalsRemote(IPolygonDelegate other) = 18; int hashCodeRemote() = 19; void setClickable(boolean click) = 20; + boolean isClickable() = 21; void setStrokeJointType(int type) = 22; int getStrokeJointType() = 23; void setStrokePattern(in List items) = 24; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolylineDelegate.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolylineDelegate.aidl index ebbb336bf..0e957b2ca 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolylineDelegate.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/internal/IPolylineDelegate.aidl @@ -1,22 +1,39 @@ package com.google.android.gms.maps.model.internal; +import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.PatternItem; +import com.google.android.gms.maps.model.StyleSpan; interface IPolylineDelegate { - void remove(); - String getId(); - void setPoints(in List points); - List getPoints(); - void setWidth(float width); - float getWidth(); - void setColor(int color); - int getColor(); - void setZIndex(float zIndex); - float getZIndex(); - void setVisible(boolean visible); - boolean isVisible(); - void setGeodesic(boolean geod); - boolean isGeodesic(); - boolean equalsRemote(IPolylineDelegate other); - int hashCodeRemote(); + void remove() = 0; + String getId() = 1; + void setPoints(in List points) = 2; + List getPoints() = 3; + void setWidth(float width) = 4; + float getWidth() = 5; + void setColor(int color) = 6; + int getColor() = 7; + void setZIndex(float zIndex) = 8; + float getZIndex() = 9; + void setVisible(boolean visible) = 10; + boolean isVisible() = 11; + void setGeodesic(boolean geod) = 12; + boolean isGeodesic() = 13; + boolean equalsRemote(IPolylineDelegate other) = 14; + int hashCodeRemote() = 15; + void setClickable(boolean clickable) = 16; + boolean isClickable() = 17; + //void setStartCap(Cap startCap) = 18; + //Cap getStartCap() = 19; + //void setEndCap(Cap endCap) = 20; + //Cap getEndCap() = 21; + void setJointType(int jointType) = 22; + int getJointType() = 23; + void setPattern(in List pattern) = 24; + List getPattern() = 25; + void setTag(IObjectWrapper tag) = 26; + IObjectWrapper getTag() = 27; + //void setSpans(in List spans) = 28; + //List getSpans() = 29 } diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/Cap.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/Cap.java new file mode 100644 index 000000000..d5d38d1f7 --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/Cap.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.maps.model; + +import android.os.IBinder; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class Cap extends AutoSafeParcelable { + @Field(2) + private int type; + @Field(3) + private IBinder bitmap; + private BitmapDescriptor bitmapDescriptor; + @Field(4) + private float bitmapRefWidth; + public static final Creator CREATOR = new AutoCreator<>(Cap.class); +} diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java index c964cb86c..6f8e3f7ab 100644 --- a/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java @@ -8,6 +8,8 @@ package com.google.android.gms.maps.model; +import android.os.Parcel; + import org.microg.gms.common.PublicApi; import org.microg.safeparcel.AutoSafeParcelable; @@ -19,7 +21,10 @@ public class PatternItem extends AutoSafeParcelable { @Field(2) private int type; @Field(3) - private Float length; + private float length; + + private PatternItem() { + } @PublicApi(exclude = true) PatternItem(int type, Float length) { @@ -32,5 +37,20 @@ public class PatternItem extends AutoSafeParcelable { return "[PatternItem: type=" + type + " length=" + length + "]"; } - public static final Creator CREATOR = new AutoCreator<>(PatternItem.class); + public static final Creator CREATOR = new AutoCreator(PatternItem.class) { + @Override + public PatternItem createFromParcel(Parcel parcel) { + PatternItem item = super.createFromParcel(parcel); + switch (item.type) { + case 0: + return new Dash(item.length); + case 1: + return new Dot(); + case 2: + return new Gap(item.length); + default: + return item; + } + } + }; } diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/PolylineOptions.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/PolylineOptions.java index d9a9dc5b4..5e2cda9b1 100644 --- a/play-services-api/src/main/java/com/google/android/gms/maps/model/PolylineOptions.java +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/PolylineOptions.java @@ -1,17 +1,6 @@ /* - * Copyright (C) 2013-2017 microG Project Team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-FileCopyrightText: 2015 microG Project Team + * SPDX-License-Identifier: Apache-2.0 */ package com.google.android.gms.maps.model; @@ -20,7 +9,6 @@ import android.graphics.Color; import org.microg.gms.common.PublicApi; import org.microg.safeparcel.AutoSafeParcelable; -import org.microg.safeparcel.SafeParceled; import java.util.ArrayList; import java.util.List; @@ -31,20 +19,32 @@ import java.util.List; */ @PublicApi public class PolylineOptions extends AutoSafeParcelable { - @SafeParceled(1) + @Field(1) private int versionCode = 1; - @SafeParceled(value = 2, subClass = LatLng.class) + @Field(value = 2, subClass = LatLng.class) private List points = new ArrayList(); - @SafeParceled(3) + @Field(3) private float width = 10; - @SafeParceled(4) + @Field(4) private int color = Color.BLACK; - @SafeParceled(5) + @Field(5) private float zIndex = 0; - @SafeParceled(6) + @Field(6) private boolean visible = true; - @SafeParceled(7) + @Field(7) private boolean geodesic = false; + @Field(8) + private boolean clickable = false; + @Field(9) + private Cap startCap; + @Field(10) + private Cap endCap; + @Field(11) + private int jointType = JointType.DEFAULT; + @Field(value = 12, subClass = PatternItem.class) + private List pattern = null; + @Field(value = 13, subClass = StyleSpan.class) + private List spans = null; public PolylineOptions() { } @@ -68,6 +68,11 @@ public class PolylineOptions extends AutoSafeParcelable { return this; } + public PolylineOptions clickable(boolean clickable) { + this.clickable = clickable; + return this; + } + public PolylineOptions color(int color) { this.color = color; return this; @@ -82,6 +87,14 @@ public class PolylineOptions extends AutoSafeParcelable { return color; } + public int getJointType() { + return jointType; + } + + public List getPattern() { + return pattern; + } + public List getPoints() { return points; } @@ -102,6 +115,10 @@ public class PolylineOptions extends AutoSafeParcelable { return visible; } + public boolean isClickable() { + return clickable; + } + public PolylineOptions visible(boolean visible) { this.visible = visible; return this; diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/StampStyle.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/StampStyle.java new file mode 100644 index 000000000..a0cf3aaff --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/StampStyle.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.maps.model; + +import android.os.IBinder; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class StampStyle extends AutoSafeParcelable { + @Field(2) + private IBinder stamp; + private BitmapDescriptor stampDescriptor; + + public static final Creator CREATOR = new AutoCreator<>(StampStyle.class); +} diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/StrokeStyle.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/StrokeStyle.java new file mode 100644 index 000000000..edc91583a --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/StrokeStyle.java @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.maps.model; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class StrokeStyle extends AutoSafeParcelable { + @Field(2) + private float width; + @Field(3) + private int color; + @Field(4) + private int toColor; + @Field(5) + private boolean isVisible; + @Field(6) + private StampStyle stamp; + + public static final Creator CREATOR = new AutoCreator<>(StrokeStyle.class); +} diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/StyleSpan.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/StyleSpan.java new file mode 100644 index 000000000..19e210141 --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/StyleSpan.java @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.maps.model; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class StyleSpan extends AutoSafeParcelable { + @Field(2) + private StrokeStyle style; + @Field(3) + private double segments; + + public double getSegments() { + return segments; + } + + public StrokeStyle getStyle() { + return style; + } + + public static final Creator CREATOR = new AutoCreator<>(StyleSpan.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 64da70428..2a5c662f4 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 @@ -59,6 +59,9 @@ import org.microg.gms.maps.mapbox.model.InfoWindow import org.microg.gms.maps.mapbox.model.getInfoWindowViewFor import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback +import com.mapbox.mapboxsdk.location.engine.LocationEngineResult +import com.mapbox.mapboxsdk.location.engine.LocationEngineRequest import org.microg.gms.maps.MapsConstants.* import org.microg.gms.maps.mapbox.model.* import org.microg.gms.maps.mapbox.utils.MapContext @@ -111,6 +114,19 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) internal var onInfoWindowCloseListener: IOnInfoWindowCloseListener? = null var currentInfoWindow: InfoWindow? = null + private var myLocationChangeListener: IOnMyLocationChangeListener? = null + + private val locationEngineCallback = object : LocationEngineCallback { + override fun onSuccess(result: LocationEngineResult?) { + result?.lastLocation?.let { location -> + Log.d(TAG, "myLocationChanged: $location") + myLocationChangeListener?.onMyLocationChanged(ObjectWrapper.wrap(location)) + } + } + override fun onFailure(e: Exception) { + Log.w(TAG, e) + } + } var lineManager: LineManager? = null val pendingLines = mutableSetOf>() @@ -143,6 +159,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) val fakeWatermark = View(mapContext) + fakeWatermark.tag = "GoogleWatermark" fakeWatermark.layoutParams = object : RelativeLayout.LayoutParams(0, 0) { @SuppressLint("RtlHardcoded") override fun addRule(verb: Int, subject: Int) { @@ -421,6 +438,15 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) try { if (locationComponent.isLocationComponentActivated) { locationComponent.isLocationComponentEnabled = myLocation + if (myLocation) { + locationComponent.locationEngine?.requestLocationUpdates( + locationComponent.locationEngineRequest, + locationEngineCallback, + null + ) + } else { + locationComponent.locationEngine?.removeLocationUpdates(locationEngineCallback) + } } } catch (e: SecurityException) { Log.w(TAG, e) @@ -431,8 +457,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } override fun getMyLocation(): Location? { - Log.d(TAG, "unimplemented Method: getMyLocation") - return null + synchronized(mapLock) { + return map?.locationComponent?.lastKnownLocation + } } override fun setLocationSource(locationSource: ILocationSourceDelegate?) { @@ -519,8 +546,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) { - Log.d(TAG, "unimplemented Method: setOnMyLocationChangeListener") - + myLocationChangeListener = listener } override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) { @@ -787,13 +813,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) renderMode = RenderMode.COMPASS } + setMyLocationEnabled(locationEnabled) + synchronized(mapLock) { - try { - map.locationComponent.isLocationComponentEnabled = locationEnabled - } catch (e: SecurityException) { - Log.w(TAG, e) - locationEnabled = false - } loaded = true if (loadedCallback != null) { Log.d(TAG, "Invoking callback delayed, as map is loaded") diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt index c0de5468e..2c10af4a7 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polygon.kt @@ -8,6 +8,7 @@ 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.maps.model.LatLng import com.google.android.gms.maps.model.PatternItem import com.google.android.gms.maps.model.PolygonOptions @@ -143,6 +144,8 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option clickable = click } + override fun isClickable(): Boolean = clickable + override fun setStrokeJointType(type: Int) { strokeJointType = type } @@ -159,7 +162,7 @@ class PolygonImpl(private val map: GoogleMapImpl, private val id: String, option tag = obj } - override fun getTag(): IObjectWrapper? = tag + override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null) override fun hashCode(): Int { return id.hashCode() diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt index f9a8f91b9..15751f906 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Polyline.kt @@ -18,7 +18,10 @@ 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.maps.model.LatLng +import com.google.android.gms.maps.model.PatternItem import com.google.android.gms.maps.model.internal.IPolylineDelegate import com.mapbox.mapboxsdk.plugins.annotation.Line import com.mapbox.mapboxsdk.plugins.annotation.LineOptions @@ -30,8 +33,12 @@ import com.google.android.gms.maps.model.PolylineOptions as GmsLineOptions class PolylineImpl(private val map: GoogleMapImpl, private val id: String, options: GmsLineOptions) : IPolylineDelegate.Stub(), Markup { private var points = ArrayList(options.points) private var width = options.width + private var jointType = options.jointType + private var pattern = ArrayList(options.pattern.orEmpty()) private var color = options.color private var visible: Boolean = options.isVisible + private var clickable: Boolean = options.isClickable + private var tag: IObjectWrapper? = null override var annotation: Line? = null override var removed: Boolean = false @@ -103,6 +110,30 @@ class PolylineImpl(private val map: GoogleMapImpl, private val id: String, optio override fun hashCodeRemote(): Int = hashCode() + override fun setClickable(clickable: Boolean) { + this.clickable = clickable + } + + override fun isClickable(): Boolean = clickable + + override fun setJointType(jointType: Int) { + this.jointType = jointType + } + + override fun getJointType(): Int = jointType + + override fun setPattern(pattern: MutableList?) { + this.pattern = ArrayList(pattern.orEmpty()) + } + + override fun getPattern(): MutableList = pattern + + override fun setTag(tag: IObjectWrapper?) { + this.tag = tag + } + + override fun getTag(): IObjectWrapper = tag ?: ObjectWrapper.wrap(null) + override fun hashCode(): Int { return id.hashCode() } @@ -128,4 +159,4 @@ class PolylineImpl(private val map: GoogleMapImpl, private val id: String, optio companion object { private val TAG = "GmsMapPolyline" } -} \ No newline at end of file +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt index 2b00202a4..a8ce14125 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/utils/MapContext.kt @@ -24,7 +24,7 @@ import android.view.LayoutInflater import org.microg.gms.common.Constants import java.io.File -class MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE and Context.CONTEXT_IGNORE_SECURITY)) { +class MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)) { private var layoutInflater: LayoutInflater? = null private val appContext: Context get() = context.applicationContext ?: context @@ -77,4 +77,4 @@ class MapContext(private val context: Context) : ContextWrapper(context.createPa companion object { val TAG = "GmsMapContext" } -} \ No newline at end of file +} diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolygonImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolygonImpl.java index cb1a55f53..23bcfc83c 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolygonImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolygonImpl.java @@ -205,6 +205,11 @@ public class PolygonImpl extends IPolygonDelegate.Stub implements DrawableMarkup } + @Override + public boolean isClickable() throws RemoteException { + return false; + } + @Override public void setStrokeJointType(int type) throws RemoteException { diff --git a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolylineImpl.java b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolylineImpl.java index b2ff4c2f3..7e098596e 100644 --- a/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolylineImpl.java +++ b/play-services-maps-core-vtm/src/main/java/org/microg/gms/maps/vtm/markup/PolylineImpl.java @@ -19,7 +19,9 @@ 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.maps.model.LatLng; +import com.google.android.gms.maps.model.PatternItem; import com.google.android.gms.maps.model.PolylineOptions; import com.google.android.gms.maps.model.internal.IPolylineDelegate; @@ -157,6 +159,47 @@ public class PolylineImpl extends IPolylineDelegate.Stub implements DrawableMark return id.hashCode(); } + // Not implemented + @Override + public void setClickable(boolean clickable) throws RemoteException { + + } + + @Override + public boolean isClickable() throws RemoteException { + return false; + } + + @Override + public void setJointType(int jointType) throws RemoteException { + + } + + @Override + public int getJointType() throws RemoteException { + return 0; + } + + @Override + public void setPattern(List pattern) throws RemoteException { + + } + + @Override + public List getPattern() throws RemoteException { + return null; + } + + @Override + public void setTag(IObjectWrapper tag) throws RemoteException { + + } + + @Override + public IObjectWrapper getTag() throws RemoteException { + return null; + } + @Override public Drawable getDrawable(Map map) { if (!isVisible() || removed) return null; -- GitLab From d49828be554b51d8559a9b801fc4d807e900c2e6 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Mon, 6 Feb 2023 11:20:58 +0100 Subject: [PATCH 8/9] =?UTF-8?q?Circle=20outline=20=E2=80=93=20first=20impl?= =?UTF-8?q?ementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../google/android/gms/maps/model/Dash.aidl | 3 + .../google/android/gms/maps/model/Dot.aidl | 3 + .../google/android/gms/maps/model/Gap.aidl | 3 + .../maps/model/internal/ICircleDelegate.aidl | 5 +- .../android/gms/maps/model/CircleOptions.java | 25 ++++++ .../android/gms/maps/model/PatternItem.java | 2 +- .../org/microg/gms/maps/mapbox/GoogleMap.kt | 26 +++++- .../org/microg/gms/maps/mapbox/Pattern.kt | 88 +++++++++++++++++++ .../microg/gms/maps/mapbox/model/Circle.kt | 32 +++++-- .../gms/maps/vtm/markup/CircleImpl.java | 9 +- 10 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl create mode 100644 play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl new file mode 100644 index 000000000..256aedac9 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dash.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Dash; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl new file mode 100644 index 000000000..c8aa8afb0 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Dot.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Dot; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl new file mode 100644 index 000000000..fd4fde3ae --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/maps/model/Gap.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.maps.model; + +parcelable Gap; 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 8f2277e9e..0a2c088af 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 @@ -2,6 +2,7 @@ package com.google.android.gms.maps.model.internal; import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.PatternItem; interface ICircleDelegate { void remove(); @@ -24,8 +25,8 @@ interface ICircleDelegate { int hashCodeRemote(); void setClickable(boolean clickable); boolean isClickable(); - void setStrokePattern(IObjectWrapper object); - IObjectWrapper getStrokePattern(); + void setStrokePattern(in List items); + List getStrokePattern(); void setTag(IObjectWrapper object); IObjectWrapper getTag(); } 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 cb14f525d..63ff492a7 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 @@ -22,6 +22,10 @@ import org.microg.gms.common.PublicApi; import org.microg.safeparcel.AutoSafeParcelable; import org.microg.safeparcel.SafeParceled; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Defines options for a Circle. */ @@ -45,6 +49,8 @@ public class CircleOptions extends AutoSafeParcelable { private boolean visible = true; @SafeParceled(9) private boolean clickable = false; + @SafeParceled(10) + private List strokePattern = null; /** * Creates circle options. @@ -239,5 +245,24 @@ public class CircleOptions extends AutoSafeParcelable { return this; } + /** + * Specifies a stroke pattern for the circle's outline. The default stroke pattern is solid, represented by {@code null}. + * + * @return this {@link CircleOptions} object with a new stroke pattern set. + */ + public CircleOptions strokePattern(List pattern) { + this.strokePattern = pattern; + return this; + } + + /** + * Gets the stroke pattern set in this {@link CircleOptions} object for the circle's outline. + * + * @return the stroke pattern of the circle's outline. + */ + public List getStrokePattern() { + return strokePattern; + } + public static Creator CREATOR = new AutoCreator(CircleOptions.class); } diff --git a/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java b/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java index 6f8e3f7ab..1278df94d 100644 --- a/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java +++ b/play-services-api/src/main/java/com/google/android/gms/maps/model/PatternItem.java @@ -21,7 +21,7 @@ public class PatternItem extends AutoSafeParcelable { @Field(2) private int type; @Field(3) - private float length; + private Float length; private PatternItem() { } 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 2a5c662f4..3e93a9283 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 @@ -18,6 +18,7 @@ package org.microg.gms.maps.mapbox import android.annotation.SuppressLint import android.content.Context +import android.graphics.Bitmap import android.graphics.Point import android.location.Location import android.os.* @@ -61,7 +62,6 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.maps.OnMapReadyCallback import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback import com.mapbox.mapboxsdk.location.engine.LocationEngineResult -import com.mapbox.mapboxsdk.location.engine.LocationEngineRequest import org.microg.gms.maps.MapsConstants.* import org.microg.gms.maps.mapbox.model.* import org.microg.gms.maps.mapbox.utils.MapContext @@ -142,6 +142,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) val markers = mutableMapOf() var markerId = 0L + val pendingBitmaps = mutableMapOf() + var groundId = 0L var tileId = 0L @@ -334,7 +336,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) return TileOverlayImpl(this, "t${tileId++}", options) } - override fun addCircle(options: CircleOptions): ICircleDelegate? { + override fun addCircle(options: CircleOptions): ICircleDelegate { val circle = CircleImpl(this, "c${fillId++}", options) synchronized(this) { val fillManager = fillManager @@ -349,6 +351,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) } else { circle.line.update(lineManager) } + circle.strokePattern?.let { + addBitmap(it.getName(circle.strokeColor), it.makeBitmap(circle.strokeColor, circle.strokeWidth)) + } } return circle } @@ -803,6 +808,9 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) pendingMarkers.forEach { it.update(symbolManager) } pendingMarkers.clear() + pendingBitmaps.forEach { map -> it.addImage(map.key, map.value) } + pendingBitmaps.clear() + val mapContext = MapContext(context) map.locationComponent.apply { activateLocationComponent(LocationComponentActivationOptions.builder(mapContext, it) @@ -837,11 +845,21 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) return false } + internal fun addBitmap(name: String, bitmap: Bitmap) { + val map = map + if (map != null) { + map.getStyle { + it.addImage(name, bitmap) + } + } else { + pendingBitmaps[name] = bitmap + } + } + override fun useViewLifecycleWhenInFragment(): Boolean { Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment") return false } - override fun onResume() = mapView?.onResume() ?: Unit override fun onPause() = mapView?.onPause() ?: Unit override fun onDestroy() { @@ -892,8 +910,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) override fun onExitAmbient() { Log.d(TAG, "unimplemented Method: onExitAmbient") } - override fun onLowMemory() = mapView?.onLowMemory() ?: Unit + override fun onSaveInstanceState(outState: Bundle) { val newBundle = Bundle() mapView?.onSaveInstanceState(newBundle) diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt new file mode 100644 index 000000000..30b85beba --- /dev/null +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt @@ -0,0 +1,88 @@ +package org.microg.gms.maps.mapbox + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Paint +import android.util.Log +import com.google.android.gms.maps.model.Dash +import com.google.android.gms.maps.model.Dot +import com.google.android.gms.maps.model.Gap +import com.google.android.gms.maps.model.PatternItem +import org.microg.gms.maps.mapbox.model.CircleImpl +import kotlin.math.max + +const val BITMAP_WIDTH = 128 + +fun PatternItem.getName(): String = when (this) { + is Dash -> "dash${this.length}" + is Gap -> "gap${this.length}" + is Dot -> "dot" + else -> this.javaClass.name +} + +/** + * Name of pattern, to identify it after it is added to map + */ +fun MutableList.getName(color: Int) = joinToString("-") { + it.getName() +} + "-${color}" + +/** + * Gets width that a bitmap for this pattern item would have if the pattern's + * bitmap were to have height 1. + */ +fun PatternItem.getVirtualWidth(strokeWidth: Float): Float = when (this) { + is Dash -> this.length + is Gap -> this.length + is Dot -> strokeWidth + else -> 1f +} + +/** + * Gets width that a bitmap for this pattern would have if it were to have + * height 1. + */ +fun MutableList.getVirtualWidth(strokeWidth: Float) = map { it.getVirtualWidth(strokeWidth) }.sum() + +fun MutableList.makeBitmap(color: Int, width: Float): Bitmap = makeBitmap(Paint().apply { + setColor(color) + style = Paint.Style.FILL +}, width) + + +fun MutableList.makeBitmap(paint: Paint, width: Float): Bitmap { + + val virtualWidth = getVirtualWidth(width) + val scale = BITMAP_WIDTH / virtualWidth + Log.d("GmsMapPattern", "vWidth: $virtualWidth, scale: $scale") + + val bitmap = Bitmap.createBitmap(BITMAP_WIDTH, width.toInt(), Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + var drawCursor = 0f + for (item in this) { + when (item) { + is Dash -> canvas.drawRect( + drawCursor, + 0f, + drawCursor + item.length * scale, + width, + paint + ) + + // is Gap -> do nothing, only move cursor + + is Dot -> canvas.drawOval( + drawCursor, + 0f, + drawCursor + item.getVirtualWidth(width) * scale, + width, + paint + ) + } + + drawCursor += item.getVirtualWidth(width) * scale + } + + return bitmap +} diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt index d0aa04dab..cff8d333b 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 @@ -22,6 +22,7 @@ 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.PatternItem import com.google.android.gms.maps.model.internal.ICircleDelegate import com.mapbox.geojson.LineString import com.mapbox.geojson.Point @@ -32,6 +33,8 @@ 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.getName +import org.microg.gms.maps.mapbox.makeBitmap import com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions val NORTH_POLE: Point = Point.fromLngLat(0.0, 90.0) @@ -50,6 +53,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 strokePattern: MutableList? = options.strokePattern private var tag: Any? = null internal val line: Markup = object : Markup { @@ -63,6 +67,11 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options ).withLineWidth(strokeWidth / map.dpiFactor) .withLineColor(ColorUtils.colorToRgbaString(strokeColor)) .withLineOpacity(if (visible) 1f else 0f) + .apply { + strokePattern?.let { + withLinePattern(it.getName(strokeColor)) + } + } override val removed: Boolean = false } @@ -74,7 +83,6 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options FillOptions() .withGeometry(makePolygon()) .withFillColor(ColorUtils.colorToRgbaString(fillColor)) - .withFillOutlineColor(ColorUtils.colorToRgbaString(strokeColor)) .withFillOpacity(if (visible && !wrapsAroundPoles()) 1f else 0f) private fun makePolygon() = TurfTransformation.circle( @@ -179,6 +187,10 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun setStrokeWidth(width: Float) { this.strokeWidth = width line.annotation?.lineWidth = width / map.dpiFactor + strokePattern?.let { + map.addBitmap(it.getName(strokeColor), it.makeBitmap(strokeColor, width)) + line.annotation?.linePattern = it.getName(strokeColor) + } map.lineManager?.let { line.update(it) } } @@ -187,6 +199,10 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun setStrokeColor(color: Int) { this.strokeColor = color line.annotation?.setLineColor(color) + strokePattern?.let { + map.addBitmap(it.getName(color), it.makeBitmap(color, strokeWidth)) + line.annotation?.linePattern = it.getName(color) + } map.lineManager?.let { line.update(it) } } @@ -243,13 +259,17 @@ 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 setStrokePattern(pattern: MutableList?) { + this.strokePattern = pattern + line.annotation?.linePattern = pattern?.getName(strokeColor) + pattern?.let { + map.addBitmap(it.getName(strokeColor), it.makeBitmap(strokeColor, strokeWidth)) + } + map.lineManager?.let { line.update(it) } } - override fun getStrokePattern(): IObjectWrapper { - Log.d(TAG, "unimplemented method: getStrokePattern") - return ObjectWrapper.wrap(null) + override fun getStrokePattern(): MutableList? { + return strokePattern } override fun setTag(o: IObjectWrapper) { 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 9fe9a05ff..8a30cd21e 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 @@ -23,6 +23,7 @@ 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.PatternItem; import com.google.android.gms.maps.model.internal.ICircleDelegate; import org.microg.gms.maps.vtm.GmsMapsTypeHelper; @@ -31,6 +32,8 @@ import org.oscim.layers.vector.geometries.Drawable; import org.oscim.layers.vector.geometries.Style; import org.oscim.map.Map; +import java.util.List; + public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { private static final String TAG = "GmsMapCircle"; @@ -155,14 +158,14 @@ public class CircleImpl extends ICircleDelegate.Stub implements DrawableMarkup { } @Override - public void setStrokePattern(IObjectWrapper object) throws RemoteException { + public void setStrokePattern(List object) throws RemoteException { Log.d(TAG, "unimplemented method: setStrokePattern"); } @Override - public IObjectWrapper getStrokePattern() throws RemoteException { + public List getStrokePattern() throws RemoteException { Log.d(TAG, "unimplemented method: getStrokePattern"); - return ObjectWrapper.wrap(null); + return null; } @Override -- GitLab From 9e4de6b3e2290f9fe99dab2db5c012b06183f2a1 Mon Sep 17 00:00:00 2001 From: Fynn Godau Date: Tue, 14 Feb 2023 20:00:58 +0100 Subject: [PATCH 9/9] Use pattern's width as stroke pattern bitmap width --- .../org/microg/gms/maps/mapbox/GoogleMap.kt | 5 ++- .../org/microg/gms/maps/mapbox/Pattern.kt | 45 +++++++++---------- .../microg/gms/maps/mapbox/model/Circle.kt | 16 ++++--- 3 files changed, 33 insertions(+), 33 deletions(-) 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 3e93a9283..7b831cbf8 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 @@ -352,7 +352,10 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) circle.line.update(lineManager) } circle.strokePattern?.let { - addBitmap(it.getName(circle.strokeColor), it.makeBitmap(circle.strokeColor, circle.strokeWidth)) + addBitmap( + it.getName(circle.strokeColor, circle.strokeWidth), + it.makeBitmap(circle.strokeColor, circle.strokeWidth) + ) } } return circle diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt index 30b85beba..646a0906a 100644 --- a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt +++ b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Pattern.kt @@ -3,15 +3,10 @@ package org.microg.gms.maps.mapbox import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Paint -import android.util.Log import com.google.android.gms.maps.model.Dash import com.google.android.gms.maps.model.Dot import com.google.android.gms.maps.model.Gap import com.google.android.gms.maps.model.PatternItem -import org.microg.gms.maps.mapbox.model.CircleImpl -import kotlin.math.max - -const val BITMAP_WIDTH = 128 fun PatternItem.getName(): String = when (this) { is Dash -> "dash${this.length}" @@ -23,15 +18,15 @@ fun PatternItem.getName(): String = when (this) { /** * Name of pattern, to identify it after it is added to map */ -fun MutableList.getName(color: Int) = joinToString("-") { +fun MutableList.getName(color: Int, strokeWidth: Float) = joinToString("-") { it.getName() -} + "-${color}" +} + "-${color}-width${strokeWidth}" /** - * Gets width that a bitmap for this pattern item would have if the pattern's - * bitmap were to have height 1. + * Gets width that a bitmap for this pattern item would have if the pattern's bitmap + * were to be drawn with respect to aspect ratio onto a canvas with height 1. */ -fun PatternItem.getVirtualWidth(strokeWidth: Float): Float = when (this) { +fun PatternItem.getWidth(strokeWidth: Float): Float = when (this) { is Dash -> this.length is Gap -> this.length is Dot -> strokeWidth @@ -39,24 +34,24 @@ fun PatternItem.getVirtualWidth(strokeWidth: Float): Float = when (this) { } /** - * Gets width that a bitmap for this pattern would have if it were to have - * height 1. + * Gets width that a bitmap for this pattern would have if it were to be drawn + * with respect to aspect ratio onto a canvas with height 1. */ -fun MutableList.getVirtualWidth(strokeWidth: Float) = map { it.getVirtualWidth(strokeWidth) }.sum() +fun MutableList.getWidth(strokeWidth: Float) = map { it.getWidth(strokeWidth) }.sum() -fun MutableList.makeBitmap(color: Int, width: Float): Bitmap = makeBitmap(Paint().apply { +fun MutableList.makeBitmap(color: Int, strokeWidth: Float): Bitmap = makeBitmap(Paint().apply { setColor(color) style = Paint.Style.FILL -}, width) +}, strokeWidth) -fun MutableList.makeBitmap(paint: Paint, width: Float): Bitmap { +fun MutableList.makeBitmap(paint: Paint, strokeWidth: Float): Bitmap { - val virtualWidth = getVirtualWidth(width) - val scale = BITMAP_WIDTH / virtualWidth - Log.d("GmsMapPattern", "vWidth: $virtualWidth, scale: $scale") + // Pattern aspect ratio is not respected by renderer + val width = getWidth(strokeWidth).toInt() + val height = strokeWidth.toInt() // avoids squished image bugs - val bitmap = Bitmap.createBitmap(BITMAP_WIDTH, width.toInt(), Bitmap.Config.ARGB_8888) + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) var drawCursor = 0f @@ -65,8 +60,8 @@ fun MutableList.makeBitmap(paint: Paint, width: Float): Bitmap { is Dash -> canvas.drawRect( drawCursor, 0f, - drawCursor + item.length * scale, - width, + drawCursor + item.length, + strokeWidth, paint ) @@ -75,13 +70,13 @@ fun MutableList.makeBitmap(paint: Paint, width: Float): Bitmap { is Dot -> canvas.drawOval( drawCursor, 0f, - drawCursor + item.getVirtualWidth(width) * scale, - width, + drawCursor + item.getWidth(strokeWidth), + strokeWidth, paint ) } - drawCursor += item.getVirtualWidth(width) * scale + drawCursor += item.getWidth(strokeWidth) } return bitmap diff --git a/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt b/play-services-maps-core-mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/model/Circle.kt index cff8d333b..9a3cb2570 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 @@ -69,7 +69,7 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options .withLineOpacity(if (visible) 1f else 0f) .apply { strokePattern?.let { - withLinePattern(it.getName(strokeColor)) + withLinePattern(it.getName(strokeColor, strokeWidth)) } } @@ -188,8 +188,9 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options this.strokeWidth = width line.annotation?.lineWidth = width / map.dpiFactor strokePattern?.let { - map.addBitmap(it.getName(strokeColor), it.makeBitmap(strokeColor, width)) - line.annotation?.linePattern = it.getName(strokeColor) + val bitmapName = it.getName(strokeColor, strokeWidth) + map.addBitmap(bitmapName, it.makeBitmap(strokeColor, width)) + line.annotation?.linePattern = bitmapName } map.lineManager?.let { line.update(it) } } @@ -200,8 +201,9 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options this.strokeColor = color line.annotation?.setLineColor(color) strokePattern?.let { - map.addBitmap(it.getName(color), it.makeBitmap(color, strokeWidth)) - line.annotation?.linePattern = it.getName(color) + val bitmapName = it.getName(color, strokeWidth) + map.addBitmap(bitmapName, it.makeBitmap(color, strokeWidth)) + line.annotation?.linePattern = bitmapName } map.lineManager?.let { line.update(it) } } @@ -261,9 +263,9 @@ class CircleImpl(private val map: GoogleMapImpl, private val id: String, options override fun setStrokePattern(pattern: MutableList?) { this.strokePattern = pattern - line.annotation?.linePattern = pattern?.getName(strokeColor) + line.annotation?.linePattern = pattern?.getName(strokeColor, strokeWidth) pattern?.let { - map.addBitmap(it.getName(strokeColor), it.makeBitmap(strokeColor, strokeWidth)) + map.addBitmap(it.getName(strokeColor, strokeWidth), it.makeBitmap(strokeColor, strokeWidth)) } map.lineManager?.let { line.update(it) } } -- GitLab