summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2018-12-11 19:00:15 +0100
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2018-12-13 19:40:24 +0100
commite86d1b2ac99452819396e2e617a77b2918cd5a04 (patch)
tree4c53f9726e44ce1483735a45cacbad6d64242171
parentbbeec8dacb1a007ffadad391b63620b6d2575eb7 (diff)
downloadqtlocation-mapboxgl-e86d1b2ac99452819396e2e617a77b2918cd5a04.tar.gz
[android] immediate location animation based on map's projection
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java65
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt7
8 files changed, 89 insertions, 15 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
index b49be5c885..8dd05c3f0c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java
@@ -13,6 +13,7 @@ import android.view.animation.LinearInterpolator;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Projection;
import java.util.ArrayList;
import java.util.List;
@@ -39,12 +40,17 @@ final class LocationAnimatorCoordinator {
final List<MapboxAnimator.OnLayerAnimationsValuesChangeListener> layerListeners = new ArrayList<>();
final List<MapboxAnimator.OnCameraAnimationsValuesChangeListener> cameraListeners = new ArrayList<>();
+ private final Projection projection;
private Location previousLocation;
private float previousAccuracyRadius = -1;
private float previousCompassBearing = -1;
private long locationUpdateTimestamp = -1;
private float durationMultiplier;
+ LocationAnimatorCoordinator(Projection projection) {
+ this.projection = projection;
+ }
+
void addLayerListener(MapboxAnimator.OnLayerAnimationsValuesChangeListener listener) {
layerListeners.add(listener);
}
@@ -81,8 +87,8 @@ final class LocationAnimatorCoordinator {
updateLayerAnimators(previousLayerLatLng, targetLatLng, previousLayerBearing, targetLayerBearing);
updateCameraAnimators(previousCameraLatLng, previousCameraBearing, targetLatLng, targetCameraBearing);
- boolean snap = immediateAnimation(previousCameraLatLng, targetLatLng, currentCameraPosition.zoom)
- || immediateAnimation(previousLayerLatLng, targetLatLng, currentCameraPosition.zoom);
+ boolean snap = immediateAnimation(projection, previousCameraLatLng, targetLatLng)
+ || immediateAnimation(projection, previousLayerLatLng, targetLatLng);
playLocationAnimators(snap ? 0 : getAnimationDuration());
previousLocation = newLocation;
@@ -317,7 +323,7 @@ final class LocationAnimatorCoordinator {
createNewAnimator(ANIMATOR_CAMERA_LATLNG,
new CameraLatLngAnimator(previousCameraTarget, currentTarget, cameraListeners));
- return immediateAnimation(previousCameraTarget, currentTarget, currentCameraPosition.zoom);
+ return immediateAnimation(projection, previousCameraTarget, currentTarget);
}
private void resetCameraGpsBearingAnimation(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
index 1c4cb39578..e426a587d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
@@ -129,7 +129,7 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation
};
CameraPosition currentPosition = mapboxMap.getCameraPosition();
- if (Utils.immediateAnimation(currentPosition.target, target, currentPosition.zoom)) {
+ if (Utils.immediateAnimation(mapboxMap.getProjection(), currentPosition.target, target)) {
mapboxMap.moveCamera(
update,
callback);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
index b6246f4abc..66eb24acbc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
@@ -1015,7 +1015,7 @@ public final class LocationComponent {
locationCameraController = new LocationCameraController(
context, mapboxMap, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener);
- locationAnimatorCoordinator = new LocationAnimatorCoordinator();
+ locationAnimatorCoordinator = new LocationAnimatorCoordinator(mapboxMap.getProjection());
locationAnimatorCoordinator.addLayerListener(locationLayerController);
locationAnimatorCoordinator.addCameraListener(locationCameraController);
locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
index 29fe413a22..912141c627 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
@@ -24,7 +24,7 @@ final class LocationComponentConstants {
static final long DEFAULT_TRACKING_TILT_ANIM_DURATION = 1250;
// Threshold value to perform immediate camera/layer position update.
- static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 500_000;
+ static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 50_000;
// Default interval between location updates
static final long DEFAULT_INTERVAL_MILLIS = 1000;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java
index 7a2415ed5d..2e95da8ad5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java
@@ -16,6 +16,7 @@ import android.support.v4.content.ContextCompat;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Projection;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD;
@@ -92,13 +93,10 @@ 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
+ static boolean immediateAnimation(@NonNull Projection projection, @NonNull LatLng current, @NonNull LatLng target) {
+ double metersPerPixel = projection.getMetersPerPixelAtLatitude((current.getLatitude() + target.getLatitude()) / 2);
double distance = current.distanceTo(target);
- if (zoom > 10) {
- distance *= zoom;
- }
- return distance > INSTANT_LOCATION_TRANSITION_THRESHOLD;
+ return distance / metersPerPixel > INSTANT_LOCATION_TRANSITION_THRESHOLD;
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt
index 2c94642610..fad71237ab 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt
@@ -6,12 +6,14 @@ import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION
import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION
import com.mapbox.mapboxsdk.location.MapboxAnimator.*
+import com.mapbox.mapboxsdk.maps.Projection
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
+import org.mockito.Mockito.mock
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
@@ -22,7 +24,7 @@ class LocationAnimatorCoordinatorTest {
@Before
fun setUp() {
- locationAnimatorCoordinator = LocationAnimatorCoordinator()
+ locationAnimatorCoordinator = LocationAnimatorCoordinator(mock(Projection::class.java))
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
index 4f950cebac..475426f77c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
@@ -454,6 +454,9 @@ public class LocationCameraControllerTest {
public void transition_trackingChanged() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -478,6 +481,9 @@ public class LocationCameraControllerTest {
public void transition_trackingNotChanged() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -504,6 +510,9 @@ public class LocationCameraControllerTest {
public void transition_canceled() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -528,6 +537,9 @@ public class LocationCameraControllerTest {
public void transition_mapboxCallbackFinished() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -558,9 +570,47 @@ public class LocationCameraControllerTest {
}
@Test
+ public void transition_mapboxCallbackFinishedImmediately() {
+ 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(1));
+ 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).moveCamera(
+ eq(CameraUpdateFactory.newCameraPosition(builder.build())),
+ 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);
+ 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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -594,6 +644,9 @@ public class LocationCameraControllerTest {
public void transition_mapboxAnimateBearing() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -616,6 +669,9 @@ public class LocationCameraControllerTest {
public void transition_mapboxAnimateNorth() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -638,6 +694,9 @@ public class LocationCameraControllerTest {
public void transition_animatorValuesDuringTransition() {
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));
final OnLocationCameraTransitionListener listener = mock(OnLocationCameraTransitionListener.class);
@@ -674,6 +733,9 @@ public class LocationCameraControllerTest {
private LocationCameraController buildCamera(OnCameraTrackingChangedListener onCameraTrackingChangedListener) {
MapboxMap mapboxMap = mock(MapboxMap.class);
when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class));
+ Projection projection = mock(Projection.class);
+ when(mapboxMap.getProjection()).thenReturn(projection);
+ when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000));
MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class);
OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class);
AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
@@ -685,6 +747,9 @@ public class LocationCameraControllerTest {
private LocationCameraController buildCamera(MoveGestureDetector moveGestureDetector) {
MapboxMap mapboxMap = mock(MapboxMap.class);
when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class));
+ Projection projection = mock(Projection.class);
+ when(mapboxMap.getProjection()).thenReturn(projection);
+ when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000));
OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class);
OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class);
AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
index 94e1f079f3..4c7baad939 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
@@ -1165,12 +1165,15 @@ class LocationComponentTest : BaseActivityTest() {
uiController: UiController, context: Context) {
component.activateLocationComponent(context, mapboxMap.style!!, false)
component.isLocationComponentEnabled = true
- val target = LatLng(51.0, 17.0)
- assertTrue(target.distanceTo(LatLng(location)) > LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD)
component.cameraMode = CameraMode.NONE
component.forceLocationUpdate(location)
+
+ val target = LatLng(51.0, 17.0)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(target))
+ mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(15.0))
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0))
+ assertTrue(Utils.immediateAnimation(mapboxMap.projection, mapboxMap.cameraPosition.target, LatLng(location)))
+
component.cameraMode = CameraMode.TRACKING_GPS
assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1)
assertEquals(location.latitude, mapboxMap.cameraPosition.target.latitude, 0.1)