Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Option to provide custom values for location camera transition #14606

Merged
merged 1 commit into from
May 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.HashSet;
import java.util.Set;

import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS;

final class LocationCameraController {

@CameraMode.Mode
Expand Down Expand Up @@ -87,10 +89,12 @@ void initializeOptions(LocationComponentOptions options) {
}

void setCameraMode(@CameraMode.Mode int cameraMode) {
setCameraMode(cameraMode, null, null);
setCameraMode(cameraMode, null, TRANSITION_ANIMATION_DURATION_MS, null, null, null, null);
}

void setCameraMode(@CameraMode.Mode final int cameraMode, @Nullable Location lastLocation,
long transitionDuration,
@Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt,
@Nullable OnLocationCameraTransitionListener internalTransitionListener) {
final boolean wasTracking = isLocationTracking();
this.cameraMode = cameraMode;
Expand All @@ -101,21 +105,35 @@ void setCameraMode(@CameraMode.Mode final int cameraMode, @Nullable Location las

adjustGesturesThresholds();
notifyCameraTrackingChangeListener(wasTracking);
transitionToCurrentLocation(wasTracking, lastLocation, internalTransitionListener);
transitionToCurrentLocation(
wasTracking, lastLocation, transitionDuration, zoom, bearing, tilt, internalTransitionListener);
}

/**
* Initiates a camera animation to the current location if location tracking was engaged.
* Notifies an internal listener when the transition's finished to invalidate animators and notify external listeners.
*/
private void transitionToCurrentLocation(boolean wasTracking, Location lastLocation,
long transitionDuration,
Double zoom, Double bearing, Double tilt,
final OnLocationCameraTransitionListener internalTransitionListener) {
if (!wasTracking && isLocationTracking() && lastLocation != null) {
isTransitioning = true;
LatLng target = new LatLng(lastLocation);

CameraPosition.Builder builder = new CameraPosition.Builder().target(target);
if (isLocationBearingTracking()) {
builder.bearing(cameraMode == CameraMode.TRACKING_GPS_NORTH ? 0 : lastLocation.getBearing());
if (zoom != null) {
builder.zoom(zoom);
}
if (tilt != null) {
builder.tilt(tilt);
}
if (bearing != null) {
builder.bearing(bearing);
} else {
if (isLocationBearingTracking()) {
builder.bearing(cameraMode == CameraMode.TRACKING_GPS_NORTH ? 0 : lastLocation.getBearing());
}
}

CameraUpdate update = CameraUpdateFactory.newCameraPosition(builder.build());
Expand Down Expand Up @@ -145,7 +163,7 @@ public void onFinish() {
} else {
mapboxMap.animateCamera(
update,
(int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS,
(int) transitionDuration,
callback);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_INTERVAL_MILLIS;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS;

/**
* The Location Component provides location awareness to your mobile application. Enabling this
Expand Down Expand Up @@ -524,7 +525,6 @@ public boolean isLocationComponentEnabled() {
* @param cameraMode one of the modes found in {@link CameraMode}
*/
public void setCameraMode(@CameraMode.Mode int cameraMode) {
checkActivationState();
setCameraMode(cameraMode, null);
}

Expand All @@ -550,8 +550,45 @@ public void setCameraMode(@CameraMode.Mode int cameraMode) {
*/
public void setCameraMode(@CameraMode.Mode int cameraMode,
@Nullable OnLocationCameraTransitionListener transitionListener) {
setCameraMode(cameraMode, TRANSITION_ANIMATION_DURATION_MS, null, null, null, transitionListener);
}

/**
* Sets the camera mode, which determines how the map camera will track the rendered location.
* <p>
* When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or
* {@link #tiltWhileTracking(double)}.
* Use {@link OnLocationCameraTransitionListener} to listen for the transition state.
* <p>
* Set values of zoom, bearing and tilt that the camera will transition to. If null is passed to any of those,
* current value will be used for that parameter instead.
* If the camera is already tracking, provided values are ignored.
* <p>
* <ul>
* <li>{@link CameraMode#NONE}: No camera tracking</li>
* <li>{@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing</li>
* <li>{@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing</li>
* <li>{@link CameraMode#TRACKING}: Camera tracks the user location</li>
* <li>{@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass</li>
* <li>{@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing</li>
* <li>{@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north</li>
* </ul>
*
* @param cameraMode one of the modes found in {@link CameraMode}
* @param transitionDuration duration of the transition in milliseconds
* @param zoom target zoom, set to null to use current camera position
* @param bearing target bearing, set to null to use current camera position
* @param tilt target tilt, set to null to use current camera position
* @param transitionListener callback that's going to be invoked when the transition animation finishes
*/
public void setCameraMode(@CameraMode.Mode int cameraMode,
long transitionDuration,
@Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt,
@Nullable OnLocationCameraTransitionListener transitionListener) {
checkActivationState();
locationCameraController.setCameraMode(cameraMode, lastLocation, new CameraTransitionListener(transitionListener));
locationCameraController.setCameraMode(
cameraMode, lastLocation, transitionDuration, zoom, bearing, tilt,
new CameraTransitionListener(transitionListener));
updateCompassListenerState(true);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.util.Set;

import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS;
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING;
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_GPS_BEARING;
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_LATLNG;
Expand Down Expand Up @@ -522,7 +523,7 @@ public void transition_locationIsNull() {
camera.initializeOptions(mock(LocationComponentOptions.class));
OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);

camera.setCameraMode(TRACKING, null, listener);
camera.setCameraMode(TRACKING, null, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);
Assert.assertEquals(TRACKING, camera.getCameraMode());
verify(listener).onLocationCameraTransitionFinished(TRACKING);
verify(mapboxMap, times(0))
Expand All @@ -537,7 +538,7 @@ public void transition_notTracking() {
OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
Location location = mock(Location.class);

camera.setCameraMode(NONE, location, listener);
camera.setCameraMode(NONE, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);
verify(listener, times(1)).onLocationCameraTransitionFinished(NONE);
verify(mapboxMap, times(0))
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
Expand All @@ -564,7 +565,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable {
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
.class));

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);
verify(listener).onLocationCameraTransitionFinished(TRACKING);
verify(mapboxMap)
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
Expand All @@ -582,7 +583,7 @@ public void transition_trackingNotChanged() {
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
Location location = mock(Location.class);

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

doAnswer(new Answer<Void>() {
@Override
Expand All @@ -593,7 +594,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable {
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
.class));

camera.setCameraMode(TRACKING_GPS_NORTH, location, listener);
camera.setCameraMode(TRACKING_GPS_NORTH, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);
verify(listener, times(1)).onLocationCameraTransitionFinished(TRACKING_GPS_NORTH);
verify(mapboxMap, times(1))
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
Expand All @@ -620,7 +621,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable {
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
.class));

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);
verify(listener).onLocationCameraTransitionCanceled(TRACKING);
verify(mapboxMap)
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
Expand All @@ -645,12 +646,12 @@ public void transition_mapboxCallbackFinished() {
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location));
verify(mapboxMap).animateCamera(
eq(CameraUpdateFactory.newCameraPosition(builder.build())),
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
eq((int) TRANSITION_ANIMATION_DURATION_MS),
callbackCaptor.capture());

Assert.assertTrue(camera.isTransitioning());
Expand Down Expand Up @@ -681,7 +682,7 @@ public void transition_mapboxCallbackFinishedImmediately() {
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location));
verify(mapboxMap).moveCamera(
Expand Down Expand Up @@ -716,12 +717,12 @@ public void transition_mapboxCallbackCanceled() {
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);

camera.setCameraMode(TRACKING, location, listener);
camera.setCameraMode(TRACKING, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location));
verify(mapboxMap).animateCamera(
eq(CameraUpdateFactory.newCameraPosition(builder.build())),
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
eq((int) TRANSITION_ANIMATION_DURATION_MS),
callbackCaptor.capture());

Assert.assertTrue(camera.isTransitioning());
Expand Down Expand Up @@ -749,12 +750,12 @@ public void transition_mapboxAnimateBearing() {
when(location.getBearing()).thenReturn(30f);
when(location.getAltitude()).thenReturn(0.0);

camera.setCameraMode(TRACKING_GPS, location, listener);
camera.setCameraMode(TRACKING_GPS, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)).bearing(30);
verify(mapboxMap).animateCamera(
eq(CameraUpdateFactory.newCameraPosition(builder.build())),
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
eq((int) TRANSITION_ANIMATION_DURATION_MS),
any(MapboxMap.CancelableCallback.class));
}

Expand All @@ -774,12 +775,12 @@ public void transition_mapboxAnimateNorth() {
when(location.getBearing()).thenReturn(30f);
when(location.getAltitude()).thenReturn(0.0);

camera.setCameraMode(TRACKING_GPS_NORTH, location, listener);
camera.setCameraMode(TRACKING_GPS_NORTH, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

CameraPosition.Builder builder = new CameraPosition.Builder().target(new LatLng(location)).bearing(0);
verify(mapboxMap).animateCamera(
eq(CameraUpdateFactory.newCameraPosition(builder.build())),
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
eq((int) TRANSITION_ANIMATION_DURATION_MS),
any(MapboxMap.CancelableCallback.class));
}

Expand All @@ -798,11 +799,11 @@ public void transition_animatorValuesDuringTransition() {
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);

camera.setCameraMode(TRACKING_GPS, location, listener);
camera.setCameraMode(TRACKING_GPS, location, TRANSITION_ANIMATION_DURATION_MS, null, null, null, listener);

verify(mapboxMap).animateCamera(
any(CameraUpdate.class),
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
eq((int) TRANSITION_ANIMATION_DURATION_MS),
callbackCaptor.capture());

LatLng latLng = new LatLng(10, 10);
Expand All @@ -823,6 +824,30 @@ public void transition_animatorValuesDuringTransition() {
verify(mapboxMap, times(4)).moveCamera(any(CameraUpdate.class));
}

@Test
public void transition_customAnimation() {
MapboxMap mapboxMap = mock(MapboxMap.class);
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
Projection projection = mock(Projection.class);
when(mapboxMap.getProjection()).thenReturn(projection);
when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000));
LocationCameraController camera = buildCamera(mapboxMap);
camera.initializeOptions(mock(LocationComponentOptions.class));
Location location = mock(Location.class);
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(new LatLng(location))
.zoom(14.0)
.bearing(13.0)
.tilt(45.0)
.build()
);

camera.setCameraMode(TRACKING, location, 1200, 14.0, 13.0, 45.0, null);
verify(mapboxMap)
.animateCamera(eq(cameraUpdate), eq(1200), any(MapboxMap.CancelableCallback.class));
}

private LocationCameraController buildCamera(OnCameraTrackingChangedListener onCameraTrackingChangedListener) {
MapboxMap mapboxMap = mock(MapboxMap.class);
when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.mapbox.android.core.location.LocationEngine
import com.mapbox.android.core.location.LocationEngineRequest
import com.mapbox.mapboxsdk.R
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS
import com.mapbox.mapboxsdk.location.modes.CameraMode
import com.mapbox.mapboxsdk.location.modes.RenderMode
import com.mapbox.mapboxsdk.maps.MapboxMap
Expand Down Expand Up @@ -174,7 +175,7 @@ class LocationComponentTest {

val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java)
locationComponent.setCameraMode(CameraMode.TRACKING, listener)
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), callback.capture())
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(TRANSITION_ANIMATION_DURATION_MS), isNull(), isNull(), isNull(), callback.capture())
callback.value.onLocationCameraTransitionFinished(CameraMode.TRACKING)

verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING)
Expand All @@ -192,13 +193,31 @@ class LocationComponentTest {

val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java)
locationComponent.setCameraMode(CameraMode.TRACKING, listener)
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), callback.capture())
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(TRANSITION_ANIMATION_DURATION_MS), isNull(), isNull(), isNull(), callback.capture())
callback.value.onLocationCameraTransitionCanceled(CameraMode.TRACKING)

verify(listener).onLocationCameraTransitionCanceled(CameraMode.TRACKING)
verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false)
}

@Test
fun transitionCustomFinishedTest() {
locationComponent.activateLocationComponent(context, mockk(), locationEngine, locationEngineRequest, locationComponentOptions)
locationComponent.onStart()
locationComponent.isLocationComponentEnabled = true
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)

val listener = mock(OnLocationCameraTransitionListener::class.java)

val callback = ArgumentCaptor.forClass(OnLocationCameraTransitionListener::class.java)
locationComponent.setCameraMode(CameraMode.TRACKING, 1200, 14.0, 13.0, 45.0, listener)
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), eq(1200L), eq(14.0), eq(13.0), eq(45.0), callback.capture())
callback.value.onLocationCameraTransitionFinished(CameraMode.TRACKING)

verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING)
verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false)
}

@Test
fun compass_listenWhenConsumedByNoneCamera() {
locationComponent.activateLocationComponent(context, mockk(), locationEngine, locationEngineRequest, locationComponentOptions)
Expand Down
Loading