Loading core/java/android/widget/Editor.java +3 −24 Original line number Diff line number Diff line Loading @@ -5921,8 +5921,6 @@ public class Editor { // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; private boolean mGestureStayedInTapRegion; // Where the user first starts the drag motion. private int mStartOffset = -1; Loading Loading @@ -6029,8 +6027,7 @@ public class Editor { eventX, eventY); // Double tap detection if (mGestureStayedInTapRegion && mTouchState.isMultiTapInSameArea() if (mTouchState.isMultiTapInSameArea() && (isMouse || isPositionOnText(eventX, eventY))) { if (TextView.DEBUG_CURSOR) { logCursor("SelectionModifierCursorController: onTouchEvent", Loading @@ -6043,7 +6040,6 @@ public class Editor { } mDiscardNextActionUp = true; } mGestureStayedInTapRegion = true; mHaventMovedEnoughToStartDrag = true; } break; Loading @@ -6059,25 +6055,8 @@ public class Editor { break; case MotionEvent.ACTION_MOVE: final ViewConfiguration viewConfig = ViewConfiguration.get( mTextView.getContext()); if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) { final float deltaX = eventX - mTouchState.getLastDownX(); final float deltaY = eventY - mTouchState.getLastDownY(); final float distanceSquared = deltaX * deltaX + deltaY * deltaY; if (mGestureStayedInTapRegion) { int doubleTapTouchSlop = viewConfig.getScaledDoubleTapTouchSlop(); mGestureStayedInTapRegion = distanceSquared <= doubleTapTouchSlop * doubleTapTouchSlop; } if (mHaventMovedEnoughToStartDrag) { // We don't start dragging until the user has moved enough. int touchSlop = viewConfig.getScaledTouchSlop(); mHaventMovedEnoughToStartDrag = distanceSquared <= touchSlop * touchSlop; } mHaventMovedEnoughToStartDrag = !mTouchState.isMovedEnoughForDrag(); } if (isMouse && !isDragAcceleratorActive()) { Loading core/java/android/widget/EditorTouchState.java +13 −1 Original line number Diff line number Diff line Loading @@ -31,13 +31,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Helper class used by {@link Editor} to track state for touch events. * Helper class used by {@link Editor} to track state for touch events. Ideally the logic here * should be replaced with {@link android.view.GestureDetector}. * * @hide */ @VisibleForTesting(visibility = PACKAGE) public class EditorTouchState { private float mLastDownX, mLastDownY; private long mLastDownMillis; private float mLastUpX, mLastUpY; private long mLastUpMillis; Loading Loading @@ -106,9 +108,18 @@ public class EditorTouchState { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE); // We check both the time between the last up and current down event, as well as the // time between the first down and up events. The latter check is necessary to handle // the case when the user taps, drags/holds for some time, and then lifts up and // quickly taps in the same area. This scenario should not be treated as a double-tap. // This follows the behavior in GestureDetector. final long millisSinceLastUp = event.getEventTime() - mLastUpMillis; final long millisBetweenLastDownAndLastUp = mLastUpMillis - mLastDownMillis; // Detect double tap and triple click. if (millisSinceLastUp <= ViewConfiguration.getDoubleTapTimeout() && millisBetweenLastDownAndLastUp <= ViewConfiguration.getDoubleTapTimeout() && (mMultiTapStatus == MultiTapStatus.FIRST_TAP || (mMultiTapStatus == MultiTapStatus.DOUBLE_TAP && isMouse))) { if (mMultiTapStatus == MultiTapStatus.FIRST_TAP) { Loading @@ -133,6 +144,7 @@ public class EditorTouchState { } mLastDownX = event.getX(); mLastDownY = event.getY(); mLastDownMillis = event.getEventTime(); mMovedEnoughForDrag = false; mIsDragCloseToVertical = false; } else if (action == MotionEvent.ACTION_UP) { Loading core/tests/coretests/src/android/widget/EditorCursorDragTest.java +66 −20 Original line number Diff line number Diff line Loading @@ -225,6 +225,61 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(initialCursorPosition)); } @Test public void testEditor_onTouchEvent_quickTapAfterDrag() throws Throwable { String text = "Hi world!"; onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); TextView tv = mActivity.findViewById(R.id.textview); Editor editor = tv.getEditorForTesting(); // Simulate a tap-and-drag gesture. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 5f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 50f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = moveEvent(event1Time, event3Time, 100f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event4Time = 2004; MotionEvent event4 = upEvent(event1Time, event4Time, 100f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); // Simulate a quick tap after the drag, near the location where the drag ended. long event5Time = 2005; MotionEvent event5 = downEvent(event5Time, event5Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event6Time = 2006; MotionEvent event6 = upEvent(event5Time, event6Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event6)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); // Simulate another quick tap in the same location; now selection should be triggered. long event7Time = 2007; MotionEvent event7 = downEvent(event7Time, event7Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event7)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); } @Test public void testEditor_onTouchEvent_cursorDrag() throws Throwable { String text = "testEditor_onTouchEvent_cursorDrag"; Loading @@ -237,29 +292,25 @@ public class EditorCursorDragTest { // Simulate a tap-and-drag gesture. This should trigger a cursor drag. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event1)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event2)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = moveEvent(event3Time, event3Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event3)); mInstrumentation.waitForIdleSync(); MotionEvent event3 = moveEvent(event1Time, event3Time, 120f, 30f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event4Time = 1004; MotionEvent event4 = upEvent(event3Time, event4Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event4)); mInstrumentation.waitForIdleSync(); MotionEvent event4 = upEvent(event1Time, event4Time, 120f, 30f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); } Loading @@ -276,36 +327,31 @@ public class EditorCursorDragTest { // Simulate a double-tap followed by a drag. This should trigger a selection drag. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event1)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event2)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = downEvent(event3Time, event3Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event3)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); long event4Time = 1004; MotionEvent event4 = moveEvent(event3Time, event4Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event4)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); long event5Time = 1005; MotionEvent event5 = upEvent(event3Time, event5Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event5)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); } Loading core/tests/coretests/src/android/widget/EditorTouchStateTest.java +54 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,60 @@ public class EditorTouchStateTest { MultiTapStatus.DOUBLE_TAP, false); } @Test public void testUpdate_doubleTap_delayAfterFirstDownEvent() throws Exception { // Simulate an ACTION_DOWN event. long event1Time = 1000; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mTouchState.update(event1, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, false); // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout. long event2Time = 1000 + ViewConfiguration.getDoubleTapTimeout() + 1; MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f); mTouchState.update(event2, mConfig); assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false); // Generate an ACTION_DOWN event whose time is within the double-tap timeout when // calculated from the last ACTION_UP event time. Even though the time between the last up // and this down event is within the double-tap timeout, this should not be considered a // double-tap (since the first down event had a longer delay). long event3Time = event2Time + 1; MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f); mTouchState.update(event3, mConfig); assertSingleTap(mTouchState, 22f, 33f, 20f, 30f, false); } @Test public void testUpdate_quickTapAfterDrag() throws Exception { // Simulate an ACTION_DOWN event. long event1Time = 1000; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mTouchState.update(event1, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, false); // Simulate an ACTION_MOVE event. long event2Time = 1001; MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f); mTouchState.update(event2, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, true); // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout. long event3Time = 5000; MotionEvent event3 = upEvent(event1Time, event3Time, 200f, 31f); mTouchState.update(event3, mConfig); assertSingleTap(mTouchState, 20f, 30f, 200f, 31f, false); // Generate an ACTION_DOWN event whose time is within the double-tap timeout when // calculated from the last ACTION_UP event time. Even though the time between the last up // and this down event is within the double-tap timeout, this should not be considered a // double-tap (since the first down event had a longer delay). long event4Time = event3Time + 1; MotionEvent event4 = downEvent(event4Time, event4Time, 200f, 31f); mTouchState.update(event4, mConfig); assertSingleTap(mTouchState, 200f, 31f, 200f, 31f, false); } @Test public void testUpdate_tripleClick_mouse() throws Exception { // Simulate an ACTION_DOWN event. Loading Loading
core/java/android/widget/Editor.java +3 −24 Original line number Diff line number Diff line Loading @@ -5921,8 +5921,6 @@ public class Editor { // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; private boolean mGestureStayedInTapRegion; // Where the user first starts the drag motion. private int mStartOffset = -1; Loading Loading @@ -6029,8 +6027,7 @@ public class Editor { eventX, eventY); // Double tap detection if (mGestureStayedInTapRegion && mTouchState.isMultiTapInSameArea() if (mTouchState.isMultiTapInSameArea() && (isMouse || isPositionOnText(eventX, eventY))) { if (TextView.DEBUG_CURSOR) { logCursor("SelectionModifierCursorController: onTouchEvent", Loading @@ -6043,7 +6040,6 @@ public class Editor { } mDiscardNextActionUp = true; } mGestureStayedInTapRegion = true; mHaventMovedEnoughToStartDrag = true; } break; Loading @@ -6059,25 +6055,8 @@ public class Editor { break; case MotionEvent.ACTION_MOVE: final ViewConfiguration viewConfig = ViewConfiguration.get( mTextView.getContext()); if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) { final float deltaX = eventX - mTouchState.getLastDownX(); final float deltaY = eventY - mTouchState.getLastDownY(); final float distanceSquared = deltaX * deltaX + deltaY * deltaY; if (mGestureStayedInTapRegion) { int doubleTapTouchSlop = viewConfig.getScaledDoubleTapTouchSlop(); mGestureStayedInTapRegion = distanceSquared <= doubleTapTouchSlop * doubleTapTouchSlop; } if (mHaventMovedEnoughToStartDrag) { // We don't start dragging until the user has moved enough. int touchSlop = viewConfig.getScaledTouchSlop(); mHaventMovedEnoughToStartDrag = distanceSquared <= touchSlop * touchSlop; } mHaventMovedEnoughToStartDrag = !mTouchState.isMovedEnoughForDrag(); } if (isMouse && !isDragAcceleratorActive()) { Loading
core/java/android/widget/EditorTouchState.java +13 −1 Original line number Diff line number Diff line Loading @@ -31,13 +31,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Helper class used by {@link Editor} to track state for touch events. * Helper class used by {@link Editor} to track state for touch events. Ideally the logic here * should be replaced with {@link android.view.GestureDetector}. * * @hide */ @VisibleForTesting(visibility = PACKAGE) public class EditorTouchState { private float mLastDownX, mLastDownY; private long mLastDownMillis; private float mLastUpX, mLastUpY; private long mLastUpMillis; Loading Loading @@ -106,9 +108,18 @@ public class EditorTouchState { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE); // We check both the time between the last up and current down event, as well as the // time between the first down and up events. The latter check is necessary to handle // the case when the user taps, drags/holds for some time, and then lifts up and // quickly taps in the same area. This scenario should not be treated as a double-tap. // This follows the behavior in GestureDetector. final long millisSinceLastUp = event.getEventTime() - mLastUpMillis; final long millisBetweenLastDownAndLastUp = mLastUpMillis - mLastDownMillis; // Detect double tap and triple click. if (millisSinceLastUp <= ViewConfiguration.getDoubleTapTimeout() && millisBetweenLastDownAndLastUp <= ViewConfiguration.getDoubleTapTimeout() && (mMultiTapStatus == MultiTapStatus.FIRST_TAP || (mMultiTapStatus == MultiTapStatus.DOUBLE_TAP && isMouse))) { if (mMultiTapStatus == MultiTapStatus.FIRST_TAP) { Loading @@ -133,6 +144,7 @@ public class EditorTouchState { } mLastDownX = event.getX(); mLastDownY = event.getY(); mLastDownMillis = event.getEventTime(); mMovedEnoughForDrag = false; mIsDragCloseToVertical = false; } else if (action == MotionEvent.ACTION_UP) { Loading
core/tests/coretests/src/android/widget/EditorCursorDragTest.java +66 −20 Original line number Diff line number Diff line Loading @@ -225,6 +225,61 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(initialCursorPosition)); } @Test public void testEditor_onTouchEvent_quickTapAfterDrag() throws Throwable { String text = "Hi world!"; onView(withId(R.id.textview)).perform(replaceText(text)); onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); TextView tv = mActivity.findViewById(R.id.textview); Editor editor = tv.getEditorForTesting(); // Simulate a tap-and-drag gesture. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 5f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 50f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = moveEvent(event1Time, event3Time, 100f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event4Time = 2004; MotionEvent event4 = upEvent(event1Time, event4Time, 100f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); // Simulate a quick tap after the drag, near the location where the drag ended. long event5Time = 2005; MotionEvent event5 = downEvent(event5Time, event5Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event6Time = 2006; MotionEvent event6 = upEvent(event5Time, event6Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event6)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); // Simulate another quick tap in the same location; now selection should be triggered. long event7Time = 2007; MotionEvent event7 = downEvent(event7Time, event7Time, 90f, 10f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event7)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); } @Test public void testEditor_onTouchEvent_cursorDrag() throws Throwable { String text = "testEditor_onTouchEvent_cursorDrag"; Loading @@ -237,29 +292,25 @@ public class EditorCursorDragTest { // Simulate a tap-and-drag gesture. This should trigger a cursor drag. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event1)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event2)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = moveEvent(event3Time, event3Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event3)); mInstrumentation.waitForIdleSync(); MotionEvent event3 = moveEvent(event1Time, event3Time, 120f, 30f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertTrue(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event4Time = 1004; MotionEvent event4 = upEvent(event3Time, event4Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event4)); mInstrumentation.waitForIdleSync(); MotionEvent event4 = upEvent(event1Time, event4Time, 120f, 30f); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); } Loading @@ -276,36 +327,31 @@ public class EditorCursorDragTest { // Simulate a double-tap followed by a drag. This should trigger a selection drag. long event1Time = 1001; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event1)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event2Time = 1002; MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event2)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); long event3Time = 1003; MotionEvent event3 = downEvent(event3Time, event3Time, 20f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event3)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); long event4Time = 1004; MotionEvent event4 = moveEvent(event3Time, event4Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event4)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertTrue(editor.getSelectionController().isCursorBeingModified()); long event5Time = 1005; MotionEvent event5 = upEvent(event3Time, event5Time, 120f, 30f); mActivity.runOnUiThread(() -> editor.onTouchEvent(event5)); mInstrumentation.waitForIdleSync(); mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5)); assertFalse(editor.getInsertionController().isCursorBeingModified()); assertFalse(editor.getSelectionController().isCursorBeingModified()); } Loading
core/tests/coretests/src/android/widget/EditorTouchStateTest.java +54 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,60 @@ public class EditorTouchStateTest { MultiTapStatus.DOUBLE_TAP, false); } @Test public void testUpdate_doubleTap_delayAfterFirstDownEvent() throws Exception { // Simulate an ACTION_DOWN event. long event1Time = 1000; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mTouchState.update(event1, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, false); // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout. long event2Time = 1000 + ViewConfiguration.getDoubleTapTimeout() + 1; MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f); mTouchState.update(event2, mConfig); assertSingleTap(mTouchState, 20f, 30f, 20f, 30f, false); // Generate an ACTION_DOWN event whose time is within the double-tap timeout when // calculated from the last ACTION_UP event time. Even though the time between the last up // and this down event is within the double-tap timeout, this should not be considered a // double-tap (since the first down event had a longer delay). long event3Time = event2Time + 1; MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f); mTouchState.update(event3, mConfig); assertSingleTap(mTouchState, 22f, 33f, 20f, 30f, false); } @Test public void testUpdate_quickTapAfterDrag() throws Exception { // Simulate an ACTION_DOWN event. long event1Time = 1000; MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f); mTouchState.update(event1, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, false); // Simulate an ACTION_MOVE event. long event2Time = 1001; MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f); mTouchState.update(event2, mConfig); assertSingleTap(mTouchState, 20f, 30f, 0, 0, true); // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout. long event3Time = 5000; MotionEvent event3 = upEvent(event1Time, event3Time, 200f, 31f); mTouchState.update(event3, mConfig); assertSingleTap(mTouchState, 20f, 30f, 200f, 31f, false); // Generate an ACTION_DOWN event whose time is within the double-tap timeout when // calculated from the last ACTION_UP event time. Even though the time between the last up // and this down event is within the double-tap timeout, this should not be considered a // double-tap (since the first down event had a longer delay). long event4Time = event3Time + 1; MotionEvent event4 = downEvent(event4Time, event4Time, 200f, 31f); mTouchState.update(event4, mConfig); assertSingleTap(mTouchState, 200f, 31f, 200f, 31f, false); } @Test public void testUpdate_tripleClick_mouse() throws Exception { // Simulate an ACTION_DOWN event. Loading