From 975f6ccbe647fe81a0e56822a340856f12df55a0 Mon Sep 17 00:00:00 2001 From: Joonas Kerttula Date: Thu, 17 Nov 2022 15:23:55 +0200 Subject: [PATCH 1/3] [google_maps_flutter] support to request a specific map renderer for android --- .../google_maps_flutter_android/CHANGELOG.md | 4 + .../google_maps_flutter_android/README.md | 23 ++++ .../plugins/googlemaps/GoogleMapFactory.java | 6 +- .../googlemaps/GoogleMapInitializer.java | 109 ++++++++++++++++++ .../plugins/googlemaps/GoogleMapsPlugin.java | 7 +- .../googlemaps/GoogleMapInitializerTest.java | 98 ++++++++++++++++ ..._maps_test.dart => google_maps_tests.dart} | 8 +- .../latest_renderer_test.dart | 41 +++++++ .../legacy_renderer_test.dart | 41 +++++++ .../example/lib/readme_excerpts.dart | 41 ++++++- .../lib/src/google_maps_flutter_android.dart | 72 ++++++++++++ .../google_maps_flutter_android/pubspec.yaml | 2 +- 12 files changed, 444 insertions(+), 8 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java rename packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/{google_maps_test.dart => google_maps_tests.dart} (99%) create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 9bc8b195f6e2..39482db8b950 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.0 + +* Adds the ability to request a specific map renderer. + ## 2.3.3 * Update android gradle plugin to 7.3.1. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/README.md b/packages/google_maps_flutter/google_maps_flutter_android/README.md index 877b9bbe9102..e07b0bc8d406 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/README.md @@ -48,7 +48,30 @@ Hybrid Composition, but currently [misses certain map updates][4]. This mode will likely become the default in future versions if/when the missed updates issue can be resolved. +## Map renderer + +This plugin supports the option to request a specific [map renderer][5]. + +The renderer must be requested before creating GoogleMap instances, as the renderer can be initialized only once per application context. + + +```dart +AndroidMapRenderer mapRenderer = AndroidMapRenderer.platformDefault; +// ยทยทยท + final GoogleMapsFlutterPlatform mapsImplementation = + GoogleMapsFlutterPlatform.instance; + if (mapsImplementation is GoogleMapsFlutterAndroid) { + WidgetsFlutterBinding.ensureInitialized(); + mapRenderer = await mapsImplementation + .initializeWithRenderer(AndroidMapRenderer.latest); + } +``` + +Available values are `AndroidMapRenderer.latest`, `AndroidMapRenderer.legacy`, `AndroidMapRenderer.platformDefault`. +Note that getting the requested renderer as a response is not guaranteed. + [1]: https://pub.dev/packages/google_maps_flutter [2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin [3]: https://docs.flutter.dev/development/platform-integration/android/platform-views [4]: https://github.com/flutter/flutter/issues/103686 +[5]: https://developers.google.com/maps/documentation/android-sdk/renderer diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index ca9ac184a76e..ffa2412f9c42 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -17,11 +17,15 @@ public class GoogleMapFactory extends PlatformViewFactory { private final BinaryMessenger binaryMessenger; private final LifecycleProvider lifecycleProvider; + private final GoogleMapInitializer googleMapInitializer; - GoogleMapFactory(BinaryMessenger binaryMessenger, LifecycleProvider lifecycleProvider) { + GoogleMapFactory( + BinaryMessenger binaryMessenger, Context context, LifecycleProvider lifecycleProvider) { super(StandardMessageCodec.INSTANCE); + this.binaryMessenger = binaryMessenger; this.lifecycleProvider = lifecycleProvider; + this.googleMapInitializer = new GoogleMapInitializer(context, binaryMessenger); } @SuppressWarnings("unchecked") diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java new file mode 100644 index 000000000000..a113c0a1c4c3 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java @@ -0,0 +1,109 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlemaps; + +import android.content.Context; +import androidx.annotation.VisibleForTesting; +import com.google.android.gms.maps.MapsInitializer; +import com.google.android.gms.maps.MapsInitializer.Renderer; +import com.google.android.gms.maps.OnMapsSdkInitializedCallback; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; + +/** GoogleMaps initializer used to initialize the Google Maps SDK with preferred settings. */ +final class GoogleMapInitializer + implements OnMapsSdkInitializedCallback, MethodChannel.MethodCallHandler { + private final MethodChannel methodChannel; + private final Context context; + private static MethodChannel.Result initializationResult; + private boolean rendererInitialized = false; + + GoogleMapInitializer(Context context, BinaryMessenger binaryMessenger) { + this.context = context; + + methodChannel = + new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_initializer"); + methodChannel.setMethodCallHandler(this); + } + + @Override + public void onMethodCall(MethodCall call, MethodChannel.Result result) { + switch (call.method) { + case "initializer#preferRenderer": + { + String preferredRenderer = (String) call.argument("value"); + initializeWithPreferredRenderer(preferredRenderer, result); + break; + } + default: + result.notImplemented(); + } + } + + /** + * Initializes map renderer to with preferred renderer type. Renderer can be initialized only once + * per application context. + * + *

