[android] CameraMode transition animation and result listeners
This commit is contained in:
committed by
Łukasz Paczos
parent
2d527c2af7
commit
d592889e86
@@ -19,7 +19,6 @@ import java.util.List;
|
||||
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION;
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.COMPASS_UPDATE_RATE_MS;
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD;
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.MAX_ANIMATION_DURATION_MS;
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS;
|
||||
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING;
|
||||
@@ -31,6 +30,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BE
|
||||
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG;
|
||||
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT;
|
||||
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM;
|
||||
import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation;
|
||||
|
||||
final class LocationAnimatorCoordinator {
|
||||
|
||||
@@ -381,13 +381,4 @@ final class LocationAnimatorCoordinator {
|
||||
void setTrackingAnimationDurationMultiplier(float trackingAnimationDurationMultiplier) {
|
||||
this.durationMultiplier = trackingAnimationDurationMultiplier;
|
||||
}
|
||||
|
||||
private boolean immediateAnimation(LatLng current, @NonNull LatLng target, double zoom) {
|
||||
// TODO: calculate the value based on the projection
|
||||
double distance = current.distanceTo(target);
|
||||
if (zoom > 10) {
|
||||
distance *= zoom;
|
||||
}
|
||||
return distance > INSTANT_LOCATION_TRANSITION_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.location.Location;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
@@ -9,6 +10,8 @@ import android.view.MotionEvent;
|
||||
import com.mapbox.android.gestures.AndroidGesturesManager;
|
||||
import com.mapbox.android.gestures.MoveGestureDetector;
|
||||
import com.mapbox.android.gestures.RotateGestureDetector;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.location.modes.CameraMode;
|
||||
@@ -30,6 +33,8 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
private final AndroidGesturesManager initialGesturesManager;
|
||||
private final AndroidGesturesManager internalGesturesManager;
|
||||
|
||||
private boolean isTransitioning;
|
||||
|
||||
LocationCameraController(
|
||||
Context context,
|
||||
MapboxMap mapboxMap,
|
||||
@@ -76,11 +81,68 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
}
|
||||
|
||||
void setCameraMode(@CameraMode.Mode int cameraMode) {
|
||||
setCameraMode(cameraMode, null, null);
|
||||
}
|
||||
|
||||
void setCameraMode(@CameraMode.Mode final int cameraMode, @Nullable Location lastLocation,
|
||||
@Nullable OnLocationCameraTransitionListener internalTransitionListener) {
|
||||
final boolean wasTracking = isLocationTracking();
|
||||
this.cameraMode = cameraMode;
|
||||
mapboxMap.cancelTransitions();
|
||||
adjustGesturesThresholds();
|
||||
notifyCameraTrackingChangeListener(wasTracking);
|
||||
transitionToCurrentLocation(wasTracking, lastLocation, 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,
|
||||
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());
|
||||
}
|
||||
|
||||
CameraUpdate update = CameraUpdateFactory.newCameraPosition(builder.build());
|
||||
MapboxMap.CancelableCallback callback = new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
isTransitioning = false;
|
||||
if (internalTransitionListener != null) {
|
||||
internalTransitionListener.onLocationCameraTransitionCanceled(cameraMode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
isTransitioning = false;
|
||||
if (internalTransitionListener != null) {
|
||||
internalTransitionListener.onLocationCameraTransitionFinished(cameraMode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CameraPosition currentPosition = mapboxMap.getCameraPosition();
|
||||
if (Utils.immediateAnimation(currentPosition.target, target, currentPosition.zoom)) {
|
||||
mapboxMap.moveCamera(
|
||||
update,
|
||||
callback);
|
||||
} else {
|
||||
mapboxMap.animateCamera(
|
||||
update,
|
||||
(int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS,
|
||||
callback);
|
||||
}
|
||||
} else {
|
||||
if (internalTransitionListener != null) {
|
||||
internalTransitionListener.onLocationCameraTransitionFinished(cameraMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getCameraMode() {
|
||||
@@ -88,21 +150,43 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
}
|
||||
|
||||
private void setBearing(float bearing) {
|
||||
if (isTransitioning) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing));
|
||||
onCameraMoveInvalidateListener.onInvalidateCameraMove();
|
||||
}
|
||||
|
||||
private void setLatLng(@NonNull LatLng latLng) {
|
||||
if (isTransitioning) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
|
||||
onCameraMoveInvalidateListener.onInvalidateCameraMove();
|
||||
|
||||
if (adjustFocalPoint) {
|
||||
PointF focalPoint = mapboxMap.getProjection().toScreenLocation(latLng);
|
||||
mapboxMap.getUiSettings().setFocalPoint(focalPoint);
|
||||
adjustFocalPoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setZoom(float zoom) {
|
||||
if (isTransitioning) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(zoom));
|
||||
onCameraMoveInvalidateListener.onInvalidateCameraMove();
|
||||
}
|
||||
|
||||
private void setTilt(float tilt) {
|
||||
if (isTransitioning) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.tiltTo(tilt));
|
||||
onCameraMoveInvalidateListener.onInvalidateCameraMove();
|
||||
}
|
||||
@@ -114,12 +198,6 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
|| cameraMode == CameraMode.TRACKING_GPS
|
||||
|| cameraMode == CameraMode.TRACKING_GPS_NORTH) {
|
||||
setLatLng(latLng);
|
||||
|
||||
if (adjustFocalPoint) {
|
||||
PointF focalPoint = mapboxMap.getProjection().toScreenLocation(latLng);
|
||||
mapboxMap.getUiSettings().setFocalPoint(focalPoint);
|
||||
adjustFocalPoint = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +231,10 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
setTilt(tilt);
|
||||
}
|
||||
|
||||
boolean isTransitioning() {
|
||||
return isTransitioning;
|
||||
}
|
||||
|
||||
private void adjustGesturesThresholds() {
|
||||
if (options.trackingGesturesManagement()) {
|
||||
if (isLocationTracking()) {
|
||||
@@ -179,6 +261,11 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
|
||||
|| cameraMode == CameraMode.TRACKING_GPS_NORTH;
|
||||
}
|
||||
|
||||
private boolean isLocationBearingTracking() {
|
||||
return cameraMode == CameraMode.TRACKING_GPS
|
||||
|| cameraMode == CameraMode.TRACKING_GPS_NORTH;
|
||||
}
|
||||
|
||||
private void notifyCameraTrackingChangeListener(boolean wasTracking) {
|
||||
internalCameraTrackingChangedListener.onCameraTrackingChanged(cameraMode);
|
||||
if (wasTracking && !isLocationTracking()) {
|
||||
|
||||
@@ -396,6 +396,10 @@ public final class LocationComponent {
|
||||
/**
|
||||
* 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>
|
||||
* <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>
|
||||
@@ -409,9 +413,65 @@ public final class LocationComponent {
|
||||
* @param cameraMode one of the modes found in {@link CameraMode}
|
||||
*/
|
||||
public void setCameraMode(@CameraMode.Mode int cameraMode) {
|
||||
locationCameraController.setCameraMode(cameraMode);
|
||||
boolean isGpsNorth = cameraMode == CameraMode.TRACKING_GPS_NORTH;
|
||||
locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(), isGpsNorth);
|
||||
setCameraMode(cameraMode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* <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 transitionListener callback that's going to be invoked when the transition animation finishes
|
||||
*/
|
||||
public void setCameraMode(@CameraMode.Mode int cameraMode,
|
||||
@Nullable OnLocationCameraTransitionListener transitionListener) {
|
||||
locationCameraController.setCameraMode(cameraMode, lastLocation, new CameraTransitionListener(transitionListener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to reset camera animators and notify listeners when the transition finishes.
|
||||
*/
|
||||
private class CameraTransitionListener implements OnLocationCameraTransitionListener {
|
||||
|
||||
private final OnLocationCameraTransitionListener externalListener;
|
||||
|
||||
private CameraTransitionListener(OnLocationCameraTransitionListener externalListener) {
|
||||
this.externalListener = externalListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationCameraTransitionFinished(int cameraMode) {
|
||||
if (externalListener != null) {
|
||||
externalListener.onLocationCameraTransitionFinished(cameraMode);
|
||||
}
|
||||
reset(cameraMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationCameraTransitionCanceled(int cameraMode) {
|
||||
if (externalListener != null) {
|
||||
externalListener.onLocationCameraTransitionCanceled(cameraMode);
|
||||
}
|
||||
reset(cameraMode);
|
||||
}
|
||||
|
||||
private void reset(@CameraMode.Mode int cameraMode) {
|
||||
locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(),
|
||||
cameraMode == CameraMode.TRACKING_GPS_NORTH);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mapbox.mapboxsdk.location;
|
||||
|
||||
import com.mapbox.mapboxsdk.location.modes.CameraMode;
|
||||
|
||||
/**
|
||||
* Callback for {@link CameraMode } transition state.
|
||||
*/
|
||||
public interface OnLocationCameraTransitionListener {
|
||||
/**
|
||||
* Invoked when the camera mode transition animation has been finished.
|
||||
*
|
||||
* @param cameraMode camera mode change that initiated the transition
|
||||
*/
|
||||
void onLocationCameraTransitionFinished(@CameraMode.Mode int cameraMode);
|
||||
|
||||
/**
|
||||
* Invoked when the camera mode transition animation has been canceled.
|
||||
* <p>
|
||||
* The camera mode is set regardless of the cancellation of the transition animation.
|
||||
*
|
||||
* @param cameraMode camera mode change that initiated the transition
|
||||
*/
|
||||
void onLocationCameraTransitionCanceled(@CameraMode.Mode int cameraMode);
|
||||
}
|
||||
@@ -14,8 +14,11 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
|
||||
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD;
|
||||
|
||||
public final class Utils {
|
||||
|
||||
private Utils() {
|
||||
@@ -89,6 +92,15 @@ public final class Utils {
|
||||
return (float) (location.getAccuracy() * (1 / metersPerPixel));
|
||||
}
|
||||
|
||||
static boolean immediateAnimation(LatLng current, @NonNull LatLng target, double zoom) {
|
||||
// TODO: calculate the value based on the projection
|
||||
double distance = current.distanceTo(target);
|
||||
if (zoom > 10) {
|
||||
distance *= zoom;
|
||||
}
|
||||
return distance > INSTANT_LOCATION_TRANSITION_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the value to an even integer.
|
||||
*/
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
package com.mapbox.mapboxsdk.location;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.location.Location;
|
||||
|
||||
import com.mapbox.android.gestures.AndroidGesturesManager;
|
||||
import com.mapbox.android.gestures.MoveGestureDetector;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.location.modes.CameraMode;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.Projection;
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -413,6 +422,255 @@ public class LocationCameraControllerTest {
|
||||
verify(moveGestureDetector, times(1)).interrupt();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_locationIsNull() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, null, listener);
|
||||
Assert.assertEquals(CameraMode.TRACKING, camera.getCameraMode());
|
||||
verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING);
|
||||
verify(mapboxMap, times(0))
|
||||
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_notTracking() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.NONE, location, listener);
|
||||
verify(listener, times(1)).onLocationCameraTransitionFinished(CameraMode.NONE);
|
||||
verify(mapboxMap, times(0))
|
||||
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_trackingChanged() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
listener.onLocationCameraTransitionFinished(CameraMode.TRACKING);
|
||||
return null;
|
||||
}
|
||||
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
|
||||
.class));
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, location, listener);
|
||||
verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING);
|
||||
verify(mapboxMap)
|
||||
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_trackingNotChanged() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, location, listener);
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
listener.onLocationCameraTransitionFinished(CameraMode.TRACKING_GPS_NORTH);
|
||||
return null;
|
||||
}
|
||||
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
|
||||
.class));
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING_GPS_NORTH, location, listener);
|
||||
verify(listener, times(1)).onLocationCameraTransitionFinished(CameraMode.TRACKING_GPS_NORTH);
|
||||
verify(mapboxMap, times(1))
|
||||
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_canceled() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
listener.onLocationCameraTransitionCanceled(CameraMode.TRACKING);
|
||||
return null;
|
||||
}
|
||||
}).when(mapboxMap).animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback
|
||||
.class));
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, location, listener);
|
||||
verify(listener).onLocationCameraTransitionCanceled(CameraMode.TRACKING);
|
||||
verify(mapboxMap)
|
||||
.animateCamera(any(CameraUpdate.class), any(Integer.class), any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_mapboxCallbackFinished() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
when(location.getLatitude()).thenReturn(1.0);
|
||||
when(location.getLongitude()).thenReturn(1.0);
|
||||
when(location.getBearing()).thenReturn(30f);
|
||||
when(location.getAltitude()).thenReturn(0.0);
|
||||
|
||||
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
|
||||
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, location, 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),
|
||||
callbackCaptor.capture());
|
||||
|
||||
Assert.assertTrue(camera.isTransitioning());
|
||||
|
||||
callbackCaptor.getValue().onFinish();
|
||||
|
||||
Assert.assertFalse(camera.isTransitioning());
|
||||
|
||||
verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_mapboxCallbackCanceled() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
when(location.getLatitude()).thenReturn(1.0);
|
||||
when(location.getLongitude()).thenReturn(1.0);
|
||||
when(location.getBearing()).thenReturn(30f);
|
||||
when(location.getAltitude()).thenReturn(0.0);
|
||||
|
||||
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
|
||||
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING, location, 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),
|
||||
callbackCaptor.capture());
|
||||
|
||||
Assert.assertTrue(camera.isTransitioning());
|
||||
|
||||
callbackCaptor.getValue().onCancel();
|
||||
|
||||
Assert.assertFalse(camera.isTransitioning());
|
||||
|
||||
verify(listener).onLocationCameraTransitionCanceled(CameraMode.TRACKING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_mapboxAnimateBearing() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
when(location.getLatitude()).thenReturn(1.0);
|
||||
when(location.getLongitude()).thenReturn(1.0);
|
||||
when(location.getBearing()).thenReturn(30f);
|
||||
when(location.getAltitude()).thenReturn(0.0);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING_GPS, location, 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),
|
||||
any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_mapboxAnimateNorth() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
when(location.getLatitude()).thenReturn(1.0);
|
||||
when(location.getLongitude()).thenReturn(1.0);
|
||||
when(location.getBearing()).thenReturn(30f);
|
||||
when(location.getAltitude()).thenReturn(0.0);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING_GPS_NORTH, location, 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),
|
||||
any(MapboxMap.CancelableCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transition_animatorValuesDuringTransition() {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getCameraPosition()).thenReturn(CameraPosition.DEFAULT);
|
||||
LocationCameraController camera = buildCamera(mapboxMap);
|
||||
camera.initializeOptions(mock(LocationComponentOptions.class));
|
||||
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
|
||||
Location location = mock(Location.class);
|
||||
|
||||
ArgumentCaptor<MapboxMap.CancelableCallback> callbackCaptor
|
||||
= ArgumentCaptor.forClass(MapboxMap.CancelableCallback.class);
|
||||
|
||||
camera.setCameraMode(CameraMode.TRACKING_GPS, location, listener);
|
||||
|
||||
verify(mapboxMap).animateCamera(
|
||||
any(CameraUpdate.class),
|
||||
eq((int) LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS),
|
||||
callbackCaptor.capture());
|
||||
|
||||
camera.onNewLatLngValue(new LatLng(10, 10));
|
||||
camera.onNewGpsBearingValue(10f);
|
||||
camera.onNewCompassBearingValue(10f);
|
||||
camera.onNewTiltValue(10f);
|
||||
camera.onNewZoomValue(10f);
|
||||
|
||||
verify(mapboxMap, times(0)).moveCamera(any(CameraUpdate.class));
|
||||
|
||||
callbackCaptor.getValue().onFinish();
|
||||
|
||||
camera.onNewLatLngValue(new LatLng(10, 10));
|
||||
camera.onNewGpsBearingValue(10f);
|
||||
camera.onNewTiltValue(10f);
|
||||
camera.onNewZoomValue(10f);
|
||||
|
||||
verify(mapboxMap, times(4)).moveCamera(any(CameraUpdate.class));
|
||||
}
|
||||
|
||||
private LocationCameraController buildCamera(OnCameraTrackingChangedListener onCameraTrackingChangedListener) {
|
||||
MapboxMap mapboxMap = mock(MapboxMap.class);
|
||||
when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class));
|
||||
|
||||
@@ -7,6 +7,8 @@ import android.os.Looper
|
||||
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.modes.CameraMode
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap
|
||||
import com.mapbox.mapboxsdk.maps.Style
|
||||
import io.mockk.mockk
|
||||
@@ -14,7 +16,7 @@ import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.*
|
||||
import org.mockito.MockitoAnnotations
|
||||
@@ -90,7 +92,7 @@ class LocationComponentTest {
|
||||
.getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold)
|
||||
doReturn(0f).`when`(resources)
|
||||
.getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold)
|
||||
locationComponent.activateLocationComponent(context, mockk(),true, locationEngineRequest)
|
||||
locationComponent.activateLocationComponent(context, mockk(), true, locationEngineRequest)
|
||||
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
|
||||
}
|
||||
|
||||
@@ -145,4 +147,40 @@ class LocationComponentTest {
|
||||
|
||||
verify(locationEngine).getLastLocation(lastListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionCallbackFinishedTest() {
|
||||
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, listener)
|
||||
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), callback.capture())
|
||||
callback.value.onLocationCameraTransitionFinished(CameraMode.TRACKING)
|
||||
|
||||
verify(listener).onLocationCameraTransitionFinished(CameraMode.TRACKING)
|
||||
verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun transitionCallbackCanceledTest() {
|
||||
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, listener)
|
||||
verify(locationCameraController).setCameraMode(eq(CameraMode.TRACKING), any(), callback.capture())
|
||||
callback.value.onLocationCameraTransitionCanceled(CameraMode.TRACKING)
|
||||
|
||||
verify(listener).onLocationCameraTransitionCanceled(CameraMode.TRACKING)
|
||||
verify(locationAnimatorCoordinator).resetAllCameraAnimations(CameraPosition.DEFAULT, false)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.location.LocationComponent;
|
||||
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
|
||||
import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;
|
||||
import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener;
|
||||
import com.mapbox.mapboxsdk.location.OnLocationClickListener;
|
||||
import com.mapbox.mapboxsdk.location.modes.CameraMode;
|
||||
import com.mapbox.mapboxsdk.location.modes.RenderMode;
|
||||
@@ -341,37 +342,49 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
|
||||
String selectedTrackingType = trackingTypes.get(position);
|
||||
locationTrackingBtn.setText(selectedTrackingType);
|
||||
if (selectedTrackingType.contentEquals("None")) {
|
||||
locationComponent.setCameraMode(CameraMode.NONE);
|
||||
setCameraTrackingMode(CameraMode.NONE);
|
||||
} else if (selectedTrackingType.contentEquals("Tracking")) {
|
||||
locationComponent.setCameraMode(CameraMode.TRACKING);
|
||||
setCameraTrackingMode(CameraMode.TRACKING);
|
||||
} else if (selectedTrackingType.contentEquals("Tracking Compass")) {
|
||||
locationComponent.setCameraMode(CameraMode.TRACKING_COMPASS);
|
||||
setCameraTrackingMode(CameraMode.TRACKING_COMPASS);
|
||||
} else if (selectedTrackingType.contentEquals("Tracking GPS")) {
|
||||
locationComponent.setCameraMode(CameraMode.TRACKING_GPS);
|
||||
setCameraTrackingMode(CameraMode.TRACKING_GPS);
|
||||
} else if (selectedTrackingType.contentEquals("Tracking GPS North")) {
|
||||
locationComponent.setCameraMode(CameraMode.TRACKING_GPS_NORTH);
|
||||
setCameraTrackingMode(CameraMode.TRACKING_GPS_NORTH);
|
||||
}
|
||||
listPopup.dismiss();
|
||||
|
||||
if (locationComponent.getCameraMode() != CameraMode.NONE) {
|
||||
locationComponent.zoomWhileTracking(15, 750, new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// No impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
locationComponent.tiltWhileTracking(45);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mapboxMap.easeCamera(CameraUpdateFactory.tiltTo(0));
|
||||
}
|
||||
});
|
||||
listPopup.show();
|
||||
}
|
||||
|
||||
private void setCameraTrackingMode(@CameraMode.Mode int mode) {
|
||||
locationComponent.setCameraMode(mode, new OnLocationCameraTransitionListener() {
|
||||
@Override
|
||||
public void onLocationCameraTransitionFinished(@CameraMode.Mode int cameraMode) {
|
||||
if (mode != CameraMode.NONE) {
|
||||
locationComponent.zoomWhileTracking(15, 750, new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
// No impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
locationComponent.tiltWhileTracking(45);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mapboxMap.easeCamera(CameraUpdateFactory.tiltTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationCameraTransitionCanceled(@CameraMode.Mode int cameraMode) {
|
||||
// No impl
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraTrackingDismissed() {
|
||||
locationTrackingBtn.setText("None");
|
||||
|
||||
Reference in New Issue
Block a user