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

Commit

Permalink
[android] option to provide custom values for location camera transition
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasPaczos authored and Łukasz Paczos committed May 9, 2019
1 parent dbfab81 commit 6fa1d35
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 50 deletions.
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

0 comments on commit 6fa1d35

Please sign in to comment.