From ac0431eac5ee6a16f7f32707effda20362107df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 11 Jul 2019 16:04:30 +0200 Subject: [android] ensure that move detector is enabled if double-tap is interrupted --- .../mapbox/mapboxsdk/maps/MapGestureDetector.java | 37 ++++++++++++++++------ .../mapboxsdk/maps/MapGestureDetectorTest.kt | 25 +++++++++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) 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 5003d62c46..eba87de0b2 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 @@ -86,6 +86,8 @@ final class MapGestureDetector { @NonNull private Handler animationsTimeoutHandler = new Handler(); + private boolean doubleTapRegistered; + MapGestureDetector(@Nullable Context context, Transform transform, Projection projection, UiSettings uiSettings, AnnotationManager annotationManager, CameraChangeDispatcher cameraChangeDispatcher) { this.annotationManager = annotationManager; @@ -199,7 +201,12 @@ final class MapGestureDetector { boolean result = gesturesManager.onTouchEvent(motionEvent); switch (motionEvent.getActionMasked()) { + case MotionEvent.ACTION_POINTER_DOWN: + doubleTapFinished(); + break; + case MotionEvent.ACTION_UP: + doubleTapFinished(); transform.setGestureInProgress(false); if (!scheduledAnimators.isEmpty()) { @@ -215,6 +222,7 @@ final class MapGestureDetector { case MotionEvent.ACTION_CANCEL: scheduledAnimators.clear(); transform.setGestureInProgress(false); + doubleTapFinished(); break; } @@ -344,16 +352,10 @@ final class MapGestureDetector { int action = motionEvent.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { doubleTapFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY()); - - // disable the move detector in preparation for the quickzoom, - // so that we don't move the map's center slightly before the quickzoom is started (see #14227) - gesturesManager.getMoveGestureDetector().setEnabled(false); + doubleTapStarted(); } if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { - // re-enable the move detector - gesturesManager.getMoveGestureDetector().setEnabled(true); - float diffX = Math.abs(motionEvent.getX() - doubleTapFocalPoint.x); float diffY = Math.abs(motionEvent.getY() - doubleTapFocalPoint.y); if (diffX > doubleTapMovementThreshold || diffY > doubleTapMovementThreshold) { @@ -426,6 +428,21 @@ final class MapGestureDetector { } } + private void doubleTapStarted() { + // disable the move detector in preparation for the quickzoom, + // so that we don't move the map's center slightly before the quickzoom is started (see #14227) + gesturesManager.getMoveGestureDetector().setEnabled(false); + doubleTapRegistered = true; + } + + private void doubleTapFinished() { + if (doubleTapRegistered) { + // re-enable the move detector in case of double tap + gesturesManager.getMoveGestureDetector().setEnabled(true); + doubleTapRegistered = false; + } + } + private final class MoveGestureListener extends MoveGestureDetector.SimpleOnMoveGestureListener { @Override public boolean onMoveBegin(@NonNull MoveGestureDetector detector) { @@ -481,6 +498,8 @@ final class MapGestureDetector { if (!uiSettings.isQuickZoomGesturesEnabled()) { return false; } + // re-try disabling the move detector in case double tap has been interrupted before quickzoom started + gesturesManager.getMoveGestureDetector().setEnabled(false); } cancelTransitionsIfRequired(); @@ -516,9 +535,7 @@ final class MapGestureDetector { @Override public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) { if (quickZoom) { - // re-enabled the move detector only if the quickzoom happened - // we need to split the responsibility of re-enabling the move detector, - // because the double tap event (where the detector is disabled) can be canceled without warning (see #14598) + // re-enabled the move detector if the quickzoom happened gesturesManager.getMoveGestureDetector().setEnabled(true); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt index 7650e1ff60..1e5cdf8b73 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapGestureDetectorTest.kt @@ -158,4 +158,29 @@ class MapGestureDetectorTest : BaseTest() { Assert.assertEquals(initialZoom!!, mapboxMap.cameraPosition.zoom, 0.01) } } + + @Test + fun doubleTap_interrupted_moveStillEnabled() { + validateTestSetup() + + rule.runOnUiThread { + mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4.0)) + } + + onView(withId(R.id.mapView)).perform(quickScale(mapboxMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L, interrupt = true)) + + var expectedTarget: LatLng? = null + rule.runOnUiThread { + val currentPoint = mapboxMap.projection.toScreenLocation(mapboxMap.cameraPosition.target) + val resultingPoint = PointF(currentPoint.x + maxWidth / 2f, currentPoint.y + maxHeight / 2f) + expectedTarget = mapboxMap.projection.fromScreenLocation(resultingPoint) + } + + // move to expected target + onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false)) + rule.runOnUiThread { + Assert.assertEquals(expectedTarget!!.latitude, mapboxMap.cameraPosition.target.latitude, 10.0) + Assert.assertEquals(expectedTarget!!.longitude, mapboxMap.cameraPosition.target.longitude, 10.0) + } + } } \ No newline at end of file -- cgit v1.2.1