Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose a MoveGestureDetector#moveThresholdRect #96

Merged
merged 3 commits into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ object GesturesUiTestUtils {
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0)
injectMotionEventToUiController(uiController, event)
} catch (ex: InjectEventSecurityException) {
throw RuntimeException("Could not perform quick scale", ex)
throw RuntimeException("Could not perform move", ex)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.mapbox.android.gestures

import GesturesUiTestUtils.DEFAULT_GESTURE_DURATION
import GesturesUiTestUtils.move
import android.graphics.PointF
import android.graphics.RectF
import androidx.test.espresso.Espresso
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import com.mapbox.android.gestures.testapp.R
import com.mapbox.android.gestures.testapp.TestActivity
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

@RunWith(AndroidJUnit4::class)
class MoveGestureDetectorTest {

@Rule
@JvmField
val activityTestRule = ActivityTestRule(TestActivity::class.java)

private lateinit var gesturesManager: AndroidGesturesManager

@Before
fun setup() {
gesturesManager = activityTestRule.activity.gesturesManager
}

@Test
fun move_ignoredWithRectThreshold() {
val rect = RectF(400f, 400f, 600f, 600f)
gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector) = true

override fun onMove(
detector: MoveGestureDetector,
distanceX: Float,
distanceY: Float
): Boolean = throw AssertionError("onMove shouldn't be called if threshold was not met")

override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit

})
gesturesManager.moveGestureDetector.moveThresholdRect = rect
Espresso.onView(ViewMatchers.withId(R.id.content)).perform(
move(
deltaX = 50f,
deltaY = 50f,
startPoint = PointF(rect.right - 100f, rect.bottom - 100f)
)
)
}

@Test
fun move_executedWhenOutsideOfRect() {
val latch = CountDownLatch(1)
val rect = RectF(400f, 400f, 600f, 600f)
gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector) = true

override fun onMove(
detector: MoveGestureDetector,
distanceX: Float,
distanceY: Float
): Boolean {
Assert.assertFalse(rect.contains(detector.focalPoint.x, detector.focalPoint.y))
latch.countDown()
return true
}

override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit

})
gesturesManager.moveGestureDetector.moveThresholdRect = rect
Espresso.onView(ViewMatchers.withId(R.id.content)).perform(
move(
deltaX = 100f,
deltaY = 100f,
startPoint = PointF(rect.right + 50f, rect.bottom + 50f)
)
)
if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) {
Assert.fail("move was not called")
}
}

@Test
fun move_executedWhenRectThresholdMet() {
val latch = CountDownLatch(1)
val rect = RectF(400f, 400f, 600f, 600f)
gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector) = true

override fun onMove(
detector: MoveGestureDetector,
distanceX: Float,
distanceY: Float
): Boolean {
Assert.assertFalse(rect.contains(detector.focalPoint.x, detector.focalPoint.y))
latch.countDown()
return true
}

override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) = Unit

})
gesturesManager.moveGestureDetector.moveThresholdRect = rect
Espresso.onView(ViewMatchers.withId(R.id.content)).perform(
move(
deltaX = -150f,
deltaY = -150f,
startPoint = PointF(500f, 500f)
)
)
if (!latch.await(DEFAULT_GESTURE_DURATION, TimeUnit.MILLISECONDS)) {
Assert.fail("move was not called")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import android.os.Build
import android.os.Handler
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.rule.ActivityTestRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import com.mapbox.android.gestures.testapp.R
import com.mapbox.android.gestures.testapp.TestActivity
import org.junit.Assert
Expand Down Expand Up @@ -449,11 +449,9 @@ class ScaleGestureDetectorTest {
override fun onScaleEnd(detector: StandardScaleGestureDetector, velocityX: Float, velocityY: Float) {
endInvocations[0]++
gesturesManager.setMoveGestureListener(object : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector?): Boolean {
return true
}
override fun onMoveBegin(detector: MoveGestureDetector) = true

override fun onMove(detector: MoveGestureDetector?, distanceX: Float, distanceY: Float): Boolean {
override fun onMove(detector: MoveGestureDetector, distanceX: Float, distanceY: Float): Boolean {
if (endInvocations[0] == 1) {
moveAfterInterruption = true
} else {
Expand All @@ -462,8 +460,7 @@ class ScaleGestureDetectorTest {
return true
}

override fun onMoveEnd(detector: MoveGestureDetector?, velocityX: Float, velocityY: Float) {
}
override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) {}
})
}
})
Expand Down Expand Up @@ -615,7 +612,6 @@ class ScaleGestureDetectorTest {
}
})

