From ae2f4706121729c4ba99e098af54e4f3ded22ced Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 26 Jun 2024 10:17:50 -0400 Subject: [PATCH 1/6] Convert native->Dart calls to FlutterApi --- .../plugins/googlemaps/CirclesController.java | 18 +- .../googlemaps/ClusterManagersController.java | 18 +- .../flutter/plugins/googlemaps/Convert.java | 71 +- .../googlemaps/GoogleMapController.java | 62 +- .../plugins/googlemaps/MarkersController.java | 39 +- .../flutter/plugins/googlemaps/Messages.java | 633 +++++++++++++++++- .../googlemaps/PolygonsController.java | 18 +- .../googlemaps/PolylinesController.java | 17 +- .../googlemaps/TileOverlaysController.java | 10 +- .../googlemaps/TileProviderController.java | 68 +- .../ClusterManagersControllerTest.java | 17 +- .../plugins/googlemaps/ConvertTest.java | 44 +- .../googlemaps/GoogleMapControllerTest.java | 5 +- .../googlemaps/MarkersControllerTest.java | 41 +- .../lib/src/google_maps_flutter_android.dart | 341 +++++----- .../lib/src/messages.g.dart | 595 +++++++++++++++- .../pigeons/messages.dart | 65 ++ .../google_maps_flutter_android_test.dart | 158 ++++- 18 files changed, 1713 insertions(+), 507 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java index 2b52641caa0..09342a7d1fa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java @@ -8,7 +8,7 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Circle; import com.google.android.gms.maps.model.CircleOptions; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -17,14 +17,14 @@ class CirclesController { private final Map circleIdToController; private final Map googleMapsCircleIdToDartCircleId; - private final MethodChannel methodChannel; + private final @NonNull MapsCallbackApi flutterApi; private final float density; private GoogleMap googleMap; - CirclesController(MethodChannel methodChannel, float density) { + CirclesController(@NonNull MapsCallbackApi flutterApi, float density) { this.circleIdToController = new HashMap<>(); this.googleMapsCircleIdToDartCircleId = new HashMap<>(); - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; this.density = density; } @@ -67,7 +67,15 @@ boolean onCircleTap(String googleCircleId) { if (circleId == null) { return false; } - methodChannel.invokeMethod("circle#onTap", Convert.circleIdToJson(circleId)); + flutterApi.onCircleTap( + circleId, + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }); CircleController circleController = circleIdToController.get(circleId); if (circleController != null) { return circleController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java index 16666ac0dc3..500857cfa85 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java @@ -15,7 +15,7 @@ import com.google.maps.android.clustering.ClusterManager; import com.google.maps.android.clustering.view.DefaultClusterRenderer; import com.google.maps.android.collections.MarkerManager; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,7 +30,7 @@ class ClusterManagersController ClusterManager.OnClusterClickListener { @NonNull private final Context context; @NonNull private final HashMap> clusterManagerIdToManager; - @NonNull private final MethodChannel methodChannel; + @NonNull private final MapsCallbackApi flutterApi; @Nullable private MarkerManager markerManager; @Nullable private GoogleMap googleMap; @@ -41,10 +41,10 @@ class ClusterManagersController private ClusterManagersController.OnClusterItemRendered clusterItemRenderedListener; - ClusterManagersController(MethodChannel methodChannel, Context context) { + ClusterManagersController(@NonNull MapsCallbackApi flutterApi, Context context) { this.clusterManagerIdToManager = new HashMap<>(); this.context = context; - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; } void init(GoogleMap googleMap, MarkerManager markerManager) { @@ -197,7 +197,15 @@ public boolean onClusterClick(Cluster cluster) { if (cluster.getSize() > 0) { MarkerBuilder[] builders = cluster.getItems().toArray(new MarkerBuilder[0]); String clusterManagerId = builders[0].clusterManagerId(); - methodChannel.invokeMethod("cluster#onTap", Convert.clusterToJson(clusterManagerId, cluster)); + flutterApi.onClusterTap( + Convert.clusterToPigeon(clusterManagerId, cluster), + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }); } // Return false to allow the default behavior of the cluster click event to occur. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 71455b668e8..e8361c291a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -373,16 +373,14 @@ private static int toInt(Object o) { return null; } - static Object cameraPositionToJson(CameraPosition position) { - if (position == null) { - return null; - } - final Map data = new HashMap<>(); - data.put("bearing", position.bearing); - data.put("target", latLngToJson(position.target)); - data.put("tilt", position.tilt); - data.put("zoom", position.zoom); - return data; + static @NonNull Messages.PlatformCameraPosition cameraPositionToPigeon( + @NonNull CameraPosition position) { + return new Messages.PlatformCameraPosition.Builder() + .setBearing((double) position.bearing) + .setTarget(latLngToPigeon(position.target)) + .setTilt((double) position.tilt) + .setZoom((double) position.zoom) + .build(); } static Object latLngBoundsToJson(LatLngBounds latLngBounds) { @@ -426,29 +424,6 @@ static Object polylineIdToJson(String polylineId) { return data; } - static Object circleIdToJson(String circleId) { - if (circleId == null) { - return null; - } - final Map data = new HashMap<>(1); - data.put("circleId", circleId); - return data; - } - - static Map tileOverlayArgumentsToJson( - String tileOverlayId, int x, int y, int zoom) { - - if (tileOverlayId == null) { - return null; - } - final Map data = new HashMap<>(4); - data.put("tileOverlayId", tileOverlayId); - data.put("x", x); - data.put("y", y); - data.put("zoom", zoom); - return data; - } - static Object latLngToJson(LatLng latLng) { return Arrays.asList(latLng.latitude, latLng.longitude); } @@ -464,36 +439,6 @@ static LatLng latLngFromPigeon(Messages.PlatformLatLng latLng) { return new LatLng(latLng.getLatitude(), latLng.getLongitude()); } - static Object clusterToJson(String clusterManagerId, Cluster cluster) { - int clusterSize = cluster.getSize(); - LatLngBounds.Builder latLngBoundsBuilder = LatLngBounds.builder(); - - String[] markerIds = new String[clusterSize]; - MarkerBuilder[] markerBuilders = cluster.getItems().toArray(new MarkerBuilder[clusterSize]); - - // Loops though cluster items and reads markers position for the LatLngBounds - // builder - // and also builds list of marker ids on the cluster. - for (int i = 0; i < clusterSize; i++) { - MarkerBuilder markerBuilder = markerBuilders[i]; - latLngBoundsBuilder.include(markerBuilder.getPosition()); - markerIds[i] = markerBuilder.markerId(); - } - - Object position = latLngToJson(cluster.getPosition()); - Object bounds = latLngBoundsToJson(latLngBoundsBuilder.build()); - - final Map data = new HashMap<>(4); - - // For dart side implementation see parseCluster method at - // packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart - data.put("clusterManagerId", clusterManagerId); - data.put("position", position); - data.put("bounds", bounds); - data.put("markerIds", Arrays.asList(markerIds)); - return data; - } - static Messages.PlatformCluster clusterToPigeon( String clusterManagerId, Cluster cluster) { int clusterSize = cluster.getSize(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index d2b6b082a27..4a29f9e58c6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -30,7 +30,6 @@ import com.google.android.gms.maps.GoogleMapOptions; import com.google.android.gms.maps.MapView; import com.google.android.gms.maps.OnMapReadyCallback; -import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.Circle; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; @@ -44,15 +43,13 @@ import com.google.maps.android.collections.MarkerManager; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugins.googlemaps.Messages.FlutterError; import io.flutter.plugins.googlemaps.Messages.MapsApi; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import io.flutter.plugins.googlemaps.Messages.MapsInspectorApi; import java.io.ByteArrayOutputStream; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -73,7 +70,7 @@ class GoogleMapController private static final String TAG = "GoogleMapController"; private final int id; - private final MethodChannel methodChannel; + private final MapsCallbackApi flutterApi; private final BinaryMessenger binaryMessenger; private final GoogleMapOptions options; @Nullable private MapView mapView; @@ -109,6 +106,18 @@ class GoogleMapController private boolean lastSetStyleSucceeded; @VisibleForTesting List initialPadding; + // A convenience object for calls to Dart where errors don't matter, such as streaming map + // information where if the corresponding Dart object is gone, the message should be silently + // dropped. + private final Messages.VoidResult noopVoidResult = + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }; + GoogleMapController( int id, Context context, @@ -121,19 +130,18 @@ class GoogleMapController this.mapView = new MapView(context, options); this.density = context.getResources().getDisplayMetrics().density; this.binaryMessenger = binaryMessenger; - methodChannel = - new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_" + id); + flutterApi = new MapsCallbackApi(binaryMessenger, Integer.toString(id)); MapsApi.setUp(binaryMessenger, Integer.toString(id), this); MapsInspectorApi.setUp(binaryMessenger, Integer.toString(id), this); AssetManager assetManager = context.getAssets(); this.lifecycleProvider = lifecycleProvider; - this.clusterManagersController = new ClusterManagersController(methodChannel, context); + this.clusterManagersController = new ClusterManagersController(flutterApi, context); this.markersController = - new MarkersController(methodChannel, clusterManagersController, assetManager, density); - this.polygonsController = new PolygonsController(methodChannel, density); - this.polylinesController = new PolylinesController(methodChannel, assetManager, density); - this.circlesController = new CirclesController(methodChannel, density); - this.tileOverlaysController = new TileOverlaysController(methodChannel); + new MarkersController(flutterApi, clusterManagersController, assetManager, density); + this.polygonsController = new PolygonsController(flutterApi, density); + this.polylinesController = new PolylinesController(flutterApi, assetManager, density); + this.circlesController = new CirclesController(flutterApi, density); + this.tileOverlaysController = new TileOverlaysController(flutterApi); } // Constructor for testing purposes only @@ -142,7 +150,7 @@ class GoogleMapController int id, Context context, BinaryMessenger binaryMessenger, - MethodChannel methodChannel, + MapsCallbackApi flutterApi, LifecycleProvider lifecycleProvider, GoogleMapOptions options, ClusterManagersController clusterManagersController, @@ -154,7 +162,7 @@ class GoogleMapController this.id = id; this.context = context; this.binaryMessenger = binaryMessenger; - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; this.options = options; this.mapView = new MapView(context, options); this.density = context.getResources().getDisplayMetrics().density; @@ -182,10 +190,6 @@ void init() { mapView.getMapAsync(this); } - private CameraPosition getCameraPosition() { - return trackCameraPosition ? googleMap.getCameraPosition() : null; - } - @Override public void onMapReady(@NonNull GoogleMap googleMap) { this.googleMap = googleMap; @@ -298,24 +302,17 @@ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { @Override public void onMapClick(@NonNull LatLng latLng) { - final Map arguments = new HashMap<>(2); - arguments.put("position", Convert.latLngToJson(latLng)); - methodChannel.invokeMethod("map#onTap", arguments); + flutterApi.onTap(Convert.latLngToPigeon(latLng), noopVoidResult); } @Override public void onMapLongClick(@NonNull LatLng latLng) { - final Map arguments = new HashMap<>(2); - arguments.put("position", Convert.latLngToJson(latLng)); - methodChannel.invokeMethod("map#onLongPress", arguments); + flutterApi.onLongPress(Convert.latLngToPigeon(latLng), noopVoidResult); } @Override public void onCameraMoveStarted(int reason) { - final Map arguments = new HashMap<>(2); - boolean isGesture = reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE; - arguments.put("isGesture", isGesture); - methodChannel.invokeMethod("camera#onMoveStarted", arguments); + flutterApi.onCameraMoveStarted(noopVoidResult); } @Override @@ -328,15 +325,14 @@ public void onCameraMove() { if (!trackCameraPosition) { return; } - final Map arguments = new HashMap<>(2); - arguments.put("position", Convert.cameraPositionToJson(googleMap.getCameraPosition())); - methodChannel.invokeMethod("camera#onMove", arguments); + flutterApi.onCameraMove( + Convert.cameraPositionToPigeon(googleMap.getCameraPosition()), noopVoidResult); } @Override public void onCameraIdle() { clusterManagersController.onCameraIdle(); - methodChannel.invokeMethod("camera#onIdle", Collections.singletonMap("map", id)); + flutterApi.onCameraIdle(noopVoidResult); } @Override diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java index 5d870e88081..d1268a84a44 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java @@ -10,7 +10,7 @@ import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.maps.android.collections.MarkerManager; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -20,21 +20,33 @@ class MarkersController { private final HashMap markerIdToMarkerBuilder; private final HashMap markerIdToController; private final HashMap googleMapsMarkerIdToDartMarkerId; - private final MethodChannel methodChannel; + private final @NonNull MapsCallbackApi flutterApi; private MarkerManager.Collection markerCollection; private final ClusterManagersController clusterManagersController; private final AssetManager assetManager; private final float density; + // A convenience object for calls to Dart where errors don't matter, such as streaming map + // information where if the corresponding Dart object is gone, the message should be silently + // dropped. + private final Messages.VoidResult noopVoidResult = + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }; + MarkersController( - MethodChannel methodChannel, + @NonNull MapsCallbackApi flutterApi, ClusterManagersController clusterManagersController, AssetManager assetManager, float density) { this.markerIdToMarkerBuilder = new HashMap<>(); this.markerIdToController = new HashMap<>(); this.googleMapsMarkerIdToDartMarkerId = new HashMap<>(); - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; this.clusterManagersController = clusterManagersController; this.assetManager = assetManager; this.density = density; @@ -126,7 +138,7 @@ boolean onMapsMarkerTap(String googleMarkerId) { } boolean onMarkerTap(String markerId) { - methodChannel.invokeMethod("marker#onTap", Convert.markerIdToJson(markerId)); + flutterApi.onMarkerTap(markerId, noopVoidResult); MarkerController markerController = markerIdToController.get(markerId); if (markerController != null) { return markerController.consumeTapEvents(); @@ -139,10 +151,7 @@ void onMarkerDragStart(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - final Map data = new HashMap<>(); - data.put("markerId", markerId); - data.put("position", Convert.latLngToJson(latLng)); - methodChannel.invokeMethod("marker#onDragStart", data); + flutterApi.onMarkerDragStart(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); } void onMarkerDrag(String googleMarkerId, LatLng latLng) { @@ -150,10 +159,7 @@ void onMarkerDrag(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - final Map data = new HashMap<>(); - data.put("markerId", markerId); - data.put("position", Convert.latLngToJson(latLng)); - methodChannel.invokeMethod("marker#onDrag", data); + flutterApi.onMarkerDrag(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); } void onMarkerDragEnd(String googleMarkerId, LatLng latLng) { @@ -161,10 +167,7 @@ void onMarkerDragEnd(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - final Map data = new HashMap<>(); - data.put("markerId", markerId); - data.put("position", Convert.latLngToJson(latLng)); - methodChannel.invokeMethod("marker#onDragEnd", data); + flutterApi.onMarkerDragEnd(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); } void onInfoWindowTap(String googleMarkerId) { @@ -172,7 +175,7 @@ void onInfoWindowTap(String googleMarkerId) { if (markerId == null) { return; } - methodChannel.invokeMethod("infoWindow#onTap", Convert.markerIdToJson(markerId)); + flutterApi.onInfoWindowTap(markerId, noopVoidResult); } /** diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java index ba47fa72d2c..db8e9f7e868 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java @@ -21,6 +21,8 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** Generated class from Pigeon. */ @@ -60,6 +62,12 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { return errorList; } + @NonNull + protected static FlutterError createConnectionError(@NonNull String channelName) { + return new FlutterError( + "channel-error", "Unable to establish connection on channel: " + channelName + ".", ""); + } + @Target(METHOD) @Retention(CLASS) @interface CanIgnoreReturnValue {} @@ -75,6 +83,135 @@ private PlatformRendererType(final int index) { } } + /** + * Pigeon representatation of a CameraPosition. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformCameraPosition { + private @NonNull Double bearing; + + public @NonNull Double getBearing() { + return bearing; + } + + public void setBearing(@NonNull Double setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"bearing\" is null."); + } + this.bearing = setterArg; + } + + private @NonNull PlatformLatLng target; + + public @NonNull PlatformLatLng getTarget() { + return target; + } + + public void setTarget(@NonNull PlatformLatLng setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"target\" is null."); + } + this.target = setterArg; + } + + private @NonNull Double tilt; + + public @NonNull Double getTilt() { + return tilt; + } + + public void setTilt(@NonNull Double setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"tilt\" is null."); + } + this.tilt = setterArg; + } + + private @NonNull Double zoom; + + public @NonNull Double getZoom() { + return zoom; + } + + public void setZoom(@NonNull Double setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"zoom\" is null."); + } + this.zoom = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformCameraPosition() {} + + public static final class Builder { + + private @Nullable Double bearing; + + @CanIgnoreReturnValue + public @NonNull Builder setBearing(@NonNull Double setterArg) { + this.bearing = setterArg; + return this; + } + + private @Nullable PlatformLatLng target; + + @CanIgnoreReturnValue + public @NonNull Builder setTarget(@NonNull PlatformLatLng setterArg) { + this.target = setterArg; + return this; + } + + private @Nullable Double tilt; + + @CanIgnoreReturnValue + public @NonNull Builder setTilt(@NonNull Double setterArg) { + this.tilt = setterArg; + return this; + } + + private @Nullable Double zoom; + + @CanIgnoreReturnValue + public @NonNull Builder setZoom(@NonNull Double setterArg) { + this.zoom = setterArg; + return this; + } + + public @NonNull PlatformCameraPosition build() { + PlatformCameraPosition pigeonReturn = new PlatformCameraPosition(); + pigeonReturn.setBearing(bearing); + pigeonReturn.setTarget(target); + pigeonReturn.setTilt(tilt); + pigeonReturn.setZoom(zoom); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(4); + toListResult.add(bearing); + toListResult.add(target); + toListResult.add(tilt); + toListResult.add(zoom); + return toListResult; + } + + static @NonNull PlatformCameraPosition fromList(@NonNull ArrayList __pigeon_list) { + PlatformCameraPosition pigeonResult = new PlatformCameraPosition(); + Object bearing = __pigeon_list.get(0); + pigeonResult.setBearing((Double) bearing); + Object target = __pigeon_list.get(1); + pigeonResult.setTarget((PlatformLatLng) target); + Object tilt = __pigeon_list.get(2); + pigeonResult.setTilt((Double) tilt); + Object zoom = __pigeon_list.get(3); + pigeonResult.setZoom((Double) zoom); + return pigeonResult; + } + } + /** * Pigeon representation of a CameraUpdate. * @@ -1120,34 +1257,36 @@ private PigeonCodec() {} protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 129: - return PlatformCameraUpdate.fromList((ArrayList) readValue(buffer)); + return PlatformCameraPosition.fromList((ArrayList) readValue(buffer)); case (byte) 130: - return PlatformCircle.fromList((ArrayList) readValue(buffer)); + return PlatformCameraUpdate.fromList((ArrayList) readValue(buffer)); case (byte) 131: - return PlatformClusterManager.fromList((ArrayList) readValue(buffer)); + return PlatformCircle.fromList((ArrayList) readValue(buffer)); case (byte) 132: - return PlatformMarker.fromList((ArrayList) readValue(buffer)); + return PlatformClusterManager.fromList((ArrayList) readValue(buffer)); case (byte) 133: - return PlatformPolygon.fromList((ArrayList) readValue(buffer)); + return PlatformMarker.fromList((ArrayList) readValue(buffer)); case (byte) 134: - return PlatformPolyline.fromList((ArrayList) readValue(buffer)); + return PlatformPolygon.fromList((ArrayList) readValue(buffer)); case (byte) 135: - return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); + return PlatformPolyline.fromList((ArrayList) readValue(buffer)); case (byte) 136: - return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); case (byte) 137: - return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + return PlatformLatLng.fromList((ArrayList) readValue(buffer)); case (byte) 138: - return PlatformCluster.fromList((ArrayList) readValue(buffer)); + return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); case (byte) 139: - return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); + return PlatformCluster.fromList((ArrayList) readValue(buffer)); case (byte) 140: - return PlatformPoint.fromList((ArrayList) readValue(buffer)); + return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); case (byte) 141: - return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + return PlatformPoint.fromList((ArrayList) readValue(buffer)); case (byte) 142: - return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); case (byte) 143: + return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + case (byte) 144: Object value = readValue(buffer); return value == null ? null : PlatformRendererType.values()[(int) value]; default: @@ -1157,50 +1296,53 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { @Override protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { - if (value instanceof PlatformCameraUpdate) { + if (value instanceof PlatformCameraPosition) { stream.write(129); + writeValue(stream, ((PlatformCameraPosition) value).toList()); + } else if (value instanceof PlatformCameraUpdate) { + stream.write(130); writeValue(stream, ((PlatformCameraUpdate) value).toList()); } else if (value instanceof PlatformCircle) { - stream.write(130); + stream.write(131); writeValue(stream, ((PlatformCircle) value).toList()); } else if (value instanceof PlatformClusterManager) { - stream.write(131); + stream.write(132); writeValue(stream, ((PlatformClusterManager) value).toList()); } else if (value instanceof PlatformMarker) { - stream.write(132); + stream.write(133); writeValue(stream, ((PlatformMarker) value).toList()); } else if (value instanceof PlatformPolygon) { - stream.write(133); + stream.write(134); writeValue(stream, ((PlatformPolygon) value).toList()); } else if (value instanceof PlatformPolyline) { - stream.write(134); + stream.write(135); writeValue(stream, ((PlatformPolyline) value).toList()); } else if (value instanceof PlatformTileOverlay) { - stream.write(135); + stream.write(136); writeValue(stream, ((PlatformTileOverlay) value).toList()); } else if (value instanceof PlatformLatLng) { - stream.write(136); + stream.write(137); writeValue(stream, ((PlatformLatLng) value).toList()); } else if (value instanceof PlatformLatLngBounds) { - stream.write(137); + stream.write(138); writeValue(stream, ((PlatformLatLngBounds) value).toList()); } else if (value instanceof PlatformCluster) { - stream.write(138); + stream.write(139); writeValue(stream, ((PlatformCluster) value).toList()); } else if (value instanceof PlatformMapConfiguration) { - stream.write(139); + stream.write(140); writeValue(stream, ((PlatformMapConfiguration) value).toList()); } else if (value instanceof PlatformPoint) { - stream.write(140); + stream.write(141); writeValue(stream, ((PlatformPoint) value).toList()); } else if (value instanceof PlatformTileLayer) { - stream.write(141); + stream.write(142); writeValue(stream, ((PlatformTileLayer) value).toList()); } else if (value instanceof PlatformZoomRange) { - stream.write(142); + stream.write(143); writeValue(stream, ((PlatformZoomRange) value).toList()); } else if (value instanceof PlatformRendererType) { - stream.write(143); + stream.write(144); writeValue(stream, value == null ? null : ((PlatformRendererType) value).index); } else { super.writeValue(stream, value); @@ -1897,6 +2039,439 @@ public void error(Throwable error) { } } } + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class MapsCallbackApi { + private final @NonNull BinaryMessenger binaryMessenger; + private final String messageChannelSuffix; + + public MapsCallbackApi(@NonNull BinaryMessenger argBinaryMessenger) { + this(argBinaryMessenger, ""); + } + + public MapsCallbackApi( + @NonNull BinaryMessenger argBinaryMessenger, @NonNull String messageChannelSuffix) { + this.binaryMessenger = argBinaryMessenger; + this.messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix; + } + + /** Public interface for sending reply. */ + /** The codec used by MapsCallbackApi. */ + static @NonNull MessageCodec getCodec() { + return PigeonCodec.INSTANCE; + } + /** Called when the map camera starts moving. */ + public void onCameraMoveStarted(@NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMoveStarted" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + null, + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when the map camera moves. */ + public void onCameraMove( + @NonNull PlatformCameraPosition cameraPositionArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMove" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(cameraPositionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when the map camera stops moving. */ + public void onCameraIdle(@NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraIdle" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + null, + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when the map, not a specifc map object, is tapped. */ + public void onTap(@NonNull PlatformLatLng positionArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(positionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when the map, not a specifc map object, is long pressed. */ + public void onLongPress(@NonNull PlatformLatLng positionArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onLongPress" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(positionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker is tapped. */ + public void onMarkerTap(@NonNull String markerIdArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(markerIdArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker drag starts. */ + public void onMarkerDragStart( + @NonNull String markerIdArg, + @NonNull PlatformLatLng positionArg, + @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragStart" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Arrays.asList(markerIdArg, positionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker drag updates. */ + public void onMarkerDrag( + @NonNull String markerIdArg, + @NonNull PlatformLatLng positionArg, + @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDrag" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Arrays.asList(markerIdArg, positionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker drag ends. */ + public void onMarkerDragEnd( + @NonNull String markerIdArg, + @NonNull PlatformLatLng positionArg, + @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragEnd" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Arrays.asList(markerIdArg, positionArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker's info window is tapped. */ + public void onInfoWindowTap(@NonNull String markerIdArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onInfoWindowTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(markerIdArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a circle is tapped. */ + public void onCircleTap(@NonNull String circleIdArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCircleTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(circleIdArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a marker cluster is tapped. */ + public void onClusterTap(@NonNull PlatformCluster clusterArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onClusterTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(clusterArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a polygon is tapped. */ + public void onPolygonTap(@NonNull String polygonIdArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolygonTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(polygonIdArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called when a polyline is tapped. */ + public void onPolylineTap(@NonNull String polylineIdArg, @NonNull VoidResult result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolylineTap" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Collections.singletonList(polylineIdArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else { + result.success(); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + /** Called to get data for a map tile. */ + public void getTileOverlayTile( + @NonNull String tileOverlayIdArg, + @NonNull PlatformPoint locationArg, + @NonNull Long zoomArg, + @NonNull Result result) { + final String channelName = + "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile" + + messageChannelSuffix; + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, channelName, getCodec()); + channel.send( + new ArrayList(Arrays.asList(tileOverlayIdArg, locationArg, zoomArg)), + channelReply -> { + if (channelReply instanceof List) { + List listReply = (List) channelReply; + if (listReply.size() > 1) { + result.error( + new FlutterError( + (String) listReply.get(0), + (String) listReply.get(1), + (String) listReply.get(2))); + } else if (listReply.get(0) == null) { + result.error( + new FlutterError( + "null-error", + "Flutter api returned null value for non-null return value.", + "")); + } else { + @SuppressWarnings("ConstantConditions") + PlatformTileOverlay output = (PlatformTileOverlay) listReply.get(0); + result.success(output); + } + } else { + result.error(createConnectionError(channelName)); + } + }); + } + } /** * Interface for global SDK initialization. * diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java index a68e3e89ea8..3c6eb98a98f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java @@ -8,7 +8,7 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polygon; import com.google.android.gms.maps.model.PolygonOptions; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -17,14 +17,14 @@ class PolygonsController { private final Map polygonIdToController; private final Map googleMapsPolygonIdToDartPolygonId; - private final MethodChannel methodChannel; + private final @NonNull MapsCallbackApi flutterApi; private final float density; private GoogleMap googleMap; - PolygonsController(MethodChannel methodChannel, float density) { + PolygonsController(@NonNull MapsCallbackApi flutterApi, float density) { this.polygonIdToController = new HashMap<>(); this.googleMapsPolygonIdToDartPolygonId = new HashMap<>(); - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; this.density = density; } @@ -67,7 +67,15 @@ boolean onPolygonTap(String googlePolygonId) { if (polygonId == null) { return false; } - methodChannel.invokeMethod("polygon#onTap", Convert.polygonIdToJson(polygonId)); + flutterApi.onPolygonTap( + polygonId, + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }); PolygonController polygonController = polygonIdToController.get(polygonId); if (polygonController != null) { return polygonController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index 043474d3dc3..b5c7c34f17b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -9,7 +9,7 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polyline; import com.google.android.gms.maps.model.PolylineOptions; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,16 +18,17 @@ class PolylinesController { private final Map polylineIdToController; private final Map googleMapsPolylineIdToDartPolylineId; - private final MethodChannel methodChannel; + private final @NonNull MapsCallbackApi flutterApi; private GoogleMap googleMap; private final float density; private final AssetManager assetManager; - PolylinesController(MethodChannel methodChannel, AssetManager assetManager, float density) { + PolylinesController( + @NonNull MapsCallbackApi flutterApi, AssetManager assetManager, float density) { this.assetManager = assetManager; this.polylineIdToController = new HashMap<>(); this.googleMapsPolylineIdToDartPolylineId = new HashMap<>(); - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; this.density = density; } @@ -70,7 +71,13 @@ boolean onPolylineTap(String googlePolylineId) { if (polylineId == null) { return false; } - methodChannel.invokeMethod("polyline#onTap", Convert.polylineIdToJson(polylineId)); + flutterApi.onPolylineTap(polylineId, new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }); PolylineController polylineController = polylineIdToController.get(polylineId); if (polylineController != null) { return polylineController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java index 5dfbe2e8ee1..1d44e56b51a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -9,7 +9,7 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.TileOverlay; import com.google.android.gms.maps.model.TileOverlayOptions; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -17,12 +17,12 @@ class TileOverlaysController { private final Map tileOverlayIdToController; - private final MethodChannel methodChannel; + private final MapsCallbackApi flutterApi; private GoogleMap googleMap; - TileOverlaysController(MethodChannel methodChannel) { + TileOverlaysController(MapsCallbackApi flutterApi) { this.tileOverlayIdToController = new HashMap<>(); - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; } void setGoogleMap(GoogleMap googleMap) { @@ -96,7 +96,7 @@ private void addJsonTileOverlay(Map tileOverlayOptions) { String tileOverlayId = Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayOptionsBuilder); TileProviderController tileProviderController = - new TileProviderController(methodChannel, tileOverlayId); + new TileProviderController(flutterApi, tileOverlayId); tileOverlayOptionsBuilder.setTileProvider(tileProviderController); TileOverlayOptions options = tileOverlayOptionsBuilder.build(); TileOverlay tileOverlay = googleMap.addTileOverlay(options); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index 434512c17fc..30373faad2b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -8,9 +8,11 @@ import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.android.gms.maps.model.Tile; import com.google.android.gms.maps.model.TileProvider; -import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.googlemaps.Messages.FlutterError; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -19,12 +21,12 @@ class TileProviderController implements TileProvider { private static final String TAG = "TileProviderController"; protected final String tileOverlayId; - protected final MethodChannel methodChannel; + protected final @NonNull MapsCallbackApi flutterApi; protected final Handler handler = new Handler(Looper.getMainLooper()); - TileProviderController(MethodChannel methodChannel, String tileOverlayId) { + TileProviderController(@NonNull MapsCallbackApi flutterApi, String tileOverlayId) { this.tileOverlayId = tileOverlayId; - this.methodChannel = methodChannel; + this.flutterApi = flutterApi; } @Override @@ -33,13 +35,13 @@ public Tile getTile(final int x, final int y, final int zoom) { return worker.getTile(); } - private final class Worker implements MethodChannel.Result { + private final class Worker implements Messages.Result { private final CountDownLatch countDownLatch = new CountDownLatch(1); private final int x; private final int y; private final int zoom; - private Map result; + private @Nullable Messages.PlatformTileOverlay result; Worker(int x, int y, int zoom) { this.x = x; @@ -49,14 +51,11 @@ private final class Worker implements MethodChannel.Result { @NonNull Tile getTile() { - handler.post( - () -> - methodChannel.invokeMethod( - "tileOverlay#getTile", - Convert.tileOverlayArgumentsToJson(tileOverlayId, x, y, zoom), - this)); + final Messages.PlatformPoint location = + new Messages.PlatformPoint.Builder().setX((long) x).setY((long) y).build(); + handler.post(() -> flutterApi.getTileOverlayTile(tileOverlayId, location, (long) zoom, this)); try { - // Because `methodChannel.invokeMethod` is async, we use a `countDownLatch` make it synchronized. + // `flutterApi.getTileOverlayTile` is async, so use a `countDownLatch` to make it synchronized. countDownLatch.await(); } catch (InterruptedException e) { Log.e( @@ -66,7 +65,13 @@ Tile getTile() { return TileProvider.NO_TILE; } try { - return Convert.interpretTile(result); + if (result == null) { + Log.e(TAG, String.format("Did not receive tile data for tile: x = %d, y= %d, zoom = %d", x, y, zoom)); + return TileProvider.NO_TILE; + } + @SuppressWarnings("unchecked") + final Map tileJson = (Map) result.getJson(); + return Convert.interpretTile(tileJson); } catch (Exception e) { Log.e(TAG, "Can't parse tile data", e); return TileProvider.NO_TILE; @@ -74,29 +79,26 @@ Tile getTile() { } @Override - @SuppressWarnings("unchecked") - public void success(Object data) { - result = (Map) data; + public void success(@NonNull Messages.PlatformTileOverlay result) { + this.result = result; countDownLatch.countDown(); } @Override - public void error(String errorCode, String errorMessage, Object data) { - Log.e( - TAG, - "Can't get tile: errorCode = " - + errorCode - + ", errorMessage = " - + errorCode - + ", date = " - + data); - result = null; - countDownLatch.countDown(); - } - - @Override - public void notImplemented() { - Log.e(TAG, "Can't get tile: notImplemented"); + public void error(@NonNull Throwable error) { + if (error instanceof FlutterError) { + FlutterError flutterError = (FlutterError) error; + Log.e( + TAG, + "Can't get tile: errorCode = " + + flutterError.code + + ", errorMessage = " + + flutterError.getMessage() + + ", date = " + + flutterError.details); + } else { + Log.e(TAG, "Can't get tile: " + error); + } result = null; countDownLatch.countDown(); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java index aaa50542e7f..f995870f1be 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -23,8 +24,7 @@ import com.google.maps.android.clustering.algo.StaticCluster; import com.google.maps.android.collections.MarkerManager; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodCodec; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -35,6 +35,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -44,7 +45,7 @@ @Config(sdk = Build.VERSION_CODES.P) public class ClusterManagersControllerTest { private Context context; - private MethodChannel methodChannel; + private MapsCallbackApi flutterApi; private ClusterManagersController controller; private GoogleMap googleMap; private MarkerManager markerManager; @@ -57,9 +58,9 @@ public void setUp() { MockitoAnnotations.openMocks(this); context = ApplicationProvider.getApplicationContext(); assetManager = context.getAssets(); - methodChannel = - spy(new MethodChannel(mock(BinaryMessenger.class), "no-name", mock(MethodCodec.class))); - controller = spy(new ClusterManagersController(methodChannel, context)); + flutterApi = + spy(new MapsCallbackApi(mock(BinaryMessenger.class))); + controller = spy(new ClusterManagersController(flutterApi, context)); googleMap = mock(GoogleMap.class); markerManager = new MarkerManager(googleMap); markerCollection = markerManager.newCollection(); @@ -195,8 +196,8 @@ public void OnClusterClickCallsMethodChannel() throws InterruptedException { cluster.add(marker2); controller.onClusterClick(cluster); - Mockito.verify(methodChannel) - .invokeMethod("cluster#onTap", Convert.clusterToJson(clusterManagerId, cluster)); + Mockito.verify(flutterApi) + .onClusterTap(eq(Convert.clusterToPigeon(clusterManagerId, cluster)), ArgumentMatchers.any()); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ConvertTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ConvertTest.java index 3680d918e2f..8e00a67f23b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ConvertTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ConvertTest.java @@ -81,7 +81,7 @@ public void ConvertToPointsConvertsThePointsWithFullPrecision() { } @Test - public void ConvertClusterToJsonReturnsCorrectData() { + public void ConvertClusterToPigeonReturnsCorrectData() { String clusterManagerId = "cm_1"; LatLng clusterPosition = new LatLng(43.00, -87.90); LatLng markerPosition1 = new LatLng(43.05, -87.95); @@ -97,34 +97,26 @@ public void ConvertClusterToJsonReturnsCorrectData() { marker2.setPosition(markerPosition2); cluster.add(marker2); - Object result = Convert.clusterToJson(clusterManagerId, cluster); - Map clusterData = (Map) result; - Assert.assertEquals(clusterManagerId, clusterData.get("clusterManagerId")); + Messages.PlatformCluster result = Convert.clusterToPigeon(clusterManagerId, cluster); + Assert.assertEquals(clusterManagerId, result.getClusterManagerId()); - List position = (List) clusterData.get("position"); - Assert.assertTrue(position instanceof List); - Assert.assertEquals(clusterPosition.latitude, (double) position.get(0), 1e-15); - Assert.assertEquals(clusterPosition.longitude, (double) position.get(1), 1e-15); - - Map bounds = (Map) clusterData.get("bounds"); - Assert.assertTrue(bounds instanceof Map); - List southwest = (List) bounds.get("southwest"); - List northeast = (List) bounds.get("northeast"); - Assert.assertTrue(southwest instanceof List); - Assert.assertTrue(northeast instanceof List); + Messages.PlatformLatLng position = result.getPosition(); + Assert.assertEquals(clusterPosition.latitude, position.getLatitude(), 1e-15); + Assert.assertEquals(clusterPosition.longitude, position.getLongitude(), 1e-15); + Messages.PlatformLatLngBounds bounds = result.getBounds(); + Messages.PlatformLatLng southwest = bounds.getSouthwest(); + Messages.PlatformLatLng northeast = bounds.getNortheast(); // bounding data should combine data from marker positions markerPosition1 and markerPosition2 - Assert.assertEquals(markerPosition2.latitude, (double) southwest.get(0), 1e-15); - Assert.assertEquals(markerPosition1.longitude, (double) southwest.get(1), 1e-15); - Assert.assertEquals(markerPosition1.latitude, (double) northeast.get(0), 1e-15); - Assert.assertEquals(markerPosition2.longitude, (double) northeast.get(1), 1e-15); - - Object markerIds = clusterData.get("markerIds"); - Assert.assertTrue(markerIds instanceof List); - List markerIdList = (List) markerIds; - Assert.assertEquals(2, markerIdList.size()); - Assert.assertEquals(marker1.markerId(), markerIdList.get(0)); - Assert.assertEquals(marker2.markerId(), markerIdList.get(1)); + Assert.assertEquals(markerPosition2.latitude, southwest.getLatitude(), 1e-15); + Assert.assertEquals(markerPosition1.longitude, southwest.getLongitude(), 1e-15); + Assert.assertEquals(markerPosition1.latitude, northeast.getLatitude(), 1e-15); + Assert.assertEquals(markerPosition2.longitude, northeast.getLongitude(), 1e-15); + + List markerIds = result.getMarkerIds(); + Assert.assertEquals(2, markerIds.size()); + Assert.assertEquals(marker1.markerId(), markerIds.get(0)); + Assert.assertEquals(marker2.markerId(), markerIds.get(1)); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java index f68ab346077..865920ee631 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java @@ -21,7 +21,6 @@ import com.google.android.gms.maps.model.Marker; import com.google.maps.android.clustering.ClusterManager; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -47,7 +46,7 @@ public class GoogleMapControllerTest { AutoCloseable mockCloseable; @Mock BinaryMessenger mockMessenger; @Mock GoogleMap mockGoogleMap; - @Mock MethodChannel mockMethodChannel; + @Mock Messages.MapsCallbackApi flutterApi; @Mock ClusterManagersController mockClusterManagersController; @Mock MarkersController mockMarkersController; @Mock PolygonsController mockPolygonsController; @@ -78,7 +77,7 @@ public GoogleMapController getGoogleMapControllerWithMockedDependencies() { 0, context, mockMessenger, - mockMethodChannel, + flutterApi, activity::getLifecycle, null, mockClusterManagersController, diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java index 41444d9f290..f3e705151bf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -21,8 +22,7 @@ import com.google.android.gms.maps.model.MarkerOptions; import com.google.maps.android.collections.MarkerManager; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodCodec; +import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -42,7 +42,7 @@ @Config(sdk = Build.VERSION_CODES.P) public class MarkersControllerTest { private Context context; - private MethodChannel methodChannel; + private MapsCallbackApi flutterApi; private ClusterManagersController clusterManagersController; private MarkersController controller; private GoogleMap googleMap; @@ -56,11 +56,11 @@ public void setUp() { MockitoAnnotations.openMocks(this); assetManager = ApplicationProvider.getApplicationContext().getAssets(); context = ApplicationProvider.getApplicationContext(); - methodChannel = - spy(new MethodChannel(mock(BinaryMessenger.class), "no-name", mock(MethodCodec.class))); - clusterManagersController = spy(new ClusterManagersController(methodChannel, context)); + flutterApi = + spy(new MapsCallbackApi(mock(BinaryMessenger.class))); + clusterManagersController = spy(new ClusterManagersController(flutterApi, context)); controller = - new MarkersController(methodChannel, clusterManagersController, assetManager, density); + new MarkersController(flutterApi, clusterManagersController, assetManager, density); googleMap = mock(GoogleMap.class); markerManager = new MarkerManager(googleMap); markerCollection = markerManager.newCollection(); @@ -85,14 +85,7 @@ public void controller_OnMarkerDragStart() { controller.addJsonMarkers(markers); controller.onMarkerDragStart(googleMarkerId, latLng); - final List points = new ArrayList<>(); - points.add(latLng.latitude); - points.add(latLng.longitude); - - final Map data = new HashMap<>(); - data.put("markerId", googleMarkerId); - data.put("position", points); - Mockito.verify(methodChannel).invokeMethod("marker#onDragStart", data); + Mockito.verify(flutterApi).onMarkerDragStart(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)) ,any()); } @Test @@ -112,14 +105,7 @@ public void controller_OnMarkerDragEnd() { controller.addJsonMarkers(markers); controller.onMarkerDragEnd(googleMarkerId, latLng); - final List points = new ArrayList<>(); - points.add(latLng.latitude); - points.add(latLng.longitude); - - final Map data = new HashMap<>(); - data.put("markerId", googleMarkerId); - data.put("position", points); - Mockito.verify(methodChannel).invokeMethod("marker#onDragEnd", data); + Mockito.verify(flutterApi).onMarkerDragEnd(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); } @Test @@ -139,14 +125,7 @@ public void controller_OnMarkerDrag() { controller.addJsonMarkers(markers); controller.onMarkerDrag(googleMarkerId, latLng); - final List points = new ArrayList<>(); - points.add(latLng.latitude); - points.add(latLng.longitude); - - final Map data = new HashMap<>(); - data.put("markerId", googleMarkerId); - data.put("position", points); - Mockito.verify(methodChannel).invokeMethod("marker#onDrag", data); + Mockito.verify(flutterApi).onMarkerDrag(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); } @Test(expected = IllegalArgumentException.class) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 3b77fa91480..d69267e4611 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -70,15 +70,16 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterAndroid(); } - // Keep a collection of id -> channel - // Every method call passes the int mapId - final Map _channels = {}; - final Map _hostMaps = {}; // A method to create MapsApi instances, which can be overridden for testing. final MapsApi Function(int mapId) _apiProvider; + /// The per-map handlers for callbacks from the host side. + @visibleForTesting + final Map hostMapHandlers = + {}; + /// Accesses the MapsApi associated to the passed mapId. MapsApi _hostApi(int mapId) { final MapsApi? api = _hostMaps[mapId]; @@ -92,17 +93,23 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { final Map> _tileOverlays = >{}; - /// Returns the channel for [mapId], creating it if it doesn't already exist. + /// Returns the handler for [mapId], creating it if it doesn't already exist. @visibleForTesting - MethodChannel ensureChannelInitialized(int mapId) { - MethodChannel? channel = _channels[mapId]; - if (channel == null) { - channel = MethodChannel('plugins.flutter.dev/google_maps_android_$mapId'); - channel.setMethodCallHandler( - (MethodCall call) => _handleMethodCall(call, mapId)); - _channels[mapId] = channel; + HostMapMessageHandler ensureHandlerInitialized(int mapId) { + HostMapMessageHandler? handler = hostMapHandlers[mapId]; + if (handler == null) { + handler = HostMapMessageHandler( + mapId, + _mapEventStreamController, + tileOverlayProvider: (TileOverlayId tileOverlayId) { + final Map? tileOverlaysForMap = + _tileOverlays[mapId]; + return tileOverlaysForMap?[tileOverlayId]; + }, + ); + hostMapHandlers[mapId] = handler; } - return channel; + return handler; } /// Returns the API instance for [mapId], creating it if it doesn't already @@ -119,7 +126,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { @override Future init(int mapId) { - ensureChannelInitialized(mapId); + ensureHandlerInitialized(mapId); final MapsApi hostApi = ensureApiInitialized(mapId); return hostApi.waitForMap(); } @@ -212,122 +219,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } - Future _handleMethodCall(MethodCall call, int mapId) async { - switch (call.method) { - case 'camera#onMoveStarted': - _mapEventStreamController.add(CameraMoveStartedEvent(mapId)); - case 'camera#onMove': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(CameraMoveEvent( - mapId, - CameraPosition.fromMap(arguments['position'])!, - )); - case 'camera#onIdle': - _mapEventStreamController.add(CameraIdleEvent(mapId)); - case 'marker#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MarkerTapEvent( - mapId, - MarkerId(arguments['markerId']! as String), - )); - case 'marker#onDragStart': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MarkerDragStartEvent( - mapId, - LatLng.fromJson(arguments['position'])!, - MarkerId(arguments['markerId']! as String), - )); - case 'marker#onDrag': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MarkerDragEvent( - mapId, - LatLng.fromJson(arguments['position'])!, - MarkerId(arguments['markerId']! as String), - )); - case 'marker#onDragEnd': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MarkerDragEndEvent( - mapId, - LatLng.fromJson(arguments['position'])!, - MarkerId(arguments['markerId']! as String), - )); - case 'infoWindow#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(InfoWindowTapEvent( - mapId, - MarkerId(arguments['markerId']! as String), - )); - case 'polyline#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(PolylineTapEvent( - mapId, - PolylineId(arguments['polylineId']! as String), - )); - case 'polygon#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(PolygonTapEvent( - mapId, - PolygonId(arguments['polygonId']! as String), - )); - case 'circle#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(CircleTapEvent( - mapId, - CircleId(arguments['circleId']! as String), - )); - case 'map#onTap': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MapTapEvent( - mapId, - LatLng.fromJson(arguments['position'])!, - )); - case 'map#onLongPress': - final Map arguments = _getArgumentDictionary(call); - _mapEventStreamController.add(MapLongPressEvent( - mapId, - LatLng.fromJson(arguments['position'])!, - )); - case 'tileOverlay#getTile': - final Map arguments = _getArgumentDictionary(call); - final Map? tileOverlaysForThisMap = - _tileOverlays[mapId]; - final String tileOverlayId = arguments['tileOverlayId']! as String; - final TileOverlay? tileOverlay = - tileOverlaysForThisMap?[TileOverlayId(tileOverlayId)]; - final TileProvider? tileProvider = tileOverlay?.tileProvider; - if (tileProvider == null) { - return TileProvider.noTile.toJson(); - } - final Tile tile = await tileProvider.getTile( - arguments['x']! as int, - arguments['y']! as int, - arguments['zoom'] as int?, - ); - return tile.toJson(); - case 'cluster#onTap': - final Map arguments = _getArgumentDictionary(call); - final Cluster cluster = parseCluster( - arguments['clusterManagerId']! as String, - arguments['position']!, - arguments['bounds']! as Map, - arguments['markerIds']! as List); - _mapEventStreamController.add(ClusterTapEvent( - mapId, - cluster, - )); - default: - throw MissingPluginException(); - } - } - - /// Returns the arguments of [call] as typed string-keyed Map. - /// - /// This does not do any type validation, so is only safe to call if the - /// arguments are known to be a map. - Map _getArgumentDictionary(MethodCall call) { - return (call.arguments as Map).cast(); - } - @override Future updateMapConfiguration( MapConfiguration configuration, { @@ -750,38 +641,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { MapsInspectorApi(messageChannelSuffix: mapId.toString())); } - /// Parses cluster data from dynamic json objects and returns [Cluster] object. - /// Used by the `cluster#onTap` method call handler and the - /// [GoogleMapsInspectorAndroid.getClusters] response parser. - static Cluster parseCluster( - String clusterManagerIdString, - Object positionObject, - Map boundsMap, - List markerIdsList) { - final ClusterManagerId clusterManagerId = - ClusterManagerId(clusterManagerIdString); - final LatLng position = LatLng.fromJson(positionObject)!; - - final Map> latLngData = boundsMap.map( - (dynamic key, dynamic object) => MapEntry>( - key as String, object as List)); - - final LatLngBounds bounds = LatLngBounds( - northeast: LatLng.fromJson(latLngData['northeast'])!, - southwest: LatLng.fromJson(latLngData['southwest'])!); - - final List markerIds = markerIdsList - .map((dynamic markerId) => MarkerId(markerId as String)) - .toList(); - - return Cluster( - clusterManagerId, - markerIds, - position: position, - bounds: bounds, - ); - } - /// Converts a Pigeon [PlatformCluster] to the corresponding [Cluster]. static Cluster clusterFromPlatformCluster(PlatformCluster cluster) { return Cluster( @@ -794,10 +653,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { bounds: _latLngBoundsFromPlatformLatLngBounds(cluster.bounds)); } - static LatLng _latLngFromPlatformLatLng(PlatformLatLng latLng) { - return LatLng(latLng.latitude, latLng.longitude); - } - static PlatformLatLng _platformLatLngFromLatLng(LatLng latLng) { return PlatformLatLng( latitude: latLng.latitude, longitude: latLng.longitude); @@ -813,13 +668,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return PlatformPoint(x: coordinate.x, y: coordinate.y); } - static LatLngBounds _latLngBoundsFromPlatformLatLngBounds( - PlatformLatLngBounds bounds) { - return LatLngBounds( - southwest: _latLngFromPlatformLatLng(bounds.southwest), - northeast: _latLngFromPlatformLatLng(bounds.northeast)); - } - static PlatformCircle _platformCircleFromCircle(Circle circle) { return PlatformCircle(json: circle.toJson()); } @@ -848,6 +696,153 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { } } +/// Callback handler for map events from the platform host. +@visibleForTesting +class HostMapMessageHandler implements MapsCallbackApi { + /// Creates a new handler that listens for events from map [mapId], and + /// broadcasts them to [streamController]. + HostMapMessageHandler( + this.mapId, + this.streamController, { + required this.tileOverlayProvider, + }) { + MapsCallbackApi.setUp(this, messageChannelSuffix: mapId.toString()); + } + + /// Removes the handler for native messages. + void dispose() { + MapsCallbackApi.setUp(null, messageChannelSuffix: mapId.toString()); + } + + /// The map ID this handler listens for events from. + final int mapId; + + /// The controller used to broadcast map events coming from the + /// host platform. + final StreamController> streamController; + + /// The callback to get a tile overlay for the corresponding map. + final TileOverlay? Function(TileOverlayId tileOverlayId) tileOverlayProvider; + + @override + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ) async { + final TileOverlay? tileOverlay = + tileOverlayProvider(TileOverlayId(tileOverlayId)); + final TileProvider? tileProvider = tileOverlay?.tileProvider; + final Tile tile = tileProvider == null + ? TileProvider.noTile + : await tileProvider.getTile(location.x, location.y, zoom); + return PlatformTileOverlay(json: tile.toJson()); + } + + @override + void onCameraIdle() { + streamController.add(CameraIdleEvent(mapId)); + } + + @override + void onCameraMove(PlatformCameraPosition cameraPosition) { + streamController.add(CameraMoveEvent( + mapId, + CameraPosition( + target: _latLngFromPlatformLatLng(cameraPosition.target), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ), + )); + } + + @override + void onCameraMoveStarted() { + streamController.add(CameraMoveStartedEvent(mapId)); + } + + @override + void onCircleTap(String circleId) { + streamController.add(CircleTapEvent(mapId, CircleId(circleId))); + } + + @override + void onClusterTap(PlatformCluster cluster) { + streamController.add(ClusterTapEvent( + mapId, + Cluster( + ClusterManagerId(cluster.clusterManagerId), + // See comment in messages.dart for why this is force-unwrapped. + cluster.markerIds.map((String? id) => MarkerId(id!)).toList(), + position: _latLngFromPlatformLatLng(cluster.position), + bounds: _latLngBoundsFromPlatformLatLngBounds(cluster.bounds), + ), + )); + } + + @override + void onInfoWindowTap(String markerId) { + streamController.add(InfoWindowTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onLongPress(PlatformLatLng position) { + streamController + .add(MapLongPressEvent(mapId, _latLngFromPlatformLatLng(position))); + } + + @override + void onMarkerDrag(String markerId, PlatformLatLng position) { + streamController.add(MarkerDragEvent( + mapId, _latLngFromPlatformLatLng(position), MarkerId(markerId))); + } + + @override + void onMarkerDragStart(String markerId, PlatformLatLng position) { + streamController.add(MarkerDragStartEvent( + mapId, _latLngFromPlatformLatLng(position), MarkerId(markerId))); + } + + @override + void onMarkerDragEnd(String markerId, PlatformLatLng position) { + streamController.add(MarkerDragEndEvent( + mapId, _latLngFromPlatformLatLng(position), MarkerId(markerId))); + } + + @override + void onMarkerTap(String markerId) { + streamController.add(MarkerTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onPolygonTap(String polygonId) { + streamController.add(PolygonTapEvent(mapId, PolygonId(polygonId))); + } + + @override + void onPolylineTap(String polylineId) { + streamController.add(PolylineTapEvent(mapId, PolylineId(polylineId))); + } + + @override + void onTap(PlatformLatLng position) { + streamController + .add(MapTapEvent(mapId, _latLngFromPlatformLatLng(position))); + } +} + +LatLng _latLngFromPlatformLatLng(PlatformLatLng latLng) { + return LatLng(latLng.latitude, latLng.longitude); +} + +LatLngBounds _latLngBoundsFromPlatformLatLngBounds( + PlatformLatLngBounds bounds) { + return LatLngBounds( + southwest: _latLngFromPlatformLatLng(bounds.southwest), + northeast: _latLngFromPlatformLatLng(bounds.northeast)); +} + Map _jsonForMapConfiguration(MapConfiguration config) { final EdgeInsets? padding = config.padding; return { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart index 23f7aa45c0a..a9e214a169d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart @@ -18,11 +18,59 @@ PlatformException _createConnectionError(String channelName) { ); } +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + enum PlatformRendererType { legacy, latest, } +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + double bearing; + + PlatformLatLng target; + + double tilt; + + double zoom; + + Object encode() { + return [ + bearing, + target, + tilt, + zoom, + ]; + } + + static PlatformCameraPosition decode(Object result) { + result as List; + return PlatformCameraPosition( + bearing: result[0]! as double, + target: result[1]! as PlatformLatLng, + tilt: result[2]! as double, + zoom: result[3]! as double, + ); + } +} + /// Pigeon representation of a CameraUpdate. class PlatformCameraUpdate { PlatformCameraUpdate({ @@ -406,50 +454,53 @@ class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is PlatformCameraUpdate) { + if (value is PlatformCameraPosition) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is PlatformCircle) { + } else if (value is PlatformCameraUpdate) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PlatformClusterManager) { + } else if (value is PlatformCircle) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PlatformMarker) { + } else if (value is PlatformClusterManager) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PlatformPolygon) { + } else if (value is PlatformMarker) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PlatformPolyline) { + } else if (value is PlatformPolygon) { buffer.putUint8(134); writeValue(buffer, value.encode()); - } else if (value is PlatformTileOverlay) { + } else if (value is PlatformPolyline) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLng) { + } else if (value is PlatformTileOverlay) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLngBounds) { + } else if (value is PlatformLatLng) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is PlatformCluster) { + } else if (value is PlatformLatLngBounds) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is PlatformMapConfiguration) { + } else if (value is PlatformCluster) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is PlatformPoint) { + } else if (value is PlatformMapConfiguration) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PlatformTileLayer) { + } else if (value is PlatformPoint) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is PlatformZoomRange) { + } else if (value is PlatformTileLayer) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is PlatformRendererType) { + } else if (value is PlatformZoomRange) { buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is PlatformRendererType) { + buffer.putUint8(144); writeValue(buffer, value.index); } else { super.writeValue(buffer, value); @@ -460,34 +511,36 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - return PlatformCameraUpdate.decode(readValue(buffer)!); + return PlatformCameraPosition.decode(readValue(buffer)!); case 130: - return PlatformCircle.decode(readValue(buffer)!); + return PlatformCameraUpdate.decode(readValue(buffer)!); case 131: - return PlatformClusterManager.decode(readValue(buffer)!); + return PlatformCircle.decode(readValue(buffer)!); case 132: - return PlatformMarker.decode(readValue(buffer)!); + return PlatformClusterManager.decode(readValue(buffer)!); case 133: - return PlatformPolygon.decode(readValue(buffer)!); + return PlatformMarker.decode(readValue(buffer)!); case 134: - return PlatformPolyline.decode(readValue(buffer)!); + return PlatformPolygon.decode(readValue(buffer)!); case 135: - return PlatformTileOverlay.decode(readValue(buffer)!); + return PlatformPolyline.decode(readValue(buffer)!); case 136: - return PlatformLatLng.decode(readValue(buffer)!); + return PlatformTileOverlay.decode(readValue(buffer)!); case 137: - return PlatformLatLngBounds.decode(readValue(buffer)!); + return PlatformLatLng.decode(readValue(buffer)!); case 138: - return PlatformCluster.decode(readValue(buffer)!); + return PlatformLatLngBounds.decode(readValue(buffer)!); case 139: - return PlatformMapConfiguration.decode(readValue(buffer)!); + return PlatformCluster.decode(readValue(buffer)!); case 140: - return PlatformPoint.decode(readValue(buffer)!); + return PlatformMapConfiguration.decode(readValue(buffer)!); case 141: - return PlatformTileLayer.decode(readValue(buffer)!); + return PlatformPoint.decode(readValue(buffer)!); case 142: - return PlatformZoomRange.decode(readValue(buffer)!); + return PlatformTileLayer.decode(readValue(buffer)!); case 143: + return PlatformZoomRange.decode(readValue(buffer)!); + case 144: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformRendererType.values[value]; default: @@ -1099,6 +1152,490 @@ class MapsApi { } } +abstract class MapsCallbackApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// Called when the map camera starts moving. + void onCameraMoveStarted(); + + /// Called when the map camera moves. + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + void onPolylineTap(String polylineId); + + /// Called to get data for a map tile. + Future getTileOverlayTile( + String tileOverlayId, PlatformPoint location, int zoom); + + static void setUp( + MapsCallbackApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMoveStarted$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + try { + api.onCameraMoveStarted(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMove$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMove was null.'); + final List args = (message as List?)!; + final PlatformCameraPosition? arg_cameraPosition = + (args[0] as PlatformCameraPosition?); + assert(arg_cameraPosition != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraMove was null, expected non-null PlatformCameraPosition.'); + try { + api.onCameraMove(arg_cameraPosition!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCameraIdle$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + try { + api.onCameraIdle(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onTap was null.'); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert(arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onTap was null, expected non-null PlatformLatLng.'); + try { + api.onTap(arg_position!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onLongPress$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onLongPress was null.'); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert(arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onLongPress was null, expected non-null PlatformLatLng.'); + try { + api.onLongPress(arg_position!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerTap was null.'); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert(arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerTap was null, expected non-null String.'); + try { + api.onMarkerTap(arg_markerId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragStart$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragStart was null.'); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert(arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragStart was null, expected non-null String.'); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert(arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragStart was null, expected non-null PlatformLatLng.'); + try { + api.onMarkerDragStart(arg_markerId!, arg_position!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDrag$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDrag was null.'); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert(arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDrag was null, expected non-null String.'); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert(arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDrag was null, expected non-null PlatformLatLng.'); + try { + api.onMarkerDrag(arg_markerId!, arg_position!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragEnd$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragEnd was null.'); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert(arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragEnd was null, expected non-null String.'); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert(arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onMarkerDragEnd was null, expected non-null PlatformLatLng.'); + try { + api.onMarkerDragEnd(arg_markerId!, arg_position!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onInfoWindowTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onInfoWindowTap was null.'); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert(arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onInfoWindowTap was null, expected non-null String.'); + try { + api.onInfoWindowTap(arg_markerId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCircleTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCircleTap was null.'); + final List args = (message as List?)!; + final String? arg_circleId = (args[0] as String?); + assert(arg_circleId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onCircleTap was null, expected non-null String.'); + try { + api.onCircleTap(arg_circleId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onClusterTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onClusterTap was null.'); + final List args = (message as List?)!; + final PlatformCluster? arg_cluster = (args[0] as PlatformCluster?); + assert(arg_cluster != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onClusterTap was null, expected non-null PlatformCluster.'); + try { + api.onClusterTap(arg_cluster!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolygonTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolygonTap was null.'); + final List args = (message as List?)!; + final String? arg_polygonId = (args[0] as String?); + assert(arg_polygonId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolygonTap was null, expected non-null String.'); + try { + api.onPolygonTap(arg_polygonId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolylineTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolylineTap was null.'); + final List args = (message as List?)!; + final String? arg_polylineId = (args[0] as String?); + assert(arg_polylineId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.onPolylineTap was null, expected non-null String.'); + try { + api.onPolylineTap(arg_polylineId!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile was null.'); + final List args = (message as List?)!; + final String? arg_tileOverlayId = (args[0] as String?); + assert(arg_tileOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile was null, expected non-null String.'); + final PlatformPoint? arg_location = (args[1] as PlatformPoint?); + assert(arg_location != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile was null, expected non-null PlatformPoint.'); + final int? arg_zoom = (args[2] as int?); + assert(arg_zoom != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile was null, expected non-null int.'); + try { + final PlatformTileOverlay output = await api.getTileOverlayTile( + arg_tileOverlayId!, arg_location!, arg_zoom!); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + /// Interface for global SDK initialization. class MapsInitializerApi { /// Constructor for [MapsInitializerApi]. The [binaryMessenger] named argument is diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart index 3b78a5b180b..fa2aa5669ce 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart @@ -14,6 +14,21 @@ import 'package:pigeon/pigeon.dart'; // Pigeon equivalent of the Java MapsInitializer.Renderer. enum PlatformRendererType { legacy, latest } +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + final double bearing; + final PlatformLatLng target; + final double tilt; + final double zoom; +} + /// Pigeon representation of a CameraUpdate. class PlatformCameraUpdate { PlatformCameraUpdate(this.json); @@ -281,6 +296,56 @@ abstract class MapsApi { Uint8List takeSnapshot(); } +@FlutterApi() +abstract class MapsCallbackApi { + /// Called when the map camera starts moving. + void onCameraMoveStarted(); + + /// Called when the map camera moves. + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + void onPolylineTap(String polylineId); + + /// Called to get data for a map tile. + @async + PlatformTileOverlay getTileOverlayTile( + String tileOverlayId, PlatformPoint location, int zoom); +} + /// Interface for global SDK initialization. @HostApi() abstract class MapsInitializerApi { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart index cfe6b976695..5e3943b26ab 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart @@ -27,15 +27,6 @@ void main() { return (maps, api); } - Future sendPlatformMessage( - int mapId, String method, Map data) async { - final ByteData byteData = - const StandardMethodCodec().encodeMethodCall(MethodCall(method, data)); - await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .handlePlatformMessage('plugins.flutter.dev/google_maps_android_$mapId', - byteData, (ByteData? data) {}); - } - test('registers instance', () async { GoogleMapsFlutterAndroid.registerWith(); expect(GoogleMapsFlutterPlatform.instance, isA()); @@ -466,24 +457,15 @@ void main() { test('markers send drag event to correct streams', () async { const int mapId = 1; - final Map jsonMarkerDragStartEvent = { - 'mapId': mapId, - 'markerId': 'drag-start-marker', - 'position': [1.0, 1.0] - }; - final Map jsonMarkerDragEvent = { - 'mapId': mapId, - 'markerId': 'drag-marker', - 'position': [1.0, 1.0] - }; - final Map jsonMarkerDragEndEvent = { - 'mapId': mapId, - 'markerId': 'drag-end-marker', - 'position': [1.0, 1.0] - }; + const String dragStartId = 'drag-start-marker'; + const String dragId = 'drag-marker'; + const String dragEndId = 'drag-end-marker'; + final PlatformLatLng fakePosition = + PlatformLatLng(latitude: 1.0, longitude: 1.0); final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); - maps.ensureChannelInitialized(mapId); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); final StreamQueue markerDragStartStream = StreamQueue(maps.onMarkerDragStart(mapId: mapId)); @@ -492,17 +474,121 @@ void main() { final StreamQueue markerDragEndStream = StreamQueue(maps.onMarkerDragEnd(mapId: mapId)); - await sendPlatformMessage( - mapId, 'marker#onDragStart', jsonMarkerDragStartEvent); - await sendPlatformMessage(mapId, 'marker#onDrag', jsonMarkerDragEvent); - await sendPlatformMessage( - mapId, 'marker#onDragEnd', jsonMarkerDragEndEvent); - - expect((await markerDragStartStream.next).value.value, - equals('drag-start-marker')); - expect((await markerDragStream.next).value.value, equals('drag-marker')); - expect((await markerDragEndStream.next).value.value, - equals('drag-end-marker')); + // Simulate messages from the native side. + callbackHandler.onMarkerDragStart(dragStartId, fakePosition); + callbackHandler.onMarkerDrag(dragId, fakePosition); + callbackHandler.onMarkerDragEnd(dragEndId, fakePosition); + + expect((await markerDragStartStream.next).value.value, equals(dragStartId)); + expect((await markerDragStream.next).value.value, equals(dragId)); + expect((await markerDragEndStream.next).value.value, equals(dragEndId)); + }); + + test('markers send tap events to correct stream', () async { + const int mapId = 1; + const String objectId = 'object-id'; + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); + + final StreamQueue stream = + StreamQueue(maps.onMarkerTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onMarkerTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('circles send tap events to correct stream', () async { + const int mapId = 1; + const String objectId = 'object-id'; + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); + + final StreamQueue stream = + StreamQueue(maps.onCircleTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onCircleTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('clusters send tap events to correct stream', () async { + const int mapId = 1; + const String managerId = 'manager-id'; + final PlatformLatLng fakePosition = + PlatformLatLng(latitude: 10, longitude: 20); + final PlatformLatLngBounds fakeBounds = PlatformLatLngBounds( + southwest: PlatformLatLng(latitude: 30, longitude: 40), + northeast: PlatformLatLng(latitude: 50, longitude: 60)); + const List markerIds = ['marker-1', 'marker-2']; + final PlatformCluster cluster = PlatformCluster( + clusterManagerId: managerId, + position: fakePosition, + bounds: fakeBounds, + markerIds: markerIds); + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); + + final StreamQueue stream = + StreamQueue(maps.onClusterTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onClusterTap(cluster); + + final Cluster eventValue = (await stream.next).value; + expect(eventValue.clusterManagerId.value, managerId); + expect(eventValue.position.latitude, fakePosition.latitude); + expect(eventValue.position.longitude, fakePosition.longitude); + expect(eventValue.bounds.southwest.latitude, fakeBounds.southwest.latitude); + expect( + eventValue.bounds.southwest.longitude, fakeBounds.southwest.longitude); + expect(eventValue.bounds.northeast.latitude, fakeBounds.northeast.latitude); + expect( + eventValue.bounds.northeast.longitude, fakeBounds.northeast.longitude); + expect(eventValue.markerIds.length, markerIds.length); + expect(eventValue.markerIds.first.value, markerIds.first); + }); + + test('polygons send tap events to correct stream', () async { + const int mapId = 1; + const String objectId = 'object-id'; + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); + + final StreamQueue stream = + StreamQueue(maps.onPolygonTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onPolygonTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('polylines send tap events to correct stream', () async { + const int mapId = 1; + const String objectId = 'object-id'; + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + final HostMapMessageHandler callbackHandler = + maps.ensureHandlerInitialized(mapId); + + final StreamQueue stream = + StreamQueue(maps.onPolylineTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onPolylineTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); }); test( From 7f310ee4b655f64bfaca4ecf9718115ce061c125 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 1 Jul 2024 14:02:25 -0400 Subject: [PATCH 2/6] Update Pigeon to get data class equality for tests --- .../flutter/plugins/googlemaps/Messages.java | 267 +++++++++++++++++- .../googlemaps/PolylinesController.java | 16 +- .../googlemaps/TileProviderController.java | 5 +- .../ClusterManagersControllerTest.java | 6 +- .../googlemaps/MarkersControllerTest.java | 12 +- .../lib/src/messages.g.dart | 2 +- .../google_maps_flutter_android/pubspec.yaml | 2 +- 7 files changed, 291 insertions(+), 19 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java index db8e9f7e868..2d678e2aac6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v20.0.1), do not edit directly. +// Autogenerated from Pigeon (v20.0.2), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.googlemaps; @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) @@ -144,6 +145,26 @@ public void setZoom(@NonNull Double setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformCameraPosition() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformCameraPosition that = (PlatformCameraPosition) o; + return bearing.equals(that.bearing) + && target.equals(that.target) + && tilt.equals(that.tilt) + && zoom.equals(that.zoom); + } + + @Override + public int hashCode() { + return Objects.hash(bearing, target, tilt, zoom); + } + public static final class Builder { private @Nullable Double bearing; @@ -239,6 +260,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformCameraUpdate() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformCameraUpdate that = (PlatformCameraUpdate) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -297,6 +335,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformCircle() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformCircle that = (PlatformCircle) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -351,6 +406,23 @@ public void setIdentifier(@NonNull String setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformClusterManager() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformClusterManager that = (PlatformClusterManager) o; + return identifier.equals(that.identifier); + } + + @Override + public int hashCode() { + return Objects.hash(identifier); + } + public static final class Builder { private @Nullable String identifier; @@ -409,6 +481,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformMarker() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformMarker that = (PlatformMarker) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -467,6 +556,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformPolygon() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformPolygon that = (PlatformPolygon) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -525,6 +631,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformPolyline() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformPolyline that = (PlatformPolyline) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -583,6 +706,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformTileOverlay() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformTileOverlay that = (PlatformTileOverlay) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -650,6 +790,23 @@ public void setLongitude(@NonNull Double setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformLatLng() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformLatLng that = (PlatformLatLng) o; + return latitude.equals(that.latitude) && longitude.equals(that.longitude); + } + + @Override + public int hashCode() { + return Objects.hash(latitude, longitude); + } + public static final class Builder { private @Nullable Double latitude; @@ -729,6 +886,23 @@ public void setSouthwest(@NonNull PlatformLatLng setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformLatLngBounds() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformLatLngBounds that = (PlatformLatLngBounds) o; + return northeast.equals(that.northeast) && southwest.equals(that.southwest); + } + + @Override + public int hashCode() { + return Objects.hash(northeast, southwest); + } + public static final class Builder { private @Nullable PlatformLatLng northeast; @@ -834,6 +1008,26 @@ public void setMarkerIds(@NonNull List setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformCluster() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformCluster that = (PlatformCluster) o; + return clusterManagerId.equals(that.clusterManagerId) + && position.equals(that.position) + && bounds.equals(that.bounds) + && markerIds.equals(that.markerIds); + } + + @Override + public int hashCode() { + return Objects.hash(clusterManagerId, position, bounds, markerIds); + } + public static final class Builder { private @Nullable String clusterManagerId; @@ -929,6 +1123,23 @@ public void setJson(@NonNull Object setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformMapConfiguration() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformMapConfiguration that = (PlatformMapConfiguration) o; + return json.equals(that.json); + } + + @Override + public int hashCode() { + return Objects.hash(json); + } + public static final class Builder { private @Nullable Object json; @@ -996,6 +1207,23 @@ public void setY(@NonNull Long setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformPoint() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformPoint that = (PlatformPoint) o; + return x.equals(that.x) && y.equals(that.y); + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } + public static final class Builder { private @Nullable Long x; @@ -1101,6 +1329,26 @@ public void setZIndex(@NonNull Double setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformTileLayer() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformTileLayer that = (PlatformTileLayer) o; + return visible.equals(that.visible) + && fadeIn.equals(that.fadeIn) + && transparency.equals(that.transparency) + && zIndex.equals(that.zIndex); + } + + @Override + public int hashCode() { + return Objects.hash(visible, fadeIn, transparency, zIndex); + } + public static final class Builder { private @Nullable Boolean visible; @@ -1204,6 +1452,23 @@ public void setMax(@NonNull Double setterArg) { /** Constructor is non-public to enforce null safety; use Builder. */ PlatformZoomRange() {} + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformZoomRange that = (PlatformZoomRange) o; + return min.equals(that.min) && max.equals(that.max); + } + + @Override + public int hashCode() { + return Objects.hash(min, max); + } + public static final class Builder { private @Nullable Double min; diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index b5c7c34f17b..c4bab7dd6be 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -71,13 +71,15 @@ boolean onPolylineTap(String googlePolylineId) { if (polylineId == null) { return false; } - flutterApi.onPolylineTap(polylineId, new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }); + flutterApi.onPolylineTap( + polylineId, + new Messages.VoidResult() { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} + }); PolylineController polylineController = polylineIdToController.get(polylineId); if (polylineController != null) { return polylineController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index 30373faad2b..25872296d30 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -66,7 +66,10 @@ Tile getTile() { } try { if (result == null) { - Log.e(TAG, String.format("Did not receive tile data for tile: x = %d, y= %d, zoom = %d", x, y, zoom)); + Log.e( + TAG, + String.format( + "Did not receive tile data for tile: x = %d, y= %d, zoom = %d", x, y, zoom)); return TileProvider.NO_TILE; } @SuppressWarnings("unchecked") diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java index f995870f1be..4133392e310 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java @@ -58,8 +58,7 @@ public void setUp() { MockitoAnnotations.openMocks(this); context = ApplicationProvider.getApplicationContext(); assetManager = context.getAssets(); - flutterApi = - spy(new MapsCallbackApi(mock(BinaryMessenger.class))); + flutterApi = spy(new MapsCallbackApi(mock(BinaryMessenger.class))); controller = spy(new ClusterManagersController(flutterApi, context)); googleMap = mock(GoogleMap.class); markerManager = new MarkerManager(googleMap); @@ -197,7 +196,8 @@ public void OnClusterClickCallsMethodChannel() throws InterruptedException { controller.onClusterClick(cluster); Mockito.verify(flutterApi) - .onClusterTap(eq(Convert.clusterToPigeon(clusterManagerId, cluster)), ArgumentMatchers.any()); + .onClusterTap( + eq(Convert.clusterToPigeon(clusterManagerId, cluster)), ArgumentMatchers.any()); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java index f3e705151bf..820ef50c451 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java @@ -56,8 +56,7 @@ public void setUp() { MockitoAnnotations.openMocks(this); assetManager = ApplicationProvider.getApplicationContext().getAssets(); context = ApplicationProvider.getApplicationContext(); - flutterApi = - spy(new MapsCallbackApi(mock(BinaryMessenger.class))); + flutterApi = spy(new MapsCallbackApi(mock(BinaryMessenger.class))); clusterManagersController = spy(new ClusterManagersController(flutterApi, context)); controller = new MarkersController(flutterApi, clusterManagersController, assetManager, density); @@ -85,7 +84,8 @@ public void controller_OnMarkerDragStart() { controller.addJsonMarkers(markers); controller.onMarkerDragStart(googleMarkerId, latLng); - Mockito.verify(flutterApi).onMarkerDragStart(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)) ,any()); + Mockito.verify(flutterApi) + .onMarkerDragStart(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); } @Test @@ -105,7 +105,8 @@ public void controller_OnMarkerDragEnd() { controller.addJsonMarkers(markers); controller.onMarkerDragEnd(googleMarkerId, latLng); - Mockito.verify(flutterApi).onMarkerDragEnd(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); + Mockito.verify(flutterApi) + .onMarkerDragEnd(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); } @Test @@ -125,7 +126,8 @@ public void controller_OnMarkerDrag() { controller.addJsonMarkers(markers); controller.onMarkerDrag(googleMarkerId, latLng); - Mockito.verify(flutterApi).onMarkerDrag(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); + Mockito.verify(flutterApi) + .onMarkerDrag(eq(googleMarkerId), eq(Convert.latLngToPigeon(latLng)), any()); } @Test(expected = IllegalArgumentException.class) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart index a9e214a169d..a02698918de 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v20.0.1), do not edit directly. +// Autogenerated from Pigeon (v20.0.2), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index e55b16a6b94..769408bba61 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -30,7 +30,7 @@ dev_dependencies: flutter_test: sdk: flutter mockito: 5.4.4 - pigeon: ^20.0.1 + pigeon: ^20.0.2 plugin_platform_interface: ^2.1.7 topics: From a3ad521a6350a82b1556893a1357a7b3f1567d48 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 1 Jul 2024 14:09:15 -0400 Subject: [PATCH 3/6] Version bump --- .../google_maps_flutter_android/CHANGELOG.md | 4 ++++ .../google_maps_flutter_android/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 7a1833338bf..f4d35e7c439 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.12.0 + +* Converts Java->Dart calls to Pigeon. + ## 2.11.0 * Converts additional platform calls to Pigeon. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 769408bba61..c02a159c839 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.11.0 +version: 2.12.0 environment: sdk: ^3.4.0 From c678de493281f05bb7c0e9663c78638f0de94b81 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 2 Jul 2024 14:33:06 -0400 Subject: [PATCH 4/6] Convert tile fetching to a real object --- .../flutter/plugins/googlemaps/Convert.java | 10 +- .../flutter/plugins/googlemaps/Messages.java | 169 ++++++++++++++++-- .../googlemaps/TileProviderController.java | 11 +- .../lib/src/google_maps_flutter_android.dart | 8 +- .../lib/src/messages.g.dart | 75 ++++++-- .../pigeons/messages.dart | 11 +- 6 files changed, 228 insertions(+), 56 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index e8361c291a6..b06efcddabf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -943,14 +943,8 @@ static String interpretTileOverlayOptions(Map data, TileOverlaySink s } } - static Tile interpretTile(Map data) { - int width = toInt(data.get("width")); - int height = toInt(data.get("height")); - byte[] dataArray = null; - if (data.get("data") != null) { - dataArray = (byte[]) data.get("data"); - } - return new Tile(width, height, dataArray); + static Tile tileFromPigeon(Messages.PlatformTile tile) { + return new Tile(tile.getWidth().intValue(), tile.getHeight().intValue(), tile.getData()); } @VisibleForTesting diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java index 2d678e2aac6..98eb86055a5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java @@ -680,6 +680,132 @@ ArrayList toList() { } } + /** + * Pigeon equivalent of the Tile class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformTile { + private @NonNull Long width; + + public @NonNull Long getWidth() { + return width; + } + + public void setWidth(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"width\" is null."); + } + this.width = setterArg; + } + + private @NonNull Long height; + + public @NonNull Long getHeight() { + return height; + } + + public void setHeight(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"height\" is null."); + } + this.height = setterArg; + } + + private @Nullable byte[] data; + + public @Nullable byte[] getData() { + return data; + } + + public void setData(@Nullable byte[] setterArg) { + this.data = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformTile() {} + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlatformTile that = (PlatformTile) o; + return width.equals(that.width) + && height.equals(that.height) + && Arrays.equals(data, that.data); + } + + @Override + public int hashCode() { + int __pigeon_result = Objects.hash(width, height); + __pigeon_result = 31 * __pigeon_result + Arrays.hashCode(data); + return __pigeon_result; + } + + public static final class Builder { + + private @Nullable Long width; + + @CanIgnoreReturnValue + public @NonNull Builder setWidth(@NonNull Long setterArg) { + this.width = setterArg; + return this; + } + + private @Nullable Long height; + + @CanIgnoreReturnValue + public @NonNull Builder setHeight(@NonNull Long setterArg) { + this.height = setterArg; + return this; + } + + private @Nullable byte[] data; + + @CanIgnoreReturnValue + public @NonNull Builder setData(@Nullable byte[] setterArg) { + this.data = setterArg; + return this; + } + + public @NonNull PlatformTile build() { + PlatformTile pigeonReturn = new PlatformTile(); + pigeonReturn.setWidth(width); + pigeonReturn.setHeight(height); + pigeonReturn.setData(data); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(3); + toListResult.add(width); + toListResult.add(height); + toListResult.add(data); + return toListResult; + } + + static @NonNull PlatformTile fromList(@NonNull ArrayList __pigeon_list) { + PlatformTile pigeonResult = new PlatformTile(); + Object width = __pigeon_list.get(0); + pigeonResult.setWidth( + (width == null) ? null : ((width instanceof Integer) ? (Integer) width : (Long) width)); + Object height = __pigeon_list.get(1); + pigeonResult.setHeight( + (height == null) + ? null + : ((height instanceof Integer) ? (Integer) height : (Long) height)); + Object data = __pigeon_list.get(2); + pigeonResult.setData((byte[]) data); + return pigeonResult; + } + } + /** * Pigeon equivalent of the TileOverlay class. * @@ -1536,22 +1662,24 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { case (byte) 135: return PlatformPolyline.fromList((ArrayList) readValue(buffer)); case (byte) 136: - return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); + return PlatformTile.fromList((ArrayList) readValue(buffer)); case (byte) 137: - return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); case (byte) 138: - return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + return PlatformLatLng.fromList((ArrayList) readValue(buffer)); case (byte) 139: - return PlatformCluster.fromList((ArrayList) readValue(buffer)); + return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); case (byte) 140: - return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); + return PlatformCluster.fromList((ArrayList) readValue(buffer)); case (byte) 141: - return PlatformPoint.fromList((ArrayList) readValue(buffer)); + return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); case (byte) 142: - return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + return PlatformPoint.fromList((ArrayList) readValue(buffer)); case (byte) 143: - return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); case (byte) 144: + return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + case (byte) 145: Object value = readValue(buffer); return value == null ? null : PlatformRendererType.values()[(int) value]; default: @@ -1582,32 +1710,35 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { } else if (value instanceof PlatformPolyline) { stream.write(135); writeValue(stream, ((PlatformPolyline) value).toList()); - } else if (value instanceof PlatformTileOverlay) { + } else if (value instanceof PlatformTile) { stream.write(136); + writeValue(stream, ((PlatformTile) value).toList()); + } else if (value instanceof PlatformTileOverlay) { + stream.write(137); writeValue(stream, ((PlatformTileOverlay) value).toList()); } else if (value instanceof PlatformLatLng) { - stream.write(137); + stream.write(138); writeValue(stream, ((PlatformLatLng) value).toList()); } else if (value instanceof PlatformLatLngBounds) { - stream.write(138); + stream.write(139); writeValue(stream, ((PlatformLatLngBounds) value).toList()); } else if (value instanceof PlatformCluster) { - stream.write(139); + stream.write(140); writeValue(stream, ((PlatformCluster) value).toList()); } else if (value instanceof PlatformMapConfiguration) { - stream.write(140); + stream.write(141); writeValue(stream, ((PlatformMapConfiguration) value).toList()); } else if (value instanceof PlatformPoint) { - stream.write(141); + stream.write(142); writeValue(stream, ((PlatformPoint) value).toList()); } else if (value instanceof PlatformTileLayer) { - stream.write(142); + stream.write(143); writeValue(stream, ((PlatformTileLayer) value).toList()); } else if (value instanceof PlatformZoomRange) { - stream.write(143); + stream.write(144); writeValue(stream, ((PlatformZoomRange) value).toList()); } else if (value instanceof PlatformRendererType) { - stream.write(144); + stream.write(145); writeValue(stream, value == null ? null : ((PlatformRendererType) value).index); } else { super.writeValue(stream, value); @@ -2703,7 +2834,7 @@ public void getTileOverlayTile( @NonNull String tileOverlayIdArg, @NonNull PlatformPoint locationArg, @NonNull Long zoomArg, - @NonNull Result result) { + @NonNull Result result) { final String channelName = "dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile" + messageChannelSuffix; @@ -2728,7 +2859,7 @@ public void getTileOverlayTile( "")); } else { @SuppressWarnings("ConstantConditions") - PlatformTileOverlay output = (PlatformTileOverlay) listReply.get(0); + PlatformTile output = (PlatformTile) listReply.get(0); result.success(output); } } else { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index 25872296d30..ea3fb8fc5c6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -13,7 +13,6 @@ import com.google.android.gms.maps.model.TileProvider; import io.flutter.plugins.googlemaps.Messages.FlutterError; import io.flutter.plugins.googlemaps.Messages.MapsCallbackApi; -import java.util.Map; import java.util.concurrent.CountDownLatch; class TileProviderController implements TileProvider { @@ -35,13 +34,13 @@ public Tile getTile(final int x, final int y, final int zoom) { return worker.getTile(); } - private final class Worker implements Messages.Result { + private final class Worker implements Messages.Result { private final CountDownLatch countDownLatch = new CountDownLatch(1); private final int x; private final int y; private final int zoom; - private @Nullable Messages.PlatformTileOverlay result; + private @Nullable Messages.PlatformTile result; Worker(int x, int y, int zoom) { this.x = x; @@ -72,9 +71,7 @@ Tile getTile() { "Did not receive tile data for tile: x = %d, y= %d, zoom = %d", x, y, zoom)); return TileProvider.NO_TILE; } - @SuppressWarnings("unchecked") - final Map tileJson = (Map) result.getJson(); - return Convert.interpretTile(tileJson); + return Convert.tileFromPigeon(result); } catch (Exception e) { Log.e(TAG, "Can't parse tile data", e); return TileProvider.NO_TILE; @@ -82,7 +79,7 @@ Tile getTile() { } @Override - public void success(@NonNull Messages.PlatformTileOverlay result) { + public void success(@NonNull Messages.PlatformTile result) { this.result = result; countDownLatch.countDown(); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index d69267e4611..05317fed2ae 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -725,7 +725,7 @@ class HostMapMessageHandler implements MapsCallbackApi { final TileOverlay? Function(TileOverlayId tileOverlayId) tileOverlayProvider; @override - Future getTileOverlayTile( + Future getTileOverlayTile( String tileOverlayId, PlatformPoint location, int zoom, @@ -736,7 +736,7 @@ class HostMapMessageHandler implements MapsCallbackApi { final Tile tile = tileProvider == null ? TileProvider.noTile : await tileProvider.getTile(location.x, location.y, zoom); - return PlatformTileOverlay(json: tile.toJson()); + return _platformTileFromTile(tile); } @override @@ -843,6 +843,10 @@ LatLngBounds _latLngBoundsFromPlatformLatLngBounds( northeast: _latLngFromPlatformLatLng(bounds.northeast)); } +PlatformTile _platformTileFromTile(Tile tile) { + return PlatformTile(width: tile.width, height: tile.height, data: tile.data); +} + Map _jsonForMapConfiguration(MapConfiguration config) { final EdgeInsets? padding = config.padding; return { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart index a02698918de..dfae653cbfc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart @@ -218,6 +218,38 @@ class PlatformPolyline { } } +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({ + required this.width, + required this.height, + this.data, + }); + + int width; + + int height; + + Uint8List? data; + + Object encode() { + return [ + width, + height, + data, + ]; + } + + static PlatformTile decode(Object result) { + result as List; + return PlatformTile( + width: result[0]! as int, + height: result[1]! as int, + data: result[2] as Uint8List?, + ); + } +} + /// Pigeon equivalent of the TileOverlay class. class PlatformTileOverlay { PlatformTileOverlay({ @@ -475,32 +507,35 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is PlatformPolyline) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is PlatformTileOverlay) { + } else if (value is PlatformTile) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLng) { + } else if (value is PlatformTileOverlay) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLngBounds) { + } else if (value is PlatformLatLng) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is PlatformCluster) { + } else if (value is PlatformLatLngBounds) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is PlatformMapConfiguration) { + } else if (value is PlatformCluster) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PlatformPoint) { + } else if (value is PlatformMapConfiguration) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is PlatformTileLayer) { + } else if (value is PlatformPoint) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is PlatformZoomRange) { + } else if (value is PlatformTileLayer) { buffer.putUint8(143); writeValue(buffer, value.encode()); - } else if (value is PlatformRendererType) { + } else if (value is PlatformZoomRange) { buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is PlatformRendererType) { + buffer.putUint8(145); writeValue(buffer, value.index); } else { super.writeValue(buffer, value); @@ -525,22 +560,24 @@ class _PigeonCodec extends StandardMessageCodec { case 135: return PlatformPolyline.decode(readValue(buffer)!); case 136: - return PlatformTileOverlay.decode(readValue(buffer)!); + return PlatformTile.decode(readValue(buffer)!); case 137: - return PlatformLatLng.decode(readValue(buffer)!); + return PlatformTileOverlay.decode(readValue(buffer)!); case 138: - return PlatformLatLngBounds.decode(readValue(buffer)!); + return PlatformLatLng.decode(readValue(buffer)!); case 139: - return PlatformCluster.decode(readValue(buffer)!); + return PlatformLatLngBounds.decode(readValue(buffer)!); case 140: - return PlatformMapConfiguration.decode(readValue(buffer)!); + return PlatformCluster.decode(readValue(buffer)!); case 141: - return PlatformPoint.decode(readValue(buffer)!); + return PlatformMapConfiguration.decode(readValue(buffer)!); case 142: - return PlatformTileLayer.decode(readValue(buffer)!); + return PlatformPoint.decode(readValue(buffer)!); case 143: - return PlatformZoomRange.decode(readValue(buffer)!); + return PlatformTileLayer.decode(readValue(buffer)!); case 144: + return PlatformZoomRange.decode(readValue(buffer)!); + case 145: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformRendererType.values[value]; default: @@ -1198,7 +1235,7 @@ abstract class MapsCallbackApi { void onPolylineTap(String polylineId); /// Called to get data for a map tile. - Future getTileOverlayTile( + Future getTileOverlayTile( String tileOverlayId, PlatformPoint location, int zoom); static void setUp( @@ -1621,7 +1658,7 @@ abstract class MapsCallbackApi { assert(arg_zoom != null, 'Argument for dev.flutter.pigeon.google_maps_flutter_android.MapsCallbackApi.getTileOverlayTile was null, expected non-null int.'); try { - final PlatformTileOverlay output = await api.getTileOverlayTile( + final PlatformTile output = await api.getTileOverlayTile( arg_tileOverlayId!, arg_location!, arg_zoom!); return wrapResponse(result: output); } on PlatformException catch (e) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart index fa2aa5669ce..3ef003759f8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart @@ -99,6 +99,15 @@ class PlatformPolyline { final Object json; } +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, required this.data}); + + final int width; + final int height; + final Uint8List? data; +} + /// Pigeon equivalent of the TileOverlay class. class PlatformTileOverlay { PlatformTileOverlay(this.json); @@ -342,7 +351,7 @@ abstract class MapsCallbackApi { /// Called to get data for a map tile. @async - PlatformTileOverlay getTileOverlayTile( + PlatformTile getTileOverlayTile( String tileOverlayId, PlatformPoint location, int zoom); } From da6da68a0d955b8157f840c30ecf20f4e51e69d9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 3 Jul 2024 16:05:05 -0400 Subject: [PATCH 5/6] Consolidate no-op handlers --- .../plugins/googlemaps/CirclesController.java | 10 +-------- .../googlemaps/ClusterManagersController.java | 9 +------- .../googlemaps/GoogleMapController.java | 22 +++++-------------- .../plugins/googlemaps/MarkersController.java | 22 +++++-------------- .../googlemaps/PolygonsController.java | 10 +-------- .../googlemaps/PolylinesController.java | 10 +-------- 6 files changed, 14 insertions(+), 69 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java index ceea54420ab..734e36c809e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java @@ -69,15 +69,7 @@ boolean onCircleTap(String googleCircleId) { if (circleId == null) { return false; } - flutterApi.onCircleTap( - circleId, - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }); + flutterApi.onCircleTap(circleId, new NoOpVoidResult()); CircleController circleController = circleIdToController.get(circleId); if (circleController != null) { return circleController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java index 500857cfa85..448d34aebb1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java @@ -198,14 +198,7 @@ public boolean onClusterClick(Cluster cluster) { MarkerBuilder[] builders = cluster.getItems().toArray(new MarkerBuilder[0]); String clusterManagerId = builders[0].clusterManagerId(); flutterApi.onClusterTap( - Convert.clusterToPigeon(clusterManagerId, cluster), - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }); + Convert.clusterToPigeon(clusterManagerId, cluster), new NoOpVoidResult()); } // Return false to allow the default behavior of the cluster click event to occur. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 4a29f9e58c6..3e8aaffe97c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -106,18 +106,6 @@ class GoogleMapController private boolean lastSetStyleSucceeded; @VisibleForTesting List initialPadding; - // A convenience object for calls to Dart where errors don't matter, such as streaming map - // information where if the corresponding Dart object is gone, the message should be silently - // dropped. - private final Messages.VoidResult noopVoidResult = - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }; - GoogleMapController( int id, Context context, @@ -302,17 +290,17 @@ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { @Override public void onMapClick(@NonNull LatLng latLng) { - flutterApi.onTap(Convert.latLngToPigeon(latLng), noopVoidResult); + flutterApi.onTap(Convert.latLngToPigeon(latLng), new NoOpVoidResult()); } @Override public void onMapLongClick(@NonNull LatLng latLng) { - flutterApi.onLongPress(Convert.latLngToPigeon(latLng), noopVoidResult); + flutterApi.onLongPress(Convert.latLngToPigeon(latLng), new NoOpVoidResult()); } @Override public void onCameraMoveStarted(int reason) { - flutterApi.onCameraMoveStarted(noopVoidResult); + flutterApi.onCameraMoveStarted(new NoOpVoidResult()); } @Override @@ -326,13 +314,13 @@ public void onCameraMove() { return; } flutterApi.onCameraMove( - Convert.cameraPositionToPigeon(googleMap.getCameraPosition()), noopVoidResult); + Convert.cameraPositionToPigeon(googleMap.getCameraPosition()), new NoOpVoidResult()); } @Override public void onCameraIdle() { clusterManagersController.onCameraIdle(); - flutterApi.onCameraIdle(noopVoidResult); + flutterApi.onCameraIdle(new NoOpVoidResult()); } @Override diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java index cac059284cd..d6546cc621b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java @@ -26,18 +26,6 @@ class MarkersController { private final AssetManager assetManager; private final float density; - // A convenience object for calls to Dart where errors don't matter, such as streaming map - // information where if the corresponding Dart object is gone, the message should be silently - // dropped. - private final Messages.VoidResult noopVoidResult = - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }; - MarkersController( @NonNull MapsCallbackApi flutterApi, ClusterManagersController clusterManagersController, @@ -140,7 +128,7 @@ boolean onMapsMarkerTap(String googleMarkerId) { } boolean onMarkerTap(String markerId) { - flutterApi.onMarkerTap(markerId, noopVoidResult); + flutterApi.onMarkerTap(markerId, new NoOpVoidResult()); MarkerController markerController = markerIdToController.get(markerId); if (markerController != null) { return markerController.consumeTapEvents(); @@ -153,7 +141,7 @@ void onMarkerDragStart(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - flutterApi.onMarkerDragStart(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); + flutterApi.onMarkerDragStart(markerId, Convert.latLngToPigeon(latLng), new NoOpVoidResult()); } void onMarkerDrag(String googleMarkerId, LatLng latLng) { @@ -161,7 +149,7 @@ void onMarkerDrag(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - flutterApi.onMarkerDrag(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); + flutterApi.onMarkerDrag(markerId, Convert.latLngToPigeon(latLng), new NoOpVoidResult()); } void onMarkerDragEnd(String googleMarkerId, LatLng latLng) { @@ -169,7 +157,7 @@ void onMarkerDragEnd(String googleMarkerId, LatLng latLng) { if (markerId == null) { return; } - flutterApi.onMarkerDragEnd(markerId, Convert.latLngToPigeon(latLng), noopVoidResult); + flutterApi.onMarkerDragEnd(markerId, Convert.latLngToPigeon(latLng), new NoOpVoidResult()); } void onInfoWindowTap(String googleMarkerId) { @@ -177,7 +165,7 @@ void onInfoWindowTap(String googleMarkerId) { if (markerId == null) { return; } - flutterApi.onInfoWindowTap(markerId, noopVoidResult); + flutterApi.onInfoWindowTap(markerId, new NoOpVoidResult()); } /** diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java index efbf7ca750f..23626edeb70 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java @@ -69,15 +69,7 @@ boolean onPolygonTap(String googlePolygonId) { if (polygonId == null) { return false; } - flutterApi.onPolygonTap( - polygonId, - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }); + flutterApi.onPolygonTap(polygonId, new NoOpVoidResult()); PolygonController polygonController = polygonIdToController.get(polygonId); if (polygonController != null) { return polygonController.consumeTapEvents(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index e9694987f16..cd388f1eae0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -73,15 +73,7 @@ boolean onPolylineTap(String googlePolylineId) { if (polylineId == null) { return false; } - flutterApi.onPolylineTap( - polylineId, - new Messages.VoidResult() { - @Override - public void success() {} - - @Override - public void error(@NonNull Throwable error) {} - }); + flutterApi.onPolylineTap(polylineId, new NoOpVoidResult()); PolylineController polylineController = polylineIdToController.get(polylineId); if (polylineController != null) { return polylineController.consumeTapEvents(); From 5f0aaae78fce48b89c866b722d22d7494a22a4d4 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Sat, 6 Jul 2024 06:16:08 -0400 Subject: [PATCH 6/6] Actually add new file --- .../plugins/googlemaps/NoOpVoidResult.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/NoOpVoidResult.java diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/NoOpVoidResult.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/NoOpVoidResult.java new file mode 100644 index 00000000000..2b8ee23e9a3 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/NoOpVoidResult.java @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlemaps; + +import androidx.annotation.NonNull; + +/** + * Response handler for calls to Dart that don't require any error handling, such as event + * notifications where if the Dart side has been torn down, silently dropping the message is the + * desired behavior. + * + *

Longer term, any call using this is likely a good candidate to migrate to event channels. + */ +public class NoOpVoidResult implements Messages.VoidResult { + @Override + public void success() {} + + @Override + public void error(@NonNull Throwable error) {} +}