summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorŁukasz Paczos <lukas.paczos@gmail.com>2018-09-25 17:41:43 +0200
committerŁukasz Paczos <lukasz.paczos@mapbox.com>2018-09-26 11:38:17 +0200
commit095ea17c7d04a7af6ec3d5bc6d1fb7035e67799f (patch)
treefa26b3a7ae695119cc11d3a269faa3069bcea3ab
parent66e95ac2ab6260654ba09b26e83591e3d4334c02 (diff)
downloadqtlocation-mapboxgl-095ea17c7d04a7af6ec3d5bc6d1fb7035e67799f.tar.gz
[android] clear CameraChangeDispatcher message queue when camera move is restarted
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java243
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java47
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java2
3 files changed, 175 insertions, 117 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
index e558a5d707..a87a290fd7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -1,14 +1,19 @@
package com.mapbox.mapboxsdk.maps;
import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.ref.WeakReference;
import java.util.concurrent.CopyOnWriteArrayList;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Class responsible for dispatching camera change events to registered listeners.
@@ -16,7 +21,7 @@ import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
- private final Handler handler = new Handler();
+ private final CameraChangeHandler handler = new CameraChangeHandler(this);
private boolean idle = true;
private int moveStartedReason;
@@ -31,83 +36,36 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
private OnCameraMoveListener onCameraMoveListener;
private OnCameraIdleListener onCameraIdleListener;
- private final Runnable onCameraMoveStartedRunnable = new Runnable() {
- @Override
- public void run() {
- if (!idle) {
- return;
- }
- idle = false;
-
- // deprecated API
- if (onCameraMoveStartedListener != null) {
- onCameraMoveStartedListener.onCameraMoveStarted(moveStartedReason);
- }
-
- // new API
- if (!onCameraMoveStarted.isEmpty()) {
- for (OnCameraMoveStartedListener cameraMoveStartedListener : onCameraMoveStarted) {
- cameraMoveStartedListener.onCameraMoveStarted(moveStartedReason);
- }
- }
- }
- };
-
- private final Runnable onCameraMoveRunnable = new Runnable() {
- @Override
- public void run() {
- // deprecated API
- if (onCameraMoveListener != null && !idle) {
- onCameraMoveListener.onCameraMove();
- }
-
- // new API
- if (!onCameraMove.isEmpty() && !idle) {
- for (OnCameraMoveListener cameraMoveListener : onCameraMove) {
- cameraMoveListener.onCameraMove();
- }
- }
- }
- };
+ @Retention(SOURCE)
+ @IntDef( {MOVE_STARTED, MOVE, MOVE_CANCELED, IDLE})
+ @interface CameraChange {
+ }
- private final Runnable onCameraMoveCancelRunnable = new Runnable() {
- @Override
- public void run() {
- // deprecated API
- if (onCameraMoveCanceledListener != null && !idle) {
- onCameraMoveCanceledListener.onCameraMoveCanceled();
- }
+ private static final int MOVE_STARTED = 0;
+ private static final int MOVE = 1;
+ private static final int MOVE_CANCELED = 2;
+ private static final int IDLE = 3;
- // new API
- if (!onCameraMoveCanceled.isEmpty() && !idle) {
- for (OnCameraMoveCanceledListener cameraMoveCanceledListener : onCameraMoveCanceled) {
- cameraMoveCanceledListener.onCameraMoveCanceled();
- }
- }
- }
- };
+ @Override
+ public void onCameraMoveStarted(final int reason) {
+ moveStartedReason = reason;
+ handler.scheduleMessage(MOVE_STARTED);
+ }
- private final Runnable onCameraIdleRunnable = new Runnable() {
- @Override
- public void run() {
- if (idle) {
- return;
- }
- idle = true;
+ @Override
+ public void onCameraMove() {
+ handler.scheduleMessage(MOVE);
+ }
- // deprecated API
- if (onCameraIdleListener != null) {
- onCameraIdleListener.onCameraIdle();
- }
+ @Override
+ public void onCameraMoveCanceled() {
+ handler.scheduleMessage(MOVE_CANCELED);
+ }
- // new API
- if (!onCameraIdle.isEmpty()) {
- for (OnCameraIdleListener cameraIdleListener : onCameraIdle) {
- cameraIdleListener.onCameraIdle();
- }
- }
- }
- };
+ @Override
+ public void onCameraIdle() {
+ handler.scheduleMessage(IDLE);
+ }
@Deprecated
void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
@@ -129,27 +87,6 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
this.onCameraIdleListener = onCameraIdleListener;
}
- @Override
- public void onCameraMoveStarted(final int reason) {
- moveStartedReason = reason;
- handler.post(onCameraMoveStartedRunnable);
- }
-
- @Override
- public void onCameraMove() {
- handler.post(onCameraMoveRunnable);
- }
-
- @Override
- public void onCameraMoveCanceled() {
- handler.post(onCameraMoveCancelRunnable);
- }
-
- @Override
- public void onCameraIdle() {
- handler.post(onCameraIdleRunnable);
- }
-
void addOnCameraIdleListener(@NonNull OnCameraIdleListener listener) {
onCameraIdle.add(listener);
}
@@ -189,4 +126,122 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
onCameraMove.remove(listener);
}
}
+
+ private void executeOnCameraMoveStarted() {
+ if (!idle) {
+ return;
+ }
+ idle = false;
+
+ // deprecated API
+ if (onCameraMoveStartedListener != null) {
+ onCameraMoveStartedListener.onCameraMoveStarted(moveStartedReason);
+ }
+
+ // new API
+ if (!onCameraMoveStarted.isEmpty()) {
+ for (OnCameraMoveStartedListener cameraMoveStartedListener : onCameraMoveStarted) {
+ cameraMoveStartedListener.onCameraMoveStarted(moveStartedReason);
+ }
+ }
+ }
+
+ private void executeOnCameraMove() {
+ // deprecated API
+ if (onCameraMoveListener != null && !idle) {
+ onCameraMoveListener.onCameraMove();
+ }
+
+ // new API
+ if (!onCameraMove.isEmpty() && !idle) {
+ for (OnCameraMoveListener cameraMoveListener : onCameraMove) {
+ cameraMoveListener.onCameraMove();
+ }
+ }
+ }
+
+ private void executeOnCameraMoveCancelled() {
+ // deprecated API
+ if (onCameraMoveCanceledListener != null && !idle) {
+ onCameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+
+ // new API
+ if (!onCameraMoveCanceled.isEmpty() && !idle) {
+ for (OnCameraMoveCanceledListener cameraMoveCanceledListener : onCameraMoveCanceled) {
+ cameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+ }
+ }
+
+ private void executeOnCameraIdle() {
+ if (idle) {
+ return;
+ }
+ idle = true;
+
+ // deprecated API
+ if (onCameraIdleListener != null) {
+ onCameraIdleListener.onCameraIdle();
+ }
+
+ // new API
+ if (!onCameraIdle.isEmpty()) {
+ for (OnCameraIdleListener cameraIdleListener : onCameraIdle) {
+ cameraIdleListener.onCameraIdle();
+ }
+ }
+ }
+
+ private static class CameraChangeHandler extends Handler {
+
+ private WeakReference<CameraChangeDispatcher> dispatcherWeakReference;
+
+ CameraChangeHandler(CameraChangeDispatcher dispatcher) {
+ super();
+ this.dispatcherWeakReference = new WeakReference<>(dispatcher);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ CameraChangeDispatcher dispatcher = dispatcherWeakReference.get();
+ if (dispatcher != null) {
+ switch (msg.what) {
+ case MOVE_STARTED:
+ dispatcher.executeOnCameraMoveStarted();
+ break;
+ case MOVE:
+ dispatcher.executeOnCameraMove();
+ break;
+ case MOVE_CANCELED:
+ dispatcher.executeOnCameraMoveCancelled();
+ break;
+ case IDLE:
+ dispatcher.executeOnCameraIdle();
+ break;
+ }
+ }
+ }
+
+ void scheduleMessage(@CameraChange int change) {
+ CameraChangeDispatcher dispatcher = dispatcherWeakReference.get();
+ if (dispatcher != null) {
+ // if there is a movement that is cancelled/stopped and restarted in the same code block
+ // we can safely assume that the movement will continue, no need for dispatching unnecessary callbacks sequence
+ if (change == MOVE_STARTED) {
+ boolean shouldReturn = !dispatcher.idle && (hasMessages(IDLE) || hasMessages(MOVE_CANCELED));
+ removeMessages(IDLE);
+ removeMessages(MOVE_CANCELED);
+
+ if (shouldReturn) {
+ return;
+ }
+ }
+
+ Message message = new Message();
+ message.what = change;
+ this.sendMessage(message);
+ }
+ }
+ }
}
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 977afe4bd9..b225f35c83 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
@@ -10,6 +10,7 @@ import android.support.annotation.Nullable;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
+
import com.mapbox.android.gestures.AndroidGesturesManager;
import com.mapbox.android.gestures.Constants;
import com.mapbox.android.gestures.MoveGestureDetector;
@@ -222,16 +223,21 @@ final class MapGestureDetector {
case MotionEvent.ACTION_UP:
transform.setGestureInProgress(false);
- // Start all awaiting velocity animations
- animationsTimeoutHandler.removeCallbacksAndMessages(null);
- for (Animator animator : scheduledAnimators) {
- animator.start();
+ if (scheduledAnimators.isEmpty()) {
+ cameraChangeDispatcher.onCameraIdle();
+ } else {
+ // Start all awaiting velocity animations
+ animationsTimeoutHandler.removeCallbacksAndMessages(null);
+ for (Animator animator : scheduledAnimators) {
+ animator.start();
+ }
+ scheduledAnimators.clear();
}
- scheduledAnimators.clear();
break;
case MotionEvent.ACTION_CANCEL:
scheduledAnimators.clear();
+ transform.cancelTransitions();
transform.setGestureInProgress(false);
break;
}
@@ -526,8 +532,6 @@ final class MapGestureDetector {
@Override
public void onScaleEnd(StandardScaleGestureDetector detector, float velocityX, float velocityY) {
- cameraChangeDispatcher.onCameraIdle();
-
if (quickZoom) {
//if quickzoom, re-enabling move gesture detector
gesturesManager.getMoveGestureDetector().setEnabled(true);
@@ -542,18 +546,19 @@ final class MapGestureDetector {
notifyOnScaleEndListeners(detector);
- if (!uiSettings.isScaleVelocityAnimationEnabled()) {
+ float velocityXY = Math.abs(velocityX) + Math.abs(velocityY);
+
+ if (!uiSettings.isScaleVelocityAnimationEnabled() || velocityXY < minimumVelocity) {
+ // notifying listeners that camera is idle only if there is no follow-up animation
+ cameraChangeDispatcher.onCameraIdle();
return;
}
- float velocityXY = Math.abs(velocityX) + Math.abs(velocityY);
- if (velocityXY > minimumVelocity) {
- double zoomAddition = calculateScale(velocityXY, detector.isScalingOut());
- double currentZoom = transform.getRawZoom();
- long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4);
- scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime);
- scheduleAnimator(scaleAnimator);
- }
+ double zoomAddition = calculateScale(velocityXY, detector.isScalingOut());
+ double currentZoom = transform.getRawZoom();
+ long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4);
+ scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime);
+ scheduleAnimator(scaleAnimator);
}
private void setScaleFocalPoint(StandardScaleGestureDetector detector) {
@@ -650,8 +655,6 @@ final class MapGestureDetector {
@Override
public void onRotateEnd(RotateGestureDetector detector, float velocityX, float velocityY, float angularVelocity) {
- cameraChangeDispatcher.onCameraIdle();
-
if (uiSettings.isIncreaseScaleThresholdWhenRotating()) {
// resetting default scale threshold values
gesturesManager.getStandardScaleGestureDetector().setSpanSinceStartThreshold(defaultSpanSinceStartThreshold);
@@ -659,11 +662,9 @@ final class MapGestureDetector {
notifyOnRotateEndListeners(detector);
- if (!uiSettings.isRotateVelocityAnimationEnabled()) {
- return;
- }
-
- if (Math.abs(angularVelocity) < minimumAngularVelocity) {
+ if (!uiSettings.isRotateVelocityAnimationEnabled() || Math.abs(angularVelocity) < minimumAngularVelocity) {
+ // notifying listeners that camera is idle only if there is no follow-up animation
+ cameraChangeDispatcher.onCameraIdle();
return;
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
index 89c8a68abd..42711a4379 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
@@ -13,6 +13,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
+
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -20,6 +21,7 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+
import timber.log.Timber;
/**