From b4d92664fbd56a3ad831c1555782920bf9c257ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 6 Dec 2018 18:03:54 +0100 Subject: [android] CameraMode transition animation and result listeners --- .../location/LocationAnimatorCoordinator.java | 11 +- .../location/LocationCameraController.java | 99 +++++++- .../mapboxsdk/location/LocationComponent.java | 66 +++++- .../OnLocationCameraTransitionListener.java | 24 ++ .../java/com/mapbox/mapboxsdk/location/Utils.java | 12 + .../location/LocationCameraControllerTest.java | 258 +++++++++++++++++++++ .../mapboxsdk/location/LocationComponentTest.kt | 42 +++- .../activity/location/LocationModesActivity.java | 51 ++-- 8 files changed, 523 insertions(+), 40 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java 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 fd8537f23f..b49be5c885 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 @@ -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; - } } 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 a50b510073..0a876fb5cb 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 @@ -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()) { 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 340e84abef..7e312a8158 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 @@ -396,6 +396,10 @@ public final class LocationComponent { /** * Sets the camera mode, which determines how the map camera will track the rendered location. *

+ * 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. + *

*