Skip to content

Commit 1a5113e

Browse files
Chris YangEgor
authored andcommitted
[google_maps_flutter] supports v2 android embedding. (flutter#2488)
1 parent 2169f13 commit 1a5113e

File tree

18 files changed

+408
-88
lines changed

18 files changed

+408
-88
lines changed

packages/google_maps_flutter/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.5.22
2+
3+
* Support Android v2 embedding.
4+
* Bump the min flutter version to `1.12.13+hotfix.5`.
5+
* Fixes some e2e tests on Android.
6+
17
## 0.5.21+17
28

39
* Fix Swift example in README.md.

packages/google_maps_flutter/android/build.gradle

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,8 @@ android {
3434

3535
dependencies {
3636
implementation 'com.google.android.gms:play-services-maps:17.0.0'
37+
androidTestImplementation 'androidx.test:runner:1.2.0'
38+
androidTestImplementation 'androidx.test:rules:1.2.0'
39+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
3740
}
3841
}
39-
40-
// TODO(cyanglaz): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348
41-
afterEvaluate {
42-
def containsEmbeddingDependencies = false
43-
for (def configuration : configurations.all) {
44-
for (def dependency : configuration.dependencies) {
45-
if (dependency.group == 'io.flutter' &&
46-
dependency.name.startsWith('flutter_embedding') &&
47-
dependency.isTransitive())
48-
{
49-
containsEmbeddingDependencies = true
50-
break
51-
}
52-
}
53-
}
54-
if (!containsEmbeddingDependencies) {
55-
android {
56-
dependencies {
57-
def lifecycle_version = "1.1.1"
58-
compileOnly "android.arch.lifecycle:runtime:$lifecycle_version"
59-
compileOnly "android.arch.lifecycle:common:$lifecycle_version"
60-
compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version"
61-
}
62-
}
63-
}
64-
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
org.gradle.jvmargs=-Xmx1536M
2+
android.enableR8=true
3+
android.useAndroidX=true
4+
android.enableJetifier=true

packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
package io.flutter.plugins.googlemaps;
66

7+
import android.app.Application;
78
import android.content.Context;
89
import android.graphics.Rect;
10+
import androidx.lifecycle.Lifecycle;
911
import com.google.android.gms.maps.GoogleMapOptions;
1012
import com.google.android.gms.maps.model.CameraPosition;
1113
import com.google.android.gms.maps.model.LatLngBounds;
14+
import io.flutter.plugin.common.BinaryMessenger;
1215
import io.flutter.plugin.common.PluginRegistry;
1316
import java.util.concurrent.atomic.AtomicInteger;
1417

@@ -27,9 +30,25 @@ class GoogleMapBuilder implements GoogleMapOptionsSink {
2730
private Rect padding = new Rect(0, 0, 0, 0);
2831

2932
GoogleMapController build(
30-
int id, Context context, AtomicInteger state, PluginRegistry.Registrar registrar) {
33+
int id,
34+
Context context,
35+
AtomicInteger state,
36+
BinaryMessenger binaryMessenger,
37+
Application application,
38+
Lifecycle lifecycle,
39+
PluginRegistry.Registrar registrar,
40+
int activityHashCode) {
3141
final GoogleMapController controller =
32-
new GoogleMapController(id, context, state, registrar, options);
42+
new GoogleMapController(
43+
id,
44+
context,
45+
state,
46+
binaryMessenger,
47+
application,
48+
lifecycle,
49+
registrar,
50+
activityHashCode,
51+
options);
3352
controller.init();
3453
controller.setMyLocationEnabled(myLocationEnabled);
3554
controller.setMyLocationButtonEnabled(myLocationButtonEnabled);

packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java

Lines changed: 123 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import android.os.Bundle;
2222
import android.util.Log;
2323
import android.view.View;
24+
import androidx.annotation.NonNull;
25+
import androidx.lifecycle.DefaultLifecycleObserver;
26+
import androidx.lifecycle.Lifecycle;
27+
import androidx.lifecycle.LifecycleOwner;
2428
import com.google.android.gms.maps.CameraUpdate;
2529
import com.google.android.gms.maps.GoogleMap;
2630
import com.google.android.gms.maps.GoogleMapOptions;
@@ -34,6 +38,8 @@
3438
import com.google.android.gms.maps.model.Marker;
3539
import com.google.android.gms.maps.model.Polygon;
3640
import com.google.android.gms.maps.model.Polyline;
41+
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
42+
import io.flutter.plugin.common.BinaryMessenger;
3743
import io.flutter.plugin.common.MethodCall;
3844
import io.flutter.plugin.common.MethodChannel;
3945
import io.flutter.plugin.common.PluginRegistry;
@@ -48,6 +54,8 @@
4854
/** Controller of a single GoogleMaps MapView instance. */
4955
final class GoogleMapController
5056
implements Application.ActivityLifecycleCallbacks,
57+
DefaultLifecycleObserver,
58+
ActivityPluginBinding.OnSaveInstanceStateListener,
5159
GoogleMap.OnCameraIdleListener,
5260
GoogleMap.OnCameraMoveListener,
5361
GoogleMap.OnCameraMoveStartedListener,
@@ -68,7 +76,6 @@ final class GoogleMapController
6876
private final int id;
6977
private final AtomicInteger activityState;
7078
private final MethodChannel methodChannel;
71-
private final PluginRegistry.Registrar registrar;
7279
private final MapView mapView;
7380
private GoogleMap googleMap;
7481
private boolean trackCameraPosition = false;
@@ -80,8 +87,13 @@ final class GoogleMapController
8087
private boolean disposed = false;
8188
private final float density;
8289
private MethodChannel.Result mapReadyResult;
83-
private final int registrarActivityHashCode;
90+
private final int
91+
activityHashCode; // Do not use directly, use getActivityHashCode() instead to get correct hashCode for both v1 and v2 embedding.
92+
private final Lifecycle lifecycle;
8493
private final Context context;
94+
private final Application
95+
mApplication; // Do not use direclty, use getApplication() instead to get correct application object for both v1 and v2 embedding.
96+
private final PluginRegistry.Registrar registrar; // For v1 embedding only.
8597
private final MarkersController markersController;
8698
private final PolygonsController polygonsController;
8799
private final PolylinesController polylinesController;
@@ -95,18 +107,23 @@ final class GoogleMapController
95107
int id,
96108
Context context,
97109
AtomicInteger activityState,
110+
BinaryMessenger binaryMessenger,
111+
Application application,
112+
Lifecycle lifecycle,
98113
PluginRegistry.Registrar registrar,
114+
int registrarActivityHashCode,
99115
GoogleMapOptions options) {
100116
this.id = id;
101117
this.context = context;
102118
this.activityState = activityState;
103-
this.registrar = registrar;
104119
this.mapView = new MapView(context, options);
105120
this.density = context.getResources().getDisplayMetrics().density;
106-
methodChannel =
107-
new MethodChannel(registrar.messenger(), "plugins.flutter.io/google_maps_" + id);
121+
methodChannel = new MethodChannel(binaryMessenger, "plugins.flutter.io/google_maps_" + id);
108122
methodChannel.setMethodCallHandler(this);
109-
this.registrarActivityHashCode = registrar.activity().hashCode();
123+
mApplication = application;
124+
this.lifecycle = lifecycle;
125+
this.registrar = registrar;
126+
this.activityHashCode = registrarActivityHashCode;
110127
this.markersController = new MarkersController(methodChannel);
111128
this.polygonsController = new PolygonsController(methodChannel);
112129
this.polylinesController = new PolylinesController(methodChannel, density);
@@ -152,7 +169,11 @@ void init() {
152169
throw new IllegalArgumentException(
153170
"Cannot interpret " + activityState.get() + " as an activity state");
154171
}
155-
registrar.activity().getApplication().registerActivityLifecycleCallbacks(this);
172+
if (lifecycle != null) {
173+
lifecycle.addObserver(this);
174+
} else {
175+
getApplication().registerActivityLifecycleCallbacks(this);
176+
}
156177
mapView.getMapAsync(this);
157178
}
158179

@@ -368,6 +389,10 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
368389
result.success(googleMap.isBuildingsEnabled());
369390
break;
370391
}
392+
case "map#getZoomLevel":
393+
{
394+
result.success(googleMap.getCameraPosition().zoom);
395+
}
371396
case "map#setStyle":
372397
{
373398
String mapStyle = (String) call.arguments;
@@ -472,7 +497,7 @@ public void dispose() {
472497
disposed = true;
473498
methodChannel.setMethodCallHandler(null);
474499
mapView.onDestroy();
475-
registrar.activity().getApplication().unregisterActivityLifecycleCallbacks(this);
500+
getApplication().unregisterActivityLifecycleCallbacks(this);
476501
}
477502

478503
// @Override
@@ -489,62 +514,129 @@ public void onInputConnectionUnlocked() {
489514
// TODO(mklim): Remove this empty override once https://github.com/flutter/flutter/issues/40126 is fixed in stable.
490515
};
491516

517+
// Application.ActivityLifecycleCallbacks methods
492518
@Override
493519
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
494-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
520+
if (disposed || activity.hashCode() != getActivityHashCode()) {
495521
return;
496522
}
497523
mapView.onCreate(savedInstanceState);
498524
}
499525

500526
@Override
501527
public void onActivityStarted(Activity activity) {
502-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
528+
if (disposed || activity.hashCode() != getActivityHashCode()) {
503529
return;
504530
}
505531
mapView.onStart();
506532
}
507533

508534
@Override
509535
public void onActivityResumed(Activity activity) {
510-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
536+
if (disposed || activity.hashCode() != getActivityHashCode()) {
511537
return;
512538
}
513539
mapView.onResume();
514540
}
515541

516542
@Override
517543
public void onActivityPaused(Activity activity) {
518-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
544+
if (disposed || activity.hashCode() != getActivityHashCode()) {
519545
return;
520546
}
521547
mapView.onPause();
522548
}
523549

524550
@Override
525551
public void onActivityStopped(Activity activity) {
526-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
552+
if (disposed || activity.hashCode() != getActivityHashCode()) {
527553
return;
528554
}
529555
mapView.onStop();
530556
}
531557

532558
@Override
533559
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
534-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
560+
if (disposed || activity.hashCode() != getActivityHashCode()) {
535561
return;
536562
}
537563
mapView.onSaveInstanceState(outState);
538564
}
539565

540566
@Override
541567
public void onActivityDestroyed(Activity activity) {
542-
if (disposed || activity.hashCode() != registrarActivityHashCode) {
568+
if (disposed || activity.hashCode() != getActivityHashCode()) {
569+
return;
570+
}
571+
mapView.onDestroy();
572+
}
573+
574+
// DefaultLifecycleObserver and OnSaveInstanceStateListener
575+
576+
@Override
577+
public void onCreate(@NonNull LifecycleOwner owner) {
578+
if (disposed) {
579+
return;
580+
}
581+
mapView.onCreate(null);
582+
}
583+
584+
@Override
585+
public void onStart(@NonNull LifecycleOwner owner) {
586+
if (disposed) {
587+
return;
588+
}
589+
mapView.onStart();
590+
}
591+
592+
@Override
593+
public void onResume(@NonNull LifecycleOwner owner) {
594+
if (disposed) {
595+
return;
596+
}
597+
mapView.onResume();
598+
}
599+
600+
@Override
601+
public void onPause(@NonNull LifecycleOwner owner) {
602+
if (disposed) {
603+
return;
604+
}
605+
mapView.onResume();
606+
}
607+
608+
@Override
609+
public void onStop(@NonNull LifecycleOwner owner) {
610+
if (disposed) {
611+
return;
612+
}
613+
mapView.onStop();
614+
}
615+
616+
@Override
617+
public void onDestroy(@NonNull LifecycleOwner owner) {
618+
if (disposed) {
543619
return;
544620
}
545621
mapView.onDestroy();
546622
}
547623

624+
@Override
625+
public void onRestoreInstanceState(Bundle bundle) {
626+
if (disposed) {
627+
return;
628+
}
629+
mapView.onCreate(bundle);
630+
}
631+
632+
@Override
633+
public void onSaveInstanceState(Bundle bundle) {
634+
if (disposed) {
635+
return;
636+
}
637+
mapView.onSaveInstanceState(bundle);
638+
}
639+
548640
// GoogleMapOptionsSink methods
549641

550642
@Override
@@ -716,6 +808,22 @@ private int checkSelfPermission(String permission) {
716808
permission, android.os.Process.myPid(), android.os.Process.myUid());
717809
}
718810

811+
private int getActivityHashCode() {
812+
if (registrar != null && registrar.activity() != null) {
813+
return registrar.activity().hashCode();
814+
} else {
815+
return activityHashCode;
816+
}
817+
}
818+
819+
private Application getApplication() {
820+
if (registrar != null && registrar.activity() != null) {
821+
return registrar.activity().getApplication();
822+
} else {
823+
return mApplication;
824+
}
825+
}
826+
719827
public void setIndoorEnabled(boolean indoorEnabled) {
720828
this.indoorEnabled = indoorEnabled;
721829
}

0 commit comments

Comments
 (0)