Skip to content

Commit 8107316

Browse files
jokerttuandroidseb
authored andcommitted
[google_maps_flutter] Add ability to animate camera with duration - platform impls (flutter#8659)
This PR contains platform implementations for the ability to animate camera with duration (flutter#7648). Linked issue: flutter/flutter#39810 Linked issue: flutter/flutter#44284
1 parent 3bc1388 commit 8107316

39 files changed

+1499
-455
lines changed

packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
## 2.16.0
2+
3+
* Adds support for animating the camera with a duration.
4+
15
## 2.15.0
26

37
* Adds support for ground overlay.
4-
8+
59
## 2.14.14
610

711
* Updates compileSdk 34 to flutter.compileSdkVersion.

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import androidx.lifecycle.DefaultLifecycleObserver;
2727
import androidx.lifecycle.Lifecycle;
2828
import androidx.lifecycle.LifecycleOwner;
29+
import com.google.android.gms.maps.CameraUpdate;
2930
import com.google.android.gms.maps.GoogleMap;
3031
import com.google.android.gms.maps.GoogleMapOptions;
3132
import com.google.android.gms.maps.MapView;
@@ -976,12 +977,18 @@ public void moveCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) {
976977
}
977978

978979
@Override
979-
public void animateCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) {
980+
public void animateCamera(
981+
@NonNull Messages.PlatformCameraUpdate cameraUpdate, @Nullable Long durationMilliseconds) {
980982
if (googleMap == null) {
981983
throw new FlutterError(
982984
"GoogleMap uninitialized", "animateCamera called prior to map initialization", null);
983985
}
984-
googleMap.animateCamera(Convert.cameraUpdateFromPigeon(cameraUpdate, density));
986+
CameraUpdate update = Convert.cameraUpdateFromPigeon(cameraUpdate, density);
987+
if (durationMilliseconds != null) {
988+
googleMap.animateCamera(update, durationMilliseconds.intValue(), null);
989+
} else {
990+
googleMap.animateCamera(update);
991+
}
985992
}
986993

987994
@Override
@@ -1100,6 +1107,11 @@ public Boolean isLiteModeEnabled() {
11001107
return Objects.requireNonNull(googleMap).isTrafficEnabled();
11011108
}
11021109

1110+
@Override
1111+
public @NonNull Messages.PlatformCameraPosition getCameraPosition() {
1112+
return Convert.cameraPositionToPigeon(Objects.requireNonNull(googleMap).getCameraPosition());
1113+
}
1114+
11031115
@Override
11041116
public @Nullable Messages.PlatformTileLayer getTileOverlayInfo(@NonNull String tileOverlayId) {
11051117
TileOverlay tileOverlay = tileOverlaysController.getTileOverlay(tileOverlayId);

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v22.7.3), do not edit directly.
4+
// Autogenerated from Pigeon (v22.7.4), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66

77
package io.flutter.plugins.googlemaps;
@@ -6567,8 +6567,12 @@ void updateGroundOverlays(
65676567
PlatformLatLngBounds getVisibleRegion();
65686568
/** Moves the camera according to [cameraUpdate] immediately, with no animation. */
65696569
void moveCamera(@NonNull PlatformCameraUpdate cameraUpdate);
6570-
/** Moves the camera according to [cameraUpdate], animating the update. */
6571-
void animateCamera(@NonNull PlatformCameraUpdate cameraUpdate);
6570+
/**
6571+
* Moves the camera according to [cameraUpdate], animating the update using a duration in
6572+
* milliseconds if provided.
6573+
*/
6574+
void animateCamera(
6575+
@NonNull PlatformCameraUpdate cameraUpdate, @Nullable Long durationMilliseconds);
65726576
/** Gets the current map zoom level. */
65736577
@NonNull
65746578
Double getZoomLevel();
@@ -6996,8 +7000,9 @@ public void error(Throwable error) {
69967000
ArrayList<Object> wrapped = new ArrayList<>();
69977001
ArrayList<Object> args = (ArrayList<Object>) message;
69987002
PlatformCameraUpdate cameraUpdateArg = (PlatformCameraUpdate) args.get(0);
7003+
Long durationMillisecondsArg = (Long) args.get(1);
69997004
try {
7000-
api.animateCamera(cameraUpdateArg);
7005+
api.animateCamera(cameraUpdateArg, durationMillisecondsArg);
70017006
wrapped.add(0, null);
70027007
} catch (Throwable exception) {
70037008
wrapped = wrapError(exception);
@@ -7809,6 +7814,9 @@ public interface MapsInspectorApi {
78097814
@NonNull
78107815
List<PlatformCluster> getClusters(@NonNull String clusterManagerId);
78117816

7817+
@NonNull
7818+
PlatformCameraPosition getCameraPosition();
7819+
78127820
/** The codec used by MapsInspectorApi. */
78137821
static @NonNull MessageCodec<Object> getCodec() {
78147822
return PigeonCodec.INSTANCE;
@@ -8176,6 +8184,29 @@ static void setUp(
81768184
channel.setMessageHandler(null);
81778185
}
81788186
}
8187+
{
8188+
BasicMessageChannel<Object> channel =
8189+
new BasicMessageChannel<>(
8190+
binaryMessenger,
8191+
"dev.flutter.pigeon.google_maps_flutter_android.MapsInspectorApi.getCameraPosition"
8192+
+ messageChannelSuffix,
8193+
getCodec());
8194+
if (api != null) {
8195+
channel.setMessageHandler(
8196+
(message, reply) -> {
8197+
ArrayList<Object> wrapped = new ArrayList<>();
8198+
try {
8199+
PlatformCameraPosition output = api.getCameraPosition();
8200+
wrapped.add(0, output);
8201+
} catch (Throwable exception) {
8202+
wrapped = wrapError(exception);
8203+
}
8204+
reply.reply(wrapped);
8205+
});
8206+
} else {
8207+
channel.setMessageHandler(null);
8208+
}
8209+
}
81798210
}
81808211
}
81818212
}

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,25 @@
77
import static org.junit.Assert.assertNotNull;
88
import static org.junit.Assert.assertNull;
99
import static org.mockito.ArgumentMatchers.any;
10+
import static org.mockito.ArgumentMatchers.anyFloat;
11+
import static org.mockito.ArgumentMatchers.eq;
12+
import static org.mockito.ArgumentMatchers.isNull;
1013
import static org.mockito.Mockito.mock;
14+
import static org.mockito.Mockito.mockStatic;
1115
import static org.mockito.Mockito.spy;
1216
import static org.mockito.Mockito.times;
1317
import static org.mockito.Mockito.verify;
18+
import static org.mockito.Mockito.when;
1419

1520
import android.content.Context;
1621
import android.os.Build;
1722
import androidx.activity.ComponentActivity;
1823
import androidx.test.core.app.ApplicationProvider;
24+
import com.google.android.gms.maps.CameraUpdate;
25+
import com.google.android.gms.maps.CameraUpdateFactory;
1926
import com.google.android.gms.maps.GoogleMap;
27+
import com.google.android.gms.maps.model.CameraPosition;
28+
import com.google.android.gms.maps.model.LatLng;
2029
import com.google.android.gms.maps.model.Marker;
2130
import com.google.maps.android.clustering.ClusterManager;
2231
import io.flutter.plugin.common.BinaryMessenger;
@@ -28,6 +37,7 @@
2837
import org.junit.Test;
2938
import org.junit.runner.RunWith;
3039
import org.mockito.Mock;
40+
import org.mockito.MockedStatic;
3141
import org.mockito.MockitoAnnotations;
3242
import org.robolectric.Robolectric;
3343
import org.robolectric.RobolectricTestRunner;
@@ -250,4 +260,64 @@ public void UpdateHeatmaps() {
250260
verify(mockHeatmapsController, times(1)).changeHeatmaps(toChange);
251261
verify(mockHeatmapsController, times(1)).removeHeatmaps(idsToRemove);
252262
}
263+
264+
@Test
265+
public void AnimateCamera() {
266+
GoogleMapController googleMapController = getGoogleMapControllerWithMockedDependencies();
267+
googleMapController.onMapReady(mockGoogleMap);
268+
269+
Messages.PlatformCameraUpdateZoomBy newCameraPosition =
270+
new Messages.PlatformCameraUpdateZoomBy.Builder().setAmount(1.0).build();
271+
Messages.PlatformCameraUpdate cameraUpdate =
272+
new Messages.PlatformCameraUpdate.Builder().setCameraUpdate(newCameraPosition).build();
273+
274+
try (MockedStatic<CameraUpdateFactory> mockedFactory = mockStatic(CameraUpdateFactory.class)) {
275+
mockedFactory
276+
.when(() -> CameraUpdateFactory.zoomBy(anyFloat()))
277+
.thenReturn(mock(CameraUpdate.class));
278+
googleMapController.animateCamera(cameraUpdate, null);
279+
}
280+
281+
verify(mockGoogleMap, times(1)).animateCamera(any(CameraUpdate.class));
282+
}
283+
284+
@Test
285+
public void AnimateCameraWithDuration() {
286+
GoogleMapController googleMapController = getGoogleMapControllerWithMockedDependencies();
287+
googleMapController.onMapReady(mockGoogleMap);
288+
289+
Messages.PlatformCameraUpdateZoomBy newCameraPosition =
290+
new Messages.PlatformCameraUpdateZoomBy.Builder().setAmount(1.0).build();
291+
Messages.PlatformCameraUpdate cameraUpdate =
292+
new Messages.PlatformCameraUpdate.Builder().setCameraUpdate(newCameraPosition).build();
293+
294+
Long durationMilliseconds = 1000L;
295+
296+
try (MockedStatic<CameraUpdateFactory> mockedFactory = mockStatic(CameraUpdateFactory.class)) {
297+
mockedFactory
298+
.when(() -> CameraUpdateFactory.zoomBy(anyFloat()))
299+
.thenReturn(mock(CameraUpdate.class));
300+
googleMapController.animateCamera(cameraUpdate, durationMilliseconds);
301+
}
302+
303+
verify(mockGoogleMap, times(1))
304+
.animateCamera(any(CameraUpdate.class), eq(durationMilliseconds.intValue()), isNull());
305+
}
306+
307+
@Test
308+
public void getCameraPositionReturnsCorrectData() {
309+
GoogleMapController googleMapController = getGoogleMapControllerWithMockedDependencies();
310+
googleMapController.onMapReady(mockGoogleMap);
311+
312+
CameraPosition cameraPosition = new CameraPosition(new LatLng(10.0, 20.0), 15.0f, 30.0f, 45.0f);
313+
when(mockGoogleMap.getCameraPosition()).thenReturn(cameraPosition);
314+
315+
Messages.PlatformCameraPosition result = googleMapController.getCameraPosition();
316+
317+
Assert.assertEquals(cameraPosition.target.latitude, result.getTarget().getLatitude(), 1e-15);
318+
Assert.assertEquals(cameraPosition.target.longitude, result.getTarget().getLongitude(), 1e-15);
319+
Assert.assertEquals(cameraPosition.zoom, result.getZoom(), 1e-15);
320+
Assert.assertEquals(cameraPosition.tilt, result.getTilt(), 1e-15);
321+
Assert.assertEquals(cameraPosition.bearing, result.getBearing(), 1e-15);
322+
}
253323
}

0 commit comments

Comments
 (0)