From 893584517182c270b7238a2fddb616a8a0e657d6 Mon Sep 17 00:00:00 2001 From: Pablo Guardiola Date: Wed, 31 May 2017 09:56:31 +0200 Subject: [android] Fix tracking mode + camera race condition (#9133) * [android] fix tracking mode + camera race condition * fix resetTrackingModesIfRequired bug (comparing current camera position with target camera position --- .../mapboxsdk/constants/MapboxConstants.java | 1 - .../mapbox/mapboxsdk/maps/MapGestureDetector.java | 8 ++-- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 30 +++++++++++- .../mapbox/mapboxsdk/maps/TrackingSettings.java | 54 ++++++---------------- .../java/com/mapbox/mapboxsdk/maps/Transform.java | 9 ++-- .../mapboxsdk/maps/widgets/MyLocationView.java | 49 ++------------------ 6 files changed, 56 insertions(+), 95 deletions(-) (limited to 'platform') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 9adefa3221..ecb6ffe24e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -113,7 +113,6 @@ public class MapboxConstants { public static final String STATE_MY_BEARING_TRACKING_MODE = "mapbox_myBearingTracking"; public static final String STATE_MY_LOCATION_TRACKING_DISMISS = "mapbox_myLocationTrackingDismiss"; public static final String STATE_MY_BEARING_TRACKING_DISMISS = "mapbox_myBearingTrackingDismiss"; - public static final String STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA = "mapbox_myBearingTrackingDismiss"; public static final String STATE_COMPASS_ENABLED = "mapbox_compassEnabled"; public static final String STATE_COMPASS_GRAVITY = "mapbox_compassGravity"; public static final String STATE_COMPASS_MARGIN_LEFT = "mapbox_compassMarginLeft"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index dca833bbf4..80fd6248bc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -347,7 +347,7 @@ final class MapGestureDetector { return false; } - trackingSettings.resetTrackingModesIfRequired(true, false); + trackingSettings.resetTrackingModesIfRequired(true, false, false); // cancel any animation transform.cancelTransitions(); @@ -390,7 +390,7 @@ final class MapGestureDetector { } // reset tracking if needed - trackingSettings.resetTrackingModesIfRequired(true, false); + trackingSettings.resetTrackingModesIfRequired(true, false, false); // Cancel any animation transform.cancelTransitions(); @@ -475,7 +475,7 @@ final class MapGestureDetector { // to be in the center of the map. Therefore the zoom will translate the map center, so tracking // should be disabled. - trackingSettings.resetTrackingModesIfRequired(!quickZoom, false); + trackingSettings.resetTrackingModesIfRequired(!quickZoom, false, false); // Scale the map if (focalPoint != null) { // arround user provided focal point @@ -560,7 +560,7 @@ final class MapGestureDetector { // rotation constitutes translation of anything except the center of // rotation, so cancel both location and bearing tracking if required - trackingSettings.resetTrackingModesIfRequired(true, true); + trackingSettings.resetTrackingModesIfRequired(true, true, false); // Get rotate value double bearing = transform.getRawBearing(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 79d36667ff..5f1ed0755c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -729,10 +729,38 @@ public final class MapboxMap { @UiThread public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, final MapboxMap.CancelableCallback callback) { + easeCamera(update, durationMs, easingInterpolator, callback, false); + } + + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling + * {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this + * method and calling it with true in the {@link CancelableCallback#onFinish()}. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param easingInterpolator True for easing interpolator, false for linear. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + * @param isDismissable true will allow animated camera changes dismiss a tracking mode. + */ + @UiThread + public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, + final MapboxMap.CancelableCallback callback, final boolean isDismissable) { new Handler().post(new Runnable() { @Override public void run() { - transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback); + transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback, isDismissable); } }); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java index 25b60aa72d..09213934ae 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java @@ -33,7 +33,6 @@ public final class TrackingSettings { private boolean myLocationEnabled; private boolean dismissLocationTrackingOnGesture = true; private boolean dismissBearingTrackingOnGesture = true; - private boolean isResetTrackingWithCameraPositionChange = true; private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; @@ -57,8 +56,6 @@ public final class TrackingSettings { outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, isDismissLocationTrackingOnGesture()); outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture()); outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); - outState.putBoolean(MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA, - isDismissTrackingModesForCameraPositionChange()); } void onRestoreInstanceState(Bundle savedInstanceState) { @@ -77,8 +74,6 @@ public final class TrackingSettings { MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean( MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true)); - setDismissTrackingModeForCameraPositionChange(savedInstanceState.getBoolean( - MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA, true)); } /** @@ -259,15 +254,16 @@ public final class TrackingSettings { } /** - * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed, - * bearing tracking if there is a rotation. + * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed and not from + * location, bearing tracking if there is a rotation. * - * @param translate true if translation - * @param rotate true if rotation + * @param translate true if translation + * @param rotate true if rotation + * @param isFromLocation true if from location */ - void resetTrackingModesIfRequired(boolean translate, boolean rotate) { + void resetTrackingModesIfRequired(boolean translate, boolean rotate, boolean isFromLocation) { // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off - if (translate && !isLocationTrackingDisabled() && isDismissLocationTrackingOnGesture()) { + if (translate && !isLocationTrackingDisabled() && isDismissLocationTrackingOnGesture() && !isFromLocation) { setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); } @@ -280,36 +276,14 @@ public final class TrackingSettings { /** * Reset the tracking modes as necessary. Animated camera position changes can reset the underlying tracking modes. * - * @param cameraPosition the changed camera position + * @param currentCameraPosition the current camera position + * @param targetCameraPosition the changed camera position + * @param isFromLocation true if from location */ - void resetTrackingModesIfRequired(CameraPosition cameraPosition) { - if (isDismissTrackingModesForCameraPositionChange()) { - resetTrackingModesIfRequired(cameraPosition.target != null, false); - } - } - - /** - * Returns if a animation allows to dismiss a tracking mode. - *

- * By default this is set to true. - *

- * - * @return True if camera animations will allow to dismiss a tracking mode - */ - public boolean isDismissTrackingModesForCameraPositionChange() { - return isResetTrackingWithCameraPositionChange; - } - - /** - * Sets a flag to allow animated camera position changes to dismiss a tracking mode. - *

- *

- *

- * - * @param willAllowToDismiss True will allow animated camera changes dismiss a trackig mode - */ - public void setDismissTrackingModeForCameraPositionChange(boolean willAllowToDismiss) { - isResetTrackingWithCameraPositionChange = willAllowToDismiss; + void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition, + boolean isFromLocation) { + resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false, + isFromLocation); } Location getMyLocation() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index e101340111..507bec270d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -87,7 +87,7 @@ final class Transform implements MapView.OnMapChangedListener { final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, MapboxMap.CancelableCallback callback) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (!cameraPosition.equals(this.cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(cameraPosition); + trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false); cancelTransitions(); mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); if (callback != null) { @@ -98,16 +98,15 @@ final class Transform implements MapView.OnMapChangedListener { @UiThread final void easeCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator, - final MapboxMap.CancelableCallback callback) { + final MapboxMap.CancelableCallback callback, boolean isDismissable) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (!cameraPosition.equals(this.cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(cameraPosition); + trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable); cancelTransitions(); if (callback != null) { cameraCancelableCallback = callback; mapView.addOnMapChangedListener(this); } - mapView.easeTo(cameraPosition.bearing, cameraPosition.target, durationMs, cameraPosition.tilt, cameraPosition.zoom, easingInterpolator); } @@ -118,7 +117,7 @@ final class Transform implements MapView.OnMapChangedListener { final MapboxMap.CancelableCallback callback) { CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); if (!cameraPosition.equals(this.cameraPosition)) { - trackingSettings.resetTrackingModesIfRequired(cameraPosition); + trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false); cancelTransitions(); if (callback != null) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index aecf3cc655..db2a335453 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -484,19 +484,8 @@ public class MyLocationView extends View { if (location != null) { if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { // center map directly - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, - new MapboxMap.CancelableCallback() { - @Override - public void onCancel() { - - } - - @Override - public void onFinish() { - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); - } - }); + null, true); } else { // do not use interpolated location from tracking mode latLng = null; @@ -662,19 +651,8 @@ public class MyLocationView extends View { private void rotateCamera(float rotation) { CameraPosition.Builder builder = new CameraPosition.Builder(); builder.bearing(rotation); - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), COMPASS_UPDATE_RATE_MS, - false /*linear interpolator*/, new MapboxMap.CancelableCallback() { - @Override - public void onCancel() { - - } - - @Override - public void onFinish() { - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); - } - }); + false /*linear interpolator*/, null); } @Override @@ -749,7 +727,7 @@ public class MyLocationView extends View { abstract void invalidate(); } - private class MyLocationTrackingBehavior extends MyLocationBehavior implements MapboxMap.CancelableCallback { + private class MyLocationTrackingBehavior extends MyLocationBehavior { @Override void updateLatLng(@NonNull Location location) { @@ -788,10 +766,9 @@ public class MyLocationView extends View { // accuracy updateAccuracy(location); - // disable dismiss of tracking settings, enabled in #onFinish - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); // ease to new camera position with a linear interpolator - mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, this); + mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, null, + true); } @Override @@ -802,22 +779,6 @@ public class MyLocationView extends View { screenLocation = new PointF(x, y); MyLocationView.this.invalidate(); } - - @Override - public void onCancel() { - //no op - } - - @Override - public void onFinish() { - // Posting to end message queue to avoid race condition #8560 - post(new Runnable() { - @Override - public void run() { - mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); - } - }); - } } private class MyLocationShowBehavior extends MyLocationBehavior { -- cgit v1.2.1