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 2291ed28c47..7a1833338bf 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.11.0 + +* Converts additional platform calls to Pigeon. + ## 2.10.0 * Converts some platform calls to Pigeon. 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 d128d9544b1..2b52641caa0 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 @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Circle; import com.google.android.gms.maps.model.CircleOptions; @@ -31,31 +32,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addCircles(List circlesToAdd) { + void addJsonCircles(List circlesToAdd) { if (circlesToAdd != null) { for (Object circleToAdd : circlesToAdd) { - addCircle(circleToAdd); + addJsonCircle(circleToAdd); } } } - void changeCircles(List circlesToChange) { - if (circlesToChange != null) { - for (Object circleToChange : circlesToChange) { - changeCircle(circleToChange); - } + void addCircles(@NonNull List circlesToAdd) { + for (Messages.PlatformCircle circleToAdd : circlesToAdd) { + addJsonCircle(circleToAdd.getJson()); } } - void removeCircles(List circleIdsToRemove) { - if (circleIdsToRemove == null) { - return; + void changeCircles(@NonNull List circlesToChange) { + for (Object circleToChange : circlesToChange) { + changeCircle(circleToChange); } - for (Object rawCircleId : circleIdsToRemove) { - if (rawCircleId == null) { - continue; - } - String circleId = (String) rawCircleId; + } + + void removeCircles(@NonNull List circleIdsToRemove) { + for (String circleId : circleIdsToRemove) { final CircleController circleController = circleIdToController.remove(circleId); if (circleController != null) { circleController.remove(); @@ -77,7 +75,7 @@ boolean onCircleTap(String googleCircleId) { return false; } - private void addCircle(Object circle) { + private void addJsonCircle(Object circle) { if (circle == null) { return; } 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 09ee5d2416f..16666ac0dc3 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 @@ -79,18 +79,25 @@ private void initListenersForClusterManager( } /** Adds new ClusterManagers to the controller. */ - void addClusterManagers(@NonNull List clusterManagersToAdd) { + void addJsonClusterManagers(@NonNull List clusterManagersToAdd) { for (Object clusterToAdd : clusterManagersToAdd) { - addClusterManager(clusterToAdd); + String clusterManagerId = getClusterManagerId(clusterToAdd); + if (clusterManagerId == null) { + throw new IllegalArgumentException("clusterManagerId was null"); + } + addClusterManager(clusterManagerId); } } - /** Adds new ClusterManager to the controller. */ - void addClusterManager(Object clusterManagerData) { - String clusterManagerId = getClusterManagerId(clusterManagerData); - if (clusterManagerId == null) { - throw new IllegalArgumentException("clusterManagerId was null"); + /** Adds new ClusterManagers to the controller. */ + void addClusterManagers(@NonNull List clusterManagersToAdd) { + for (Messages.PlatformClusterManager clusterToAdd : clusterManagersToAdd) { + addClusterManager(clusterToAdd.getIdentifier()); } + } + + /** Adds new ClusterManager to the controller. */ + void addClusterManager(String clusterManagerId) { ClusterManager clusterManager = new ClusterManager(context, googleMap, markerManager); ClusterRenderer clusterRenderer = @@ -101,12 +108,8 @@ void addClusterManager(Object clusterManagerData) { } /** Removes ClusterManagers by given cluster manager IDs from the controller. */ - public void removeClusterManagers(@NonNull List clusterManagerIdsToRemove) { - for (Object rawClusterManagerId : clusterManagerIdsToRemove) { - if (rawClusterManagerId == null) { - continue; - } - String clusterManagerId = (String) rawClusterManagerId; + public void removeClusterManagers(@NonNull List clusterManagerIdsToRemove) { + for (String clusterManagerId : clusterManagerIdsToRemove) { removeClusterManager(clusterManagerId); } } 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 e1817597f16..71455b668e8 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 @@ -9,9 +9,11 @@ import android.graphics.BitmapFactory; import android.graphics.Point; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.MapsInitializer; import com.google.android.gms.maps.model.BitmapDescriptor; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.ButtCap; @@ -357,6 +359,20 @@ private static int toInt(Object o) { return ((Number) o).intValue(); } + static @Nullable MapsInitializer.Renderer toMapRendererType( + @Nullable Messages.PlatformRendererType type) { + if (type == null) { + return null; + } + switch (type) { + case LATEST: + return MapsInitializer.Renderer.LATEST; + case LEGACY: + return MapsInitializer.Renderer.LEGACY; + } + return null; + } + static Object cameraPositionToJson(CameraPosition position) { if (position == null) { return null; 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 e3eee3bc1a7..d2b6b082a27 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 @@ -26,7 +26,6 @@ import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; -import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMapOptions; import com.google.android.gms.maps.MapView; @@ -45,7 +44,6 @@ 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.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugins.googlemaps.Messages.FlutterError; @@ -70,7 +68,6 @@ class GoogleMapController GoogleMapOptionsSink, MapsApi, MapsInspectorApi, - MethodChannel.MethodCallHandler, OnMapReadyCallback, PlatformView { @@ -126,7 +123,6 @@ class GoogleMapController this.binaryMessenger = binaryMessenger; methodChannel = new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_" + id); - methodChannel.setMethodCallHandler(this); MapsApi.setUp(binaryMessenger, Integer.toString(id), this); MapsInspectorApi.setUp(binaryMessenger, Integer.toString(id), this); AssetManager assetManager = context.getAssets(); @@ -186,14 +182,6 @@ void init() { mapView.getMapAsync(this); } - private void moveCamera(CameraUpdate cameraUpdate) { - googleMap.moveCamera(cameraUpdate); - } - - private void animateCamera(CameraUpdate cameraUpdate) { - googleMap.animateCamera(cameraUpdate); - } - private CameraPosition getCameraPosition() { return trackCameraPosition ? googleMap.getCameraPosition() : null; } @@ -308,104 +296,6 @@ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { }); } - @Override - public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "map#update": - { - Convert.interpretGoogleMapOptions(call.argument("options"), this); - result.success(Convert.cameraPositionToJson(getCameraPosition())); - break; - } - case "camera#move": - { - final CameraUpdate cameraUpdate = - Convert.toCameraUpdate(call.argument("cameraUpdate"), density); - moveCamera(cameraUpdate); - result.success(null); - break; - } - case "camera#animate": - { - final CameraUpdate cameraUpdate = - Convert.toCameraUpdate(call.argument("cameraUpdate"), density); - animateCamera(cameraUpdate); - result.success(null); - break; - } - case "markers#update": - { - List markersToAdd = call.argument("markersToAdd"); - markersController.addMarkers(markersToAdd); - List markersToChange = call.argument("markersToChange"); - markersController.changeMarkers(markersToChange); - List markerIdsToRemove = call.argument("markerIdsToRemove"); - markersController.removeMarkers(markerIdsToRemove); - result.success(null); - break; - } - case "clusterManagers#update": - { - List clusterManagersToAdd = call.argument("clusterManagersToAdd"); - if (clusterManagersToAdd != null) { - clusterManagersController.addClusterManagers(clusterManagersToAdd); - } - List clusterManagerIdsToRemove = call.argument("clusterManagerIdsToRemove"); - if (clusterManagerIdsToRemove != null) { - clusterManagersController.removeClusterManagers(clusterManagerIdsToRemove); - } - result.success(null); - break; - } - case "polygons#update": - { - List polygonsToAdd = call.argument("polygonsToAdd"); - polygonsController.addPolygons(polygonsToAdd); - List polygonsToChange = call.argument("polygonsToChange"); - polygonsController.changePolygons(polygonsToChange); - List polygonIdsToRemove = call.argument("polygonIdsToRemove"); - polygonsController.removePolygons(polygonIdsToRemove); - result.success(null); - break; - } - case "polylines#update": - { - List polylinesToAdd = call.argument("polylinesToAdd"); - polylinesController.addPolylines(polylinesToAdd); - List polylinesToChange = call.argument("polylinesToChange"); - polylinesController.changePolylines(polylinesToChange); - List polylineIdsToRemove = call.argument("polylineIdsToRemove"); - polylinesController.removePolylines(polylineIdsToRemove); - result.success(null); - break; - } - case "circles#update": - { - List circlesToAdd = call.argument("circlesToAdd"); - circlesController.addCircles(circlesToAdd); - List circlesToChange = call.argument("circlesToChange"); - circlesController.changeCircles(circlesToChange); - List circleIdsToRemove = call.argument("circleIdsToRemove"); - circlesController.removeCircles(circleIdsToRemove); - result.success(null); - break; - } - case "tileOverlays#update": - { - List> tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); - tileOverlaysController.addTileOverlays(tileOverlaysToAdd); - List> tileOverlaysToChange = call.argument("tileOverlaysToChange"); - tileOverlaysController.changeTileOverlays(tileOverlaysToChange); - List tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); - tileOverlaysController.removeTileOverlays(tileOverlaysToRemove); - result.success(null); - break; - } - default: - result.notImplemented(); - } - } - @Override public void onMapClick(@NonNull LatLng latLng) { final Map arguments = new HashMap<>(2); @@ -490,7 +380,6 @@ public void dispose() { return; } disposed = true; - methodChannel.setMethodCallHandler(null); MapsApi.setUp(binaryMessenger, Integer.toString(id), null); MapsInspectorApi.setUp(binaryMessenger, Integer.toString(id), null); setGoogleMapListener(null); @@ -753,7 +642,7 @@ public void setInitialMarkers(Object initialMarkers) { } private void updateInitialMarkers() { - markersController.addMarkers(initialMarkers); + markersController.addJsonMarkers(initialMarkers); } @Override @@ -767,7 +656,7 @@ public void setInitialClusterManagers(Object initialClusterManagers) { private void updateInitialClusterManagers() { if (initialClusterManagers != null) { - clusterManagersController.addClusterManagers(initialClusterManagers); + clusterManagersController.addJsonClusterManagers(initialClusterManagers); } } @@ -781,7 +670,7 @@ public void setInitialPolygons(Object initialPolygons) { } private void updateInitialPolygons() { - polygonsController.addPolygons(initialPolygons); + polygonsController.addJsonPolygons(initialPolygons); } @Override @@ -794,7 +683,7 @@ public void setInitialPolylines(Object initialPolylines) { } private void updateInitialPolylines() { - polylinesController.addPolylines(initialPolylines); + polylinesController.addJsonPolylines(initialPolylines); } @Override @@ -807,7 +696,7 @@ public void setInitialCircles(Object initialCircles) { } private void updateInitialCircles() { - circlesController.addCircles(initialCircles); + circlesController.addJsonCircles(initialCircles); } @Override @@ -819,7 +708,7 @@ public void setInitialTileOverlays(List> initialTileOverlays) { } private void updateInitialTileOverlays() { - tileOverlaysController.addTileOverlays(initialTileOverlays); + tileOverlaysController.addJsonTileOverlays(initialTileOverlays); } @SuppressLint("MissingPermission") @@ -914,6 +803,68 @@ public void waitForMap(@NonNull Messages.VoidResult result) { } } + @Override + public void updateMapConfiguration(@NonNull Messages.PlatformMapConfiguration configuration) { + Convert.interpretGoogleMapOptions(configuration.getJson(), this); + } + + @Override + public void updateCircles( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + circlesController.addCircles(toAdd); + circlesController.changeCircles(toChange); + circlesController.removeCircles(idsToRemove); + } + + @Override + public void updateClusterManagers( + @NonNull List toAdd, @NonNull List idsToRemove) { + clusterManagersController.addClusterManagers(toAdd); + clusterManagersController.removeClusterManagers(idsToRemove); + } + + @Override + public void updateMarkers( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + markersController.addMarkers(toAdd); + markersController.changeMarkers(toChange); + markersController.removeMarkers(idsToRemove); + } + + @Override + public void updatePolygons( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + polygonsController.addPolygons(toAdd); + polygonsController.changePolygons(toChange); + polygonsController.removePolygons(idsToRemove); + } + + @Override + public void updatePolylines( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + polylinesController.addPolylines(toAdd); + polylinesController.changePolylines(toChange); + polylinesController.removePolylines(idsToRemove); + } + + @Override + public void updateTileOverlays( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + tileOverlaysController.addTileOverlays(toAdd); + tileOverlaysController.changeTileOverlays(toChange); + tileOverlaysController.removeTileOverlays(idsToRemove); + } + @Override public @NonNull Messages.PlatformPoint getScreenCoordinate( @NonNull Messages.PlatformLatLng latLng) { @@ -950,6 +901,24 @@ public void waitForMap(@NonNull Messages.VoidResult result) { return Convert.latLngBoundsToPigeon(latLngBounds); } + @Override + public void moveCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) { + if (googleMap == null) { + throw new FlutterError( + "GoogleMap uninitialized", "moveCamera called prior to map initialization", null); + } + googleMap.moveCamera(Convert.toCameraUpdate(cameraUpdate.getJson(), density)); + } + + @Override + public void animateCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) { + if (googleMap == null) { + throw new FlutterError( + "GoogleMap uninitialized", "animateCamera called prior to map initialization", null); + } + googleMap.animateCamera(Convert.toCameraUpdate(cameraUpdate.getJson(), density)); + } + @Override public @NonNull Double getZoomLevel() { if (googleMap == null) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java index a113c0a1c4c..e4bea6b8ffa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java @@ -5,74 +5,39 @@ package io.flutter.plugins.googlemaps; import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.gms.maps.MapsInitializer; -import com.google.android.gms.maps.MapsInitializer.Renderer; import com.google.android.gms.maps.OnMapsSdkInitializedCallback; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; /** GoogleMaps initializer used to initialize the Google Maps SDK with preferred settings. */ final class GoogleMapInitializer - implements OnMapsSdkInitializedCallback, MethodChannel.MethodCallHandler { - private final MethodChannel methodChannel; + implements OnMapsSdkInitializedCallback, Messages.MapsInitializerApi { private final Context context; - private static MethodChannel.Result initializationResult; + private static Messages.Result initializationResult; private boolean rendererInitialized = false; GoogleMapInitializer(Context context, BinaryMessenger binaryMessenger) { this.context = context; - methodChannel = - new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_initializer"); - methodChannel.setMethodCallHandler(this); + Messages.MapsInitializerApi.setUp(binaryMessenger, this); } @Override - public void onMethodCall(MethodCall call, MethodChannel.Result result) { - switch (call.method) { - case "initializer#preferRenderer": - { - String preferredRenderer = (String) call.argument("value"); - initializeWithPreferredRenderer(preferredRenderer, result); - break; - } - default: - result.notImplemented(); - } - } - - /** - * Initializes map renderer to with preferred renderer type. Renderer can be initialized only once - * per application context. - * - *