onView(withId(R.id.content)).perform(quickScale(gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L))
onView(withId(R.id.content)).perform(move(300f, 300f, withVelocity = false))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import android.content.Context;
import android.graphics.PointF;
import android.graphics.RectF;
import android.view.MotionEvent;

import androidx.annotation.DimenRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import android.view.MotionEvent;

import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -38,7 +41,10 @@ public class MoveGestureDetector extends ProgressiveGesture<MoveGestureDetector.
handledTypes.add(GESTURE_TYPE_MOVE);
}

@Nullable
private RectF moveThresholdRect;
private float moveThreshold;

private final Map<Integer, MoveDistancesObject> moveDistancesObjectMap = new HashMap<>();

public MoveGestureDetector(Context context, AndroidGesturesManager gesturesManager) {
Expand Down Expand Up @@ -172,10 +178,11 @@ private void updateMoveDistancesObjects() {

boolean checkAnyMoveAboveThreshold() {
for (MoveDistancesObject moveDistancesObject : moveDistancesObjectMap.values()) {
if (Math.abs(moveDistancesObject.getDistanceXSinceStart()) >= moveThreshold
|| Math.abs(moveDistancesObject.getDistanceYSinceStart()) >= moveThreshold) {
return true;
}
boolean thresholdExceeded = Math.abs(moveDistancesObject.getDistanceXSinceStart()) >= moveThreshold
|| Math.abs(moveDistancesObject.getDistanceYSinceStart()) >= moveThreshold;

boolean isInRect = moveThresholdRect != null && moveThresholdRect.contains(getFocalPoint().x, getFocalPoint().y);
return !isInRect && thresholdExceeded;
pengdev marked this conversation as resolved.
Show resolved Hide resolved
}
return false;
}
Expand Down Expand Up @@ -205,6 +212,7 @@ protected int getRequiredPointersCount() {
* Get the delta pixel threshold required to qualify it as a move gesture.
*
* @return delta pixel threshold
* @see #getMoveThresholdRect()
*/
public float getMoveThreshold() {
return moveThreshold;
Expand All @@ -216,11 +224,35 @@ public float getMoveThreshold() {
* We encourage to set those values from dimens to accommodate for various screen sizes.
*
* @param moveThreshold delta threshold
* @see #setMoveThresholdRect(RectF)
*/
public void setMoveThreshold(float moveThreshold) {
this.moveThreshold = moveThreshold;
}

/**
* Get the screen area in which the move gesture cannot be started.
* If the gesture is already in progress, this value is ignored.
* This condition is evaluated before {@link #setMoveThreshold(float)}.
*
* @return the screen area in which the gesture cannot be started
*/
@Nullable
public RectF getMoveThresholdRect() {
return moveThresholdRect;
}

/**
* Set the screen area in which the move gesture cannot be started.
* If the gesture is already in progress, this value is ignored.
* This condition is evaluated before {@link #setMoveThreshold(float)}.
*
* @param moveThresholdRect the screen area in which the gesture cannot be started
*/
public void setMoveThresholdRect(@Nullable RectF moveThresholdRect) {
this.moveThresholdRect = moveThresholdRect;
}

/**
* Set the delta dp threshold required to qualify it as a move gesture.
*
Expand Down