Skip to content

Commit 221eb21

Browse files
authored
[google_maps_flutter] Android cluster pin info window onTap callback not firing (#11390)
As described in flutter/flutter#184338, Google Maps Flutter Android has an issue where the cluster pin info window doesn't fire the `onTap` callback. That's the info window that shows when you tap a clustered pin (a pin which is part of a cluster manager). While the info window shows properly, the `onTap` doesn't fire in Android, but properly fires in other platforms. Fixes flutter/flutter#184338 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent d9a2050 commit 221eb21

6 files changed

Lines changed: 76 additions & 5 deletions

File tree

packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.19.6
2+
3+
* Fixes the onTap callback for clustered pin info window taps.
4+
15
## 2.19.5
26

37
* Fixes a crash when using the legacy map renderer by adding the `org.apache.http.legacy` library.

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ class ClusterManagersController
4646
@Nullable
4747
private ClusterManager.OnClusterItemClickListener<MarkerBuilder> clusterItemClickListener;
4848

49+
@Nullable
50+
private ClusterManager.OnClusterItemInfoWindowClickListener<MarkerBuilder>
51+
clusterItemInfoWindowClickListener;
52+
4953
@Nullable
5054
private ClusterManagersController.OnClusterItemRendered<MarkerBuilder>
5155
clusterItemRenderedListener;
@@ -71,6 +75,12 @@ void setClusterItemClickListener(
7175
initListenersForClusterManagers();
7276
}
7377

78+
void setClusterItemInfoWindowClickListener(
79+
@Nullable ClusterManager.OnClusterItemInfoWindowClickListener<MarkerBuilder> listener) {
80+
clusterItemInfoWindowClickListener = listener;
81+
initListenersForClusterManagers();
82+
}
83+
7484
void setClusterItemRenderedListener(
7585
@Nullable ClusterManagersController.OnClusterItemRendered<MarkerBuilder> listener) {
7686
clusterItemRenderedListener = listener;
@@ -79,16 +89,21 @@ void setClusterItemRenderedListener(
7989
private void initListenersForClusterManagers() {
8090
for (Map.Entry<String, ClusterManager<MarkerBuilder>> entry :
8191
clusterManagerIdToManager.entrySet()) {
82-
initListenersForClusterManager(entry.getValue(), this, clusterItemClickListener);
92+
initListenersForClusterManager(
93+
entry.getValue(), this, clusterItemClickListener, clusterItemInfoWindowClickListener);
8394
}
8495
}
8596

8697
private void initListenersForClusterManager(
8798
ClusterManager<MarkerBuilder> clusterManager,
8899
@Nullable ClusterManager.OnClusterClickListener<MarkerBuilder> clusterClickListener,
89-
@Nullable ClusterManager.OnClusterItemClickListener<MarkerBuilder> clusterItemClickListener) {
100+
@Nullable ClusterManager.OnClusterItemClickListener<MarkerBuilder> clusterItemClickListener,
101+
@Nullable
102+
ClusterManager.OnClusterItemInfoWindowClickListener<MarkerBuilder>
103+
clusterItemInfoWindowClickListener) {
90104
clusterManager.setOnClusterClickListener(clusterClickListener);
91105
clusterManager.setOnClusterItemClickListener(clusterItemClickListener);
106+
clusterManager.setOnClusterItemInfoWindowClickListener(clusterItemInfoWindowClickListener);
92107
}
93108

94109
/** Adds new ClusterManagers to the controller. */
@@ -123,7 +138,8 @@ private void initializeRenderer(ClusterManager<MarkerBuilder> clusterManager) {
123138
break;
124139
}
125140
clusterManager.setRenderer(clusterRenderer);
126-
initListenersForClusterManager(clusterManager, this, clusterItemClickListener);
141+
initListenersForClusterManager(
142+
clusterManager, this, clusterItemClickListener, clusterItemInfoWindowClickListener);
127143
}
128144

129145
/** Removes ClusterManagers by given cluster manager IDs from the controller. */
@@ -145,7 +161,7 @@ private void removeClusterManager(Object clusterManagerId) {
145161
if (clusterManager == null) {
146162
return;
147163
}
148-
initListenersForClusterManager(clusterManager, null, null);
164+
initListenersForClusterManager(clusterManager, null, null, null);
149165
clusterManager.clearItems();
150166
clusterManager.cluster();
151167
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
class GoogleMapController
6363
implements ActivityPluginBinding.OnSaveInstanceStateListener,
6464
ClusterManager.OnClusterItemClickListener<MarkerBuilder>,
65+
ClusterManager.OnClusterItemInfoWindowClickListener<MarkerBuilder>,
6566
ClusterManagersController.OnClusterItemRendered<MarkerBuilder>,
6667
DefaultLifecycleObserver,
6768
GoogleMapListener,
@@ -223,6 +224,7 @@ public void onMapReady(@NonNull GoogleMap googleMap) {
223224
groundOverlaysController.setGoogleMap(googleMap);
224225
setMarkerCollectionListener(this);
225226
setClusterItemClickListener(this);
227+
setClusterItemInfoWindowClickListener(this);
226228
setClusterItemRenderedListener(this);
227229
updateInitialClusterManagers();
228230
updateInitialMarkers();
@@ -398,6 +400,7 @@ public void dispose() {
398400
setGoogleMapListener(null);
399401
setMarkerCollectionListener(null);
400402
setClusterItemClickListener(null);
403+
setClusterItemInfoWindowClickListener(null);
401404
setClusterItemRenderedListener(null);
402405
destroyMapViewIfNecessary();
403406
Lifecycle lifecycle = lifecycleProvider.getLifecycle();
@@ -445,6 +448,17 @@ public void setClusterItemClickListener(
445448
clusterManagersController.setClusterItemClickListener(listener);
446449
}
447450

451+
@VisibleForTesting
452+
public void setClusterItemInfoWindowClickListener(
453+
@Nullable ClusterManager.OnClusterItemInfoWindowClickListener<MarkerBuilder> listener) {
454+
if (googleMap == null) {
455+
Log.v(TAG, "Controller was disposed before GoogleMap was ready.");
456+
return;
457+
}
458+
459+
clusterManagersController.setClusterItemInfoWindowClickListener(listener);
460+
}
461+
448462
@VisibleForTesting
449463
public void setClusterItemRenderedListener(
450464
@Nullable ClusterManagersController.OnClusterItemRendered<MarkerBuilder> listener) {
@@ -827,6 +841,11 @@ public boolean onClusterItemClick(MarkerBuilder item) {
827841
return markersController.onMarkerTap(item.markerId());
828842
}
829843

844+
@Override
845+
public void onClusterItemInfoWindowClick(MarkerBuilder item) {
846+
markersController.onClusterItemInfoWindowTap(item.markerId());
847+
}
848+
830849
public void setMapStyle(@Nullable String style) {
831850
if (googleMap == null) {
832851
initialMapStyle = style;

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ void onInfoWindowTap(String googleMarkerId) {
307307
flutterApi.onInfoWindowTap(markerId, new NoOpVoidResult());
308308
}
309309

310+
/**
311+
* Called when a cluster-managed marker's info window is tapped. Takes the Dart marker ID
312+
* directly.
313+
*/
314+
void onClusterItemInfoWindowTap(String markerId) {
315+
flutterApi.onInfoWindowTap(markerId, new NoOpVoidResult());
316+
}
317+
310318
/**
311319
* Called each time clusterManager adds new visible marker to the map. Creates markerController
312320
* for marker for realtime marker updates.

packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,21 @@ public void OnMapReadySetsClusterItemClickListener() {
185185
verify(spyGoogleMapController, times(1)).setClusterItemClickListener(null);
186186
}
187187

188+
@Test
189+
@SuppressWarnings("unchecked")
190+
public void OnMapReadySetsClusterItemInfoWindowClickListener() {
191+
GoogleMapController googleMapController = getGoogleMapController();
192+
GoogleMapController spyGoogleMapController = spy(googleMapController);
193+
spyGoogleMapController.onMapReady(mockGoogleMap);
194+
195+
verify(spyGoogleMapController, times(1))
196+
.setClusterItemInfoWindowClickListener(
197+
any(ClusterManager.OnClusterItemInfoWindowClickListener.class));
198+
199+
spyGoogleMapController.dispose();
200+
verify(spyGoogleMapController, times(1)).setClusterItemInfoWindowClickListener(null);
201+
}
202+
188203
@Test
189204
@SuppressWarnings("unchecked")
190205
public void OnMapReadySetsClusterItemRenderedListener() {
@@ -235,6 +250,15 @@ public void OnClusterItemClickCallsMarkersController() {
235250
verify(mockMarkersController, times(1)).onMarkerTap(markerBuilder.markerId());
236251
}
237252

253+
@Test
254+
public void OnClusterItemInfoWindowClickCallsMarkersController() {
255+
GoogleMapController googleMapController = getGoogleMapControllerWithMockedDependencies();
256+
MarkerBuilder markerBuilder = new MarkerBuilder("m_1", "cm_1", PlatformMarkerType.MARKER);
257+
258+
googleMapController.onClusterItemInfoWindowClick(markerBuilder);
259+
verify(mockMarkersController, times(1)).onClusterItemInfoWindowTap(markerBuilder.markerId());
260+
}
261+
238262
@Test
239263
public void SetInitialHeatmaps() {
240264
GoogleMapController googleMapController = getGoogleMapControllerWithMockedDependencies();

packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: google_maps_flutter_android
22
description: Android implementation of the google_maps_flutter plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
5-
version: 2.19.5
5+
version: 2.19.6
66

77
environment:
88
sdk: ^3.9.0

0 commit comments

Comments
 (0)