diff options
author | Łukasz Paczos <lukas.paczos@gmail.com> | 2018-12-06 18:03:54 +0100 |
---|---|---|
committer | Łukasz Paczos <lukasz.paczos@mapbox.com> | 2018-12-12 12:31:40 +0100 |
commit | d592889e861fa28776ec41a7d9316e2e3ac1a229 (patch) | |
tree | ddfc89ad1397616ad4be93926e93a70758b490fb /platform/android/MapboxGLAndroidSDK/src/main/java | |
parent | 2d527c2af7224d03429b8b2ccb7c1712e8ffe12b (diff) | |
download | qtlocation-mapboxgl-d592889e861fa28776ec41a7d9316e2e3ac1a229.tar.gz |
[android] CameraMode transition animation and result listeners
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java')
5 files changed, 193 insertions, 19 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 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. * <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); + } } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java new file mode 100644 index 0000000000..824432efc3 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/OnLocationCameraTransitionListener.java @@ -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); +} 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 8907b93b5f..7a2415ed5d 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 @@ -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. */ |