Supported renderer types are "latest", "legacy" and "default". + */ + private void initializeWithPreferredRenderer( + String preferredRenderer, MethodChannel.Result result) { + if (rendererInitialized || initializationResult != null) { + result.error( + "Renderer already initialized", "Renderer initialization called multiple times", null); + } else { + initializationResult = result; + switch (preferredRenderer) { + case "latest": + initializeWithRendererRequest(Renderer.LATEST); + break; + case "legacy": + initializeWithRendererRequest(Renderer.LEGACY); + break; + case "default": + initializeWithRendererRequest(null); + break; + default: + initializationResult.error( + "Invalid renderer type", + "Renderer initialization called with invalid renderer type", + null); + initializationResult = null; + } + } + } + + /** + * Initializes map renderer to with preferred renderer type. + * + *

This method is visible for testing purposes only and should never be used outside this + * class. + */ + @VisibleForTesting + public void initializeWithRendererRequest(MapsInitializer.Renderer renderer) { + MapsInitializer.initialize(context, renderer, this); + } + + /** Is called by Google Maps SDK to determine which version of the renderer was initialized. */ + @Override + public void onMapsSdkInitialized(MapsInitializer.Renderer renderer) { + rendererInitialized = true; + if (initializationResult != null) { + switch (renderer) { + case LATEST: + initializationResult.success("latest"); + break; + case LEGACY: + initializationResult.success("legacy"); + break; + default: + initializationResult.error( + "Unknown renderer type", "Initialized with unknown renderer type", null); + } + initializationResult = null; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index 715b357566da..20fc15e72b6e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -46,6 +46,7 @@ public static void registerWith( VIEW_TYPE, new GoogleMapFactory( registrar.messenger(), + registrar.context(), new LifecycleProvider() { @Override public Lifecycle getLifecycle() { @@ -57,7 +58,10 @@ public Lifecycle getLifecycle() { .platformViewRegistry() .registerViewFactory( VIEW_TYPE, - new GoogleMapFactory(registrar.messenger(), new ProxyLifecycleProvider(activity))); + new GoogleMapFactory( + registrar.messenger(), + registrar.context(), + new ProxyLifecycleProvider(activity))); } } @@ -73,6 +77,7 @@ public void onAttachedToEngine(FlutterPluginBinding binding) { VIEW_TYPE, new GoogleMapFactory( binding.getBinaryMessenger(), + binding.getApplicationContext(), new LifecycleProvider() { @Nullable @Override diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java new file mode 100644 index 000000000000..2f9f5e5619fd --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java @@ -0,0 +1,98 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlemaps; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import com.google.android.gms.maps.MapsInitializer.Renderer; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import java.util.HashMap; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = Build.VERSION_CODES.P) +public class GoogleMapInitializerTest { + private GoogleMapInitializer googleMapInitializer; + + @Mock BinaryMessenger mockMessenger; + + @Before + public void before() { + MockitoAnnotations.openMocks(this); + Context context = ApplicationProvider.getApplicationContext(); + googleMapInitializer = spy(new GoogleMapInitializer(context, mockMessenger)); + } + + @Test + public void initializer_OnMapsSdkInitializedWithLatestRenderer() { + doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LATEST); + MethodChannel.Result result = mock(MethodChannel.Result.class); + googleMapInitializer.onMethodCall( + new MethodCall( + "initializer#preferRenderer", + new HashMap() { + { + put("value", "latest"); + } + }), + result); + googleMapInitializer.onMapsSdkInitialized(Renderer.LATEST); + verify(result, times(1)).success("latest"); + verify(result, never()).error(any(), any(), any()); + } + + @Test + public void initializer_OnMapsSdkInitializedWithLegacyRenderer() { + doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); + MethodChannel.Result result = mock(MethodChannel.Result.class); + googleMapInitializer.onMethodCall( + new MethodCall( + "initializer#preferRenderer", + new HashMap() { + { + put("value", "legacy"); + } + }), + result); + googleMapInitializer.onMapsSdkInitialized(Renderer.LEGACY); + verify(result, times(1)).success("legacy"); + verify(result, never()).error(any(), any(), any()); + } + + @Test + public void initializer_onMethodCallWithUnknownRenderer() { + doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); + MethodChannel.Result result = mock(MethodChannel.Result.class); + googleMapInitializer.onMethodCall( + new MethodCall( + "initializer#preferRenderer", + new HashMap() { + { + put("value", "wrong_renderer"); + } + }), + result); + verify(result, never()).success(any()); + verify(result, times(1)).error(eq("Invalid renderer type"), any(), any()); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart similarity index 99% rename from packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_test.dart rename to packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart index 0945740b1e45..bd72b7ba52d2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart @@ -12,15 +12,13 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; import 'package:google_maps_flutter_example/example_google_map.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; -import 'package:integration_test/integration_test.dart'; const LatLng _kInitialMapCenter = LatLng(0, 0); const double _kInitialZoomLevel = 5; const CameraPosition _kInitialCameraPosition = CameraPosition(target: _kInitialMapCenter, zoom: _kInitialZoomLevel); -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); +void googleMapsTests() { GoogleMapsFlutterPlatform.instance.enableDebugInspection(); // Repeatedly checks an asynchronous value against a test condition, waiting @@ -511,7 +509,9 @@ void main() { await waitForValueMatchingPredicate( tester, () => mapController.getVisibleRegion(), - (LatLngBounds bounds) => bounds != zeroLatLngBounds) ?? + (LatLngBounds bounds) => + bounds != zeroLatLngBounds && + bounds.northeast != bounds.southwest) ?? zeroLatLngBounds; expect(firstVisibleRegion, isNot(zeroLatLngBounds)); expect(firstVisibleRegion.contains(_kInitialMapCenter), isTrue); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart new file mode 100644 index 000000000000..25a15b1eee52 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart @@ -0,0 +1,41 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'google_maps_tests.dart' show googleMapsTests; + +void main() { + late AndroidMapRenderer initializedRenderer; + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + setUpAll(() async { + final GoogleMapsFlutterAndroid instance = + GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; + initializedRenderer = + await instance.initializeWithRenderer(AndroidMapRenderer.latest); + }); + + testWidgets('initialized with latest renderer', (WidgetTester _) async { + expect(initializedRenderer, AndroidMapRenderer.latest); + }); + + testWidgets('throws PlatformException on multiple renderer initializations', + (WidgetTester _) async { + final GoogleMapsFlutterAndroid instance = + GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; + expect( + () async => + await instance.initializeWithRenderer(AndroidMapRenderer.latest), + throwsA(isA().having((PlatformException e) => e.code, + 'code', 'Renderer already initialized'))); + }); + + // Run tests. + googleMapsTests(); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart new file mode 100644 index 000000000000..d7fd7e470cdf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart @@ -0,0 +1,41 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'google_maps_tests.dart' show googleMapsTests; + +void main() { + late AndroidMapRenderer initializedRenderer; + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + setUpAll(() async { + final GoogleMapsFlutterAndroid instance = + GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; + initializedRenderer = + await instance.initializeWithRenderer(AndroidMapRenderer.legacy); + }); + + testWidgets('initialized with legacy renderer', (WidgetTester _) async { + expect(initializedRenderer, AndroidMapRenderer.legacy); + }); + + testWidgets('throws PlatformException on multiple renderer initializations', + (WidgetTester _) async { + final GoogleMapsFlutterAndroid instance = + GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; + expect( + () async => + await instance.initializeWithRenderer(AndroidMapRenderer.legacy), + throwsA(isA().having((PlatformException e) => e.code, + 'code', 'Renderer already initialized'))); + }); + + // Run tests. + googleMapsTests(); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/readme_excerpts.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/readme_excerpts.dart index 5911c062e444..0f6b26de00b6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/readme_excerpts.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/readme_excerpts.dart @@ -2,6 +2,8 @@ // 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 'package:flutter/material.dart'; // #docregion DisplayMode import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; @@ -15,7 +17,44 @@ void main() { mapsImplementation.useAndroidViewSurface = true; } // #enddocregion DisplayMode - runApp(const MaterialApp()); + runApp(const MyApp()); // #docregion DisplayMode } // #enddocregion DisplayMode + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + // #docregion MapRenderer + AndroidMapRenderer mapRenderer = AndroidMapRenderer.platformDefault; + // #enddocregion MapRenderer + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('README snippet app'), + ), + body: const Text('See example in main.dart'), + ), + ); + } + + Future initializeLatestMapRenderer() async { + // #docregion MapRenderer + final GoogleMapsFlutterPlatform mapsImplementation = + GoogleMapsFlutterPlatform.instance; + if (mapsImplementation is GoogleMapsFlutterAndroid) { + WidgetsFlutterBinding.ensureInitialized(); + mapRenderer = await mapsImplementation + .initializeWithRenderer(AndroidMapRenderer.latest); + } + // #enddocregion MapRenderer + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 06c5bdcd7e0f..5cbe40d2d342 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -41,6 +41,19 @@ class UnknownMapIDError extends Error { } } +/// The possible android map renderer types that can be +/// requested from the native Google Maps SDK. +enum AndroidMapRenderer { + /// Latest renderer type. + latest, + + /// Legacy renderer type. + legacy, + + /// Requests the default map renderer type. + platformDefault, +} + /// An implementation of [GoogleMapsFlutterPlatform] for Android. class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { /// Registers the Android implementation of GoogleMapsFlutterPlatform. @@ -48,6 +61,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterAndroid(); } + /// The method channel used to initialize the native Google Maps SDK. + final MethodChannel _initializerChannel = const MethodChannel( + 'plugins.flutter.dev/google_maps_android_initializer'); + // Keep a collection of id -> channel // Every method call passes the int mapId final Map _channels = {}; @@ -480,6 +497,48 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { /// Currently defaults to true, but the default is subject to change. bool useAndroidViewSurface = true; + /// Requests Google Map Renderer with [AndroidMapRenderer] type. + /// + /// See https://pub.dev/packages/google_maps_flutter_android#map-renderer + /// for more information. + /// + /// The returned [Future] completes after renderer has been initialized. + /// Initialized [AndroidMapRenderer] type is returned. + Future initializeWithRenderer( + AndroidMapRenderer? rendererType) async { + String preferredRenderer; + switch (rendererType) { + case AndroidMapRenderer.latest: + preferredRenderer = 'latest'; + break; + case AndroidMapRenderer.legacy: + preferredRenderer = 'legacy'; + break; + case AndroidMapRenderer.platformDefault: + default: + preferredRenderer = 'default'; + } + + final String? initializedRenderer = await _initializerChannel + .invokeMethod('initializer#preferRenderer', + {'value': preferredRenderer}); + + if (initializedRenderer == null) { + throw AndroidMapRendererException('Failed to initialize map renderer.'); + } + + // Returns mapped [AndroidMapRenderer] enum type. + switch (initializedRenderer) { + case 'latest': + return AndroidMapRenderer.latest; + case 'legacy': + return AndroidMapRenderer.legacy; + default: + throw AndroidMapRendererException( + 'Failed to initialize latest or legacy renderer. Got $initializedRenderer'); + } + } + Widget _buildView( int creationId, PlatformViewCreatedCallback onPlatformViewCreated, { @@ -689,3 +748,16 @@ class _TileOverlayUpdates extends MapsObjectUpdates { /// Set of TileOverlays to be changed in this update. Set get tileOverlaysToChange => objectsToChange; } + +/// Thrown to indicate that a platform interaction failed to initialize renderer. +class AndroidMapRendererException implements Exception { + /// Creates a [AndroidMapRendererException] with an optional human-readable + /// error message. + AndroidMapRendererException([this.message]); + + /// A human-readable error message, possibly null. + final String? message; + + @override + String toString() => 'AndroidMapRendererException($message)'; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index d20322bc6ee1..bdf2f4165408 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.3.3 +version: 2.4.0 environment: sdk: ">=2.14.0 <3.0.0" From 44f33b1c8327909be453f40bc595888404c9c124 Mon Sep 17 00:00:00 2001 From: Joonas Kerttula Date: Thu, 17 Nov 2022 15:44:35 +0200 Subject: [PATCH 2/3] [google_maps_flutter] Minor fixes to comments and error messages --- .../lib/src/google_maps_flutter_android.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 5cbe40d2d342..11af3fe7f8df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -502,6 +502,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { /// See https://pub.dev/packages/google_maps_flutter_android#map-renderer /// for more information. /// + /// The renderer must be requested before creating GoogleMap instances as the + /// renderer can be initialized only once per application context. + /// Throws a [PlatformException] if method is called multiple times. + /// /// The returned [Future] completes after renderer has been initialized. /// Initialized [AndroidMapRenderer] type is returned. Future initializeWithRenderer( @@ -535,7 +539,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return AndroidMapRenderer.legacy; default: throw AndroidMapRendererException( - 'Failed to initialize latest or legacy renderer. Got $initializedRenderer'); + 'Failed to initialize latest or legacy renderer, got $initializedRenderer.'); } } From c6373175d9aa1a64b57aaec5f6cab2559fd0fca3 Mon Sep 17 00:00:00 2001 From: Joonas Kerttula Date: Wed, 23 Nov 2022 11:32:33 +0200 Subject: [PATCH 3/3] [google_maps_flutter] fix linting issues --- .../example/integration_test/latest_renderer_test.dart | 3 +-- .../example/integration_test/legacy_renderer_test.dart | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart index 25a15b1eee52..64bff8f6c616 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/latest_renderer_test.dart @@ -30,8 +30,7 @@ void main() { final GoogleMapsFlutterAndroid instance = GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; expect( - () async => - await instance.initializeWithRenderer(AndroidMapRenderer.latest), + () async => instance.initializeWithRenderer(AndroidMapRenderer.latest), throwsA(isA().having((PlatformException e) => e.code, 'code', 'Renderer already initialized'))); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart index d7fd7e470cdf..95b1134d566f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/legacy_renderer_test.dart @@ -30,8 +30,7 @@ void main() { final GoogleMapsFlutterAndroid instance = GoogleMapsFlutterPlatform.instance as GoogleMapsFlutterAndroid; expect( - () async => - await instance.initializeWithRenderer(AndroidMapRenderer.legacy), + () async => instance.initializeWithRenderer(AndroidMapRenderer.legacy), throwsA(isA().having((PlatformException e) => e.code, 'code', 'Renderer already initialized'))); });