From 25f8b291963988bc028674f81db4f7c010140352 Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 21 Sep 2019 17:07:53 +0300 Subject: [PATCH 01/28] Add TileOverlay support for Android. --- packages/google_maps_flutter/CHANGELOG.md | 4 + .../google_maps_flutter/android/build.gradle | 7 + .../flutter/plugins/googlemaps/Convert.java | 55 +++++ .../plugins/googlemaps/GoogleMapBuilder.java | 7 + .../googlemaps/GoogleMapController.java | 35 +++ .../plugins/googlemaps/GoogleMapFactory.java | 3 + .../googlemaps/GoogleMapOptionsSink.java | 2 + .../googlemaps/TileOverlayBuilder.java | 42 ++++ .../googlemaps/TileOverlayController.java | 47 ++++ .../plugins/googlemaps/TileOverlaySink.java | 19 ++ .../googlemaps/TileOverlaysController.java | 109 +++++++++ .../googlemaps/TileProviderController.java | 89 ++++++++ .../google_maps_flutter/example/lib/main.dart | 2 + .../example/lib/tile_overlay.dart | 149 ++++++++++++ .../lib/google_maps_flutter.dart | 4 + .../lib/src/controller.dart | 35 +++ .../lib/src/google_map.dart | 31 +++ .../google_maps_flutter/lib/src/tile.dart | 32 +++ .../lib/src/tile_overlay.dart | 149 ++++++++++++ .../lib/src/tile_overlay_updates.dart | 96 ++++++++ .../lib/src/tile_provider.dart | 10 + packages/google_maps_flutter/pubspec.yaml | 2 +- .../test/fake_maps_controllers.dart | 65 ++++++ .../test/tile_overlay_updates_test.dart | 216 ++++++++++++++++++ 24 files changed, 1209 insertions(+), 1 deletion(-) create mode 100644 packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java create mode 100644 packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java create mode 100644 packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java create mode 100644 packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java create mode 100644 packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java create mode 100644 packages/google_maps_flutter/example/lib/tile_overlay.dart create mode 100644 packages/google_maps_flutter/lib/src/tile.dart create mode 100644 packages/google_maps_flutter/lib/src/tile_overlay.dart create mode 100644 packages/google_maps_flutter/lib/src/tile_overlay_updates.dart create mode 100644 packages/google_maps_flutter/lib/src/tile_provider.dart create mode 100644 packages/google_maps_flutter/test/tile_overlay_updates_test.dart diff --git a/packages/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/CHANGELOG.md index e6f2ff00d02f..e0c810bff8ea 100644 --- a/packages/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.22 + +* Add TileOverlay support for Android. + ## 0.5.21+2 * Fix more `prefer_const_constructors` analyzer warnings in example app. diff --git a/packages/google_maps_flutter/android/build.gradle b/packages/google_maps_flutter/android/build.gradle index e7bc80c42c52..ab996fbf0c4d 100644 --- a/packages/google_maps_flutter/android/build.gradle +++ b/packages/google_maps_flutter/android/build.gradle @@ -34,6 +34,9 @@ rootProject.allprojects { apply plugin: 'com.android.library' +sourceCompatibility = JavaVersion.VERSION_1_8 +sourceCompatibility = JavaVersion.VERSION_1_8 + android { compileSdkVersion 28 @@ -44,6 +47,10 @@ android { lintOptions { disable 'InvalidPackage' } + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } dependencies { implementation 'com.google.android.gms:play-services-maps:17.0.0' diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 76e14faaf01e..2c208b527c54 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -23,6 +23,8 @@ import com.google.android.gms.maps.model.PatternItem; import com.google.android.gms.maps.model.RoundCap; import com.google.android.gms.maps.model.SquareCap; +import com.google.android.gms.maps.model.Tile; + import io.flutter.view.FlutterMain; import java.util.ArrayList; import java.util.Arrays; @@ -142,6 +144,13 @@ private static int toInt(Object o) { return ((Number) o).intValue(); } + private static byte[] toByteArray(Object o) { + if (o == null) { + return null; + } + return (byte[]) o; + } + static Object cameraPositionToJson(CameraPosition position) { if (position == null) { return null; @@ -197,6 +206,18 @@ static Object circleIdToJson(String circleId) { return data; } + static Object tileOverlayArgumentsToJson(String tileOverlayId, int x, int y, int zoom) { + if (tileOverlayId == null) { + return null; + } + final Map data = new HashMap<>(4); + data.put("tileOverlayId", tileOverlayId); + data.put("x", x); + data.put("y", y); + data.put("zoom", zoom); + return data; + } + static Object latLngToJson(LatLng latLng) { return Arrays.asList(latLng.latitude, latLng.longitude); } @@ -591,4 +612,38 @@ private static Cap toCap(Object o) { throw new IllegalArgumentException("Cannot interpret " + o + " as Cap"); } } + + static String interpretTileOverlayOptions(Object o, TileOverlaySink sink) { + final Map data = toMap(o); + final Object fadeIn = data.get("fadeIn"); + if (fadeIn != null) { + sink.setFadeIn(toBoolean(fadeIn)); + } + final Object transparency = data.get("transparency"); + if (transparency != null) { + sink.setTransparency(toFloat(transparency)); + } + final Object zIndex = data.get("zIndex"); + if (zIndex != null) { + sink.setZIndex(toFloat(zIndex)); + } + final Object visible = data.get("visible"); + if (visible != null) { + sink.setVisible(toBoolean(visible)); + } + final String tileOverlayId = (String) data.get("tileOverlayId"); + if (tileOverlayId == null) { + throw new IllegalArgumentException("tileOverlayId was null"); + } else { + return tileOverlayId; + } + } + + static Tile interpretTile(Object o) { + final Map data = toMap(o); + int width = toInt(data.get("width")); + int height = toInt(data.get("height")); + byte[] dataArray = toByteArray(data.get("data")); + return new Tile(width, height, dataArray); + } } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 651dd3e17198..a51ae27a0c4d 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -23,6 +23,7 @@ class GoogleMapBuilder implements GoogleMapOptionsSink { private Object initialPolygons; private Object initialPolylines; private Object initialCircles; + private Object initialTileOverlays; private Rect padding = new Rect(0, 0, 0, 0); GoogleMapController build( @@ -39,6 +40,7 @@ GoogleMapController build( controller.setInitialPolygons(initialPolygons); controller.setInitialPolylines(initialPolylines); controller.setInitialCircles(initialCircles); + controller.setInitialTileOverlays(initialTileOverlays); controller.setPadding(padding.top, padding.left, padding.bottom, padding.right); return controller; } @@ -146,4 +148,9 @@ public void setInitialPolylines(Object initialPolylines) { public void setInitialCircles(Object initialCircles) { this.initialCircles = initialCircles; } + + @Override + public void setInitialTileOverlays(Object initialTileOverlays) { + this.initialTileOverlays = initialTileOverlays; + } } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index de6a1158023d..6ac327f1955f 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -84,10 +84,12 @@ final class GoogleMapController private final PolygonsController polygonsController; private final PolylinesController polylinesController; private final CirclesController circlesController; + private final TileOverlaysController tileOverlayController; private List initialMarkers; private List initialPolygons; private List initialPolylines; private List initialCircles; + private List initialTileOverlays; GoogleMapController( int id, @@ -109,6 +111,7 @@ final class GoogleMapController this.polygonsController = new PolygonsController(methodChannel); this.polylinesController = new PolylinesController(methodChannel, density); this.circlesController = new CirclesController(methodChannel); + this.tileOverlayController = new TileOverlaysController(methodChannel); } @Override @@ -191,10 +194,12 @@ public void onMapReady(GoogleMap googleMap) { polygonsController.setGoogleMap(googleMap); polylinesController.setGoogleMap(googleMap); circlesController.setGoogleMap(googleMap); + tileOverlayController.setGoogleMap(googleMap); updateInitialMarkers(); updateInitialPolygons(); updateInitialPolylines(); updateInitialCircles(); + updateInitialTileOverlays(); } @Override @@ -352,6 +357,24 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { result.success(mapStyleResult); break; } + case "tileOverlays#update": + { + Object tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); + tileOverlayController.addTileOverlays((List) tileOverlaysToAdd); + Object tileOverlaysToChange = call.argument("tileOverlaysToChange"); + tileOverlayController.changeTileOverlays((List) tileOverlaysToChange); + Object tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); + tileOverlayController.removeTileOverlays((List) tileOverlaysToRemove); + result.success(null); + break; + } + case "tileOverlays#clearTileCache": + { + Object rawTileOverlayId = call.argument("tileOverlayId"); + tileOverlayController.clearTileCache(rawTileOverlayId); + result.success(null); + break; + } default: result.notImplemented(); } @@ -636,6 +659,18 @@ private void updateInitialCircles() { circlesController.addCircles(initialCircles); } + @Override + public void setInitialTileOverlays(Object initialTileOverlays) { + this.initialTileOverlays = (List) initialTileOverlays; + if(googleMap!=null) { + updateInitialTileOverlays(); + } + } + + private void updateInitialTileOverlays() { + tileOverlayController.addTileOverlays(initialTileOverlays); + } + @SuppressLint("MissingPermission") private void updateMyLocationSettings() { if (hasLocationPermission()) { diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index 9d1b3310779e..dbdd777fab7d 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -48,6 +48,9 @@ public PlatformView create(Context context, int id, Object args) { if (params.containsKey("circlesToAdd")) { builder.setInitialCircles(params.get("circlesToAdd")); } + if(params.containsKey("tileOverlaysToAdd")) { + builder.setInitialTileOverlays(params.get("tileOverlaysToAdd")); + } return builder.build(id, context, mActivityState, mPluginRegistrar); } } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 1f01298a3ce1..f991ec19a7a5 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java @@ -45,4 +45,6 @@ interface GoogleMapOptionsSink { void setInitialPolylines(Object initialPolylines); void setInitialCircles(Object initialCircles); + + void setInitialTileOverlays(Object initialTileOverlays); } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java new file mode 100644 index 000000000000..9c978af16f2d --- /dev/null +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java @@ -0,0 +1,42 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; + +public class TileOverlayBuilder implements TileOverlaySink { + private final TileOverlayOptions tileOverlayOptions; + + TileOverlayBuilder() { + this.tileOverlayOptions = new TileOverlayOptions(); + } + + TileOverlayOptions build() { + return tileOverlayOptions; + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlayOptions.fadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlayOptions.transparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlayOptions.zIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlayOptions.visible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + tileOverlayOptions.tileProvider(tileProvider); + } + +} \ No newline at end of file diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java new file mode 100644 index 000000000000..2d8af55e131b --- /dev/null +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java @@ -0,0 +1,47 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileProvider; + +public class TileOverlayController implements TileOverlaySink { + + private final TileOverlay tileOverlay; + + public TileOverlayController(TileOverlay tileOverlay) { + this.tileOverlay = tileOverlay; + } + + void remove() { + tileOverlay.remove(); + } + + void clearTileCache() { + tileOverlay.clearTileCache(); + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlay.setFadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlay.setTransparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlay.setZIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlay.setVisible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + // You can not change tile provider after creation + } + +} \ No newline at end of file diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java new file mode 100644 index 000000000000..49cf7026f793 --- /dev/null +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java @@ -0,0 +1,19 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileProvider; + +/** + * Receiver of TileOverlayOptions configuration. + */ +public interface TileOverlaySink { + void setFadeIn(boolean fadeIn); + + void setTransparency(float transparency); + + void setZIndex(float zIndex); + + void setVisible(boolean visible); + + void setTileProvider(TileProvider tileProvider); + +} \ No newline at end of file diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java new file mode 100644 index 000000000000..81be7ed806b4 --- /dev/null +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -0,0 +1,109 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.flutter.plugin.common.MethodChannel; + +class TileOverlaysController { + + private final Map tileOverlayIdToController; + private final MethodChannel methodChannel; + private GoogleMap googleMap; + + TileOverlaysController(MethodChannel methodChannel) { + this.tileOverlayIdToController = new HashMap<>(); + this.methodChannel = methodChannel; + } + + void setGoogleMap(GoogleMap googleMap) { + this.googleMap = googleMap; + } + + void addTileOverlays(List tileOverlaysToAdd) { + if (tileOverlaysToAdd == null) { + return; + } + for (Object tileOverlayToAdd : tileOverlaysToAdd) { + addTileOverlay(tileOverlayToAdd); + } + } + + void changeTileOverlays(List tileOverlaysToChange) { + if (tileOverlaysToChange == null) { + return; + } + for (Object tileOverlayToChange : tileOverlaysToChange) { + changeTileOverlay(tileOverlayToChange); + } + } + + void removeTileOverlays(List tileOverlayIdsToRemove) { + if (tileOverlayIdsToRemove == null) { + return; + } + for (Object rawTileOverlayId : tileOverlayIdsToRemove) { + if (rawTileOverlayId == null) { + continue; + } + String tileOverlayId = (String) rawTileOverlayId; + removeTileOverlay(tileOverlayId); + } + } + + void clearTileCache(Object rawTileOverlayId) { + if (rawTileOverlayId == null) { + return; + } + String tileOverlayId = (String) rawTileOverlayId; + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.clearTileCache(); + } + } + + private void addTileOverlay(Object tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; + } + TileOverlayBuilder tileOverlayOptionsBuilder = new TileOverlayBuilder(); + String tileOverlayId = Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayOptionsBuilder); + TileProviderController tileProviderController = new TileProviderController(methodChannel, tileOverlayId); + tileOverlayOptionsBuilder.setTileProvider(tileProviderController); + TileOverlayOptions options = tileOverlayOptionsBuilder.build(); + TileOverlay tileOverlay = googleMap.addTileOverlay(options); + TileOverlayController tileOverlayController = new TileOverlayController(tileOverlay); + tileOverlayIdToController.put(tileOverlayId, tileOverlayController); + } + + private void changeTileOverlay(Object tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; + } + String tileOverlayId = getTileOverlayId(tileOverlayOptions); + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayController); + } + } + + private void removeTileOverlay(String tileOverlayId) { + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.remove(); + tileOverlayIdToController.remove(tileOverlayId); + } + } + + @SuppressWarnings("unchecked") + private static String getTileOverlayId(Object tileOverlay) { + Map tileOverlayMap = (Map) tileOverlay; + return (String) tileOverlayMap.get("tileOverlayId"); + } + +} \ No newline at end of file diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java new file mode 100644 index 000000000000..d24f4cf3e005 --- /dev/null +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -0,0 +1,89 @@ +package io.flutter.plugins.googlemaps; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileProvider; + +import java.util.concurrent.CountDownLatch; + +import io.flutter.plugin.common.MethodChannel; + +public class TileProviderController implements TileProvider { + + private static final String TAG = "TileProviderController"; + + private final String tileOverlayId; + private final MethodChannel methodChannel; + private final Handler handler = new Handler(Looper.getMainLooper()); + + TileProviderController(MethodChannel methodChannel, String tileOverlayId) { + this.tileOverlayId = tileOverlayId; + this.methodChannel = methodChannel; + } + + @Override + public Tile getTile(final int x, final int y, final int zoom) { + Worker worker = new Worker(x, y, zoom); + return worker.getTile(); + } + + private final class Worker implements MethodChannel.Result { + + private final CountDownLatch countDownLatch = new CountDownLatch(1); + private final int x; + private final int y; + private final int zoom; + private Object result; + + Worker(int x, int y, int zoom) { + this.x = x; + this.y = y; + this.zoom = zoom; + } + + @NonNull + Tile getTile() { + handler.post(() -> methodChannel.invokeMethod("tileOverlay#getTile", + Convert.tileOverlayArgumentsToJson(tileOverlayId, x, y, zoom), + this)); + try { + countDownLatch.await(); + } catch (InterruptedException e) { + Log.e(TAG, String.format("countDownLatch: can't get tile: x = %d, y= %d, zoom = %d", x, y, zoom), e); + return TileProvider.NO_TILE; + } + try { + return Convert.interpretTile(result); + } catch (Exception ex) { + Log.e(TAG, "Can't parse tile data", ex); + return TileProvider.NO_TILE; + } + } + + @Override + public void success(Object data) { + result = data; + countDownLatch.countDown(); + } + + @Override + public void error(String errorCode, String errorMessage, Object data) { + Log.e(TAG, String.format("Can't get tile: errorCode = %s, errorMessage = %s, date = %s", errorCode, errorCode, data)); + result = null; + countDownLatch.countDown(); + } + + @Override + public void notImplemented() { + Log.e(TAG, "Can't get tile: notImplemented"); + result = null; + countDownLatch.countDown(); + } + } + +} \ No newline at end of file diff --git a/packages/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/example/lib/main.dart index c082f188ff91..e9d607423da0 100644 --- a/packages/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/example/lib/main.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_example/tile_overlay.dart'; import 'animate_camera.dart'; import 'map_click.dart'; import 'map_coordinates.dart'; @@ -30,6 +31,7 @@ final List _allPages = [ PlacePolygonPage(), PlaceCirclePage(), PaddingPage(), + TileOverlayPage(), ]; class MapsDemo extends StatelessWidget { diff --git a/packages/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/example/lib/tile_overlay.dart new file mode 100644 index 000000000000..f8597ce2e325 --- /dev/null +++ b/packages/google_maps_flutter/example/lib/tile_overlay.dart @@ -0,0 +1,149 @@ +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'page.dart'; + +class TileOverlayPage extends Page { + TileOverlayPage() : super(const Icon(Icons.map), 'Tile overlay'); + + @override + Widget build(BuildContext context) { + return const TileOverlayBody(); + } +} + +class TileOverlayBody extends StatefulWidget { + const TileOverlayBody(); + + @override + State createState() => TileOverlayBodyState(); +} + +class TileOverlayBodyState extends State { + TileOverlayBodyState(); + + GoogleMapController controller; + TileOverlay _tileOverlay; + + void _onMapCreated(GoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeTileOverlay() { + print("Remove tile overlay"); + setState(() { + _tileOverlay = null; + }); + } + + void _addTileOverlay() { + print("Add tile overlay"); + final TileOverlay tileOverlay = TileOverlay( + tileOverlayId: TileOverlayId("tile_overlay_1"), + tileProvider: DebugTileProvider(), + ); + setState(() { + _tileOverlay = tileOverlay; + }); + } + + void _clearTileCache() { + print("Clear tile cahce"); + if (_tileOverlay != null && controller != null) { + controller.clearTileCache(_tileOverlay.tileOverlayId); + } + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: GoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 7.0, + ), + tileOverlays: + _tileOverlay != null ? {_tileOverlay} : null, + onMapCreated: _onMapCreated, + ), + ), + ), + FlatButton( + child: const Text('Add tile overlay'), + onPressed: _addTileOverlay, + ), + FlatButton( + child: const Text('Remove tile overlay'), + onPressed: _removeTileOverlay, + ), + FlatButton( + child: const Text('Clear tile cache'), + onPressed: _clearTileCache, + ), + ], + ); + } +} + +class DebugTileProvider implements TileProvider { + DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static final TextStyle textStyle = TextStyle( + color: Colors.red, + fontSize: 20, + ); + + @override + Future getTile(int x, int y, int zoom) async { + print("TileProvider: getTile x = $x, y = $y, zoom = $zoom"); + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final TextSpan textSpan = TextSpan( + text: "$x,$y", + style: textStyle, + ); + final TextPainter textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout( + minWidth: 0.0, + maxWidth: width.toDouble(), + ); + final Offset offset = const Offset(0, 0); + textPainter.paint(canvas, offset); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then((ui.Image image) => + image.toByteData(format: ui.ImageByteFormat.png)) + .then((ByteData byteData) => byteData.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} diff --git a/packages/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/lib/google_maps_flutter.dart index 91f037192255..b5c627f9cc67 100644 --- a/packages/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/lib/google_maps_flutter.dart @@ -31,3 +31,7 @@ part 'src/polyline_updates.dart'; part 'src/circle.dart'; part 'src/circle_updates.dart'; part 'src/ui.dart'; +part 'src/tile.dart'; +part 'src/tile_provider.dart'; +part 'src/tile_overlay.dart'; +part 'src/tile_overlay_updates.dart'; diff --git a/packages/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/lib/src/controller.dart index ec77111bae9d..8749ffd66b35 100644 --- a/packages/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/lib/src/controller.dart @@ -80,6 +80,14 @@ class GoogleMapController { _googleMapState .onLongPress(LatLng._fromJson(call.arguments['position'])); break; + case 'tileOverlay#getTile': + return await _googleMapState.onGetTile( + call.arguments['tileOverlayId'], + call.arguments['x'], + call.arguments['y'], + call.arguments['zoom'], + ); + break; default: throw MissingPluginException(); } @@ -177,6 +185,33 @@ class GoogleMapController { }); } + /// Updates tile overlays configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future _updateTileOverlays( + _TileOverlayUpdates tileOverlayUpdates) async { + assert(tileOverlayUpdates != null); + await channel.invokeMethod( + 'tileOverlays#update', + tileOverlayUpdates._toMap(), + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The API maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + Future clearTileCache(TileOverlayId tileOverlayId) async { + await channel + .invokeMethod('tileOverlays#clearTileCache', { + 'tileOverlayId': tileOverlayId.value, + }); + } + /// Sets the styling of the base map. /// /// Set to `null` to clear any previous custom styling. diff --git a/packages/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/lib/src/google_map.dart index fa5c3fdac490..019c606c791b 100644 --- a/packages/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/lib/src/google_map.dart @@ -40,6 +40,7 @@ class GoogleMap extends StatefulWidget { this.polygons, this.polylines, this.circles, + this.tileOverlays, this.onCameraMoveStarted, this.onCameraMove, this.onCameraIdle, @@ -97,6 +98,9 @@ class GoogleMap extends StatefulWidget { /// Circles to be placed on the map. final Set circles; + /// Tile overlays to be placed on the map. + final Set tileOverlays; + /// Called when the camera starts moving. /// /// This can be initiated by the following: @@ -191,6 +195,8 @@ class _GoogleMapState extends State { Map _polygons = {}; Map _polylines = {}; Map _circles = {}; + Map _tileOverlays = + {}; _GoogleMapOptions _googleMapOptions; @override @@ -202,6 +208,7 @@ class _GoogleMapState extends State { 'polygonsToAdd': _serializePolygonSet(widget.polygons), 'polylinesToAdd': _serializePolylineSet(widget.polylines), 'circlesToAdd': _serializeCircleSet(widget.circles), + 'tileOverlaysToAdd': _serializeTileOverlaySet(widget.tileOverlays), }; if (defaultTargetPlatform == TargetPlatform.android) { return AndroidView( @@ -233,6 +240,7 @@ class _GoogleMapState extends State { _polygons = _keyByPolygonId(widget.polygons); _polylines = _keyByPolylineId(widget.polylines); _circles = _keyByCircleId(widget.circles); + _tileOverlays = _keyTileOverlayId(widget.tileOverlays); } @override @@ -243,6 +251,7 @@ class _GoogleMapState extends State { _updatePolygons(); _updatePolylines(); _updateCircles(); + _updateTileOverlays(); } void _updateOptions() async { @@ -285,6 +294,13 @@ class _GoogleMapState extends State { _circles = _keyByCircleId(widget.circles); } + void _updateTileOverlays() async { + final GoogleMapController controller = await _controller.future; + controller._updateTileOverlays(_TileOverlayUpdates.from( + _tileOverlays.values.toSet(), widget.tileOverlays)); + _tileOverlays = _keyTileOverlayId(widget.tileOverlays); + } + Future onPlatformViewCreated(int id) async { final GoogleMapController controller = await GoogleMapController.init( id, @@ -354,6 +370,21 @@ class _GoogleMapState extends State { widget.onLongPress(position); } } + + Future> onGetTile( + String tileOverlayIdParam, int x, int y, int zoom) async { + assert(tileOverlayIdParam != null); + final TileOverlayId tileOverlayId = TileOverlayId(tileOverlayIdParam); + final TileOverlay tileOverlay = _tileOverlays[tileOverlayId]; + Tile tile; + if (tileOverlay != null && tileOverlay.tileProvider != null) { + tile = await tileOverlay.tileProvider.getTile(x, y, zoom); + } + if (tile == null) { + tile = TileProvider.noTile; + } + return tile.toJson(); + } } /// Configuration options for the GoogleMaps user interface. diff --git a/packages/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/lib/src/tile.dart new file mode 100644 index 000000000000..919e5a088554 --- /dev/null +++ b/packages/google_maps_flutter/lib/src/tile.dart @@ -0,0 +1,32 @@ +part of google_maps_flutter; + +/// Contains information about a Tile that is returned by a [TileProvider]. +@immutable +class Tile { + const Tile(this.width, this.height, this.data); + + /// The width of the image encoded by data in pixels. + final int width; + + /// The height of the image encoded by data in pixels. + final int height; + + /// A byte array containing the image data. + final Uint8List data; + + dynamic toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('width', width); + addIfPresent('height', height); + addIfPresent('data', data); + + return json; + } +} \ No newline at end of file diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/lib/src/tile_overlay.dart new file mode 100644 index 000000000000..a8edc59b517d --- /dev/null +++ b/packages/google_maps_flutter/lib/src/tile_overlay.dart @@ -0,0 +1,149 @@ +part of google_maps_flutter; + +/// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. +/// +/// This does not have to be globally unique, only unique among the list. +@immutable +class TileOverlayId { + TileOverlayId(this.value) : assert(value != null); + + /// value of the [TileOverlayId]. + final String value; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + final TileOverlayId typedOther = other; + return value == typedOther.value; + } + + @override + int get hashCode => value.hashCode; + + @override + String toString() { + return 'TileOverlay{value: $value}'; + } +} + +/// A Tile Overlay is a set of images which are displayed on top of the base map tiles. +/// These tiles may be transparent, allowing you to add features to existing maps. +/// +/// Tile Coordinates +/// +/// Note that the world is projected using the Mercator projection +/// (see [Wikipedia](https://en.wikipedia.org/wiki/Mercator_projection)) with the left (west) side +/// of the map corresponding to -180 degrees of longitude and the right (east) side of the map +/// corresponding to 180 degrees of longitude. To make the map square, the top (north) side of the +/// map corresponds to 85.0511 degrees of latitude and the bottom (south) side of the map +/// corresponds to -85.0511 degrees of latitude. Areas outside this latitude range are not rendered. +/// +/// At each zoom level, the map is divided into tiles and only the tiles that overlap the screen are +/// downloaded and rendered. Each tile is square and the map is divided into tiles as follows: +/// +/// * At zoom level 0, one tile represents the entire world. The coordinates of that tile are +/// (x, y) = (0, 0). +/// * At zoom level 1, the world is divided into 4 tiles arranged in a 2 x 2 grid. +/// * ... +/// * At zoom level N, the world is divided into 4N tiles arranged in a 2N x 2N grid. +/// +/// Note that the minimum zoom level that the camera supports (which can depend on various factors) +/// is GoogleMap.getMinZoomLevel and the maximum zoom level is GoogleMap.getMaxZoomLevel. +/// +/// The coordinates of the tiles are measured from the top left (northwest) corner of the map. +/// At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from +/// west to east and the y values range from 0 to 2N - 1 and increase from north to south. +class TileOverlay { + const TileOverlay({ + @required this.tileOverlayId, + this.fadeIn = true, + this.tileProvider, + this.transparency = 0.0, + this.zIndex, + this.visible = true, + }) : assert(transparency >= 0.0 && transparency <= 1.0); + + /// Uniquely identifies a [TileOverlay]. + final TileOverlayId tileOverlayId; + + /// Whether the tiles should fade in. The default is true. + final bool fadeIn; + + /// The tile provider to use for this tile overlay. + final TileProvider tileProvider; + + /// The transparency of the tile overlay. The default transparency is 0 (opaque). + final double transparency; + + /// The tile overlay's zIndex, i.e., the order in which it will be drawn where + /// overlays with larger values are drawn above those with lower values + final double zIndex; + + /// The visibility for the tile overlay. The default visibility is true. + final bool visible; + + /// Creates a new [Polygon] object whose values are the same as this instance, + /// unless overwritten by the specified parameters. + TileOverlay copyWith({ + TileOverlayId tileOverlayId, + bool fadeInParam, + double transparencyParam, + double zIndexParam, + bool visibleParam, + }) { + return TileOverlay( + tileOverlayId: tileOverlayId, + fadeIn: fadeInParam ?? fadeIn, + transparency: transparencyParam ?? transparency, + zIndex: zIndexParam ?? zIndex, + visible: visibleParam ?? visible, + ); + } + + dynamic _toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('tileOverlayId', tileOverlayId.value); + addIfPresent('fadeIn', fadeIn); + addIfPresent('transparency', transparency); + addIfPresent('zIndex', zIndex); + addIfPresent('visible', visible); + + return json; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + final TileOverlay typedOther = other; + return tileOverlayId == typedOther.tileOverlayId; + } + + @override + int get hashCode => tileOverlayId.hashCode; +} + +Map _keyTileOverlayId(Iterable tileOverlays) { + if (tileOverlays == null) { + return {}; + } + return Map.fromEntries(tileOverlays.map((TileOverlay tileOverlay) => + MapEntry(tileOverlay.tileOverlayId, tileOverlay))); +} + +List> _serializeTileOverlaySet(Set tileOverlays) { + if (tileOverlays == null) { + return null; + } + return tileOverlays + .map>((TileOverlay p) => p._toJson()) + .toList(); +} \ No newline at end of file diff --git a/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart b/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart new file mode 100644 index 000000000000..b5bad83e0eea --- /dev/null +++ b/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart @@ -0,0 +1,96 @@ +part of google_maps_flutter; + +/// [TileProvider] update events to be applied to the [GoogleMap]. +/// +/// Used in [GoogleMapController] when the map is updated. +class _TileOverlayUpdates { + /// Computes [_MarkerUpdates] given previous and current [Marker]s. + _TileOverlayUpdates.from( + Set previous, Set current) { + if (previous == null) { + previous = Set.identity(); + } + + if (current == null) { + current = Set.identity(); + } + + final Map previousTileOverlays = + _keyTileOverlayId(previous); + final Map currentTileOverlays = + _keyTileOverlayId(current); + + final Set prevTileOverlayIds = + previousTileOverlays.keys.toSet(); + final Set currentTileOverlayIds = + currentTileOverlays.keys.toSet(); + + TileOverlay idToCurrentTileOverlay(TileOverlayId id) { + return currentTileOverlays[id]; + } + + final Set _tileOverlayIdsToRemove = + prevTileOverlayIds.difference(currentTileOverlayIds); + + final Set _tileOverlaysToAdd = currentTileOverlayIds + .difference(prevTileOverlayIds) + .map(idToCurrentTileOverlay) + .toSet(); + + final Set _tileOverlaysToChange = currentTileOverlayIds + .intersection(prevTileOverlayIds) + .map(idToCurrentTileOverlay) + .toSet(); + + tileOverlaysToAdd = _tileOverlaysToAdd; + tileOverlayIdsToRemove = _tileOverlayIdsToRemove; + tileOverlaysToChange = _tileOverlaysToChange; + } + + Set tileOverlaysToAdd; + Set tileOverlayIdsToRemove; + Set tileOverlaysToChange; + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull( + 'tileOverlaysToAdd', _serializeTileOverlaySet(tileOverlaysToAdd)); + addIfNonNull( + 'tileOverlaysToChange', _serializeTileOverlaySet(tileOverlaysToChange)); + addIfNonNull( + 'tileOverlayIdsToRemove', + tileOverlayIdsToRemove + .map((TileOverlayId m) => m.value) + .toList()); + + return updateMap; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + final _TileOverlayUpdates typedOther = other; + return setEquals(tileOverlaysToAdd, typedOther.tileOverlaysToAdd) && + setEquals(tileOverlayIdsToRemove, typedOther.tileOverlayIdsToRemove) && + setEquals(tileOverlaysToChange, typedOther.tileOverlaysToChange); + } + + @override + int get hashCode => hashValues( + tileOverlaysToAdd, tileOverlayIdsToRemove, tileOverlaysToChange); + + @override + String toString() { + return '_TileOverlayUpdates{tileOverlaysToAdd: $tileOverlaysToAdd, ' + 'tileOverlayIdsToRemove: $tileOverlayIdsToRemove, ' + 'tileOverlaysToChange: $tileOverlaysToChange}'; + } +} \ No newline at end of file diff --git a/packages/google_maps_flutter/lib/src/tile_provider.dart b/packages/google_maps_flutter/lib/src/tile_provider.dart new file mode 100644 index 000000000000..61e1dc202db2 --- /dev/null +++ b/packages/google_maps_flutter/lib/src/tile_provider.dart @@ -0,0 +1,10 @@ +part of google_maps_flutter; + +/// An interface for a class that provides the tile images for a TileOverlay. +abstract class TileProvider { + /// Stub tile that is used to indicate that no tile exists for a specific tile coordinate. + static const Tile noTile = Tile(-1, -1, null); + + /// Returns the tile to be used for this tile coordinate. + Future getTile(int x, int y, int zoom); +} \ No newline at end of file diff --git a/packages/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/pubspec.yaml index 7de1fd6bca7d..4d05d47a77e2 100644 --- a/packages/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.5.21+2 +version: 0.5.22 dependencies: flutter: diff --git a/packages/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/test/fake_maps_controllers.dart index 0ae12c815ff3..6e3559316e4c 100644 --- a/packages/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/test/fake_maps_controllers.dart @@ -19,6 +19,7 @@ class FakePlatformGoogleMap { updatePolygons(params); updatePolylines(params); updateCircles(params); + updateTileOverlays(params); } MethodChannel channel; @@ -77,6 +78,12 @@ class FakePlatformGoogleMap { Set circlesToChange; + Set tileOverlayIdsToRemove; + + Set tileOverlaysToAdd; + + Set tileOverlaysToChange; + Future onMethodCall(MethodCall call) { switch (call.method) { case 'map#update': @@ -94,6 +101,9 @@ class FakePlatformGoogleMap { case 'circles#update': updateCircles(call.arguments); return Future.sync(() {}); + case 'tileOverlays#update': + updateTileOverlays(call.arguments); + return Future.sync(() {}); default: return Future.sync(() {}); } @@ -266,6 +276,18 @@ class FakePlatformGoogleMap { circlesToChange = _deserializeCircles(circleUpdates['circlesToChange']); } + void updateTileOverlays(Map updateTileOverlayUpdates) { + if (updateTileOverlayUpdates == null) { + return; + } + tileOverlaysToAdd = + _deserializeTileOverlays(updateTileOverlayUpdates['tileOverlaysToAdd']); + tileOverlayIdsToRemove = _deserializeTileOverlayIds( + updateTileOverlayUpdates['tileOverlayIdsToRemove']); + tileOverlaysToChange = _deserializeTileOverlays( + updateTileOverlayUpdates['tileOverlaysToChange']); + } + Set _deserializeCircleIds(List circleIds) { if (circleIds == null) { // TODO(iskakaushik): Remove this when collection literals makes it to stable. @@ -303,6 +325,49 @@ class FakePlatformGoogleMap { return result; } + Set _deserializeTileOverlayIds(List tileOverlayIds) { + if (tileOverlayIds == null) { + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + return Set(); + } + return tileOverlayIds + .map((dynamic tileOverlayId) => TileOverlayId(tileOverlayId)) + .toSet(); + } + + Set _deserializeTileOverlays(dynamic tileOverlays) { + if (tileOverlays == null) { + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + return Set(); + } + final List tileOverlaysData = tileOverlays; + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + final Set result = Set(); + for (Map tileOverlayData in tileOverlaysData) { + final String tileOverlayId = tileOverlayData['tileOverlayId']; + final bool fadeIn = tileOverlayData['fadeIn']; + final double transparency = tileOverlayData['transparency']; + final double zIndex = tileOverlayData['zIndex']; + final bool visible = tileOverlayData['visible']; + + result.add(TileOverlay( + tileOverlayId: TileOverlayId(tileOverlayId), + fadeIn: fadeIn, + transparency: transparency, + zIndex: zIndex, + visible: visible, + )); + } + + return result; + } + void updateOptions(Map options) { if (options.containsKey('compassEnabled')) { compassEnabled = options['compassEnabled']; diff --git a/packages/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/test/tile_overlay_updates_test.dart new file mode 100644 index 000000000000..158f9fa67c4c --- /dev/null +++ b/packages/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -0,0 +1,216 @@ +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'fake_maps_controllers.dart'; + +Set _toSet({TileOverlay t1, TileOverlay t2, TileOverlay t3}) { + final Set res = Set.identity(); + if (t1 != null) { + res.add(t1); + } + if (t2 != null) { + res.add(t2); + } + if (t3 != null) { + res.add(t3); + } + return res; +} + +Widget _mapWithTileOverlays(Set tileOverlays) { + return Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + tileOverlays: tileOverlays, + ), + ); +} + +void main() { + final FakePlatformViewsController fakePlatformViewsController = + FakePlatformViewsController(); + + setUpAll(() { + SystemChannels.platform_views.setMockMethodCallHandler( + fakePlatformViewsController.fakePlatformViewsMethodHandler); + }); + + setUp(() { + fakePlatformViewsController.reset(); + }); + + testWidgets('Initializing a tile overlay', (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + + final TileOverlay initializedTileOverlay = + platformGoogleMap.tileOverlaysToAdd.first; + expect(initializedTileOverlay, equals(t1)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); + }); + + testWidgets("Adding a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1, t2: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + + final TileOverlay addedTileOverlay = + platformGoogleMap.tileOverlaysToAdd.first; + expect(addedTileOverlay, equals(t2)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + expect(platformGoogleMap.tileOverlaysToChange.first, equals(t1)); + }); + + testWidgets("Removing a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(null)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlayIdsToRemove.length, 1); + expect(platformGoogleMap.tileOverlayIdsToRemove.first, + equals(t1.tileOverlayId)); + + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Updating a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + expect(platformGoogleMap.tileOverlaysToChange.first, equals(t2)); + + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Updating a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + + final TileOverlay update = platformGoogleMap.tileOverlaysToChange.first; + expect(update, equals(t2)); + expect(update.zIndex, 10); + }); + + testWidgets("Multi Update", (WidgetTester tester) async { + TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + final Set prev = _toSet(t1: t1, t2: t2); + t1 = TileOverlay( + tileOverlayId: TileOverlayId("tile_overlay_1"), visible: false); + t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange, cur); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Multi Update", (WidgetTester tester) async { + TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + final TileOverlay t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); + final Set prev = _toSet(t2: t2, t3: t3); + + // t1 is added, t2 is updated, t3 is removed. + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + expect(platformGoogleMap.tileOverlayIdsToRemove.length, 1); + + expect(platformGoogleMap.tileOverlaysToChange.first, equals(t2)); + expect(platformGoogleMap.tileOverlaysToAdd.first, equals(t1)); + expect(platformGoogleMap.tileOverlayIdsToRemove.first, + equals(t3.tileOverlayId)); + }); + + testWidgets( + "Partial Update", + (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + final Set prev = _toSet(t1: t1, t2: t2); + t2 = TileOverlay( + tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange, _toSet(t2: t2)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }, + // The test is currently broken due to a bug (we're updating all tile overlays + // instead of just the ones that were changed): + // TODO(otopba): enable this test when the issue is fixed. + skip: true, + ); +} \ No newline at end of file From 684c2b4ff0fb0a4c7ffc4612112ce96c0c63d587 Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 21 Sep 2019 17:55:03 +0300 Subject: [PATCH 02/28] Avoid unnecessary redraws --- .../lib/src/tile_overlay.dart | 19 +++-- .../lib/src/tile_overlay_updates.dart | 20 +++-- .../test/tile_overlay_updates_test.dart | 82 +++++++++---------- 3 files changed, 65 insertions(+), 56 deletions(-) diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/lib/src/tile_overlay.dart index a8edc59b517d..fb2985ece046 100644 --- a/packages/google_maps_flutter/lib/src/tile_overlay.dart +++ b/packages/google_maps_flutter/lib/src/tile_overlay.dart @@ -124,26 +124,33 @@ class TileOverlay { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; final TileOverlay typedOther = other; - return tileOverlayId == typedOther.tileOverlayId; + return tileOverlayId == typedOther.tileOverlayId && + fadeIn == typedOther.fadeIn && + transparency == typedOther.transparency && + zIndex == typedOther.zIndex && + visible == typedOther.visible; } @override int get hashCode => tileOverlayId.hashCode; } -Map _keyTileOverlayId(Iterable tileOverlays) { +Map _keyTileOverlayId( + Iterable tileOverlays) { if (tileOverlays == null) { return {}; } - return Map.fromEntries(tileOverlays.map((TileOverlay tileOverlay) => - MapEntry(tileOverlay.tileOverlayId, tileOverlay))); + return Map.fromEntries(tileOverlays.map( + (TileOverlay tileOverlay) => MapEntry( + tileOverlay.tileOverlayId, tileOverlay))); } -List> _serializeTileOverlaySet(Set tileOverlays) { +List> _serializeTileOverlaySet( + Set tileOverlays) { if (tileOverlays == null) { return null; } return tileOverlays .map>((TileOverlay p) => p._toJson()) .toList(); -} \ No newline at end of file +} diff --git a/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart b/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart index b5bad83e0eea..0d5f800b9756 100644 --- a/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart +++ b/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart @@ -16,30 +16,38 @@ class _TileOverlayUpdates { } final Map previousTileOverlays = - _keyTileOverlayId(previous); + _keyTileOverlayId(previous); final Map currentTileOverlays = - _keyTileOverlayId(current); + _keyTileOverlayId(current); final Set prevTileOverlayIds = - previousTileOverlays.keys.toSet(); + previousTileOverlays.keys.toSet(); final Set currentTileOverlayIds = - currentTileOverlays.keys.toSet(); + currentTileOverlays.keys.toSet(); TileOverlay idToCurrentTileOverlay(TileOverlayId id) { return currentTileOverlays[id]; } final Set _tileOverlayIdsToRemove = - prevTileOverlayIds.difference(currentTileOverlayIds); + prevTileOverlayIds.difference(currentTileOverlayIds); final Set _tileOverlaysToAdd = currentTileOverlayIds .difference(prevTileOverlayIds) .map(idToCurrentTileOverlay) .toSet(); + /// Returns `true` if [current] is not equals to previous one with the + /// same id. + bool hasChanged(TileOverlay current) { + final TileOverlay previous = previousTileOverlays[current.tileOverlayId]; + return current != previous; + } + final Set _tileOverlaysToChange = currentTileOverlayIds .intersection(prevTileOverlayIds) .map(idToCurrentTileOverlay) + .where(hasChanged) .toSet(); tileOverlaysToAdd = _tileOverlaysToAdd; @@ -93,4 +101,4 @@ class _TileOverlayUpdates { 'tileOverlayIdsToRemove: $tileOverlayIdsToRemove, ' 'tileOverlaysToChange: $tileOverlaysToChange}'; } -} \ No newline at end of file +} diff --git a/packages/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/test/tile_overlay_updates_test.dart index 158f9fa67c4c..b94d4906dec7 100644 --- a/packages/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -31,7 +31,7 @@ Widget _mapWithTileOverlays(Set tileOverlays) { void main() { final FakePlatformViewsController fakePlatformViewsController = - FakePlatformViewsController(); + FakePlatformViewsController(); setUpAll(() { SystemChannels.platform_views.setMockMethodCallHandler( @@ -44,7 +44,7 @@ void main() { testWidgets('Initializing a tile overlay', (WidgetTester tester) async { final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); final FakePlatformGoogleMap platformGoogleMap = @@ -60,9 +60,9 @@ void main() { testWidgets("Adding a tile overlay", (WidgetTester tester) async { final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); final TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1, t2: t2))); @@ -76,13 +76,12 @@ void main() { expect(addedTileOverlay, equals(t2)); expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); - expect(platformGoogleMap.tileOverlaysToChange.length, 1); - expect(platformGoogleMap.tileOverlaysToChange.first, equals(t1)); + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); }); testWidgets("Removing a tile overlay", (WidgetTester tester) async { final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); await tester.pumpWidget(_mapWithTileOverlays(null)); @@ -99,9 +98,9 @@ void main() { testWidgets("Updating a tile overlay", (WidgetTester tester) async { final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); final TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); @@ -117,9 +116,9 @@ void main() { testWidgets("Updating a tile overlay", (WidgetTester tester) async { final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); final TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); @@ -135,9 +134,9 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); final Set prev = _toSet(t1: t1, t2: t2); t1 = TileOverlay( tileOverlayId: TileOverlayId("tile_overlay_1"), visible: false); @@ -158,14 +157,14 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); final TileOverlay t3 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); final Set prev = _toSet(t2: t2, t3: t3); // t1 is added, t2 is updated, t3 is removed. final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); final Set cur = _toSet(t1: t1, t2: t2); @@ -186,31 +185,26 @@ void main() { equals(t3.tileOverlayId)); }); - testWidgets( - "Partial Update", - (WidgetTester tester) async { - final TileOverlay t1 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); - TileOverlay t2 = - TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); - final Set prev = _toSet(t1: t1, t2: t2); - t2 = TileOverlay( - tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); - final Set cur = _toSet(t1: t1, t2: t2); - - await tester.pumpWidget(_mapWithTileOverlays(prev)); - await tester.pumpWidget(_mapWithTileOverlays(cur)); - - final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; - - expect(platformGoogleMap.tileOverlaysToChange, _toSet(t2: t2)); - expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); - expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); - }, - // The test is currently broken due to a bug (we're updating all tile overlays - // instead of just the ones that were changed): - // TODO(otopba): enable this test when the issue is fixed. - skip: true, - ); -} \ No newline at end of file + testWidgets("Partial Update", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + TileOverlay t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); + final Set prev = _toSet(t1: t1, t2: t2, t3: t3); + t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2, t3: t3); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange, _toSet(t3: t3)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); +} From bd8143aea337ca4ec38d307dc9107855db42755b Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 21 Sep 2019 18:19:48 +0300 Subject: [PATCH 03/28] fix format --- .../flutter/plugins/googlemaps/Convert.java | 73 ++++---- .../googlemaps/GoogleMapController.java | 34 ++-- .../plugins/googlemaps/GoogleMapFactory.java | 2 +- .../googlemaps/TileOverlayBuilder.java | 71 ++++---- .../googlemaps/TileOverlayController.java | 79 +++++---- .../plugins/googlemaps/TileOverlaySink.java | 17 +- .../googlemaps/TileOverlaysController.java | 163 +++++++++--------- .../googlemaps/TileProviderController.java | 137 ++++++++------- .../google_maps_flutter/lib/src/tile.dart | 2 +- .../lib/src/tile_provider.dart | 2 +- 10 files changed, 289 insertions(+), 291 deletions(-) diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 2c208b527c54..06cfd084889f 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -24,7 +24,6 @@ import com.google.android.gms.maps.model.RoundCap; import com.google.android.gms.maps.model.SquareCap; import com.google.android.gms.maps.model.Tile; - import io.flutter.view.FlutterMain; import java.util.ArrayList; import java.util.Arrays; @@ -144,12 +143,12 @@ private static int toInt(Object o) { return ((Number) o).intValue(); } - private static byte[] toByteArray(Object o) { - if (o == null) { - return null; - } - return (byte[]) o; + private static byte[] toByteArray(Object o) { + if (o == null) { + return null; } + return (byte[]) o; + } static Object cameraPositionToJson(CameraPosition position) { if (position == null) { @@ -613,37 +612,37 @@ private static Cap toCap(Object o) { } } - static String interpretTileOverlayOptions(Object o, TileOverlaySink sink) { - final Map data = toMap(o); - final Object fadeIn = data.get("fadeIn"); - if (fadeIn != null) { - sink.setFadeIn(toBoolean(fadeIn)); - } - final Object transparency = data.get("transparency"); - if (transparency != null) { - sink.setTransparency(toFloat(transparency)); - } - final Object zIndex = data.get("zIndex"); - if (zIndex != null) { - sink.setZIndex(toFloat(zIndex)); - } - final Object visible = data.get("visible"); - if (visible != null) { - sink.setVisible(toBoolean(visible)); - } - final String tileOverlayId = (String) data.get("tileOverlayId"); - if (tileOverlayId == null) { - throw new IllegalArgumentException("tileOverlayId was null"); - } else { - return tileOverlayId; - } + static String interpretTileOverlayOptions(Object o, TileOverlaySink sink) { + final Map data = toMap(o); + final Object fadeIn = data.get("fadeIn"); + if (fadeIn != null) { + sink.setFadeIn(toBoolean(fadeIn)); } - - static Tile interpretTile(Object o) { - final Map data = toMap(o); - int width = toInt(data.get("width")); - int height = toInt(data.get("height")); - byte[] dataArray = toByteArray(data.get("data")); - return new Tile(width, height, dataArray); + final Object transparency = data.get("transparency"); + if (transparency != null) { + sink.setTransparency(toFloat(transparency)); + } + final Object zIndex = data.get("zIndex"); + if (zIndex != null) { + sink.setZIndex(toFloat(zIndex)); + } + final Object visible = data.get("visible"); + if (visible != null) { + sink.setVisible(toBoolean(visible)); } + final String tileOverlayId = (String) data.get("tileOverlayId"); + if (tileOverlayId == null) { + throw new IllegalArgumentException("tileOverlayId was null"); + } else { + return tileOverlayId; + } + } + + static Tile interpretTile(Object o) { + final Map data = toMap(o); + int width = toInt(data.get("width")); + int height = toInt(data.get("height")); + byte[] dataArray = toByteArray(data.get("data")); + return new Tile(width, height, dataArray); + } } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 6ac327f1955f..8a94be2a1b11 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -358,23 +358,23 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { break; } case "tileOverlays#update": - { - Object tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); - tileOverlayController.addTileOverlays((List) tileOverlaysToAdd); - Object tileOverlaysToChange = call.argument("tileOverlaysToChange"); - tileOverlayController.changeTileOverlays((List) tileOverlaysToChange); - Object tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); - tileOverlayController.removeTileOverlays((List) tileOverlaysToRemove); - result.success(null); - break; - } + { + Object tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); + tileOverlayController.addTileOverlays((List) tileOverlaysToAdd); + Object tileOverlaysToChange = call.argument("tileOverlaysToChange"); + tileOverlayController.changeTileOverlays((List) tileOverlaysToChange); + Object tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); + tileOverlayController.removeTileOverlays((List) tileOverlaysToRemove); + result.success(null); + break; + } case "tileOverlays#clearTileCache": - { - Object rawTileOverlayId = call.argument("tileOverlayId"); - tileOverlayController.clearTileCache(rawTileOverlayId); - result.success(null); - break; - } + { + Object rawTileOverlayId = call.argument("tileOverlayId"); + tileOverlayController.clearTileCache(rawTileOverlayId); + result.success(null); + break; + } default: result.notImplemented(); } @@ -662,7 +662,7 @@ private void updateInitialCircles() { @Override public void setInitialTileOverlays(Object initialTileOverlays) { this.initialTileOverlays = (List) initialTileOverlays; - if(googleMap!=null) { + if (googleMap != null) { updateInitialTileOverlays(); } } diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index dbdd777fab7d..f4960454be4b 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -48,7 +48,7 @@ public PlatformView create(Context context, int id, Object args) { if (params.containsKey("circlesToAdd")) { builder.setInitialCircles(params.get("circlesToAdd")); } - if(params.containsKey("tileOverlaysToAdd")) { + if (params.containsKey("tileOverlaysToAdd")) { builder.setInitialTileOverlays(params.get("tileOverlaysToAdd")); } return builder.build(id, context, mActivityState, mPluginRegistrar); diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java index 9c978af16f2d..f363957d555e 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java @@ -4,39 +4,38 @@ import com.google.android.gms.maps.model.TileProvider; public class TileOverlayBuilder implements TileOverlaySink { - private final TileOverlayOptions tileOverlayOptions; - - TileOverlayBuilder() { - this.tileOverlayOptions = new TileOverlayOptions(); - } - - TileOverlayOptions build() { - return tileOverlayOptions; - } - - @Override - public void setFadeIn(boolean fadeIn) { - tileOverlayOptions.fadeIn(fadeIn); - } - - @Override - public void setTransparency(float transparency) { - tileOverlayOptions.transparency(transparency); - } - - @Override - public void setZIndex(float zIndex) { - tileOverlayOptions.zIndex(zIndex); - } - - @Override - public void setVisible(boolean visible) { - tileOverlayOptions.visible(visible); - } - - @Override - public void setTileProvider(TileProvider tileProvider) { - tileOverlayOptions.tileProvider(tileProvider); - } - -} \ No newline at end of file + private final TileOverlayOptions tileOverlayOptions; + + TileOverlayBuilder() { + this.tileOverlayOptions = new TileOverlayOptions(); + } + + TileOverlayOptions build() { + return tileOverlayOptions; + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlayOptions.fadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlayOptions.transparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlayOptions.zIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlayOptions.visible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + tileOverlayOptions.tileProvider(tileProvider); + } +} diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java index 2d8af55e131b..55db9e6a2d70 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java @@ -5,43 +5,42 @@ public class TileOverlayController implements TileOverlaySink { - private final TileOverlay tileOverlay; - - public TileOverlayController(TileOverlay tileOverlay) { - this.tileOverlay = tileOverlay; - } - - void remove() { - tileOverlay.remove(); - } - - void clearTileCache() { - tileOverlay.clearTileCache(); - } - - @Override - public void setFadeIn(boolean fadeIn) { - tileOverlay.setFadeIn(fadeIn); - } - - @Override - public void setTransparency(float transparency) { - tileOverlay.setTransparency(transparency); - } - - @Override - public void setZIndex(float zIndex) { - tileOverlay.setZIndex(zIndex); - } - - @Override - public void setVisible(boolean visible) { - tileOverlay.setVisible(visible); - } - - @Override - public void setTileProvider(TileProvider tileProvider) { - // You can not change tile provider after creation - } - -} \ No newline at end of file + private final TileOverlay tileOverlay; + + public TileOverlayController(TileOverlay tileOverlay) { + this.tileOverlay = tileOverlay; + } + + void remove() { + tileOverlay.remove(); + } + + void clearTileCache() { + tileOverlay.clearTileCache(); + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlay.setFadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlay.setTransparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlay.setZIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlay.setVisible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + // You can not change tile provider after creation + } +} diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java index 49cf7026f793..bed0ae49df7d 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java @@ -2,18 +2,15 @@ import com.google.android.gms.maps.model.TileProvider; -/** - * Receiver of TileOverlayOptions configuration. - */ +/** Receiver of TileOverlayOptions configuration. */ public interface TileOverlaySink { - void setFadeIn(boolean fadeIn); + void setFadeIn(boolean fadeIn); - void setTransparency(float transparency); + void setTransparency(float transparency); - void setZIndex(float zIndex); + void setZIndex(float zIndex); - void setVisible(boolean visible); + void setVisible(boolean visible); - void setTileProvider(TileProvider tileProvider); - -} \ No newline at end of file + void setTileProvider(TileProvider tileProvider); +} diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java index 81be7ed806b4..fcbb6b83b865 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -3,107 +3,106 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.TileOverlay; import com.google.android.gms.maps.model.TileOverlayOptions; - +import io.flutter.plugin.common.MethodChannel; import java.util.HashMap; import java.util.List; import java.util.Map; -import io.flutter.plugin.common.MethodChannel; - class TileOverlaysController { - private final Map tileOverlayIdToController; - private final MethodChannel methodChannel; - private GoogleMap googleMap; + private final Map tileOverlayIdToController; + private final MethodChannel methodChannel; + private GoogleMap googleMap; - TileOverlaysController(MethodChannel methodChannel) { - this.tileOverlayIdToController = new HashMap<>(); - this.methodChannel = methodChannel; - } + TileOverlaysController(MethodChannel methodChannel) { + this.tileOverlayIdToController = new HashMap<>(); + this.methodChannel = methodChannel; + } - void setGoogleMap(GoogleMap googleMap) { - this.googleMap = googleMap; - } + void setGoogleMap(GoogleMap googleMap) { + this.googleMap = googleMap; + } - void addTileOverlays(List tileOverlaysToAdd) { - if (tileOverlaysToAdd == null) { - return; - } - for (Object tileOverlayToAdd : tileOverlaysToAdd) { - addTileOverlay(tileOverlayToAdd); - } + void addTileOverlays(List tileOverlaysToAdd) { + if (tileOverlaysToAdd == null) { + return; } - - void changeTileOverlays(List tileOverlaysToChange) { - if (tileOverlaysToChange == null) { - return; - } - for (Object tileOverlayToChange : tileOverlaysToChange) { - changeTileOverlay(tileOverlayToChange); - } + for (Object tileOverlayToAdd : tileOverlaysToAdd) { + addTileOverlay(tileOverlayToAdd); } + } - void removeTileOverlays(List tileOverlayIdsToRemove) { - if (tileOverlayIdsToRemove == null) { - return; - } - for (Object rawTileOverlayId : tileOverlayIdsToRemove) { - if (rawTileOverlayId == null) { - continue; - } - String tileOverlayId = (String) rawTileOverlayId; - removeTileOverlay(tileOverlayId); - } + void changeTileOverlays(List tileOverlaysToChange) { + if (tileOverlaysToChange == null) { + return; } - - void clearTileCache(Object rawTileOverlayId) { - if (rawTileOverlayId == null) { - return; - } - String tileOverlayId = (String) rawTileOverlayId; - TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); - if (tileOverlayController != null) { - tileOverlayController.clearTileCache(); - } + for (Object tileOverlayToChange : tileOverlaysToChange) { + changeTileOverlay(tileOverlayToChange); } + } - private void addTileOverlay(Object tileOverlayOptions) { - if (tileOverlayOptions == null) { - return; - } - TileOverlayBuilder tileOverlayOptionsBuilder = new TileOverlayBuilder(); - String tileOverlayId = Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayOptionsBuilder); - TileProviderController tileProviderController = new TileProviderController(methodChannel, tileOverlayId); - tileOverlayOptionsBuilder.setTileProvider(tileProviderController); - TileOverlayOptions options = tileOverlayOptionsBuilder.build(); - TileOverlay tileOverlay = googleMap.addTileOverlay(options); - TileOverlayController tileOverlayController = new TileOverlayController(tileOverlay); - tileOverlayIdToController.put(tileOverlayId, tileOverlayController); + void removeTileOverlays(List tileOverlayIdsToRemove) { + if (tileOverlayIdsToRemove == null) { + return; } - - private void changeTileOverlay(Object tileOverlayOptions) { - if (tileOverlayOptions == null) { - return; - } - String tileOverlayId = getTileOverlayId(tileOverlayOptions); - TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); - if (tileOverlayController != null) { - Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayController); - } + for (Object rawTileOverlayId : tileOverlayIdsToRemove) { + if (rawTileOverlayId == null) { + continue; + } + String tileOverlayId = (String) rawTileOverlayId; + removeTileOverlay(tileOverlayId); } + } - private void removeTileOverlay(String tileOverlayId) { - TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); - if (tileOverlayController != null) { - tileOverlayController.remove(); - tileOverlayIdToController.remove(tileOverlayId); - } + void clearTileCache(Object rawTileOverlayId) { + if (rawTileOverlayId == null) { + return; + } + String tileOverlayId = (String) rawTileOverlayId; + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.clearTileCache(); } + } - @SuppressWarnings("unchecked") - private static String getTileOverlayId(Object tileOverlay) { - Map tileOverlayMap = (Map) tileOverlay; - return (String) tileOverlayMap.get("tileOverlayId"); + private void addTileOverlay(Object tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; } + TileOverlayBuilder tileOverlayOptionsBuilder = new TileOverlayBuilder(); + String tileOverlayId = + Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayOptionsBuilder); + TileProviderController tileProviderController = + new TileProviderController(methodChannel, tileOverlayId); + tileOverlayOptionsBuilder.setTileProvider(tileProviderController); + TileOverlayOptions options = tileOverlayOptionsBuilder.build(); + TileOverlay tileOverlay = googleMap.addTileOverlay(options); + TileOverlayController tileOverlayController = new TileOverlayController(tileOverlay); + tileOverlayIdToController.put(tileOverlayId, tileOverlayController); + } + + private void changeTileOverlay(Object tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; + } + String tileOverlayId = getTileOverlayId(tileOverlayOptions); + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayController); + } + } -} \ No newline at end of file + private void removeTileOverlay(String tileOverlayId) { + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.remove(); + tileOverlayIdToController.remove(tileOverlayId); + } + } + + @SuppressWarnings("unchecked") + private static String getTileOverlayId(Object tileOverlay) { + Map tileOverlayMap = (Map) tileOverlay; + return (String) tileOverlayMap.get("tileOverlayId"); + } +} diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index d24f4cf3e005..215c84194973 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -3,87 +3,92 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; - import androidx.annotation.NonNull; - import com.google.android.gms.maps.model.Tile; import com.google.android.gms.maps.model.TileProvider; - -import java.util.concurrent.CountDownLatch; - import io.flutter.plugin.common.MethodChannel; +import java.util.concurrent.CountDownLatch; public class TileProviderController implements TileProvider { - private static final String TAG = "TileProviderController"; + private static final String TAG = "TileProviderController"; - private final String tileOverlayId; - private final MethodChannel methodChannel; - private final Handler handler = new Handler(Looper.getMainLooper()); + private final String tileOverlayId; + private final MethodChannel methodChannel; + private final Handler handler = new Handler(Looper.getMainLooper()); - TileProviderController(MethodChannel methodChannel, String tileOverlayId) { - this.tileOverlayId = tileOverlayId; - this.methodChannel = methodChannel; - } + TileProviderController(MethodChannel methodChannel, String tileOverlayId) { + this.tileOverlayId = tileOverlayId; + this.methodChannel = methodChannel; + } - @Override - public Tile getTile(final int x, final int y, final int zoom) { - Worker worker = new Worker(x, y, zoom); - return worker.getTile(); - } + @Override + public Tile getTile(final int x, final int y, final int zoom) { + Worker worker = new Worker(x, y, zoom); + return worker.getTile(); + } - private final class Worker implements MethodChannel.Result { + private final class Worker implements MethodChannel.Result { - private final CountDownLatch countDownLatch = new CountDownLatch(1); - private final int x; - private final int y; - private final int zoom; - private Object result; + private final CountDownLatch countDownLatch = new CountDownLatch(1); + private final int x; + private final int y; + private final int zoom; + private Object result; - Worker(int x, int y, int zoom) { - this.x = x; - this.y = y; - this.zoom = zoom; - } - - @NonNull - Tile getTile() { - handler.post(() -> methodChannel.invokeMethod("tileOverlay#getTile", - Convert.tileOverlayArgumentsToJson(tileOverlayId, x, y, zoom), - this)); - try { - countDownLatch.await(); - } catch (InterruptedException e) { - Log.e(TAG, String.format("countDownLatch: can't get tile: x = %d, y= %d, zoom = %d", x, y, zoom), e); - return TileProvider.NO_TILE; - } - try { - return Convert.interpretTile(result); - } catch (Exception ex) { - Log.e(TAG, "Can't parse tile data", ex); - return TileProvider.NO_TILE; - } - } + Worker(int x, int y, int zoom) { + this.x = x; + this.y = y; + this.zoom = zoom; + } - @Override - public void success(Object data) { - result = data; - countDownLatch.countDown(); - } + @NonNull + Tile getTile() { + handler.post( + () -> + methodChannel.invokeMethod( + "tileOverlay#getTile", + Convert.tileOverlayArgumentsToJson(tileOverlayId, x, y, zoom), + this)); + try { + countDownLatch.await(); + } catch (InterruptedException e) { + Log.e( + TAG, + String.format("countDownLatch: can't get tile: x = %d, y= %d, zoom = %d", x, y, zoom), + e); + return TileProvider.NO_TILE; + } + try { + return Convert.interpretTile(result); + } catch (Exception ex) { + Log.e(TAG, "Can't parse tile data", ex); + return TileProvider.NO_TILE; + } + } - @Override - public void error(String errorCode, String errorMessage, Object data) { - Log.e(TAG, String.format("Can't get tile: errorCode = %s, errorMessage = %s, date = %s", errorCode, errorCode, data)); - result = null; - countDownLatch.countDown(); - } + @Override + public void success(Object data) { + result = data; + countDownLatch.countDown(); + } - @Override - public void notImplemented() { - Log.e(TAG, "Can't get tile: notImplemented"); - result = null; - countDownLatch.countDown(); - } + @Override + public void error(String errorCode, String errorMessage, Object data) { + Log.e( + TAG, + String.format( + "Can't get tile: errorCode = %s, errorMessage = %s, date = %s", + errorCode, errorCode, data)); + result = null; + countDownLatch.countDown(); } -} \ No newline at end of file + @Override + public void notImplemented() { + Log.e(TAG, "Can't get tile: notImplemented"); + result = null; + countDownLatch.countDown(); + } + } +} diff --git a/packages/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/lib/src/tile.dart index 919e5a088554..aef6fe841645 100644 --- a/packages/google_maps_flutter/lib/src/tile.dart +++ b/packages/google_maps_flutter/lib/src/tile.dart @@ -29,4 +29,4 @@ class Tile { return json; } -} \ No newline at end of file +} diff --git a/packages/google_maps_flutter/lib/src/tile_provider.dart b/packages/google_maps_flutter/lib/src/tile_provider.dart index 61e1dc202db2..d60a81954ab4 100644 --- a/packages/google_maps_flutter/lib/src/tile_provider.dart +++ b/packages/google_maps_flutter/lib/src/tile_provider.dart @@ -7,4 +7,4 @@ abstract class TileProvider { /// Returns the tile to be used for this tile coordinate. Future getTile(int x, int y, int zoom); -} \ No newline at end of file +} From e038a3ee111ff7f047d301ef637b5e988a4e1cc8 Mon Sep 17 00:00:00 2001 From: otopba Date: Wed, 22 Jan 2020 00:19:46 +0300 Subject: [PATCH 04/28] Add dummy map initialization --- .../plugins/googlemaps/GoogleMapsPlugin.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index b27fea425ba5..9888b5ff8d93 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -6,7 +6,12 @@ import android.app.Activity; import android.app.Application; +import android.app.FragmentManager; import android.os.Bundle; +import androidx.annotation.NonNull; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapFragment; +import com.google.android.gms.maps.OnMapReadyCallback; import io.flutter.plugin.common.PluginRegistry.Registrar; import java.util.concurrent.atomic.AtomicInteger; @@ -25,6 +30,7 @@ public class GoogleMapsPlugin implements Application.ActivityLifecycleCallbacks static final int DESTROYED = 6; private final AtomicInteger state = new AtomicInteger(0); private final int registrarActivityHashCode; + private boolean dummyMapInitialized; public static void registerWith(Registrar registrar) { if (registrar.activity() == null) { @@ -94,5 +100,34 @@ public void onActivityDestroyed(Activity activity) { private GoogleMapsPlugin(Registrar registrar) { this.registrarActivityHashCode = registrar.activity().hashCode(); + if (dummyMapInitialized) { + return; + } + Activity activity = registrar.activity(); + if (activity == null) { + return; + } + FragmentManager fragmentManager = activity.getFragmentManager(); + if (fragmentManager == null) { + return; + } + initDummyMap(fragmentManager); + dummyMapInitialized = true; + } + + /** + * This method creates dummy map. This call will initialize all services needed by GoogleMaps This + * will speed up next GoogleMap view initialization + */ + private static void initDummyMap(@NonNull final FragmentManager fragmentManager) { + final MapFragment mapFragment = new MapFragment(); + fragmentManager.beginTransaction().add(mapFragment, "DummyMap").commit(); + mapFragment.getMapAsync( + new OnMapReadyCallback() { + @Override + public void onMapReady(GoogleMap googleMap) { + fragmentManager.beginTransaction().remove(mapFragment).commit(); + } + }); } } From 4345ed504c7d6042fa04b429d97d9f0dad68a28a Mon Sep 17 00:00:00 2001 From: otopba Date: Wed, 22 Jan 2020 00:21:30 +0300 Subject: [PATCH 05/28] Revert "Add dummy map initialization" This reverts commit e038a3ee --- .../plugins/googlemaps/GoogleMapsPlugin.java | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index 9888b5ff8d93..b27fea425ba5 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -6,12 +6,7 @@ import android.app.Activity; import android.app.Application; -import android.app.FragmentManager; import android.os.Bundle; -import androidx.annotation.NonNull; -import com.google.android.gms.maps.GoogleMap; -import com.google.android.gms.maps.MapFragment; -import com.google.android.gms.maps.OnMapReadyCallback; import io.flutter.plugin.common.PluginRegistry.Registrar; import java.util.concurrent.atomic.AtomicInteger; @@ -30,7 +25,6 @@ public class GoogleMapsPlugin implements Application.ActivityLifecycleCallbacks static final int DESTROYED = 6; private final AtomicInteger state = new AtomicInteger(0); private final int registrarActivityHashCode; - private boolean dummyMapInitialized; public static void registerWith(Registrar registrar) { if (registrar.activity() == null) { @@ -100,34 +94,5 @@ public void onActivityDestroyed(Activity activity) { private GoogleMapsPlugin(Registrar registrar) { this.registrarActivityHashCode = registrar.activity().hashCode(); - if (dummyMapInitialized) { - return; - } - Activity activity = registrar.activity(); - if (activity == null) { - return; - } - FragmentManager fragmentManager = activity.getFragmentManager(); - if (fragmentManager == null) { - return; - } - initDummyMap(fragmentManager); - dummyMapInitialized = true; - } - - /** - * This method creates dummy map. This call will initialize all services needed by GoogleMaps This - * will speed up next GoogleMap view initialization - */ - private static void initDummyMap(@NonNull final FragmentManager fragmentManager) { - final MapFragment mapFragment = new MapFragment(); - fragmentManager.beginTransaction().add(mapFragment, "DummyMap").commit(); - mapFragment.getMapAsync( - new OnMapReadyCallback() { - @Override - public void onMapReady(GoogleMap googleMap) { - fragmentManager.beginTransaction().remove(mapFragment).commit(); - } - }); } } From 5850b8152697c407feeb3a847d47c7f38f540aef Mon Sep 17 00:00:00 2001 From: otopba Date: Fri, 24 Jan 2020 15:13:41 +0300 Subject: [PATCH 06/28] fix changelog --- packages/google_maps_flutter/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/CHANGELOG.md index 0044af471872..4596c860f707 100644 --- a/packages/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/CHANGELOG.md @@ -27,7 +27,6 @@ ## 0.5.21+11 * Define clang module for iOS, fix analyzer warnings. ->>>>>>>>> Temporary merge branch 2 ## 0.5.21+10 From aa9a5338b73c068ba80d107bf42e469653aec127 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Mon, 27 Jan 2020 21:12:31 +0100 Subject: [PATCH 07/28] Add iOS implementation of TileOverlays --- .../ios/Classes/FLTGoogleMapsPlugin.h | 1 + .../ios/Classes/GoogleMapController.h | 1 + .../ios/Classes/GoogleMapController.m | 22 ++ .../Classes/GoogleMapTileOverlayController.h | 36 ++++ .../Classes/GoogleMapTileOverlayController.m | 204 ++++++++++++++++++ 5 files changed, 264 insertions(+) create mode 100644 packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h create mode 100644 packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m diff --git a/packages/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h index 645ace34f9ed..780243f45682 100644 --- a/packages/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h @@ -9,6 +9,7 @@ #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" +#import "GoogleMapTileOverlayController.h" @interface FLTGoogleMapsPlugin : NSObject @end diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h index 1bc8536f97d9..113d290d4d73 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h @@ -8,6 +8,7 @@ #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" +#import "GoogleMapTileOverlayController.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m index da20706656e1..4ccdcf06aa38 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -59,6 +59,7 @@ @implementation FLTGoogleMapController { FLTPolygonsController* _polygonsController; FLTPolylinesController* _polylinesController; FLTCirclesController* _circlesController; + FLTTileOverlaysController* _tileOverlaysController; } - (instancetype)initWithFrame:(CGRect)frame @@ -98,6 +99,9 @@ - (instancetype)initWithFrame:(CGRect)frame _circlesController = [[FLTCirclesController alloc] init:_channel mapView:_mapView registrar:registrar]; + _tileOverlaysController = [[FLTTileOverlaysController alloc] init:_channel + mapView:_mapView + registrar:registrar]; id markersToAdd = args[@"markersToAdd"]; if ([markersToAdd isKindOfClass:[NSArray class]]) { [_markersController addMarkers:markersToAdd]; @@ -227,6 +231,24 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [_circlesController removeCircleIds:circleIdsToRemove]; } result(nil); + } else if ([call.method isEqualToString:@"tileOverlays#update"]) { + id tileOverlaysToAdd = call.arguments[@"tileOverlaysToAdd"]; + if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { + [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; + } + id tileOverlaysToChange = call.arguments[@"tileOverlaysToChange"]; + if ([tileOverlaysToChange isKindOfClass:[NSArray class]]) { + [_tileOverlaysController changeTileOverlays:tileOverlaysToChange]; + } + id tileOverlayIdsToRemove = call.arguments[@"tileOverlayIdsToRemove"]; + if ([tileOverlayIdsToRemove isKindOfClass:[NSArray class]]) { + [_tileOverlaysController removeTileOverlayIds:tileOverlayIdsToRemove]; + } + result(nil); + } else if ([call.method isEqualToString:@"tileOverlays#clearTileCache"]) { + id rawTileOverlayId = call.arguments[@"tileOverlayId"]; + [_tileOverlaysController clearTileCache:rawTileOverlayId]; + result(nil); } else if ([call.method isEqualToString:@"map#isCompassEnabled"]) { NSNumber* isCompassEnabled = @(_mapView.settings.compassButton); result(isCompassEnabled); diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h new file mode 100644 index 000000000000..7f860a3764cb --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h @@ -0,0 +1,36 @@ +// Copyright 2018 The Chromium 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 +#import + +@protocol FLTGoogleMapTileOverlayOptionsSink +- (void)setFadeIn:(BOOL)fadeIn; +- (void)setTransparency:(float)transparency; +- (void)setZIndex:(int)zIndex; +- (void)setVisible:(BOOL)visible; +- (void)setTileSize:(NSInteger)tileSize; +@end + +@interface FLTGoogleMapTileOverlayController : NSObject +- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView; +- (void)removeTileOverlay; +- (void)clearTileCache; +@end + +@interface FLTTileProviderController : GMSTileLayer +@property(atomic, readonly) NSString* tileOverlayId; +- (instancetype)init:(FlutterMethodChannel*)methodChannel + tileOverlayId:(NSString*)tileOverlayId; +@end + +@interface FLTTileOverlaysController : NSObject +- (instancetype)init:(FlutterMethodChannel*)methodChannel + mapView:(GMSMapView*)mapView + registrar:(NSObject*)registrar; +- (void)addTileOverlays:(NSArray*)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray*)tileOverlaysToChange; +- (void)removeTileOverlayIds:(NSArray*)tileOverlayIdsToRemove; +- (void)clearTileCache:(NSString*)tileOverlayId; +@end diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m new file mode 100644 index 000000000000..94c28b460f0e --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m @@ -0,0 +1,204 @@ +// Copyright 2018 The Chromium 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 "GoogleMapTileOverlayController.h" +#import "JsonConversions.h" + +@implementation FLTGoogleMapTileOverlayController { + GMSTileLayer* _layer; + GMSMapView* _mapView; +} + +- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _layer = tileLayer; + _mapView = mapView; + } + return self; +} + +- (void)removeTileOverlay { + _layer.map = nil; +} + +- (void)clearTileCache { + [_layer clearTileCache]; +} + +#pragma mark - FLTGoogleMapTileOverlayOptionsSink methods + +- (void)setFadeIn:(BOOL)fadeIn { + _layer.fadeIn = fadeIn; +} + +- (void)setTransparency:(float)transparency { + float opacity = 1.0 - transparency; + _layer.opacity = opacity; +} + +- (void)setVisible:(BOOL)visible { + _layer.map = visible ? _mapView : nil; +} + +- (void)setZIndex:(int)zIndex { + _layer.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + _layer.tileSize = tileSize; +} +@end + +@implementation FLTTileProviderController { + FlutterMethodChannel* _methodChannel; + NSString* _tileOverlayId; +} +- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId { + self = [super init]; + if (self) { + _methodChannel = methodChannel; + _tileOverlayId = tileOverlayId; + } + return self; +} + +- (void)requestTileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom receiver:(id)receiver { + NSNumber* xn = [NSNumber numberWithUnsignedInteger:x]; + NSNumber* yn = [NSNumber numberWithUnsignedInteger:y]; + NSNumber* zoomn = [NSNumber numberWithUnsignedInteger:zoom]; + + [_methodChannel invokeMethod:@"tileOverlay#getTile" + arguments:@{ + @"tileOverlayId": _tileOverlayId, + @"x":xn, + @"y":yn, + @"zoom":zoomn + } result: ^(id _Nullable result) { + UIImage* tileImage; + if ([result isKindOfClass:[NSDictionary class]]) { + FlutterStandardTypedData* typedData = (FlutterStandardTypedData*) result[@"data"]; + tileImage = [UIImage imageWithData:typedData.data]; + } else { + if ([result isKindOfClass:[FlutterError class]]) { + FlutterError* error = (FlutterError*)result; + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, date = %@", + [error code], + [error message], + [error details]); + } + if ([result isKindOfClass:[FlutterMethodNotImplemented class]]) { + NSLog(@"Can't get tile: notImplemented"); + } + tileImage = kGMSTileLayerNoTile; + } + + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; +} +@end + +static BOOL ToBool(NSNumber* data) { return [FLTGoogleMapJsonConversions toBool:data]; } + +static float ToFloat(NSNumber* data) { return [FLTGoogleMapJsonConversions toFloat:data]; } + +static int ToInt(NSNumber* data) { return [FLTGoogleMapJsonConversions toInt:data]; } + +static void InterpretTileOverlayOptions(NSDictionary* data, id sink, + NSObject* registrar) { + + NSNumber* visible = data[@"visible"]; + if (visible != nil) { + [sink setVisible:ToBool(visible)]; + } + + NSNumber* transparency = data[@"transparency"]; + if (transparency != nil) { + [sink setTransparency:ToFloat(transparency)]; + } + + NSNumber* zIndex = data[@"zIndex"]; + if (zIndex != nil) { + [sink setZIndex:ToInt(zIndex)]; + } + + NSNumber* fadeIn = data[@"fadeIn"]; + if (fadeIn != nil) { + [sink setFadeIn:ToBool(fadeIn)]; + } + + NSNumber* tileSize = data[@"tileSize"]; + if (tileSize != nil) { + [sink setTileSize:[tileSize integerValue]]; + } +} + +@implementation FLTTileOverlaysController { + NSMutableDictionary* _tileOverlayIdToController; + FlutterMethodChannel* _methodChannel; + NSObject* _registrar; + GMSMapView* _mapView; +} +- (instancetype)init:(FlutterMethodChannel*)methodChannel + mapView:(GMSMapView*)mapView + registrar:(NSObject*)registrar { + self = [super init]; + if (self) { + _methodChannel = methodChannel; + _mapView = mapView; + _tileOverlayIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd { + for (NSDictionary* tileOverlay in tileOverlaysToAdd) { + + NSString* tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; + FLTTileProviderController* tileProvider = [[FLTTileProviderController alloc] init:_methodChannel tileOverlayId:tileOverlayId]; + FLTGoogleMapTileOverlayController* controller = + [[FLTGoogleMapTileOverlayController alloc] initWithTileLayer:tileProvider + mapView:_mapView]; + InterpretTileOverlayOptions(tileOverlay, controller, _registrar); + _tileOverlayIdToController[tileOverlayId] = controller; + } +} + +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange { + for (NSDictionary* tileOverlay in tileOverlaysToChange) { + NSString* tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; + FLTGoogleMapTileOverlayController* controller = _tileOverlayIdToController[tileOverlayId]; + if (!controller) { + continue; + } + InterpretTileOverlayOptions(tileOverlay, controller, _registrar); + } +} +- (void)removeTileOverlayIds:(NSArray *)tileOverlayIdsToRemove { + for (NSString* tileOverlayId in tileOverlayIdsToRemove) { + if (!tileOverlayId) { + continue; + } + FLTGoogleMapTileOverlayController* controller = _tileOverlayIdToController[tileOverlayId]; + if (!controller) { + continue; + } + [controller removeTileOverlay]; + [_tileOverlayIdToController removeObjectForKey:tileOverlayId]; + } +} + +- (void)clearTileCache:(NSString*)tileOverlayId { + FLTGoogleMapTileOverlayController* controller = _tileOverlayIdToController[tileOverlayId]; + if (!controller) { + return; + } + [controller clearTileCache]; +} + ++ (NSString*)getTileOverlayId:(NSDictionary*)tileOverlay { + return tileOverlay[@"tileOverlayId"]; +} +@end From 5a5482c113bc2224de1683ff2d2efd0dd8ffcb21 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Wed, 29 Jan 2020 13:02:46 +0100 Subject: [PATCH 08/28] Fix typo --- packages/google_maps_flutter/example/lib/tile_overlay.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/example/lib/tile_overlay.dart index f8597ce2e325..6f46ad9a98be 100644 --- a/packages/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/example/lib/tile_overlay.dart @@ -56,7 +56,7 @@ class TileOverlayBodyState extends State { } void _clearTileCache() { - print("Clear tile cahce"); + print("Clear tile cache"); if (_tileOverlay != null && controller != null) { controller.clearTileCache(_tileOverlay.tileOverlayId); } From 3b8b6b54f8137d8f8ba0dbcfb8811bf0fcc2e756 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Wed, 29 Jan 2020 15:43:57 +0100 Subject: [PATCH 09/28] Add tileSize option in flutter TileOverlay class --- .../lib/src/tile_overlay.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/lib/src/tile_overlay.dart index fb2985ece046..08d221ef9ef4 100644 --- a/packages/google_maps_flutter/lib/src/tile_overlay.dart +++ b/packages/google_maps_flutter/lib/src/tile_overlay.dart @@ -62,6 +62,7 @@ class TileOverlay { this.transparency = 0.0, this.zIndex, this.visible = true, + this.tileSize = 256, }) : assert(transparency >= 0.0 && transparency <= 1.0); /// Uniquely identifies a [TileOverlay]. @@ -83,6 +84,15 @@ class TileOverlay { /// The visibility for the tile overlay. The default visibility is true. final bool visible; + /// Specifies the number of pixels (not points) that the returned tile images will prefer + /// to display as. iOS only. + /// + /// Defaults to 256, which is the traditional size of Google Maps tiles. + /// As an example, an application developer may wish to provide retina tiles (512 pixel edge length) + /// on retina devices, to keep the same number of tiles per view as the default value of 256 + /// would give on a non-retina device. + final int tileSize; + /// Creates a new [Polygon] object whose values are the same as this instance, /// unless overwritten by the specified parameters. TileOverlay copyWith({ @@ -91,6 +101,7 @@ class TileOverlay { double transparencyParam, double zIndexParam, bool visibleParam, + int tileSizeParam, }) { return TileOverlay( tileOverlayId: tileOverlayId, @@ -98,6 +109,7 @@ class TileOverlay { transparency: transparencyParam ?? transparency, zIndex: zIndexParam ?? zIndex, visible: visibleParam ?? visible, + tileSize: tileSizeParam ?? tileSize, ); } @@ -115,6 +127,7 @@ class TileOverlay { addIfPresent('transparency', transparency); addIfPresent('zIndex', zIndex); addIfPresent('visible', visible); + addIfPresent('tileSize', tileSize); return json; } @@ -128,7 +141,8 @@ class TileOverlay { fadeIn == typedOther.fadeIn && transparency == typedOther.transparency && zIndex == typedOther.zIndex && - visible == typedOther.visible; + visible == typedOther.visible && + tileSize == typedOther.tileSize; } @override From 246636a554f46d00bdf36b7b5cc8c932460d921e Mon Sep 17 00:00:00 2001 From: NeoKree Date: Wed, 29 Jan 2020 15:51:53 +0100 Subject: [PATCH 10/28] Unify zIndex property type to other overlays All overlays (like polygon, circle, polyline) were using the type int instead of double, except for TileOverlay. We changed it to have the same interface and be compatible with iOS, which require an int type. --- packages/google_maps_flutter/lib/src/tile_overlay.dart | 4 ++-- packages/google_maps_flutter/test/fake_maps_controllers.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/lib/src/tile_overlay.dart index 08d221ef9ef4..59394b9c5247 100644 --- a/packages/google_maps_flutter/lib/src/tile_overlay.dart +++ b/packages/google_maps_flutter/lib/src/tile_overlay.dart @@ -79,7 +79,7 @@ class TileOverlay { /// The tile overlay's zIndex, i.e., the order in which it will be drawn where /// overlays with larger values are drawn above those with lower values - final double zIndex; + final int zIndex; /// The visibility for the tile overlay. The default visibility is true. final bool visible; @@ -99,7 +99,7 @@ class TileOverlay { TileOverlayId tileOverlayId, bool fadeInParam, double transparencyParam, - double zIndexParam, + int zIndexParam, bool visibleParam, int tileSizeParam, }) { diff --git a/packages/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/test/fake_maps_controllers.dart index 6ee2ec7340fa..c28fa7a11c1c 100644 --- a/packages/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/test/fake_maps_controllers.dart @@ -365,7 +365,7 @@ class FakePlatformGoogleMap { final String tileOverlayId = tileOverlayData['tileOverlayId']; final bool fadeIn = tileOverlayData['fadeIn']; final double transparency = tileOverlayData['transparency']; - final double zIndex = tileOverlayData['zIndex']; + final int zIndex = tileOverlayData['zIndex']; final bool visible = tileOverlayData['visible']; result.add(TileOverlay( From a92d75dc0e16f2e98a3e00e6219bf0f5b2de1c37 Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 1 Feb 2020 15:35:11 +0300 Subject: [PATCH 11/28] merge --- packages/google_maps_flutter/CHANGELOG.md | 2 +- .../Classes/GoogleMapTileOverlayController.h | 19 ++--- .../Classes/GoogleMapTileOverlayController.m | 85 +++++++++---------- packages/google_maps_flutter/pubspec.yaml | 2 +- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/packages/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/CHANGELOG.md index 204f2971976d..3834cef0dafa 100644 --- a/packages/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.5.23 -* Add TileOverlay support for Android. +* Add TileOverlay support. ## 0.5.22 diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h index 7f860a3764cb..2e277fb8490a 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h @@ -20,17 +20,16 @@ @end @interface FLTTileProviderController : GMSTileLayer -@property(atomic, readonly) NSString* tileOverlayId; -- (instancetype)init:(FlutterMethodChannel*)methodChannel - tileOverlayId:(NSString*)tileOverlayId; +@property(atomic, readonly) NSString *tileOverlayId; +- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId; @end @interface FLTTileOverlaysController : NSObject -- (instancetype)init:(FlutterMethodChannel*)methodChannel - mapView:(GMSMapView*)mapView - registrar:(NSObject*)registrar; -- (void)addTileOverlays:(NSArray*)tileOverlaysToAdd; -- (void)changeTileOverlays:(NSArray*)tileOverlaysToChange; -- (void)removeTileOverlayIds:(NSArray*)tileOverlayIdsToRemove; -- (void)clearTileCache:(NSString*)tileOverlayId; +- (instancetype)init:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar; +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; +- (void)removeTileOverlayIds:(NSArray *)tileOverlayIdsToRemove; +- (void)clearTileCache:(NSString *)tileOverlayId; @end diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m index 94c28b460f0e..6ef669a8b2d4 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m @@ -10,7 +10,7 @@ @implementation FLTGoogleMapTileOverlayController { GMSMapView* _mapView; } -- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView { +- (instancetype)initWithTileLayer:(GMSTileLayer*)tileLayer mapView:(GMSMapView*)mapView { self = [super init]; if (self) { _layer = tileLayer; @@ -55,7 +55,7 @@ @implementation FLTTileProviderController { FlutterMethodChannel* _methodChannel; NSString* _tileOverlayId; } -- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId { +- (instancetype)init:(FlutterMethodChannel*)methodChannel tileOverlayId:(NSString*)tileOverlayId { self = [super init]; if (self) { _methodChannel = methodChannel; @@ -64,38 +64,36 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSStri return self; } -- (void)requestTileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom receiver:(id)receiver { +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver { NSNumber* xn = [NSNumber numberWithUnsignedInteger:x]; NSNumber* yn = [NSNumber numberWithUnsignedInteger:y]; NSNumber* zoomn = [NSNumber numberWithUnsignedInteger:zoom]; - - [_methodChannel invokeMethod:@"tileOverlay#getTile" - arguments:@{ - @"tileOverlayId": _tileOverlayId, - @"x":xn, - @"y":yn, - @"zoom":zoomn - } result: ^(id _Nullable result) { - UIImage* tileImage; - if ([result isKindOfClass:[NSDictionary class]]) { - FlutterStandardTypedData* typedData = (FlutterStandardTypedData*) result[@"data"]; - tileImage = [UIImage imageWithData:typedData.data]; - } else { - if ([result isKindOfClass:[FlutterError class]]) { - FlutterError* error = (FlutterError*)result; - NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, date = %@", - [error code], - [error message], - [error details]); - } - if ([result isKindOfClass:[FlutterMethodNotImplemented class]]) { - NSLog(@"Can't get tile: notImplemented"); - } - tileImage = kGMSTileLayerNoTile; - } - - [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; - }]; + + [_methodChannel + invokeMethod:@"tileOverlay#getTile" + arguments:@{@"tileOverlayId" : _tileOverlayId, @"x" : xn, @"y" : yn, @"zoom" : zoomn} + result:^(id _Nullable result) { + UIImage* tileImage; + if ([result isKindOfClass:[NSDictionary class]]) { + FlutterStandardTypedData* typedData = (FlutterStandardTypedData*)result[@"data"]; + tileImage = [UIImage imageWithData:typedData.data]; + } else { + if ([result isKindOfClass:[FlutterError class]]) { + FlutterError* error = (FlutterError*)result; + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, date = %@", + [error code], [error message], [error details]); + } + if ([result isKindOfClass:[FlutterMethodNotImplemented class]]) { + NSLog(@"Can't get tile: notImplemented"); + } + tileImage = kGMSTileLayerNoTile; + } + + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; } @end @@ -105,14 +103,14 @@ - (void)requestTileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom rece static int ToInt(NSNumber* data) { return [FLTGoogleMapJsonConversions toInt:data]; } -static void InterpretTileOverlayOptions(NSDictionary* data, id sink, - NSObject* registrar) { - +static void InterpretTileOverlayOptions(NSDictionary* data, + id sink, + NSObject* registrar) { NSNumber* visible = data[@"visible"]; if (visible != nil) { [sink setVisible:ToBool(visible)]; } - + NSNumber* transparency = data[@"transparency"]; if (transparency != nil) { [sink setTransparency:ToFloat(transparency)]; @@ -122,12 +120,12 @@ static void InterpretTileOverlayOptions(NSDictionary* data, id Date: Sat, 1 Feb 2020 16:24:57 +0300 Subject: [PATCH 12/28] fix analyze --- packages/google_maps_flutter/lib/src/tile.dart | 1 + packages/google_maps_flutter/lib/src/tile_overlay.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/lib/src/tile.dart index aef6fe841645..b068195c1570 100644 --- a/packages/google_maps_flutter/lib/src/tile.dart +++ b/packages/google_maps_flutter/lib/src/tile.dart @@ -3,6 +3,7 @@ part of google_maps_flutter; /// Contains information about a Tile that is returned by a [TileProvider]. @immutable class Tile { + /// Creates an immutable representation of a [Tile] to draw by [TileProvider]. const Tile(this.width, this.height, this.data); /// The width of the image encoded by data in pixels. diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/lib/src/tile_overlay.dart index 59394b9c5247..298e5df0935e 100644 --- a/packages/google_maps_flutter/lib/src/tile_overlay.dart +++ b/packages/google_maps_flutter/lib/src/tile_overlay.dart @@ -5,6 +5,7 @@ part of google_maps_flutter; /// This does not have to be globally unique, only unique among the list. @immutable class TileOverlayId { + /// Creates an immutable identifier for a [TileOverlay]. TileOverlayId(this.value) : assert(value != null); /// value of the [TileOverlayId]. @@ -55,6 +56,7 @@ class TileOverlayId { /// At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from /// west to east and the y values range from 0 to 2N - 1 and increase from north to south. class TileOverlay { + /// Creates an immutable representation of a [TileOverlay] to draw on [GoogleMap]. const TileOverlay({ @required this.tileOverlayId, this.fadeIn = true, From 4ec2520fa60a0ce15500c7be02d4e23a611edef8 Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 1 Feb 2020 16:25:38 +0300 Subject: [PATCH 13/28] fix analyze --- packages/google_maps_flutter/lib/src/google_map.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/lib/src/google_map.dart index 8b5471c35dcd..86dd16fc0960 100644 --- a/packages/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/lib/src/google_map.dart @@ -317,6 +317,7 @@ class _GoogleMapState extends State { void _updateTileOverlays() async { final GoogleMapController controller = await _controller.future; + // ignore: unawaited_futures controller._updateTileOverlays(_TileOverlayUpdates.from( _tileOverlays.values.toSet(), widget.tileOverlays)); _tileOverlays = _keyTileOverlayId(widget.tileOverlays); From f22aebd88ec84b55ee31dd91ec0e1d111e8e6e88 Mon Sep 17 00:00:00 2001 From: otopba Date: Sat, 1 Feb 2020 16:33:24 +0300 Subject: [PATCH 14/28] fix analyze --- packages/google_maps_flutter/example/lib/tile_overlay.dart | 6 ++++++ packages/google_maps_flutter/lib/src/google_map.dart | 2 +- packages/google_maps_flutter/lib/src/tile.dart | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/example/lib/tile_overlay.dart index 6f46ad9a98be..07f27bf7442c 100644 --- a/packages/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/example/lib/tile_overlay.dart @@ -1,3 +1,9 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + import 'dart:typed_data'; import 'dart:ui' as ui; diff --git a/packages/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/lib/src/google_map.dart index 86dd16fc0960..3411bef998df 100644 --- a/packages/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/lib/src/google_map.dart @@ -405,7 +405,7 @@ class _GoogleMapState extends State { if (tile == null) { tile = TileProvider.noTile; } - return tile.toJson(); + return tile._toJson(); } } diff --git a/packages/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/lib/src/tile.dart index b068195c1570..a7a18808fd6c 100644 --- a/packages/google_maps_flutter/lib/src/tile.dart +++ b/packages/google_maps_flutter/lib/src/tile.dart @@ -15,7 +15,7 @@ class Tile { /// A byte array containing the image data. final Uint8List data; - dynamic toJson() { + dynamic _toJson() { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { From 29de40b4e7167e324a009100f9137a248e4ebe7f Mon Sep 17 00:00:00 2001 From: otopba Date: Mon, 24 Feb 2020 21:33:26 +0300 Subject: [PATCH 15/28] move file --- .../{ => google_maps_flutter}/example/lib/tile_overlay.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/google_maps_flutter/{ => google_maps_flutter}/example/lib/tile_overlay.dart (100%) diff --git a/packages/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart similarity index 100% rename from packages/google_maps_flutter/example/lib/tile_overlay.dart rename to packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart From b173a9c44c619b8b5aa593a87dc86f2f9bbd2dd5 Mon Sep 17 00:00:00 2001 From: otopba Date: Mon, 24 Feb 2020 21:46:01 +0300 Subject: [PATCH 16/28] move files --- .../{ => google_maps_flutter}/lib/src/tile.dart | 0 .../{ => google_maps_flutter}/lib/src/tile_overlay.dart | 0 .../{ => google_maps_flutter}/lib/src/tile_overlay_updates.dart | 0 .../{ => google_maps_flutter}/lib/src/tile_provider.dart | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename packages/google_maps_flutter/{ => google_maps_flutter}/lib/src/tile.dart (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/lib/src/tile_overlay.dart (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/lib/src/tile_overlay_updates.dart (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/lib/src/tile_provider.dart (100%) diff --git a/packages/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/tile.dart similarity index 100% rename from packages/google_maps_flutter/lib/src/tile.dart rename to packages/google_maps_flutter/google_maps_flutter/lib/src/tile.dart diff --git a/packages/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay.dart similarity index 100% rename from packages/google_maps_flutter/lib/src/tile_overlay.dart rename to packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay.dart diff --git a/packages/google_maps_flutter/lib/src/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay_updates.dart similarity index 100% rename from packages/google_maps_flutter/lib/src/tile_overlay_updates.dart rename to packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay_updates.dart diff --git a/packages/google_maps_flutter/lib/src/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_provider.dart similarity index 100% rename from packages/google_maps_flutter/lib/src/tile_provider.dart rename to packages/google_maps_flutter/google_maps_flutter/lib/src/tile_provider.dart From fba1dd4bbe93ceaa5f513dfe61b7b6fc618cc408 Mon Sep 17 00:00:00 2001 From: otopba Date: Mon, 24 Feb 2020 21:53:35 +0300 Subject: [PATCH 17/28] move files --- .../java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java | 0 .../io/flutter/plugins/googlemaps/TileOverlayController.java | 0 .../java/io/flutter/plugins/googlemaps/TileOverlaySink.java | 0 .../io/flutter/plugins/googlemaps/TileOverlaysController.java | 0 .../io/flutter/plugins/googlemaps/TileProviderController.java | 0 .../ios/Classes/GoogleMapTileOverlayController.h | 0 .../ios/Classes/GoogleMapTileOverlayController.m | 0 .../test/tile_overlay_updates_test.dart | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename packages/google_maps_flutter/{ => google_maps_flutter}/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/ios/Classes/GoogleMapTileOverlayController.h (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/ios/Classes/GoogleMapTileOverlayController.m (100%) rename packages/google_maps_flutter/{ => google_maps_flutter}/test/tile_overlay_updates_test.dart (99%) diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java similarity index 100% rename from packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java rename to packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java similarity index 100% rename from packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java rename to packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java similarity index 100% rename from packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java rename to packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java similarity index 100% rename from packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java rename to packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java similarity index 100% rename from packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java rename to packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h similarity index 100% rename from packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h rename to packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.h diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m similarity index 100% rename from packages/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m rename to packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m diff --git a/packages/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart similarity index 99% rename from packages/google_maps_flutter/test/tile_overlay_updates_test.dart rename to packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index b94d4906dec7..a7d718bd9b7f 100644 --- a/packages/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'fake_maps_controllers.dart'; +import '../../test/fake_maps_controllers.dart'; Set _toSet({TileOverlay t1, TileOverlay t2, TileOverlay t3}) { final Set res = Set.identity(); From 1936b1013bf5de016f5342698b59e4d7f007628f Mon Sep 17 00:00:00 2001 From: otopba Date: Mon, 24 Feb 2020 21:58:11 +0300 Subject: [PATCH 18/28] fix path --- .../google_maps_flutter/test/tile_overlay_updates_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index a7d718bd9b7f..b94d4906dec7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import '../../test/fake_maps_controllers.dart'; +import 'fake_maps_controllers.dart'; Set _toSet({TileOverlay t1, TileOverlay t2, TileOverlay t3}) { final Set res = Set.identity(); From f46e1ba555101d5b836477decb531eb1312cd480 Mon Sep 17 00:00:00 2001 From: otopba Date: Sun, 22 Mar 2020 22:20:15 +0300 Subject: [PATCH 19/28] merge --- packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index e6dfb6bea412..507343e6a7ac 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 0.5.25 +version: 0.5.26 dependencies: flutter: From 7245d7f53974820e1281cca1962dca498f2044ec Mon Sep 17 00:00:00 2001 From: NeoKree Date: Mon, 13 Apr 2020 14:55:59 +0200 Subject: [PATCH 20/28] Do not check for `tileOverlayId` nullability in native code Dart `TileOverlayId`'s class constructor assert the value must not be null. --- .../ios/Classes/GoogleMapTileOverlayController.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m index 6ef669a8b2d4..54a6b42ec867 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapTileOverlayController.m @@ -175,9 +175,6 @@ - (void)changeTileOverlays:(NSArray*)tileOverlaysToChange { } - (void)removeTileOverlayIds:(NSArray*)tileOverlayIdsToRemove { for (NSString* tileOverlayId in tileOverlayIdsToRemove) { - if (!tileOverlayId) { - continue; - } FLTGoogleMapTileOverlayController* controller = _tileOverlayIdToController[tileOverlayId]; if (!controller) { continue; From 0a904478a38e5a7bf3b8aba46c1e9246b287913e Mon Sep 17 00:00:00 2001 From: otopba Date: Sun, 1 Nov 2020 18:31:04 +0300 Subject: [PATCH 21/28] update versions --- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 4 ++-- .../google_maps_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../google_maps_flutter_platform_interface/pubspec.yaml | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index a2e0c1bc3df6..825b1747315a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.6 + +Add TileOverlay support. + ## 1.0.5 Overhaul lifecycle management in GoogleMapsPlugin. diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index dadedb8cce3b..3cb5c9f178b4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,13 +1,13 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.5 +version: 1.0.6 dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.0.4 + google_maps_flutter_platform_interface: ^1.0.5 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index dc8eddf8b557..d84363595b5e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.5 + +Add TileOverlay support. + ## 1.0.4 * Add a `dispose` method to the interface, so implementations may cleanup resources acquired on `init`. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index fd3a1c434960..a2b5ff56fee1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_platform_interface # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 1.0.4 +version: 1.0.5 dependencies: flutter: From e1b39bd631024a1e9f1f6cbaa9d17d4185044ba0 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Wed, 25 Nov 2020 21:00:07 +0100 Subject: [PATCH 22/28] Move types into google_maps_flutter_platform_interface package --- .../lib/google_maps_flutter.dart | 6 ++- .../google_maps_flutter/pubspec.yaml | 3 +- .../lib/src/types}/tile.dart | 11 +++++- .../lib/src/types}/tile_overlay.dart | 30 ++++----------- .../lib/src/types}/tile_overlay_updates.dart | 38 +++++++++++++------ .../lib/src/types}/tile_provider.dart | 6 ++- .../lib/src/types/types.dart | 4 ++ .../lib/src/types/utils/tile_overlay.dart | 23 +++++++++++ 8 files changed, 82 insertions(+), 39 deletions(-) rename packages/google_maps_flutter/{google_maps_flutter/lib/src => google_maps_flutter_platform_interface/lib/src/types}/tile.dart (70%) rename packages/google_maps_flutter/{google_maps_flutter/lib/src => google_maps_flutter_platform_interface/lib/src/types}/tile_overlay.dart (89%) rename packages/google_maps_flutter/{google_maps_flutter/lib/src => google_maps_flutter_platform_interface/lib/src/types}/tile_overlay_updates.dart (71%) rename packages/google_maps_flutter/{google_maps_flutter/lib/src => google_maps_flutter_platform_interface/lib/src/types}/tile_provider.dart (65%) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index b879f3d302cf..e06f141c187b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -43,7 +43,11 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf PolygonId, Polyline, PolylineId, - ScreenCoordinate; + ScreenCoordinate, + Tile, + TileOverlayId, + TileOverlay, + TileProvider; part 'src/controller.dart'; part 'src/google_map.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 780061fcf409..6eeb12af30cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -7,7 +7,8 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.0.5 + google_maps_flutter_platform_interface: + path: ../google_maps_flutter_platform_interface dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart similarity index 70% rename from packages/google_maps_flutter/google_maps_flutter/lib/src/tile.dart rename to packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart index a7a18808fd6c..3fe49fcbe1fb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart @@ -1,4 +1,10 @@ -part of google_maps_flutter; +// Copyright 2018 The Chromium 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 'dart:typed_data'; + +import 'package:meta/meta.dart' show immutable; /// Contains information about a Tile that is returned by a [TileProvider]. @immutable @@ -15,7 +21,8 @@ class Tile { /// A byte array containing the image data. final Uint8List data; - dynamic _toJson() { + /// Converts this object to something serializable in JSON. + dynamic toJson() { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart similarity index 89% rename from packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay.dart rename to packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index 298e5df0935e..374dd19c20c3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -1,4 +1,9 @@ -part of google_maps_flutter; +// Copyright 2018 The Chromium 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 'types.dart'; +import 'package:meta/meta.dart' show immutable, required; /// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. /// @@ -115,7 +120,8 @@ class TileOverlay { ); } - dynamic _toJson() { + /// Converts this object to something serializable in JSON. + dynamic toJson() { final Map json = {}; void addIfPresent(String fieldName, dynamic value) { @@ -150,23 +156,3 @@ class TileOverlay { @override int get hashCode => tileOverlayId.hashCode; } - -Map _keyTileOverlayId( - Iterable tileOverlays) { - if (tileOverlays == null) { - return {}; - } - return Map.fromEntries(tileOverlays.map( - (TileOverlay tileOverlay) => MapEntry( - tileOverlay.tileOverlayId, tileOverlay))); -} - -List> _serializeTileOverlaySet( - Set tileOverlays) { - if (tileOverlays == null) { - return null; - } - return tileOverlays - .map>((TileOverlay p) => p._toJson()) - .toList(); -} diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart similarity index 71% rename from packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay_updates.dart rename to packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart index 0d5f800b9756..8ab1466eacad 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_overlay_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart @@ -1,12 +1,20 @@ -part of google_maps_flutter; +// Copyright 2018 The Chromium 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 'dart:ui' show hashValues; + +import 'package:flutter/foundation.dart' show setEquals; + +import 'utils/tile_overlay.dart'; +import 'types.dart'; /// [TileProvider] update events to be applied to the [GoogleMap]. /// /// Used in [GoogleMapController] when the map is updated. -class _TileOverlayUpdates { - /// Computes [_MarkerUpdates] given previous and current [Marker]s. - _TileOverlayUpdates.from( - Set previous, Set current) { +class TileOverlayUpdates { + /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. + TileOverlayUpdates.from(Set previous, Set current) { if (previous == null) { previous = Set.identity(); } @@ -16,9 +24,9 @@ class _TileOverlayUpdates { } final Map previousTileOverlays = - _keyTileOverlayId(previous); + keyTileOverlayId(previous); final Map currentTileOverlays = - _keyTileOverlayId(current); + keyTileOverlayId(current); final Set prevTileOverlayIds = previousTileOverlays.keys.toSet(); @@ -55,11 +63,17 @@ class _TileOverlayUpdates { tileOverlaysToChange = _tileOverlaysToChange; } + /// Set of TileOverlays to be added in this update. Set tileOverlaysToAdd; + + /// Set of TileOverlayIds to be removed in this update. Set tileOverlayIdsToRemove; + + /// Set of TileOverlays to be changed in this update. Set tileOverlaysToChange; - Map _toMap() { + /// Converts this object to something serializable in JSON. + Map toJson() { final Map updateMap = {}; void addIfNonNull(String fieldName, dynamic value) { @@ -69,9 +83,9 @@ class _TileOverlayUpdates { } addIfNonNull( - 'tileOverlaysToAdd', _serializeTileOverlaySet(tileOverlaysToAdd)); + 'tileOverlaysToAdd', serializeTileOverlaySet(tileOverlaysToAdd)); addIfNonNull( - 'tileOverlaysToChange', _serializeTileOverlaySet(tileOverlaysToChange)); + 'tileOverlaysToChange', serializeTileOverlaySet(tileOverlaysToChange)); addIfNonNull( 'tileOverlayIdsToRemove', tileOverlayIdsToRemove @@ -85,7 +99,7 @@ class _TileOverlayUpdates { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final _TileOverlayUpdates typedOther = other; + final TileOverlayUpdates typedOther = other; return setEquals(tileOverlaysToAdd, typedOther.tileOverlaysToAdd) && setEquals(tileOverlayIdsToRemove, typedOther.tileOverlayIdsToRemove) && setEquals(tileOverlaysToChange, typedOther.tileOverlaysToChange); @@ -97,7 +111,7 @@ class _TileOverlayUpdates { @override String toString() { - return '_TileOverlayUpdates{tileOverlaysToAdd: $tileOverlaysToAdd, ' + return 'TileOverlayUpdates{tileOverlaysToAdd: $tileOverlaysToAdd, ' 'tileOverlayIdsToRemove: $tileOverlayIdsToRemove, ' 'tileOverlaysToChange: $tileOverlaysToChange}'; } diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart similarity index 65% rename from packages/google_maps_flutter/google_maps_flutter/lib/src/tile_provider.dart rename to packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart index d60a81954ab4..f0754159c941 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/tile_provider.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart @@ -1,4 +1,8 @@ -part of google_maps_flutter; +// Copyright 2018 The Chromium 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 'types.dart'; /// An interface for a class that provides the tile images for a TileOverlay. abstract class TileProvider { diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index e56c3a5dd646..3e2002f80ae3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -19,6 +19,9 @@ export 'polygon.dart'; export 'polyline_updates.dart'; export 'polyline.dart'; export 'screen_coordinate.dart'; +export 'tile.dart'; +export 'tile_overlay.dart'; +export 'tile_provider.dart'; export 'ui.dart'; // Export the utils, they're used by the Widget @@ -26,3 +29,4 @@ export 'utils/circle.dart'; export 'utils/marker.dart'; export 'utils/polygon.dart'; export 'utils/polyline.dart'; +export 'utils/tile_overlay.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart new file mode 100644 index 000000000000..0736c836481f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart @@ -0,0 +1,23 @@ +import '../types.dart'; + +/// Converts an [Iterable] of TileOverlay in a Map of TileOverlayId -> TileOverlay. +Map keyTileOverlayId( + Iterable tileOverlays) { + if (tileOverlays == null) { + return {}; + } + return Map.fromEntries(tileOverlays.map( + (TileOverlay tileOverlay) => MapEntry( + tileOverlay.tileOverlayId, tileOverlay))); +} + +/// Converts a Set of TileOverlays into something serializable in JSON. +List> serializeTileOverlaySet( + Set tileOverlays) { + if (tileOverlays == null) { + return null; + } + return tileOverlays + .map>((TileOverlay p) => p.toJson()) + .toList(); +} From f40930b60e5de2f9cca3757805a4c76d52601b74 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Wed, 25 Nov 2020 22:03:31 +0100 Subject: [PATCH 23/28] Restore `updateTileOverlays` and `clearTileCache` methods --- .../lib/src/controller.dart | 23 +++++++++++++ .../lib/src/google_map.dart | 17 ++++++++++ .../method_channel_google_maps_flutter.dart | 34 +++++++++++++++++++ .../google_maps_flutter_platform.dart | 25 ++++++++++++++ .../lib/src/types/types.dart | 1 + 5 files changed, 100 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index f47b8e57b049..e1889a81f97f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -152,6 +152,29 @@ class GoogleMapController { mapId: mapId); } + /// Updates tile overlays configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future _updateTileOverlays(TileOverlayUpdates tileOverlayUpdates) { + assert(tileOverlayUpdates != null); + return _googleMapsFlutterPlatform.updateTileOverlays(tileOverlayUpdates, + mapId: mapId); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The API maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + Future clearTileCache(TileOverlayId tileOverlayId) async { + assert(tileOverlayId != null); + return _googleMapsFlutterPlatform.clearTileCache(tileOverlayId, + mapId: mapId); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index d7f0f1a4e280..6ba8590de8d7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -49,6 +49,7 @@ class GoogleMap extends StatefulWidget { this.polygons, this.polylines, this.circles, + this.tileOverlays, this.onCameraMoveStarted, this.onCameraMove, this.onCameraIdle, @@ -120,6 +121,9 @@ class GoogleMap extends StatefulWidget { /// Circles to be placed on the map. final Set circles; + /// Tile overlays to be placed on the map. + final Set tileOverlays; + /// Called when the camera starts moving. /// /// This can be initiated by the following: @@ -220,6 +224,8 @@ class _GoogleMapState extends State { Map _polygons = {}; Map _polylines = {}; Map _circles = {}; + Map _tileOverlays = + {}; _GoogleMapOptions _googleMapOptions; @override @@ -231,6 +237,7 @@ class _GoogleMapState extends State { 'polygonsToAdd': serializePolygonSet(widget.polygons), 'polylinesToAdd': serializePolylineSet(widget.polylines), 'circlesToAdd': serializeCircleSet(widget.circles), + 'tileOverlaysToAdd': serializeTileOverlaySet(widget.tileOverlays), '_webOnlyMapCreationId': _webOnlyMapCreationId, }; @@ -249,6 +256,7 @@ class _GoogleMapState extends State { _polygons = keyByPolygonId(widget.polygons); _polylines = keyByPolylineId(widget.polylines); _circles = keyByCircleId(widget.circles); + _tileOverlays = keyTileOverlayId(widget.tileOverlays); } @override @@ -266,6 +274,7 @@ class _GoogleMapState extends State { _updatePolygons(); _updatePolylines(); _updateCircles(); + _updateTileOverlays(); } void _updateOptions() async { @@ -313,6 +322,14 @@ class _GoogleMapState extends State { _circles = keyByCircleId(widget.circles); } + void _updateTileOverlays() async { + final GoogleMapController controller = await _controller.future; + // ignore: unawaited_futures + controller._updateTileOverlays(TileOverlayUpdates.from( + _tileOverlays.values.toSet(), widget.tileOverlays)); + _tileOverlays = keyTileOverlayId(widget.tileOverlays); + } + Future onPlatformViewCreated(int id) async { final GoogleMapController controller = await GoogleMapController.init( id, diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 31392354d946..9f84cdbfbbe5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -281,6 +281,40 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } + /// Updates tile overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + @override + Future updateTileOverlays( + TileOverlayUpdates tileOverlayUpdates, { + @required int mapId, + }) { + assert(tileOverlayUpdates != null); + return channel(mapId).invokeMethod( + 'tileOverlays#update', + tileOverlayUpdates.toJson(), + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The API maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + @required int mapId, + }) { + return channel(mapId) + .invokeMethod('tileOverlays#clearTileCache', { + 'tileOverlayId': tileOverlayId.value, + }); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index a4f487740811..b8a6002d7b12 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -115,6 +115,31 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { throw UnimplementedError('updateCircles() has not been implemented.'); } + /// Updates tile overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future updateTileOverlays( + TileOverlayUpdates tileOverlayUpdates, { + @required int mapId, + }) { + throw UnimplementedError('updateTileOverlays() has not been implemented.'); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The API maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + Future clearTileCache( + TileOverlayId tileOverlayId, { + @required int mapId, + }) { + throw UnimplementedError('clearTileCache() has not been implemented.'); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index 3e2002f80ae3..b872f2ff84ed 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -21,6 +21,7 @@ export 'polyline.dart'; export 'screen_coordinate.dart'; export 'tile.dart'; export 'tile_overlay.dart'; +export 'tile_overlay_updates.dart'; export 'tile_provider.dart'; export 'ui.dart'; From 510e7b54562ae28c608b23cc4a9c110545ed2dc3 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Sat, 28 Nov 2020 16:13:01 +0100 Subject: [PATCH 24/28] Fix example app compilation error --- .../google_maps_flutter/example/lib/main.dart | 2 ++ .../google_maps_flutter/example/lib/tile_overlay.dart | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart index 13763edb8216..b795040658e6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart @@ -20,6 +20,7 @@ import 'place_polygon.dart'; import 'place_polyline.dart'; import 'scrolling_map.dart'; import 'snapshot.dart'; +import 'tile_overlay.dart'; final List _allPages = [ MapUiPage(), @@ -36,6 +37,7 @@ final List _allPages = [ PaddingPage(), SnapshotPage(), LiteModePage(), + TileOverlayPage(), ]; class MapsDemo extends StatelessWidget { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart index 07f27bf7442c..ebcc2c233249 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -12,7 +12,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'page.dart'; -class TileOverlayPage extends Page { +class TileOverlayPage extends GoogleMapExampleAppPage { TileOverlayPage() : super(const Icon(Icons.map), 'Tile overlay'); @override From d6347d0079c72e438b18a6910fb90154253a2c71 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Sat, 28 Nov 2020 17:29:40 +0100 Subject: [PATCH 25/28] Fix getTile method --- .../lib/src/controller.dart | 2 ++ .../lib/src/google_map.dart | 19 +++++++++++++++++++ .../method_channel_google_maps_flutter.dart | 18 ++++++++++++++++++ .../google_maps_flutter_platform.dart | 10 ++++++++++ 4 files changed, 49 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index e1889a81f97f..764b484f756e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -18,6 +18,8 @@ class GoogleMapController { @required this.mapId, }) : assert(_googleMapsFlutterPlatform != null) { _connectStreams(mapId); + _googleMapsFlutterPlatform.setGetTileCallback( + mapId: mapId, callback: _googleMapState._onGetTile); } /// Initialize control of a [GoogleMap] with [id]. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index 6ba8590de8d7..37571f56a5b0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -393,6 +393,25 @@ class _GoogleMapState extends State { widget.onLongPress(position); } } + + // Returns the [Tile] from an added [TileOverlay]. + // + // If the TileOverlay or his TileProvider is not found, + // a [TileProvider.noTile] is returned. + Future _onGetTile( + String tileOverlayIdRaw, int x, int y, int zoom) async { + assert(tileOverlayIdRaw != null); + final TileOverlayId tileOverlayId = TileOverlayId(tileOverlayIdRaw); + final TileOverlay tileOverlay = _tileOverlays[tileOverlayId]; + Tile tile; + if (tileOverlay != null && tileOverlay.tileProvider != null) { + tile = await tileOverlay.tileProvider.getTile(x, y, zoom); + } + if (tile == null) { + tile = TileProvider.noTile; + } + return tile; + } } /// Configuration options for the GoogleMaps user interface. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 9f84cdbfbbe5..ba62d0e6ee77 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -33,6 +33,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return _channels[mapId]; } + // Keep a collection of id -> GetTileCallback + // Every method call passes the int mapId + final Map _getTileCallbacks = {}; + /// Initializes the platform interface with [id]. /// /// This method is called when the plugin is first initialized. @@ -184,6 +188,15 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { LatLng.fromJson(call.arguments['position']), )); break; + case 'tileOverlay#getTile': + final getTileCallback = _getTileCallbacks[mapId]; + final Tile tile = await getTileCallback( + call.arguments['tileOverlayId'], + call.arguments['x'], + call.arguments['y'], + call.arguments['zoom'], + ); + return tile.toJson(); default: throw MissingPluginException(); } @@ -485,6 +498,11 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return channel(mapId).invokeMethod('map#takeSnapshot'); } + @override + void setGetTileCallback({@required int mapId, MapGetTileCallback callback}) { + _getTileCallbacks[mapId] = callback; + } + /// This method builds the appropriate platform view where the map /// can be rendered. /// The `mapId` is passed as a parameter from the framework on the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index b8a6002d7b12..a5fd5d69807a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -15,6 +15,10 @@ import 'package:google_maps_flutter_platform_interface/src/method_channel/method import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +/// Callback method for when a [Tile] is requested from a [TileProvider] +typedef Future MapGetTileCallback( + String tileOverlayId, int x, int y, int zoom); + /// The interface that platform-specific implementations of `google_maps_flutter` must extend. /// /// Avoid `implements` of this interface. Using `implements` makes adding any new @@ -271,6 +275,12 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { throw UnimplementedError('takeSnapshot() has not been implemented.'); } + /// Set the [MapGetTileCallback] for the map, which will be called + /// when a [Tile] is requested for an added [TileProvider]. + void setGetTileCallback({@required int mapId, MapGetTileCallback callback}) { + throw UnimplementedError('onGetTile() has not been implemented.'); + } + // The following are the 11 possible streams of data from the native side // into the plugin From 4825de185cd6b45cb1c3400f509b7107a7713b73 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Sat, 28 Nov 2020 17:31:37 +0100 Subject: [PATCH 26/28] Use new pub google_maps_flutter_platform_interface package --- packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 6eeb12af30cd..52fdd40be361 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -7,8 +7,7 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: - path: ../google_maps_flutter_platform_interface + google_maps_flutter_platform_interface: ^1.0.6 dev_dependencies: flutter_test: From b8fb61e3f7f9debfbdd70dc056d90a4178f43156 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Sat, 28 Nov 2020 17:48:41 +0100 Subject: [PATCH 27/28] Revert "Use new pub google_maps_flutter_platform_interface package" This reverts commit 4825de18 --- packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 52fdd40be361..6eeb12af30cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -7,7 +7,8 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.0.6 + google_maps_flutter_platform_interface: + path: ../google_maps_flutter_platform_interface dev_dependencies: flutter_test: From 139bf05c03bce24fac40b1021742cc9991e71da8 Mon Sep 17 00:00:00 2001 From: NeoKree Date: Sat, 28 Nov 2020 18:04:23 +0100 Subject: [PATCH 28/28] Fix tile overlays not showed up before `onMapCreated` is called on iOS --- .../google_maps_flutter/ios/Classes/GoogleMapController.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m index 80fcedfd9346..c28cd3a39e4f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -114,6 +114,10 @@ - (instancetype)initWithFrame:(CGRect)frame if ([circlesToAdd isKindOfClass:[NSArray class]]) { [_circlesController addCircles:circlesToAdd]; } + id tileOverlaysToAdd = args[@"tileOverlaysToAdd"]; + if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { + [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; + } } return self; }