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 fe592337f435adcb46a223dc347b13732cb4f085..bcb27314f2b22d02c4b3c5e33895b26ccf936cf6 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; @@ -126,7 +127,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 0000000000000000000000000000000000000000..cd7ad60e6c5875aa1e6468d86a77a176a8cc32e0 --- /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 719d8eab6b3094e799e6a49c0079ee1c92a5c8b6..8f2277e9e3fdb0658a1c1e5ebd3d40e0b5ebce93 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 { @@ -21,4 +22,10 @@ interface ICircleDelegate { boolean isVisible(); boolean equalsRemote(ICircleDelegate other); 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-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 9f61106023db2e59b13f7a09d3472ce8ca4fa62a..cb14f525ded630e42a24a3f898ef8cc319195e2a 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/build.gradle b/play-services-maps-core-mapbox/build.gradle index a5bbf5ae0170519210cf20a5852c9a8d097f1ba8..e0fcff51b45c9b0fa657a07f20a9a770a8da4baf 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 87d5bdfa07101711a992f9a482cbc97fa5ef8e77..64da70428878d77c3c02d659b1b694f3cb6cdc1f 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 @@ -103,6 +103,8 @@ 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 + private var infoWindowAdapter: IInfoWindowAdapter = DefaultInfoWindowAdapter(MapContext(context)) internal var onInfoWindowClickListener: IOnInfoWindowClickListener? = null internal var onInfoWindowLongClickListener: IOnInfoWindowLongClickListener? = null @@ -111,17 +113,14 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) var currentInfoWindow: InfoWindow? = null var lineManager: LineManager? = null - val pendingLines = mutableSetOf() + val pendingLines = mutableSetOf>() var lineId = 0L var fillManager: FillManager? = null - val pendingFills = mutableSetOf() + val pendingFills = mutableSetOf>() + val circles = mutableMapOf() var fillId = 0L - var circleManager: CircleManager? = null - val pendingCircles = mutableSetOf() - var circleId = 0L - var symbolManager: SymbolManager? = null val pendingMarkers = mutableSetOf() val markers = mutableMapOf() @@ -319,20 +318,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) } @@ -359,12 +363,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) } } @@ -491,6 +493,10 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) markerDragListener = listener } + override fun setCircleClickListener(listener: IOnCircleClickListener?) { + circleClickListener = listener + } + override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) { onInfoWindowClickListener = listener } @@ -691,11 +697,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) @@ -703,7 +707,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 @@ -743,15 +746,30 @@ 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() + 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) } @@ -806,14 +824,13 @@ 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 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 aa016ea8005c4b92a936a52836c67f60d7352c1f..d0aa04dab38b3d015a80f7c0f3235a0166fe53fb 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,78 +18,184 @@ 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.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 = 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 + 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 + private var clickable: Boolean = options.isClickable + private var tag: Any? = 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: Circle? = null + 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(): MutableList { + val pointList = TurfMeta.coordAll( + makePolygon(), wrapsAroundPoles() + ) + // 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 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) + } + } + } + + // In this case no changes were made + return pointList + } + + 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 +211,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 @@ -116,6 +221,43 @@ 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 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() } 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 301c7ed2ecfc43db890def0471f1f4f4c180b85b..8eae51a68e63bc3c6a09a353a525782e34ada03b 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.IOnInfoWindowCloseListener; import com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener; @@ -214,6 +215,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 18b4a999450e3772d948d40c195775e465bdd5b5..9fe9a05ff6297742344c8a7b14026c60379ba0c6 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,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.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; @@ -30,6 +33,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 +144,38 @@ 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 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);