Supported renderer types are "latest", "legacy" and "default". - */ - private void initializeWithPreferredRenderer( - String preferredRenderer, MethodChannel.Result result) { + public void initializeWithPreferredRenderer( + @Nullable Messages.PlatformRendererType type, + @NonNull Messages.Result result) { if (rendererInitialized || initializationResult != null) { result.error( - "Renderer already initialized", "Renderer initialization called multiple times", null); + new Messages.FlutterError( + "Renderer already initialized", + "Renderer initialization called multiple times", + null)); } else { initializationResult = result; - switch (preferredRenderer) { - case "latest": - initializeWithRendererRequest(Renderer.LATEST); - break; - case "legacy": - initializeWithRendererRequest(Renderer.LEGACY); - break; - case "default": - initializeWithRendererRequest(null); - break; - default: - initializationResult.error( - "Invalid renderer type", - "Renderer initialization called with invalid renderer type", - null); - initializationResult = null; - } + initializeWithRendererRequest(Convert.toMapRendererType(type)); } } @@ -83,25 +48,28 @@ private void initializeWithPreferredRenderer( * class. */ @VisibleForTesting - public void initializeWithRendererRequest(MapsInitializer.Renderer renderer) { + public void initializeWithRendererRequest(@Nullable MapsInitializer.Renderer renderer) { MapsInitializer.initialize(context, renderer, this); } /** Is called by Google Maps SDK to determine which version of the renderer was initialized. */ @Override - public void onMapsSdkInitialized(MapsInitializer.Renderer renderer) { + public void onMapsSdkInitialized(@NonNull MapsInitializer.Renderer renderer) { rendererInitialized = true; if (initializationResult != null) { switch (renderer) { case LATEST: - initializationResult.success("latest"); + initializationResult.success(Messages.PlatformRendererType.LATEST); break; case LEGACY: - initializationResult.success("legacy"); + initializationResult.success(Messages.PlatformRendererType.LEGACY); break; default: initializationResult.error( - "Unknown renderer type", "Initialized with unknown renderer type", null); + new Messages.FlutterError( + "Unknown renderer type", + "Initialized with unknown renderer type", + renderer.name())); } initializationResult = null; } 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 0f47fecaa50..5d870e88081 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 @@ -5,6 +5,7 @@ package io.flutter.plugins.googlemaps; import android.content.res.AssetManager; +import androidx.annotation.NonNull; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; @@ -43,31 +44,28 @@ void setCollection(MarkerManager.Collection markerCollection) { this.markerCollection = markerCollection; } - void addMarkers(List markersToAdd) { + void addJsonMarkers(List markersToAdd) { if (markersToAdd != null) { for (Object markerToAdd : markersToAdd) { - addMarker(markerToAdd); + addJsonMarker(markerToAdd); } } } - void changeMarkers(List markersToChange) { - if (markersToChange != null) { - for (Object markerToChange : markersToChange) { - changeMarker(markerToChange); - } + void addMarkers(@NonNull List markersToAdd) { + for (Messages.PlatformMarker markerToAdd : markersToAdd) { + addJsonMarker(markerToAdd.getJson()); } } - void removeMarkers(List markerIdsToRemove) { - if (markerIdsToRemove == null) { - return; + void changeMarkers(@NonNull List markersToChange) { + for (Messages.PlatformMarker markerToChange : markersToChange) { + changeJsonMarker(markerToChange.getJson()); } - for (Object rawMarkerId : markerIdsToRemove) { - if (rawMarkerId == null) { - continue; - } - String markerId = (String) rawMarkerId; + } + + void removeMarkers(@NonNull List markerIdsToRemove) { + for (String markerId : markerIdsToRemove) { removeMarker(markerId); } } @@ -188,7 +186,7 @@ public void onClusterItemRendered(MarkerBuilder markerBuilder, Marker marker) { } } - private void addMarker(Object marker) { + private void addJsonMarker(Object marker) { if (marker == null) { return; } @@ -234,7 +232,7 @@ private void createControllerForMarker(String markerId, Marker marker, boolean c googleMapsMarkerIdToDartMarkerId.put(marker.getId(), markerId); } - private void changeMarker(Object marker) { + private void changeJsonMarker(Object marker) { if (marker == null) { return; } @@ -252,7 +250,7 @@ private void changeMarker(Object marker) { // be removed and re-added to update its cluster manager state. if (!(Objects.equals(clusterManagerId, oldClusterManagerId))) { removeMarker(markerId); - addMarker(marker); + addJsonMarker(marker); return; } 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 5c537c9c3bf..ba47fa72d2c 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 @@ -64,6 +64,420 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { @Retention(CLASS) @interface CanIgnoreReturnValue {} + public enum PlatformRendererType { + LEGACY(0), + LATEST(1); + + final int index; + + private PlatformRendererType(final int index) { + this.index = index; + } + } + + /** + * Pigeon representation of a CameraUpdate. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformCameraUpdate { + /** + * The update data, as JSON. This should only be set from CameraUpdate.toJson, and the native + * code must intepret it according to the internal implementation details of the CameraUpdate + * class. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformCameraUpdate() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformCameraUpdate build() { + PlatformCameraUpdate pigeonReturn = new PlatformCameraUpdate(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformCameraUpdate fromList(@NonNull ArrayList __pigeon_list) { + PlatformCameraUpdate pigeonResult = new PlatformCameraUpdate(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Circle class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformCircle { + /** + * The circle data, as JSON. This should only be set from Circle.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformCircle() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformCircle build() { + PlatformCircle pigeonReturn = new PlatformCircle(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformCircle fromList(@NonNull ArrayList __pigeon_list) { + PlatformCircle pigeonResult = new PlatformCircle(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the ClusterManager class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformClusterManager { + private @NonNull String identifier; + + public @NonNull String getIdentifier() { + return identifier; + } + + public void setIdentifier(@NonNull String setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"identifier\" is null."); + } + this.identifier = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformClusterManager() {} + + public static final class Builder { + + private @Nullable String identifier; + + @CanIgnoreReturnValue + public @NonNull Builder setIdentifier(@NonNull String setterArg) { + this.identifier = setterArg; + return this; + } + + public @NonNull PlatformClusterManager build() { + PlatformClusterManager pigeonReturn = new PlatformClusterManager(); + pigeonReturn.setIdentifier(identifier); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(identifier); + return toListResult; + } + + static @NonNull PlatformClusterManager fromList(@NonNull ArrayList __pigeon_list) { + PlatformClusterManager pigeonResult = new PlatformClusterManager(); + Object identifier = __pigeon_list.get(0); + pigeonResult.setIdentifier((String) identifier); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Marker class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformMarker { + /** + * The marker data, as JSON. This should only be set from Marker.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformMarker() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformMarker build() { + PlatformMarker pigeonReturn = new PlatformMarker(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformMarker fromList(@NonNull ArrayList __pigeon_list) { + PlatformMarker pigeonResult = new PlatformMarker(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Polygon class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformPolygon { + /** + * The polygon data, as JSON. This should only be set from Polygon.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformPolygon() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformPolygon build() { + PlatformPolygon pigeonReturn = new PlatformPolygon(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformPolygon fromList(@NonNull ArrayList __pigeon_list) { + PlatformPolygon pigeonResult = new PlatformPolygon(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Polyline class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformPolyline { + /** + * The polyline data, as JSON. This should only be set from Polyline.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformPolyline() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformPolyline build() { + PlatformPolyline pigeonReturn = new PlatformPolyline(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformPolyline fromList(@NonNull ArrayList __pigeon_list) { + PlatformPolyline pigeonResult = new PlatformPolyline(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the TileOverlay class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformTileOverlay { + /** + * The tile overlay data, as JSON. This should only be set from TileOverlay.toJson, and the + * native code must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformTileOverlay() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformTileOverlay build() { + PlatformTileOverlay pigeonReturn = new PlatformTileOverlay(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformTileOverlay fromList(@NonNull ArrayList __pigeon_list) { + PlatformTileOverlay pigeonResult = new PlatformTileOverlay(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + /** * Pigeon equivalent of LatLng. * @@ -351,6 +765,65 @@ ArrayList toList() { } } + /** + * Pigeon equivalent of MapConfiguration. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformMapConfiguration { + /** + * The configuration options, as JSON. This should only be set from _jsonForMapConfiguration, + * and the native code must intepret it according to the internal implementation details of that + * method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformMapConfiguration() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformMapConfiguration build() { + PlatformMapConfiguration pigeonReturn = new PlatformMapConfiguration(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformMapConfiguration fromList(@NonNull ArrayList __pigeon_list) { + PlatformMapConfiguration pigeonResult = new PlatformMapConfiguration(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + /** * Pigeon representation of an x,y coordinate. * @@ -647,17 +1120,36 @@ private PigeonCodec() {} protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 129: - return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + return PlatformCameraUpdate.fromList((ArrayList) readValue(buffer)); case (byte) 130: - return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + return PlatformCircle.fromList((ArrayList) readValue(buffer)); case (byte) 131: - return PlatformCluster.fromList((ArrayList) readValue(buffer)); + return PlatformClusterManager.fromList((ArrayList) readValue(buffer)); case (byte) 132: - return PlatformPoint.fromList((ArrayList) readValue(buffer)); + return PlatformMarker.fromList((ArrayList) readValue(buffer)); case (byte) 133: - return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + return PlatformPolygon.fromList((ArrayList) readValue(buffer)); case (byte) 134: + return PlatformPolyline.fromList((ArrayList) readValue(buffer)); + case (byte) 135: + return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); + case (byte) 136: + return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + case (byte) 137: + return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + case (byte) 138: + return PlatformCluster.fromList((ArrayList) readValue(buffer)); + case (byte) 139: + return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); + case (byte) 140: + return PlatformPoint.fromList((ArrayList) readValue(buffer)); + case (byte) 141: + return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + case (byte) 142: return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + case (byte) 143: + Object value = readValue(buffer); + return value == null ? null : PlatformRendererType.values()[(int) value]; default: return super.readValueOfType(type, buffer); } @@ -665,24 +1157,51 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { @Override protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { - if (value instanceof PlatformLatLng) { + if (value instanceof PlatformCameraUpdate) { stream.write(129); + writeValue(stream, ((PlatformCameraUpdate) value).toList()); + } else if (value instanceof PlatformCircle) { + stream.write(130); + writeValue(stream, ((PlatformCircle) value).toList()); + } else if (value instanceof PlatformClusterManager) { + stream.write(131); + writeValue(stream, ((PlatformClusterManager) value).toList()); + } else if (value instanceof PlatformMarker) { + stream.write(132); + writeValue(stream, ((PlatformMarker) value).toList()); + } else if (value instanceof PlatformPolygon) { + stream.write(133); + writeValue(stream, ((PlatformPolygon) value).toList()); + } else if (value instanceof PlatformPolyline) { + stream.write(134); + writeValue(stream, ((PlatformPolyline) value).toList()); + } else if (value instanceof PlatformTileOverlay) { + stream.write(135); + writeValue(stream, ((PlatformTileOverlay) value).toList()); + } else if (value instanceof PlatformLatLng) { + stream.write(136); writeValue(stream, ((PlatformLatLng) value).toList()); } else if (value instanceof PlatformLatLngBounds) { - stream.write(130); + stream.write(137); writeValue(stream, ((PlatformLatLngBounds) value).toList()); } else if (value instanceof PlatformCluster) { - stream.write(131); + stream.write(138); writeValue(stream, ((PlatformCluster) value).toList()); + } else if (value instanceof PlatformMapConfiguration) { + stream.write(139); + writeValue(stream, ((PlatformMapConfiguration) value).toList()); } else if (value instanceof PlatformPoint) { - stream.write(132); + stream.write(140); writeValue(stream, ((PlatformPoint) value).toList()); } else if (value instanceof PlatformTileLayer) { - stream.write(133); + stream.write(141); writeValue(stream, ((PlatformTileLayer) value).toList()); } else if (value instanceof PlatformZoomRange) { - stream.write(134); + stream.write(142); writeValue(stream, ((PlatformZoomRange) value).toList()); + } else if (value instanceof PlatformRendererType) { + stream.write(143); + writeValue(stream, value == null ? null : ((PlatformRendererType) value).index); } else { super.writeValue(stream, value); } @@ -723,6 +1242,41 @@ public interface VoidResult { public interface MapsApi { /** Returns once the map instance is available. */ void waitForMap(@NonNull VoidResult result); + /** + * Updates the map's configuration options. + * + *

Only non-null configuration values will result in updates; options with null values will + * remain unchanged. + */ + void updateMapConfiguration(@NonNull PlatformMapConfiguration configuration); + /** Updates the set of circles on the map. */ + void updateCircles( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of custer managers for clusters on the map. */ + void updateClusterManagers( + @NonNull List toAdd, @NonNull List idsToRemove); + /** Updates the set of markers on the map. */ + void updateMarkers( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of polygonss on the map. */ + void updatePolygons( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of polylines on the map. */ + void updatePolylines( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of tile overlays on the map. */ + void updateTileOverlays( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); /** Gets the screen coordinate for the given map location. */ @NonNull PlatformPoint getScreenCoordinate(@NonNull PlatformLatLng latLng); @@ -732,6 +1286,10 @@ public interface MapsApi { /** Gets the map region currently displayed on the map. */ @NonNull PlatformLatLngBounds getVisibleRegion(); + /** Moves the camera according to [cameraUpdate] immediately, with no animation. */ + void moveCamera(@NonNull PlatformCameraUpdate cameraUpdate); + /** Moves the camera according to [cameraUpdate], animating the update. */ + void animateCamera(@NonNull PlatformCameraUpdate cameraUpdate); /** Gets the current map zoom level. */ @NonNull Double getZoomLevel(); @@ -808,6 +1366,199 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMapConfiguration" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformMapConfiguration configurationArg = (PlatformMapConfiguration) args.get(0); + try { + api.updateMapConfiguration(configurationArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateCircles" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateCircles(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateClusterManagers" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List idsToRemoveArg = (List) args.get(1); + try { + api.updateClusterManagers(toAddArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMarkers" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateMarkers(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolygons" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updatePolygons(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolylines" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updatePolylines(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateTileOverlays" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateTileOverlays(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -884,6 +1635,58 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.moveCamera" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformCameraUpdate cameraUpdateArg = (PlatformCameraUpdate) args.get(0); + try { + api.moveCamera(cameraUpdateArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.animateCamera" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformCameraUpdate cameraUpdateArg = (PlatformCameraUpdate) args.get(0); + try { + api.animateCamera(cameraUpdateArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -1094,6 +1897,72 @@ public void error(Throwable error) { } } } + /** + * Interface for global SDK initialization. + * + *

Generated interface from Pigeon that represents a handler of messages from Flutter. + */ + public interface MapsInitializerApi { + /** + * Initializes the Google Maps SDK with the given renderer preference. + * + *

A null renderer preference will result in the default renderer. + * + *

Calling this more than once in the lifetime of an application will result in an error. + */ + void initializeWithPreferredRenderer( + @Nullable PlatformRendererType type, @NonNull Result result); + + /** The codec used by MapsInitializerApi. */ + static @NonNull MessageCodec getCodec() { + return PigeonCodec.INSTANCE; + } + /** + * Sets up an instance of `MapsInitializerApi` to handle messages through the `binaryMessenger`. + */ + static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable MapsInitializerApi api) { + setUp(binaryMessenger, "", api); + } + + static void setUp( + @NonNull BinaryMessenger binaryMessenger, + @NonNull String messageChannelSuffix, + @Nullable MapsInitializerApi api) { + messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix; + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsInitializerApi.initializeWithPreferredRenderer" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformRendererType typeArg = (PlatformRendererType) args.get(0); + Result resultCallback = + new Result() { + public void success(PlatformRendererType result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.initializeWithPreferredRenderer(typeArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } /** * Inspector API only intended for use in integration tests. * 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 6f855db0799..a68e3e89ea8 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 @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polygon; import com.google.android.gms.maps.model.PolygonOptions; @@ -31,31 +32,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addPolygons(List polygonsToAdd) { + void addJsonPolygons(List polygonsToAdd) { if (polygonsToAdd != null) { for (Object polygonToAdd : polygonsToAdd) { - addPolygon(polygonToAdd); + addJsonPolygon(polygonToAdd); } } } - void changePolygons(List polygonsToChange) { - if (polygonsToChange != null) { - for (Object polygonToChange : polygonsToChange) { - changePolygon(polygonToChange); - } + void addPolygons(@NonNull List polygonsToAdd) { + for (Messages.PlatformPolygon polygonToAdd : polygonsToAdd) { + addJsonPolygon(polygonToAdd.getJson()); } } - void removePolygons(List polygonIdsToRemove) { - if (polygonIdsToRemove == null) { - return; + void changePolygons(@NonNull List polygonsToChange) { + for (Messages.PlatformPolygon polygonToChange : polygonsToChange) { + changeJsonPolygon(polygonToChange.getJson()); } - for (Object rawPolygonId : polygonIdsToRemove) { - if (rawPolygonId == null) { - continue; - } - String polygonId = (String) rawPolygonId; + } + + void removePolygons(@NonNull List polygonIdsToRemove) { + for (String polygonId : polygonIdsToRemove) { final PolygonController polygonController = polygonIdToController.remove(polygonId); if (polygonController != null) { polygonController.remove(); @@ -77,7 +75,7 @@ boolean onPolygonTap(String googlePolygonId) { return false; } - private void addPolygon(Object polygon) { + private void addJsonPolygon(Object polygon) { if (polygon == null) { return; } @@ -95,7 +93,7 @@ private void addPolygon( googleMapsPolygonIdToDartPolygonId.put(polygon.getId(), polygonId); } - private void changePolygon(Object polygon) { + private void changeJsonPolygon(Object polygon) { if (polygon == null) { return; } 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 2dbad98fcfe..043474d3dc3 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 @@ -5,6 +5,7 @@ package io.flutter.plugins.googlemaps; import android.content.res.AssetManager; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polyline; import com.google.android.gms.maps.model.PolylineOptions; @@ -34,31 +35,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addPolylines(List polylinesToAdd) { + void addJsonPolylines(List polylinesToAdd) { if (polylinesToAdd != null) { for (Object polylineToAdd : polylinesToAdd) { - addPolyline(polylineToAdd); + addJsonPolyline(polylineToAdd); } } } - void changePolylines(List polylinesToChange) { - if (polylinesToChange != null) { - for (Object polylineToChange : polylinesToChange) { - changePolyline(polylineToChange); - } + void addPolylines(@NonNull List polylinesToAdd) { + for (Messages.PlatformPolyline polylineToAdd : polylinesToAdd) { + addJsonPolyline(polylineToAdd.getJson()); } } - void removePolylines(List polylineIdsToRemove) { - if (polylineIdsToRemove == null) { - return; + void changePolylines(@NonNull List polylinesToChange) { + for (Messages.PlatformPolyline polylineToChange : polylinesToChange) { + changeJsonPolyline(polylineToChange.getJson()); } - for (Object rawPolylineId : polylineIdsToRemove) { - if (rawPolylineId == null) { - continue; - } - String polylineId = (String) rawPolylineId; + } + + void removePolylines(@NonNull List polylineIdsToRemove) { + for (String polylineId : polylineIdsToRemove) { final PolylineController polylineController = polylineIdToController.remove(polylineId); if (polylineController != null) { polylineController.remove(); @@ -80,7 +78,7 @@ boolean onPolylineTap(String googlePolylineId) { return false; } - private void addPolyline(Object polyline) { + private void addJsonPolyline(Object polyline) { if (polyline == null) { return; } @@ -99,7 +97,7 @@ private void addPolyline( googleMapsPolylineIdToDartPolylineId.put(polyline.getId(), polylineId); } - private void changePolyline(Object polyline) { + private void changeJsonPolyline(Object polyline) { if (polyline == null) { return; } 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 52b9d1e6bc9..5dfbe2e8ee1 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 @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.TileOverlay; @@ -28,21 +29,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addTileOverlays(List> tileOverlaysToAdd) { + void addJsonTileOverlays(List> tileOverlaysToAdd) { if (tileOverlaysToAdd == null) { return; } for (Map tileOverlayToAdd : tileOverlaysToAdd) { - addTileOverlay(tileOverlayToAdd); + addJsonTileOverlay(tileOverlayToAdd); } } - void changeTileOverlays(List> tileOverlaysToChange) { - if (tileOverlaysToChange == null) { - return; + void addTileOverlays(@NonNull List tileOverlaysToAdd) { + for (Messages.PlatformTileOverlay tileOverlayToAdd : tileOverlaysToAdd) { + @SuppressWarnings("unchecked") + final Map overlayJson = (Map) tileOverlayToAdd.getJson(); + addJsonTileOverlay(overlayJson); } - for (Map tileOverlayToChange : tileOverlaysToChange) { - changeTileOverlay(tileOverlayToChange); + } + + void changeTileOverlays(@NonNull List tileOverlaysToChange) { + for (Messages.PlatformTileOverlay tileOverlayToChange : tileOverlaysToChange) { + @SuppressWarnings("unchecked") + final Map overlayJson = (Map) tileOverlayToChange.getJson(); + changeJsonTileOverlay(overlayJson); } } @@ -80,7 +88,7 @@ TileOverlay getTileOverlay(String tileOverlayId) { return tileOverlayController.getTileOverlay(); } - private void addTileOverlay(Map tileOverlayOptions) { + private void addJsonTileOverlay(Map tileOverlayOptions) { if (tileOverlayOptions == null) { return; } @@ -96,7 +104,7 @@ private void addTileOverlay(Map tileOverlayOptions) { tileOverlayIdToController.put(tileOverlayId, tileOverlayController); } - private void changeTileOverlay(Map tileOverlayOptions) { + private void changeJsonTileOverlay(Map tileOverlayOptions) { if (tileOverlayOptions == null) { return; } 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 bc80627c35f..aaa50542e7f 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 @@ -68,7 +68,7 @@ public void setUp() { @Test @SuppressWarnings("unchecked") - public void AddClusterManagersAndMarkers() throws InterruptedException { + public void AddJsonClusterManagersAndMarkers() throws InterruptedException { final String clusterManagerId = "cm_1"; final String markerId1 = "mid_1"; final String markerId2 = "mid_2"; @@ -90,6 +90,61 @@ public void AddClusterManagersAndMarkers() throws InterruptedException { initialClusterManager.put("clusterManagerId", clusterManagerId); List clusterManagersToAdd = new ArrayList<>(); clusterManagersToAdd.add(initialClusterManager); + controller.addJsonClusterManagers(clusterManagersToAdd); + + MarkerBuilder markerBuilder1 = new MarkerBuilder(markerId1, clusterManagerId); + MarkerBuilder markerBuilder2 = new MarkerBuilder(markerId2, clusterManagerId); + + final Map markerData1 = + createMarkerData(markerId1, location1, clusterManagerId); + final Map markerData2 = + createMarkerData(markerId2, location2, clusterManagerId); + + Convert.interpretMarkerOptions(markerData1, markerBuilder1, assetManager, density); + Convert.interpretMarkerOptions(markerData2, markerBuilder2, assetManager, density); + + controller.addItem(markerBuilder1); + controller.addItem(markerBuilder2); + + Set> clusters = + controller.getClustersWithClusterManagerId(clusterManagerId); + assertEquals("Amount of clusters should be 1", 1, clusters.size()); + + Cluster cluster = clusters.iterator().next(); + assertNotNull("Cluster position should not be null", cluster.getPosition()); + Set markerIds = new HashSet<>(); + for (MarkerBuilder marker : cluster.getItems()) { + markerIds.add(marker.markerId()); + } + assertTrue("Marker IDs should contain markerId1", markerIds.contains(markerId1)); + assertTrue("Marker IDs should contain markerId2", markerIds.contains(markerId2)); + assertEquals("Cluster should contain exactly 2 markers", 2, cluster.getSize()); + } + + @Test + @SuppressWarnings("unchecked") + public void AddClusterManagersAndMarkers() throws InterruptedException { + final String clusterManagerId = "cm_1"; + final String markerId1 = "mid_1"; + final String markerId2 = "mid_2"; + + final LatLng latLng1 = new LatLng(1.1, 2.2); + final LatLng latLng2 = new LatLng(3.3, 4.4); + + final List location1 = new ArrayList<>(); + location1.add(latLng1.latitude); + location1.add(latLng1.longitude); + + final List location2 = new ArrayList<>(); + location2.add(latLng2.latitude); + location2.add(latLng2.longitude); + + when(googleMap.getCameraPosition()) + .thenReturn(CameraPosition.builder().target(new LatLng(0, 0)).build()); + Messages.PlatformClusterManager initialClusterManager = + new Messages.PlatformClusterManager.Builder().setIdentifier(clusterManagerId).build(); + List clusterManagersToAdd = new ArrayList<>(); + clusterManagersToAdd.add(initialClusterManager); controller.addClusterManagers(clusterManagersToAdd); MarkerBuilder markerBuilder1 = new MarkerBuilder(markerId1, clusterManagerId); @@ -150,9 +205,9 @@ public void RemoveClusterManagers() { when(googleMap.getCameraPosition()) .thenReturn(CameraPosition.builder().target(new LatLng(0, 0)).build()); - Map initialClusterManager = new HashMap<>(); - initialClusterManager.put("clusterManagerId", clusterManagerId); - List clusterManagersToAdd = new ArrayList<>(); + Messages.PlatformClusterManager initialClusterManager = + new Messages.PlatformClusterManager.Builder().setIdentifier(clusterManagerId).build(); + List clusterManagersToAdd = new ArrayList<>(); clusterManagersToAdd.add(initialClusterManager); controller.addClusterManagers(clusterManagersToAdd); 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 3459b9b3139..f68ab346077 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 @@ -203,7 +203,7 @@ public void SetInitialClusterManagers() { googleMapController.onMapReady(mockGoogleMap); // Verify if the ClusterManagersController.addClusterManagers method is called with initial cluster managers. - verify(mockClusterManagersController, times(1)).addClusterManagers(any()); + verify(mockClusterManagersController, times(1)).addJsonClusterManagers(any()); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java index 2f9f5e5619f..374964cbad6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java @@ -6,7 +6,6 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -18,9 +17,6 @@ import androidx.test.core.app.ApplicationProvider; import com.google.android.gms.maps.MapsInitializer.Renderer; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import java.util.HashMap; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -46,53 +42,33 @@ public void before() { @Test public void initializer_OnMapsSdkInitializedWithLatestRenderer() { doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LATEST); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "latest"); - } - }), - result); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer( + Messages.PlatformRendererType.LATEST, result); googleMapInitializer.onMapsSdkInitialized(Renderer.LATEST); - verify(result, times(1)).success("latest"); - verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(Messages.PlatformRendererType.LATEST); + verify(result, never()).error(any()); } @Test public void initializer_OnMapsSdkInitializedWithLegacyRenderer() { doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "legacy"); - } - }), - result); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer( + Messages.PlatformRendererType.LEGACY, result); googleMapInitializer.onMapsSdkInitialized(Renderer.LEGACY); - verify(result, times(1)).success("legacy"); - verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(Messages.PlatformRendererType.LEGACY); + verify(result, never()).error(any()); } @Test - public void initializer_onMethodCallWithUnknownRenderer() { - doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "wrong_renderer"); - } - }), - result); - verify(result, never()).success(any()); - verify(result, times(1)).error(eq("Invalid renderer type"), any(), any()); + public void initializer_onMethodCallWithNoRendererPreference() { + doNothing().when(googleMapInitializer).initializeWithRendererRequest(null); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer(null, result); + verify(result, never()).error(any()); } } 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 116f8381bce..41444d9f290 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 @@ -25,6 +25,7 @@ import io.flutter.plugin.common.MethodCodec; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -81,7 +82,7 @@ public void controller_OnMarkerDragStart() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDragStart(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -108,7 +109,7 @@ public void controller_OnMarkerDragEnd() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDragEnd(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -135,7 +136,7 @@ public void controller_OnMarkerDrag() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDrag(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -154,7 +155,7 @@ public void controller_AddMarkerThrowsErrorIfMarkerIdIsNull() { final List markers = Arrays.asList(markerOptions); try { - controller.addMarkers(markers); + controller.addJsonMarkers(markers); } catch (IllegalArgumentException e) { assertEquals("markerId was null", e.getMessage()); throw e; @@ -183,7 +184,7 @@ public void controller_AddChangeAndRemoveMarkerWithClusterManagerId() { final List markers = Arrays.asList(markerOptions1); // Add marker and capture the markerBuilder - controller.addMarkers(markers); + controller.addJsonMarkers(markers); ArgumentCaptor captor = ArgumentCaptor.forClass(MarkerBuilder.class); Mockito.verify(clusterManagersController, times(1)).addItem(captor.capture()); MarkerBuilder capturedMarkerBuilder = captor.getValue(); @@ -202,7 +203,9 @@ public void controller_AddChangeAndRemoveMarkerWithClusterManagerId() { markerOptions2.put("markerId", googleMarkerId); markerOptions2.put("position", location2); markerOptions2.put("clusterManagerId", clusterManagerId); - final List updatedMarkers = Arrays.asList(markerOptions2); + final List updatedMarkers = + Collections.singletonList( + new Messages.PlatformMarker.Builder().setJson(markerOptions2).build()); controller.changeMarkers(updatedMarkers); Mockito.verify(marker, times(1)).setPosition(latLng2); @@ -232,7 +235,7 @@ public void controller_AddChangeAndRemoveMarkerWithoutClusterManagerId() { markerOptions1.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions1); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); // clusterManagersController should not be called when adding the marker Mockito.verify(clusterManagersController, times(0)).addItem(any()); @@ -244,7 +247,9 @@ public void controller_AddChangeAndRemoveMarkerWithoutClusterManagerId() { markerOptions2.put("markerId", googleMarkerId); markerOptions2.put("alpha", alpha); - final List markerUpdates = Arrays.asList(markerOptions2); + final List markerUpdates = + Collections.singletonList( + new Messages.PlatformMarker.Builder().setJson(markerOptions2).build()); controller.changeMarkers(markerUpdates); Mockito.verify(marker, times(1)).setAlpha(alpha); 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 0664ae3accd..3b77fa91480 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,10 +70,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterAndroid(); } - /// The method channel used to initialize the native Google Maps SDK. - final MethodChannel _initializerChannel = const MethodChannel( - 'plugins.flutter.dev/google_maps_android_initializer'); - // Keep a collection of id -> channel // Every method call passes the int mapId final Map _channels = {}; @@ -83,15 +79,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { // A method to create MapsApi instances, which can be overridden for testing. final MapsApi Function(int mapId) _apiProvider; - /// Accesses the MethodChannel associated to the passed mapId. - MethodChannel _channel(int mapId) { - final MethodChannel? channel = _channels[mapId]; - if (channel == null) { - throw UnknownMapIDError(mapId); - } - return channel; - } - /// Accesses the MapsApi associated to the passed mapId. MapsApi _hostApi(int mapId) { final MapsApi? api = _hostMaps[mapId]; @@ -341,17 +328,22 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return (call.arguments as Map).cast(); } + @override + Future updateMapConfiguration( + MapConfiguration configuration, { + required int mapId, + }) { + return updateMapOptions(_jsonForMapConfiguration(configuration), + mapId: mapId); + } + @override Future updateMapOptions( Map optionsUpdate, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'map#update', - { - 'options': optionsUpdate, - }, - ); + return _hostApi(mapId) + .updateMapConfiguration(PlatformMapConfiguration(json: optionsUpdate)); } @override @@ -359,9 +351,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { MarkerUpdates markerUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'markers#update', - markerUpdates.toJson(), + return _hostApi(mapId).updateMarkers( + markerUpdates.markersToAdd.map(_platformMarkerFromMarker).toList(), + markerUpdates.markersToChange.map(_platformMarkerFromMarker).toList(), + markerUpdates.markerIdsToRemove.map((MarkerId id) => id.value).toList(), ); } @@ -370,9 +363,12 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { PolygonUpdates polygonUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'polygons#update', - polygonUpdates.toJson(), + return _hostApi(mapId).updatePolygons( + polygonUpdates.polygonsToAdd.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonsToChange.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonIdsToRemove + .map((PolygonId id) => id.value) + .toList(), ); } @@ -381,9 +377,16 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { PolylineUpdates polylineUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'polylines#update', - polylineUpdates.toJson(), + return _hostApi(mapId).updatePolylines( + polylineUpdates.polylinesToAdd + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylinesToChange + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylineIdsToRemove + .map((PolylineId id) => id.value) + .toList(), ); } @@ -392,9 +395,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CircleUpdates circleUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'circles#update', - circleUpdates.toJson(), + return _hostApi(mapId).updateCircles( + circleUpdates.circlesToAdd.map(_platformCircleFromCircle).toList(), + circleUpdates.circlesToChange.map(_platformCircleFromCircle).toList(), + circleUpdates.circleIdsToRemove.map((CircleId id) => id.value).toList(), ); } @@ -411,9 +415,16 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { final _TileOverlayUpdates updates = _TileOverlayUpdates.from(previousSet, newTileOverlays); _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); - return _channel(mapId).invokeMethod( - 'tileOverlays#update', - updates.toJson(), + return _hostApi(mapId).updateTileOverlays( + updates.tileOverlaysToAdd + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlaysToChange + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlayIdsToRemove + .map((TileOverlayId id) => id.value) + .toList(), ); } @@ -422,9 +433,13 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { ClusterManagerUpdates clusterManagerUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'clusterManagers#update', - serializeClusterManagerUpdates(clusterManagerUpdates), + return _hostApi(mapId).updateClusterManagers( + clusterManagerUpdates.clusterManagersToAdd + .map(_platformClusterManagerFromClusterManager) + .toList(), + clusterManagerUpdates.clusterManagerIdsToRemove + .map((ClusterManagerId id) => id.value) + .toList(), ); } @@ -441,10 +456,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CameraUpdate cameraUpdate, { required int mapId, }) { - return _channel(mapId) - .invokeMethod('camera#animate', { - 'cameraUpdate': cameraUpdate.toJson(), - }); + return _hostApi(mapId) + .animateCamera(PlatformCameraUpdate(json: cameraUpdate.toJson())); } @override @@ -452,9 +465,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CameraUpdate cameraUpdate, { required int mapId, }) { - return _channel(mapId).invokeMethod('camera#move', { - 'cameraUpdate': cameraUpdate.toJson(), - }); + return _hostApi(mapId) + .moveCamera(PlatformCameraUpdate(json: cameraUpdate.toJson())); } @override @@ -561,35 +573,25 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { /// Initialized [AndroidMapRenderer] type is returned. Future initializeWithRenderer( AndroidMapRenderer? rendererType) async { - String preferredRenderer; + PlatformRendererType? preferredRenderer; switch (rendererType) { case AndroidMapRenderer.latest: - preferredRenderer = 'latest'; + preferredRenderer = PlatformRendererType.latest; case AndroidMapRenderer.legacy: - preferredRenderer = 'legacy'; + preferredRenderer = PlatformRendererType.legacy; case AndroidMapRenderer.platformDefault: case null: - preferredRenderer = 'default'; + preferredRenderer = null; } - final String? initializedRenderer = await _initializerChannel - .invokeMethod('initializer#preferRenderer', - {'value': preferredRenderer}); - - if (initializedRenderer == null) { - throw AndroidMapRendererException('Failed to initialize map renderer.'); - } + final MapsInitializerApi hostApi = MapsInitializerApi(); + final PlatformRendererType initializedRenderer = + await hostApi.initializeWithPreferredRenderer(preferredRenderer); - // Returns mapped [AndroidMapRenderer] enum type. - switch (initializedRenderer) { - case 'latest': - return AndroidMapRenderer.latest; - case 'legacy': - return AndroidMapRenderer.legacy; - default: - throw AndroidMapRendererException( - 'Failed to initialize latest or legacy renderer, got $initializedRenderer.'); - } + return switch (initializedRenderer) { + PlatformRendererType.latest => AndroidMapRenderer.latest, + PlatformRendererType.legacy => AndroidMapRenderer.legacy, + }; } Widget _buildView( @@ -599,6 +601,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { MapObjects mapObjects = const MapObjects(), Map mapOptions = const {}, }) { + // TODO(stuartmorgan): Convert this to Pigeon-generated structures once + // https://github.com/flutter/flutter/issues/150631 is fixed. final Map creationParams = { 'initialCameraPosition': widgetConfiguration.initialCameraPosition.toMap(), @@ -815,6 +819,33 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { southwest: _latLngFromPlatformLatLng(bounds.southwest), northeast: _latLngFromPlatformLatLng(bounds.northeast)); } + + static PlatformCircle _platformCircleFromCircle(Circle circle) { + return PlatformCircle(json: circle.toJson()); + } + + static PlatformClusterManager _platformClusterManagerFromClusterManager( + ClusterManager clusterManager) { + return PlatformClusterManager( + identifier: clusterManager.clusterManagerId.value); + } + + static PlatformMarker _platformMarkerFromMarker(Marker marker) { + return PlatformMarker(json: marker.toJson()); + } + + static PlatformPolygon _platformPolygonFromPolygon(Polygon polygon) { + return PlatformPolygon(json: polygon.toJson()); + } + + static PlatformPolyline _platformPolylineFromPolyline(Polyline polyline) { + return PlatformPolyline(json: polyline.toJson()); + } + + static PlatformTileOverlay _platformTileOverlayFromTileOverlay( + TileOverlay tileOverlay) { + return PlatformTileOverlay(json: tileOverlay.toJson()); + } } Map _jsonForMapConfiguration(MapConfiguration config) { 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 fa7445f748f..23f7aa45c0a 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,6 +18,183 @@ PlatformException _createConnectionError(String channelName) { ); } +enum PlatformRendererType { + legacy, + latest, +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate({ + required this.json, + }); + + /// The update data, as JSON. This should only be set from + /// CameraUpdate.toJson, and the native code must intepret it according to the + /// internal implementation details of the CameraUpdate class. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformCameraUpdate decode(Object result) { + result as List; + return PlatformCameraUpdate( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + required this.json, + }); + + /// The circle data, as JSON. This should only be set from + /// Circle.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformCircle decode(Object result) { + result as List; + return PlatformCircle( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({ + required this.identifier, + }); + + String identifier; + + Object encode() { + return [ + identifier, + ]; + } + + static PlatformClusterManager decode(Object result) { + result as List; + return PlatformClusterManager( + identifier: result[0]! as String, + ); + } +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + required this.json, + }); + + /// The marker data, as JSON. This should only be set from + /// Marker.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformMarker decode(Object result) { + result as List; + return PlatformMarker( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.json, + }); + + /// The polygon data, as JSON. This should only be set from + /// Polygon.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformPolygon decode(Object result) { + result as List; + return PlatformPolygon( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.json, + }); + + /// The polyline data, as JSON. This should only be set from + /// Polyline.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformPolyline decode(Object result) { + result as List; + return PlatformPolyline( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.json, + }); + + /// The tile overlay data, as JSON. This should only be set from + /// TileOverlay.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformTileOverlay decode(Object result) { + result as List; + return PlatformTileOverlay( + json: result[0]!, + ); + } +} + /// Pigeon equivalent of LatLng. class PlatformLatLng { PlatformLatLng({ @@ -109,6 +286,31 @@ class PlatformCluster { } } +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + required this.json, + }); + + /// The configuration options, as JSON. This should only be set from + /// _jsonForMapConfiguration, and the native code must intepret it according + /// to the internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformMapConfiguration decode(Object result) { + result as List; + return PlatformMapConfiguration( + json: result[0]!, + ); + } +} + /// Pigeon representation of an x,y coordinate. class PlatformPoint { PlatformPoint({ @@ -204,24 +406,51 @@ class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is PlatformLatLng) { + if (value is PlatformCameraUpdate) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLngBounds) { + } else if (value is PlatformCircle) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PlatformCluster) { + } else if (value is PlatformClusterManager) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PlatformPoint) { + } else if (value is PlatformMarker) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PlatformTileLayer) { + } else if (value is PlatformPolygon) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PlatformZoomRange) { + } else if (value is PlatformPolyline) { buffer.putUint8(134); writeValue(buffer, value.encode()); + } else if (value is PlatformTileOverlay) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLng) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLngBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PlatformCluster) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapConfiguration) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PlatformPoint) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileLayer) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PlatformZoomRange) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PlatformRendererType) { + buffer.putUint8(143); + writeValue(buffer, value.index); } else { super.writeValue(buffer, value); } @@ -231,17 +460,36 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - return PlatformLatLng.decode(readValue(buffer)!); + return PlatformCameraUpdate.decode(readValue(buffer)!); case 130: - return PlatformLatLngBounds.decode(readValue(buffer)!); + return PlatformCircle.decode(readValue(buffer)!); case 131: - return PlatformCluster.decode(readValue(buffer)!); + return PlatformClusterManager.decode(readValue(buffer)!); case 132: - return PlatformPoint.decode(readValue(buffer)!); + return PlatformMarker.decode(readValue(buffer)!); case 133: - return PlatformTileLayer.decode(readValue(buffer)!); + return PlatformPolygon.decode(readValue(buffer)!); case 134: + return PlatformPolyline.decode(readValue(buffer)!); + case 135: + return PlatformTileOverlay.decode(readValue(buffer)!); + case 136: + return PlatformLatLng.decode(readValue(buffer)!); + case 137: + return PlatformLatLngBounds.decode(readValue(buffer)!); + case 138: + return PlatformCluster.decode(readValue(buffer)!); + case 139: + return PlatformMapConfiguration.decode(readValue(buffer)!); + case 140: + return PlatformPoint.decode(readValue(buffer)!); + case 141: + return PlatformTileLayer.decode(readValue(buffer)!); + case 142: return PlatformZoomRange.decode(readValue(buffer)!); + case 143: + final int? value = readValue(buffer) as int?; + return value == null ? null : PlatformRendererType.values[value]; default: return super.readValueOfType(type, buffer); } @@ -290,6 +538,191 @@ class MapsApi { } } + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + Future updateMapConfiguration( + PlatformMapConfiguration configuration) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMapConfiguration$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([configuration]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of circles on the map. + Future updateCircles(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateCircles$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of custer managers for clusters on the map. + Future updateClusterManagers( + List toAdd, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateClusterManagers$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of markers on the map. + Future updateMarkers(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMarkers$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polygonss on the map. + Future updatePolygons(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolygons$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polylines on the map. + Future updatePolylines(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolylines$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of tile overlays on the map. + Future updateTileOverlays(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateTileOverlays$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + /// Gets the screen coordinate for the given map location. Future getScreenCoordinate(PlatformLatLng latLng) async { final String __pigeon_channelName = @@ -380,6 +813,57 @@ class MapsApi { } } + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + Future moveCamera(PlatformCameraUpdate cameraUpdate) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.moveCamera$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([cameraUpdate]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Moves the camera according to [cameraUpdate], animating the update. + Future animateCamera(PlatformCameraUpdate cameraUpdate) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.animateCamera$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([cameraUpdate]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + /// Gets the current map zoom level. Future getZoomLevel() async { final String __pigeon_channelName = @@ -615,6 +1099,59 @@ class MapsApi { } } +/// Interface for global SDK initialization. +class MapsInitializerApi { + /// Constructor for [MapsInitializerApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsInitializerApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : __pigeon_binaryMessenger = binaryMessenger, + __pigeon_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? __pigeon_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String __pigeon_messageChannelSuffix; + + /// Initializes the Google Maps SDK with the given renderer preference. + /// + /// A null renderer preference will result in the default renderer. + /// + /// Calling this more than once in the lifetime of an application will result + /// in an error. + Future initializeWithPreferredRenderer( + PlatformRendererType? type) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsInitializerApi.initializeWithPreferredRenderer$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([type]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as PlatformRendererType?)!; + } + } +} + /// Inspector API only intended for use in integration tests. class MapsInspectorApi { /// Constructor for [MapsInspectorApi]. The [binaryMessenger] named argument is diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart index cdb1d2c9244..1aab89354a0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart @@ -17,18 +17,3 @@ Object _serializeClusterManager(ClusterManager clusterManager) { json['clusterManagerId'] = clusterManager.clusterManagerId.value; return json; } - -/// Converts a Cluster Manager updates into object serializable in JSON. -Object serializeClusterManagerUpdates( - ClusterManagerUpdates clusterManagerUpdates) { - final Map updateMap = {}; - - updateMap['clusterManagersToAdd'] = - serializeClusterManagerSet(clusterManagerUpdates.objectsToAdd); - updateMap['clusterManagerIdsToRemove'] = clusterManagerUpdates - .objectIdsToRemove - .map((MapsObjectId id) => id.value) - .toList(); - - return updateMap; -} 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 1a50204c580..3b78a5b180b 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 @@ -11,6 +11,91 @@ import 'package:pigeon/pigeon.dart'; copyrightHeader: 'pigeons/copyright.txt', )) +// Pigeon equivalent of the Java MapsInitializer.Renderer. +enum PlatformRendererType { legacy, latest } + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate(this.json); + + /// The update data, as JSON. This should only be set from + /// CameraUpdate.toJson, and the native code must intepret it according to the + /// internal implementation details of the CameraUpdate class. + // TODO(stuartmorgan): Update the google_maps_platform_interface CameraUpdate + // class to provide a structured representation of an update. Currently it + // uses JSON as its only state, so there is no way to preserve structure. + // This wrapper class exists as a placeholder for now to at least provide + // type safety in the top-level call's arguments. + final Object json; +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle(this.json); + + /// The circle data, as JSON. This should only be set from + /// Circle.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + final String identifier; +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker(this.json); + + /// The marker data, as JSON. This should only be set from + /// Marker.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon(this.json); + + /// The polygon data, as JSON. This should only be set from + /// Polygon.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline(this.json); + + /// The polyline data, as JSON. This should only be set from + /// Polyline.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay(this.json); + + /// The tile overlay data, as JSON. This should only be set from + /// TileOverlay.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + /// Pigeon equivalent of LatLng. class PlatformLatLng { PlatformLatLng({required this.latitude, required this.longitude}); @@ -45,6 +130,18 @@ class PlatformCluster { final List markerIds; } +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({required this.json}); + + /// The configuration options, as JSON. This should only be set from + /// _jsonForMapConfiguration, and the native code must intepret it according + /// to the internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + /// Pigeon representation of an x,y coordinate. class PlatformPoint { PlatformPoint({required this.x, required this.y}); @@ -85,6 +182,54 @@ abstract class MapsApi { @async void waitForMap(); + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + void updateMapConfiguration(PlatformMapConfiguration configuration); + + /// Updates the set of circles on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateCircles(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of custer managers for clusters on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateClusterManagers( + List toAdd, List idsToRemove); + + /// Updates the set of markers on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateMarkers(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of polygonss on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updatePolygons(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of polylines on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updatePolylines(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of tile overlays on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateTileOverlays(List toAdd, + List toChange, List idsToRemove); + /// Gets the screen coordinate for the given map location. PlatformPoint getScreenCoordinate(PlatformLatLng latLng); @@ -94,6 +239,13 @@ abstract class MapsApi { /// Gets the map region currently displayed on the map. PlatformLatLngBounds getVisibleRegion(); + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + void moveCamera(PlatformCameraUpdate cameraUpdate); + + /// Moves the camera according to [cameraUpdate], animating the update. + void animateCamera(PlatformCameraUpdate cameraUpdate); + /// Gets the current map zoom level. double getZoomLevel(); @@ -129,6 +281,20 @@ abstract class MapsApi { Uint8List takeSnapshot(); } +/// Interface for global SDK initialization. +@HostApi() +abstract class MapsInitializerApi { + /// Initializes the Google Maps SDK with the given renderer preference. + /// + /// A null renderer preference will result in the default renderer. + /// + /// Calling this more than once in the lifetime of an application will result + /// in an error. + @async + PlatformRendererType initializeWithPreferredRenderer( + PlatformRendererType? type); +} + /// Inspector API only intended for use in integration tests. @HostApi() abstract class MapsInspectorApi { 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 087914e6b3e..e55b16a6b94 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.10.0 +version: 2.11.0 environment: sdk: ^3.4.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart deleted file mode 100644 index 56963ddbdd9..00000000000 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -// 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. -import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter_android/src/utils/cluster_manager_utils.dart'; -import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; - -void main() { - test('serializeClusterManagerUpdates', () async { - const ClusterManagerId clusterManagerId1 = ClusterManagerId('cm1'); - const ClusterManagerId clusterManagerId2 = ClusterManagerId('cm2'); - - const ClusterManager clusterManager1 = ClusterManager( - clusterManagerId: clusterManagerId1, - ); - const ClusterManager clusterManager2 = ClusterManager( - clusterManagerId: clusterManagerId2, - ); - - final Set clusterManagersSet1 = {}; - final Set clusterManagersSet2 = { - clusterManager1, - clusterManager2 - }; - final Set clusterManagersSet3 = { - clusterManager1 - }; - - final ClusterManagerUpdates clusterManagerUpdates1 = - ClusterManagerUpdates.from(clusterManagersSet1, clusterManagersSet2); - final Map serializedData1 = - serializeClusterManagerUpdates(clusterManagerUpdates1) - as Map; - expect(serializedData1['clusterManagersToAdd'], isNotNull); - final List clusterManagersToAdd1 = - serializedData1['clusterManagersToAdd']! as List; - expect(clusterManagersToAdd1.length, 2); - expect(serializedData1['clusterManagerIdsToRemove'], isNotNull); - final List clusterManagersToRemove1 = - serializedData1['clusterManagerIdsToRemove']! as List; - expect(clusterManagersToRemove1.length, 0); - - final ClusterManagerUpdates clusterManagerUpdates2 = - ClusterManagerUpdates.from(clusterManagersSet2, clusterManagersSet3); - serializeClusterManagerUpdates(clusterManagerUpdates2); - final Map serializedData2 = - serializeClusterManagerUpdates(clusterManagerUpdates2) - as Map; - expect(serializedData2['clusterManagersToAdd'], isNotNull); - final List clusterManagersToAdd2 = - serializedData2['clusterManagersToAdd']! as List; - expect(clusterManagersToAdd2.length, 0); - expect(serializedData1['clusterManagerIdsToRemove'], isNotNull); - final List clusterManagersToRemove2 = - serializedData2['clusterManagerIdsToRemove']! as List; - expect(clusterManagersToRemove2.length, 1); - expect(clusterManagersToRemove2.first as String, equals('cm2')); - }); -} 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 109b9411a32..cfe6b976695 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 @@ -113,6 +113,35 @@ void main() { expect(bounds, expectedBounds); }); + test('moveCamera calls through', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final PlatformCameraUpdate passedUpdate = + verification.captured[0] as PlatformCameraUpdate; + expect(passedUpdate.json, update.toJson()); + }); + + test('animateCamera calls through', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.animateCamera(update, mapId: mapId); + + final VerificationResult verification = + verify(api.animateCamera(captureAny)); + final PlatformCameraUpdate passedUpdate = + verification.captured[0] as PlatformCameraUpdate; + expect(passedUpdate.json, update.toJson()); + }); + test('getZoomLevel passes values correctly', () async { const int mapId = 1; final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = @@ -183,6 +212,258 @@ void main() { verify(api.clearTileCache(tileOverlayId)); }); + test('updateMapConfiguration passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + // Set some arbitrary options. + const MapConfiguration config = MapConfiguration( + compassEnabled: true, + liteModeEnabled: false, + mapType: MapType.terrain, + ); + await maps.updateMapConfiguration(config, mapId: mapId); + + final VerificationResult verification = + verify(api.updateMapConfiguration(captureAny)); + final PlatformMapConfiguration passedConfig = + verification.captured[0] as PlatformMapConfiguration; + final Map passedConfigJson = + passedConfig.json as Map; + // Each set option should be present. + expect(passedConfigJson['compassEnabled'], true); + expect(passedConfigJson['liteModeEnabled'], false); + expect(passedConfigJson['mapType'], MapType.terrain.index); + // Spot-check that unset options are not be present. + expect(passedConfigJson['myLocationEnabled'], isNull); + expect(passedConfigJson['cameraTargetBounds'], isNull); + expect(passedConfigJson['padding'], isNull); + }); + + test('updateMapOptions passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + // Set some arbitrary options. + final Map config = { + 'compassEnabled': true, + 'liteModeEnabled': false, + 'mapType': MapType.terrain.index, + }; + await maps.updateMapOptions(config, mapId: mapId); + + final VerificationResult verification = + verify(api.updateMapConfiguration(captureAny)); + final PlatformMapConfiguration passedConfig = + verification.captured[0] as PlatformMapConfiguration; + final Map passedConfigJson = + passedConfig.json as Map; + // Each set option should be present. + expect(passedConfigJson['compassEnabled'], true); + expect(passedConfigJson['liteModeEnabled'], false); + expect(passedConfigJson['mapType'], MapType.terrain.index); + // Spot-check that unset options are not be present. + expect(passedConfigJson['myLocationEnabled'], isNull); + expect(passedConfigJson['cameraTargetBounds'], isNull); + expect(passedConfigJson['padding'], isNull); + }); + + test('updateCircles passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Circle object1 = Circle(circleId: CircleId('1')); + const Circle object2old = Circle(circleId: CircleId('2')); + final Circle object2new = object2old.copyWith(radiusParam: 42); + const Circle object3 = Circle(circleId: CircleId('3')); + await maps.updateCircles( + CircleUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateCircles(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.circleId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updateClusterManagers passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const ClusterManager object1 = + ClusterManager(clusterManagerId: ClusterManagerId('1')); + const ClusterManager object3 = + ClusterManager(clusterManagerId: ClusterManagerId('3')); + await maps.updateClusterManagers( + ClusterManagerUpdates.from( + {object1}, {object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateClusterManagers(captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toRemove = verification.captured[1] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.clusterManagerId.value); + // Unlike other map object types, changes are not possible for cluster + // managers, since they have no non-ID properties. + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.identifier, object3.clusterManagerId.value); + }); + + test('updateMarkers passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Marker object1 = Marker(markerId: MarkerId('1')); + const Marker object2old = Marker(markerId: MarkerId('2')); + final Marker object2new = object2old.copyWith(rotationParam: 42); + const Marker object3 = Marker(markerId: MarkerId('3')); + await maps.updateMarkers( + MarkerUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateMarkers(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.markerId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updatePolygons passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Polygon object1 = Polygon(polygonId: PolygonId('1')); + const Polygon object2old = Polygon(polygonId: PolygonId('2')); + final Polygon object2new = object2old.copyWith(strokeWidthParam: 42); + const Polygon object3 = Polygon(polygonId: PolygonId('3')); + await maps.updatePolygons( + PolygonUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updatePolygons(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polygonId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updatePolylines passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Polyline object1 = Polyline(polylineId: PolylineId('1')); + const Polyline object2old = Polyline(polylineId: PolylineId('2')); + final Polyline object2new = object2old.copyWith(widthParam: 42); + const Polyline object3 = Polyline(polylineId: PolylineId('3')); + await maps.updatePolylines( + PolylineUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updatePolylines(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polylineId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updateTileOverlays passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const TileOverlay object1 = TileOverlay(tileOverlayId: TileOverlayId('1')); + const TileOverlay object2old = + TileOverlay(tileOverlayId: TileOverlayId('2')); + final TileOverlay object2new = object2old.copyWith(zIndexParam: 42); + const TileOverlay object3 = TileOverlay(tileOverlayId: TileOverlayId('3')); + // Pre-set the initial state, since this update method doesn't take the old + // state. + await maps.updateTileOverlays( + newTileOverlays: {object1, object2old}, mapId: mapId); + clearInteractions(api); + + await maps.updateTileOverlays( + newTileOverlays: {object2new, object3}, mapId: mapId); + + final VerificationResult verification = + verify(api.updateTileOverlays(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.tileOverlayId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + test('markers send drag event to correct streams', () async { const int mapId = 1; final Map jsonMarkerDragStartEvent = { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart index f819660e213..c49d6268926 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart @@ -68,6 +68,130 @@ class MockMapsApi extends _i1.Mock implements _i2.MapsApi { returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); + @override + _i3.Future updateMapConfiguration( + _i2.PlatformMapConfiguration? configuration) => + (super.noSuchMethod( + Invocation.method( + #updateMapConfiguration, + [configuration], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateCircles( + List<_i2.PlatformCircle?>? toAdd, + List<_i2.PlatformCircle?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateCircles, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateClusterManagers( + List<_i2.PlatformClusterManager?>? toAdd, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateClusterManagers, + [ + toAdd, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateMarkers( + List<_i2.PlatformMarker?>? toAdd, + List<_i2.PlatformMarker?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateMarkers, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updatePolygons( + List<_i2.PlatformPolygon?>? toAdd, + List<_i2.PlatformPolygon?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updatePolygons, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updatePolylines( + List<_i2.PlatformPolyline?>? toAdd, + List<_i2.PlatformPolyline?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updatePolylines, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateTileOverlays( + List<_i2.PlatformTileOverlay?>? toAdd, + List<_i2.PlatformTileOverlay?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateTileOverlays, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future<_i2.PlatformPoint> getScreenCoordinate( _i2.PlatformLatLng? latLng) => @@ -143,6 +267,28 @@ class MockMapsApi extends _i1.Mock implements _i2.MapsApi { )), ) as _i3.Future<_i2.PlatformLatLngBounds>); + @override + _i3.Future moveCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method( + #moveCamera, + [cameraUpdate], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future animateCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method( + #animateCamera, + [cameraUpdate], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future getZoomLevel() => (super.noSuchMethod( Invocation.method(