diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 5135fdd6e2e2..afe8638e0fe1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.0.4 + +* Cleanup of Android code: +* A few minor formatting changes and additions of `@Nullable` annotations. +* Removed pass-through of `activityHashCode` to `GoogleMapController`. +* Replaced custom lifecycle state ints with `androidx.lifecycle.Lifecycle.State` enum. +* Fixed a bug where the Lifecycle object was being leaked `onDetachFromActivity`, by nulling out the field. +* Moved GoogleMapListener to its own file. Declaring multiple top level classes in the same file is discouraged. + ## 1.0.3 * Update android compileSdkVersion to 29. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter/android/build.gradle index f12e3f211131..a1d7da08a8d9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.5.0' } } @@ -33,6 +33,7 @@ android { } dependencies { + implementation "androidx.annotation:annotation:1.1.0" implementation 'com.google.android.gms:play-services-maps:17.0.0' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 97af63c9f63b..ca47be87f049 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -7,13 +7,14 @@ import android.app.Application; import android.content.Context; import android.graphics.Rect; +import androidx.annotation.Nullable; import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle.State; import com.google.android.gms.maps.GoogleMapOptions; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLngBounds; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.PluginRegistry; -import java.util.concurrent.atomic.AtomicInteger; class GoogleMapBuilder implements GoogleMapOptionsSink { private final GoogleMapOptions options = new GoogleMapOptions(); @@ -32,24 +33,15 @@ class GoogleMapBuilder implements GoogleMapOptionsSink { GoogleMapController build( int id, Context context, - AtomicInteger state, + State lifecycleState, BinaryMessenger binaryMessenger, - Application application, - Lifecycle lifecycle, - PluginRegistry.Registrar registrar, - int activityHashCode) { + @Nullable Application application, + @Nullable Lifecycle lifecycle, + @Nullable PluginRegistry.Registrar registrar) { final GoogleMapController controller = new GoogleMapController( - id, - context, - state, - binaryMessenger, - application, - lifecycle, - registrar, - activityHashCode, - options); - controller.init(); + id, context, binaryMessenger, application, lifecycle, registrar, options); + controller.init(lifecycleState); controller.setMyLocationEnabled(myLocationEnabled); controller.setMyLocationButtonEnabled(myLocationButtonEnabled); controller.setIndoorEnabled(indoorEnabled); diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 58e8bb073bb7..ea3322d4f3e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -4,13 +4,6 @@ package io.flutter.plugins.googlemaps; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.CREATED; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.DESTROYED; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.PAUSED; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.RESUMED; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.STARTED; -import static io.flutter.plugins.googlemaps.GoogleMapsPlugin.STOPPED; - import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; @@ -26,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle.State; import androidx.lifecycle.LifecycleOwner; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.GoogleMap; @@ -53,7 +47,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; /** Controller of a single GoogleMaps MapView instance. */ final class GoogleMapController @@ -68,7 +61,6 @@ final class GoogleMapController private static final String TAG = "GoogleMapController"; private final int id; - private final AtomicInteger activityState; private final MethodChannel methodChannel; private final GoogleMapOptions options; @Nullable private MapView mapView; @@ -83,13 +75,12 @@ final class GoogleMapController private boolean disposed = false; private final float density; private MethodChannel.Result mapReadyResult; - private final int - activityHashCode; // Do not use directly, use getActivityHashCode() instead to get correct hashCode for both v1 and v2 embedding. - private final Lifecycle lifecycle; + @Nullable private final Lifecycle lifecycle; private final Context context; - private final Application - mApplication; // Do not use direclty, use getApplication() instead to get correct application object for both v1 and v2 embedding. - private final PluginRegistry.Registrar registrar; // For v1 embedding only. + // Do not use directly, use getApplication() instead to get correct application object for both v1 + // and v2 embedding. + @Nullable private final Application mApplication; + @Nullable private final PluginRegistry.Registrar registrar; // For v1 embedding only. private final MarkersController markersController; private final PolygonsController polygonsController; private final PolylinesController polylinesController; @@ -102,16 +93,13 @@ final class GoogleMapController GoogleMapController( int id, Context context, - AtomicInteger activityState, BinaryMessenger binaryMessenger, - Application application, - Lifecycle lifecycle, - PluginRegistry.Registrar registrar, - int registrarActivityHashCode, + @Nullable Application application, + @Nullable Lifecycle lifecycle, + @Nullable PluginRegistry.Registrar registrar, GoogleMapOptions options) { this.id = id; this.context = context; - this.activityState = activityState; this.options = options; this.mapView = new MapView(context, options); this.density = context.getResources().getDisplayMetrics().density; @@ -120,7 +108,6 @@ final class GoogleMapController mApplication = application; this.lifecycle = lifecycle; this.registrar = registrar; - this.activityHashCode = registrarActivityHashCode; this.markersController = new MarkersController(methodChannel); this.polygonsController = new PolygonsController(methodChannel, density); this.polylinesController = new PolylinesController(methodChannel, density); @@ -132,21 +119,8 @@ public View getView() { return mapView; } - void init() { - switch (activityState.get()) { - case STOPPED: - mapView.onCreate(null); - mapView.onStart(); - mapView.onResume(); - mapView.onPause(); - mapView.onStop(); - break; - case PAUSED: - mapView.onCreate(null); - mapView.onStart(); - mapView.onResume(); - mapView.onPause(); - break; + void init(State lifecycleState) { + switch (lifecycleState) { case RESUMED: mapView.onCreate(null); mapView.onStart(); @@ -160,11 +134,9 @@ void init() { mapView.onCreate(null); break; case DESTROYED: - // Nothing to do, the activity has been completely destroyed. + case INITIALIZED: + // Nothing to do, the activity has been completely destroyed or not yet created. break; - default: - throw new IllegalArgumentException( - "Cannot interpret " + activityState.get() + " as an activity state"); } if (lifecycle != null) { lifecycle.addObserver(this); @@ -556,14 +528,14 @@ private void setGoogleMapListener(@Nullable GoogleMapListener listener) { // does. This will override it when available even with the annotation commented out. public void onInputConnectionLocked() { // TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable. - }; + } // @Override // The minimum supported version of Flutter doesn't have this method on the PlatformView interface, but the maximum // does. This will override it when available even with the annotation commented out. public void onInputConnectionUnlocked() { // TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable. - }; + } // Application.ActivityLifecycleCallbacks methods @Override @@ -880,7 +852,9 @@ private int getActivityHashCode() { if (registrar != null && registrar.activity() != null) { return registrar.activity().hashCode(); } else { - return activityHashCode; + // TODO(cyanglaz): Remove `getActivityHashCode()` and use a cached hashCode when creating the view for V1 embedding. + // https://github.com/flutter/flutter/issues/69128 + return -1; } } @@ -916,16 +890,3 @@ public void setBuildingsEnabled(boolean buildingsEnabled) { this.buildingsEnabled = buildingsEnabled; } } - -interface GoogleMapListener - extends GoogleMap.OnCameraIdleListener, - GoogleMap.OnCameraMoveListener, - GoogleMap.OnCameraMoveStartedListener, - GoogleMap.OnInfoWindowClickListener, - GoogleMap.OnMarkerClickListener, - GoogleMap.OnPolygonClickListener, - GoogleMap.OnPolylineClickListener, - GoogleMap.OnCircleClickListener, - GoogleMap.OnMapClickListener, - GoogleMap.OnMapLongClickListener, - GoogleMap.OnMarkerDragListener {} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index b6bc7e5d4c45..7d665d4e2377 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -6,7 +6,9 @@ import android.app.Application; import android.content.Context; +import androidx.annotation.Nullable; import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle.State; import com.google.android.gms.maps.model.CameraPosition; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.PluginRegistry; @@ -14,29 +16,26 @@ import io.flutter.plugin.platform.PlatformView; import io.flutter.plugin.platform.PlatformViewFactory; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; public class GoogleMapFactory extends PlatformViewFactory { - private final AtomicInteger mActivityState; + private final AtomicReference lifecycleState; private final BinaryMessenger binaryMessenger; - private final Application application; - private final int activityHashCode; - private final Lifecycle lifecycle; - private final PluginRegistry.Registrar registrar; // V1 embedding only. + @Nullable private final Application application; + @Nullable private final Lifecycle lifecycle; + @Nullable private final PluginRegistry.Registrar registrar; // V1 embedding only. GoogleMapFactory( - AtomicInteger state, + AtomicReference lifecycleState, BinaryMessenger binaryMessenger, - Application application, - Lifecycle lifecycle, - PluginRegistry.Registrar registrar, - int activityHashCode) { + @Nullable Application application, + @Nullable Lifecycle lifecycle, + @Nullable PluginRegistry.Registrar registrar) { super(StandardMessageCodec.INSTANCE); - mActivityState = state; + this.lifecycleState = lifecycleState; this.binaryMessenger = binaryMessenger; this.application = application; - this.activityHashCode = activityHashCode; this.lifecycle = lifecycle; this.registrar = registrar; } @@ -65,13 +64,6 @@ public PlatformView create(Context context, int id, Object args) { builder.setInitialCircles(params.get("circlesToAdd")); } return builder.build( - id, - context, - mActivityState, - binaryMessenger, - application, - lifecycle, - registrar, - activityHashCode); + id, context, lifecycleState.get(), binaryMessenger, application, lifecycle, registrar); } } diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java new file mode 100644 index 000000000000..518d45c4a9f6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java @@ -0,0 +1,20 @@ +// 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. + +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.GoogleMap; + +interface GoogleMapListener + extends GoogleMap.OnCameraIdleListener, + GoogleMap.OnCameraMoveListener, + GoogleMap.OnCameraMoveStartedListener, + GoogleMap.OnInfoWindowClickListener, + GoogleMap.OnMarkerClickListener, + GoogleMap.OnPolygonClickListener, + GoogleMap.OnPolylineClickListener, + GoogleMap.OnCircleClickListener, + GoogleMap.OnMapClickListener, + GoogleMap.OnMapLongClickListener, + GoogleMap.OnMarkerDragListener {} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index f434a05bf1b7..811ea97e4b80 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -4,18 +4,25 @@ package io.flutter.plugins.googlemaps; +import static androidx.lifecycle.Lifecycle.State.CREATED; +import static androidx.lifecycle.Lifecycle.State.DESTROYED; +import static androidx.lifecycle.Lifecycle.State.INITIALIZED; +import static androidx.lifecycle.Lifecycle.State.RESUMED; +import static androidx.lifecycle.Lifecycle.State.STARTED; + import android.app.Activity; import android.app.Application; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.Lifecycle.State; import androidx.lifecycle.LifecycleOwner; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Plugin for controlling a set of GoogleMap views to be shown as overlays on top of the Flutter @@ -28,13 +35,7 @@ public class GoogleMapsPlugin FlutterPlugin, ActivityAware, DefaultLifecycleObserver { - static final int CREATED = 1; - static final int STARTED = 2; - static final int RESUMED = 3; - static final int PAUSED = 4; - static final int STOPPED = 5; - static final int DESTROYED = 6; - private final AtomicInteger state = new AtomicInteger(0); + private final AtomicReference state = new AtomicReference<>(INITIALIZED); private int registrarActivityHashCode; private FlutterPluginBinding pluginBinding; private Lifecycle lifecycle; @@ -54,11 +55,15 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra .platformViewRegistry() .registerViewFactory( VIEW_TYPE, - new GoogleMapFactory(plugin.state, registrar.messenger(), null, null, registrar, -1)); + new GoogleMapFactory(plugin.state, registrar.messenger(), null, null, registrar)); } public GoogleMapsPlugin() {} + private GoogleMapsPlugin(Activity activity) { + this.registrarActivityHashCode = activity.hashCode(); + } + // FlutterPlugin @Override @@ -86,13 +91,13 @@ public void onAttachedToActivity(ActivityPluginBinding binding) { pluginBinding.getBinaryMessenger(), binding.getActivity().getApplication(), lifecycle, - null, - binding.getActivity().hashCode())); + null)); } @Override public void onDetachedFromActivity() { lifecycle.removeObserver(this); + lifecycle = null; } @Override @@ -125,12 +130,12 @@ public void onResume(@NonNull LifecycleOwner owner) { @Override public void onPause(@NonNull LifecycleOwner owner) { - state.set(PAUSED); + state.set(STARTED); } @Override public void onStop(@NonNull LifecycleOwner owner) { - state.set(STOPPED); + state.set(CREATED); } @Override @@ -169,7 +174,7 @@ public void onActivityPaused(Activity activity) { if (activity.hashCode() != registrarActivityHashCode) { return; } - state.set(PAUSED); + state.set(STARTED); } @Override @@ -177,7 +182,7 @@ public void onActivityStopped(Activity activity) { if (activity.hashCode() != registrarActivityHashCode) { return; } - state.set(STOPPED); + state.set(CREATED); } @Override @@ -191,8 +196,4 @@ public void onActivityDestroyed(Activity activity) { activity.getApplication().unregisterActivityLifecycleCallbacks(this); state.set(DESTROYED); } - - private GoogleMapsPlugin(Activity activity) { - this.registrarActivityHashCode = activity.hashCode(); - } } diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java index 04b5f6fd3793..09f0c78da74a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java @@ -5,11 +5,11 @@ import android.app.Application; import android.content.Context; +import androidx.lifecycle.Lifecycle.State; import androidx.lifecycle.LifecycleOwner; import androidx.test.core.app.ApplicationProvider; import com.google.android.gms.maps.GoogleMap; import io.flutter.plugin.common.BinaryMessenger; -import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,9 +34,8 @@ public void before() { context = ApplicationProvider.getApplicationContext(); application = ApplicationProvider.getApplicationContext(); googleMapController = - new GoogleMapController( - 0, context, new AtomicInteger(1), mockMessenger, application, null, null, 0, null); - googleMapController.init(); + new GoogleMapController(0, context, mockMessenger, application, null, null, null); + googleMapController.init(State.CREATED); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 5a9aae8fedef..1c6ba4a94871 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: 1.0.3 +version: 1.0.4 dependencies: flutter: