Loading services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +117 −22 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.server.accessibility.autoclick.AutoclickScrollPanel.DI import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_DOUBLE_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_DRAG; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType; Loading Loading @@ -85,6 +86,11 @@ public class AutoclickController extends BaseEventStreamTransformation { public static final int DEFAULT_AUTOCLICK_DELAY_TIME = Flags.enableAutoclickIndicator() ? AUTOCLICK_DELAY_WITH_INDICATOR_DEFAULT : AUTOCLICK_DELAY_DEFAULT; // Duration before a press turns into a long press. // Factor 1.5 is needed, otherwise a long press is not safely detected. public static final long LONG_PRESS_TIMEOUT = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); private static final String LOG_TAG = AutoclickController.class.getSimpleName(); // TODO(b/393559560): Finalize scroll amount. private static final float SCROLL_AMOUNT = 1.0f; Loading Loading @@ -125,6 +131,12 @@ public class AutoclickController extends BaseEventStreamTransformation { // move. private long mDragModeClickDownTime; // True during the duration of a long press event. private boolean mHasOngoingLongPress = false; // The MotionEvent downTime attribute associated with the originating click for a long press // move. private long mLongPressDownTime; @VisibleForTesting final ClickPanelControllerInterface clickPanelController = new ClickPanelControllerInterface() { Loading Loading @@ -426,6 +438,11 @@ public class AutoclickController extends BaseEventStreamTransformation { return mDragModeIsDragging; } @VisibleForTesting boolean hasOngoingLongPressForTesting() { return mHasOngoingLongPress; } /** * Observes autoclick setting values, and updates ClickScheduler delay and indicator size * whenever the setting value changes. Loading Loading @@ -768,6 +785,11 @@ public class AutoclickController extends BaseEventStreamTransformation { if (mDragModeIsDragging) { clearDraggingState(); } if (mHasOngoingLongPress) { clearLongPressState(); } resetInternalState(); mHandler.removeCallbacks(this); } Loading @@ -789,6 +811,23 @@ public class AutoclickController extends BaseEventStreamTransformation { mDragModeIsDragging = false; } // Cancel the pending long press to avoid potential side effects from // leaving it in an inconsistent state. private void clearLongPressState() { if (mLastMotionEvent != null) { // A final ACTION_CANCEL event needs to be sent to alert the system that long press // has ended. MotionEvent cancelEvent = MotionEvent.obtain(mLastMotionEvent); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); cancelEvent.setDownTime(mLongPressDownTime); AutoclickController.super.onMotionEvent(cancelEvent, cancelEvent, mEventPolicyFlags); } resetSelectedClickTypeIfNecessary(); mHasOngoingLongPress = false; } /** * Updates the meta state that should be used for click sequence. */ Loading Loading @@ -943,6 +982,12 @@ public class AutoclickController extends BaseEventStreamTransformation { return; } // Clear pending long press in case another click action jumps between long pressing // down and up events. if (mHasOngoingLongPress) { clearLongPressState(); } // Always triggers left-click when the cursor hovers over the autoclick type panel, to // always allow users to change a different click type. Otherwise, if one chooses the // right-click, this user won't be able to rely on autoclick to select other click Loading Loading @@ -989,6 +1034,10 @@ public class AutoclickController extends BaseEventStreamTransformation { startDragEvent(); } return; case AUTOCLICK_TYPE_LONG_PRESS: actionButton = BUTTON_PRIMARY; sendLongPress(); return; default: break; } Loading Loading @@ -1043,22 +1092,8 @@ public class AutoclickController extends BaseEventStreamTransformation { } private void sendMotionEvent(int actionButton, long eventTime) { MotionEvent downEvent = MotionEvent.obtain( /* downTime= */ eventTime, /* eventTime= */ eventTime, MotionEvent.ACTION_DOWN, /* pointerCount= */ 1, mTempPointerProperties, mTempPointerCoords, mMetaState, actionButton, /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, mLastMotionEvent.getDeviceId(), /* edgeFlags= */ 0, mLastMotionEvent.getSource(), mLastMotionEvent.getFlags()); MotionEvent downEvent = buildMotionEvent( eventTime, eventTime, actionButton, mLastMotionEvent); MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); Loading Loading @@ -1086,6 +1121,66 @@ public class AutoclickController extends BaseEventStreamTransformation { upEvent.recycle(); } // TODO(b/400744833): Reset Autoclick type to left click whenever a long press happens. private void sendLongPress() { mHasOngoingLongPress = true; mLongPressDownTime = SystemClock.uptimeMillis(); MotionEvent downEvent = buildMotionEvent( mLongPressDownTime, mLongPressDownTime, BUTTON_PRIMARY, mLastMotionEvent); MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); AutoclickController.super.onMotionEvent(downEvent, downEvent, mEventPolicyFlags); AutoclickController.super.onMotionEvent(pressEvent, pressEvent, mEventPolicyFlags); mHandler.postDelayed(new Runnable() { @Override public void run() { long upTime = SystemClock.uptimeMillis(); MotionEvent releaseEvent = buildMotionEvent( mLongPressDownTime, upTime, BUTTON_PRIMARY, downEvent); releaseEvent.setAction(MotionEvent.ACTION_BUTTON_RELEASE); releaseEvent.setButtonState(0); MotionEvent upEvent = MotionEvent.obtain(releaseEvent); upEvent.setAction(MotionEvent.ACTION_UP); upEvent.setButtonState(0); AutoclickController.super.onMotionEvent( releaseEvent, releaseEvent, mEventPolicyFlags); AutoclickController.super.onMotionEvent( upEvent, upEvent, mEventPolicyFlags); downEvent.recycle(); pressEvent.recycle(); releaseEvent.recycle(); upEvent.recycle(); mHasOngoingLongPress = false; } }, LONG_PRESS_TIMEOUT); } private @NonNull MotionEvent buildMotionEvent( long downTime, long eventTime, int actionButton, @NonNull MotionEvent lastMotionEvent) { return MotionEvent.obtain( /* downTime= */ downTime, /* eventTime= */ eventTime, MotionEvent.ACTION_DOWN, /* pointerCount= */ 1, mTempPointerProperties, mTempPointerCoords, mMetaState, actionButton, /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, lastMotionEvent.getDeviceId(), /* edgeFlags= */ 0, lastMotionEvent.getSource(), lastMotionEvent.getFlags()); } // To start a drag event, only send the DOWN and BUTTON_PRESS events. private void startDragEvent() { mDragModeClickDownTime = SystemClock.uptimeMillis(); Loading services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java +89 −5 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; /** Test cases for {@link AutoclickController}. */ @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) Loading @@ -83,31 +86,44 @@ public class AutoclickControllerTest { public MotionEvent buttonReleaseEvent; public MotionEvent upEvent; public MotionEvent moveEvent; public MotionEvent cancelEvent; public int eventCount = 0; private List<MotionEvent> mEventList = new ArrayList<>(); @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { MotionEvent eventCopy = MotionEvent.obtain(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_BUTTON_PRESS: buttonPressEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_BUTTON_RELEASE: buttonReleaseEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_UP: upEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_MOVE: moveEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_CANCEL: cancelEvent = eventCopy; break; default: return; } mEventList.add(eventCopy); eventCount++; } public void assertCapturedEvents(int... actionsInOrder) { assertThat(eventCount).isEqualTo(mEventList.size()); for (int i = 0; i < eventCount; i++) { assertThat(actionsInOrder[i]) .isEqualTo(mEventList.get(i).getAction()); } } } Loading Loading @@ -1187,6 +1203,74 @@ public class AutoclickControllerTest { verify(mockAutoclickTypePanel, Mockito.never()).resetSelectedClickType(); } @Test @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) public void sendClick_clickType_longPress_triggerPressAndHold() { MotionEventCaptor motionEventCaptor = new MotionEventCaptor(); mController.setNext(motionEventCaptor); injectFakeMouseActionHoverMoveEvent(); // Set delay to zero so click is scheduled to run immediately. mController.mClickScheduler.updateDelay(0); // Set click type to long press. mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS); AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); mController.mAutoclickTypePanel = mockAutoclickTypePanel; // Send hover move event. injectFakeMouseMoveEvent(/* x= */ 30f, /* y= */ 0, MotionEvent.ACTION_HOVER_MOVE); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.downEvent).isNotNull(); assertThat(motionEventCaptor.downEvent.getButtonState()).isEqualTo( MotionEvent.BUTTON_PRIMARY); assertThat(motionEventCaptor.upEvent).isNull(); // When all messages (with delays) are processed. mTestableLooper.moveTimeForward(mController.LONG_PRESS_TIMEOUT); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.upEvent).isNotNull(); motionEventCaptor.assertCapturedEvents( MotionEvent.ACTION_DOWN, MotionEvent.ACTION_BUTTON_PRESS, MotionEvent.ACTION_BUTTON_RELEASE, MotionEvent.ACTION_UP); } @Test @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) public void sendClick_clickType_longPress_interruptCancelsLongPress() { MotionEventCaptor motionEventCaptor = new MotionEventCaptor(); mController.setNext(motionEventCaptor); injectFakeMouseActionHoverMoveEvent(); // Set delay to zero so click is scheduled to run immediately. mController.mClickScheduler.updateDelay(0); // Set click type to long press. mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS); AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); mController.mAutoclickTypePanel = mockAutoclickTypePanel; // Send hover move event. injectFakeMouseMoveEvent(/* x= */ 100f, /* y= */ 0, MotionEvent.ACTION_HOVER_MOVE); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.downEvent).isNotNull(); assertThat(motionEventCaptor.downEvent.getButtonState()).isEqualTo( MotionEvent.BUTTON_PRIMARY); assertThat(motionEventCaptor.upEvent).isNull(); assertThat(mController.hasOngoingLongPressForTesting()).isTrue(); assertThat(motionEventCaptor.cancelEvent).isNull(); // Send another hover move event to interrupt the long press. mTestableLooper.moveTimeForward(mController.LONG_PRESS_TIMEOUT / 2); mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK); injectFakeMouseMoveEvent(/* x= */ 0, /* y= */ 30f, MotionEvent.ACTION_HOVER_MOVE); mController.mClickScheduler.run(); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.cancelEvent).isNotNull(); assertThat(mController.hasOngoingLongPressForTesting()).isFalse(); } /** * ========================================================================= * Helper Functions Loading Loading
services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +117 −22 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.server.accessibility.autoclick.AutoclickScrollPanel.DI import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_DOUBLE_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_DRAG; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType; Loading Loading @@ -85,6 +86,11 @@ public class AutoclickController extends BaseEventStreamTransformation { public static final int DEFAULT_AUTOCLICK_DELAY_TIME = Flags.enableAutoclickIndicator() ? AUTOCLICK_DELAY_WITH_INDICATOR_DEFAULT : AUTOCLICK_DELAY_DEFAULT; // Duration before a press turns into a long press. // Factor 1.5 is needed, otherwise a long press is not safely detected. public static final long LONG_PRESS_TIMEOUT = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); private static final String LOG_TAG = AutoclickController.class.getSimpleName(); // TODO(b/393559560): Finalize scroll amount. private static final float SCROLL_AMOUNT = 1.0f; Loading Loading @@ -125,6 +131,12 @@ public class AutoclickController extends BaseEventStreamTransformation { // move. private long mDragModeClickDownTime; // True during the duration of a long press event. private boolean mHasOngoingLongPress = false; // The MotionEvent downTime attribute associated with the originating click for a long press // move. private long mLongPressDownTime; @VisibleForTesting final ClickPanelControllerInterface clickPanelController = new ClickPanelControllerInterface() { Loading Loading @@ -426,6 +438,11 @@ public class AutoclickController extends BaseEventStreamTransformation { return mDragModeIsDragging; } @VisibleForTesting boolean hasOngoingLongPressForTesting() { return mHasOngoingLongPress; } /** * Observes autoclick setting values, and updates ClickScheduler delay and indicator size * whenever the setting value changes. Loading Loading @@ -768,6 +785,11 @@ public class AutoclickController extends BaseEventStreamTransformation { if (mDragModeIsDragging) { clearDraggingState(); } if (mHasOngoingLongPress) { clearLongPressState(); } resetInternalState(); mHandler.removeCallbacks(this); } Loading @@ -789,6 +811,23 @@ public class AutoclickController extends BaseEventStreamTransformation { mDragModeIsDragging = false; } // Cancel the pending long press to avoid potential side effects from // leaving it in an inconsistent state. private void clearLongPressState() { if (mLastMotionEvent != null) { // A final ACTION_CANCEL event needs to be sent to alert the system that long press // has ended. MotionEvent cancelEvent = MotionEvent.obtain(mLastMotionEvent); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); cancelEvent.setDownTime(mLongPressDownTime); AutoclickController.super.onMotionEvent(cancelEvent, cancelEvent, mEventPolicyFlags); } resetSelectedClickTypeIfNecessary(); mHasOngoingLongPress = false; } /** * Updates the meta state that should be used for click sequence. */ Loading Loading @@ -943,6 +982,12 @@ public class AutoclickController extends BaseEventStreamTransformation { return; } // Clear pending long press in case another click action jumps between long pressing // down and up events. if (mHasOngoingLongPress) { clearLongPressState(); } // Always triggers left-click when the cursor hovers over the autoclick type panel, to // always allow users to change a different click type. Otherwise, if one chooses the // right-click, this user won't be able to rely on autoclick to select other click Loading Loading @@ -989,6 +1034,10 @@ public class AutoclickController extends BaseEventStreamTransformation { startDragEvent(); } return; case AUTOCLICK_TYPE_LONG_PRESS: actionButton = BUTTON_PRIMARY; sendLongPress(); return; default: break; } Loading Loading @@ -1043,22 +1092,8 @@ public class AutoclickController extends BaseEventStreamTransformation { } private void sendMotionEvent(int actionButton, long eventTime) { MotionEvent downEvent = MotionEvent.obtain( /* downTime= */ eventTime, /* eventTime= */ eventTime, MotionEvent.ACTION_DOWN, /* pointerCount= */ 1, mTempPointerProperties, mTempPointerCoords, mMetaState, actionButton, /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, mLastMotionEvent.getDeviceId(), /* edgeFlags= */ 0, mLastMotionEvent.getSource(), mLastMotionEvent.getFlags()); MotionEvent downEvent = buildMotionEvent( eventTime, eventTime, actionButton, mLastMotionEvent); MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); Loading Loading @@ -1086,6 +1121,66 @@ public class AutoclickController extends BaseEventStreamTransformation { upEvent.recycle(); } // TODO(b/400744833): Reset Autoclick type to left click whenever a long press happens. private void sendLongPress() { mHasOngoingLongPress = true; mLongPressDownTime = SystemClock.uptimeMillis(); MotionEvent downEvent = buildMotionEvent( mLongPressDownTime, mLongPressDownTime, BUTTON_PRIMARY, mLastMotionEvent); MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); AutoclickController.super.onMotionEvent(downEvent, downEvent, mEventPolicyFlags); AutoclickController.super.onMotionEvent(pressEvent, pressEvent, mEventPolicyFlags); mHandler.postDelayed(new Runnable() { @Override public void run() { long upTime = SystemClock.uptimeMillis(); MotionEvent releaseEvent = buildMotionEvent( mLongPressDownTime, upTime, BUTTON_PRIMARY, downEvent); releaseEvent.setAction(MotionEvent.ACTION_BUTTON_RELEASE); releaseEvent.setButtonState(0); MotionEvent upEvent = MotionEvent.obtain(releaseEvent); upEvent.setAction(MotionEvent.ACTION_UP); upEvent.setButtonState(0); AutoclickController.super.onMotionEvent( releaseEvent, releaseEvent, mEventPolicyFlags); AutoclickController.super.onMotionEvent( upEvent, upEvent, mEventPolicyFlags); downEvent.recycle(); pressEvent.recycle(); releaseEvent.recycle(); upEvent.recycle(); mHasOngoingLongPress = false; } }, LONG_PRESS_TIMEOUT); } private @NonNull MotionEvent buildMotionEvent( long downTime, long eventTime, int actionButton, @NonNull MotionEvent lastMotionEvent) { return MotionEvent.obtain( /* downTime= */ downTime, /* eventTime= */ eventTime, MotionEvent.ACTION_DOWN, /* pointerCount= */ 1, mTempPointerProperties, mTempPointerCoords, mMetaState, actionButton, /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, lastMotionEvent.getDeviceId(), /* edgeFlags= */ 0, lastMotionEvent.getSource(), lastMotionEvent.getFlags()); } // To start a drag event, only send the DOWN and BUTTON_PRESS events. private void startDragEvent() { mDragModeClickDownTime = SystemClock.uptimeMillis(); Loading
services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java +89 −5 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; /** Test cases for {@link AutoclickController}. */ @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) Loading @@ -83,31 +86,44 @@ public class AutoclickControllerTest { public MotionEvent buttonReleaseEvent; public MotionEvent upEvent; public MotionEvent moveEvent; public MotionEvent cancelEvent; public int eventCount = 0; private List<MotionEvent> mEventList = new ArrayList<>(); @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { MotionEvent eventCopy = MotionEvent.obtain(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_BUTTON_PRESS: buttonPressEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_BUTTON_RELEASE: buttonReleaseEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_UP: upEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_MOVE: moveEvent = eventCopy; eventCount++; break; case MotionEvent.ACTION_CANCEL: cancelEvent = eventCopy; break; default: return; } mEventList.add(eventCopy); eventCount++; } public void assertCapturedEvents(int... actionsInOrder) { assertThat(eventCount).isEqualTo(mEventList.size()); for (int i = 0; i < eventCount; i++) { assertThat(actionsInOrder[i]) .isEqualTo(mEventList.get(i).getAction()); } } } Loading Loading @@ -1187,6 +1203,74 @@ public class AutoclickControllerTest { verify(mockAutoclickTypePanel, Mockito.never()).resetSelectedClickType(); } @Test @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) public void sendClick_clickType_longPress_triggerPressAndHold() { MotionEventCaptor motionEventCaptor = new MotionEventCaptor(); mController.setNext(motionEventCaptor); injectFakeMouseActionHoverMoveEvent(); // Set delay to zero so click is scheduled to run immediately. mController.mClickScheduler.updateDelay(0); // Set click type to long press. mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS); AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); mController.mAutoclickTypePanel = mockAutoclickTypePanel; // Send hover move event. injectFakeMouseMoveEvent(/* x= */ 30f, /* y= */ 0, MotionEvent.ACTION_HOVER_MOVE); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.downEvent).isNotNull(); assertThat(motionEventCaptor.downEvent.getButtonState()).isEqualTo( MotionEvent.BUTTON_PRIMARY); assertThat(motionEventCaptor.upEvent).isNull(); // When all messages (with delays) are processed. mTestableLooper.moveTimeForward(mController.LONG_PRESS_TIMEOUT); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.upEvent).isNotNull(); motionEventCaptor.assertCapturedEvents( MotionEvent.ACTION_DOWN, MotionEvent.ACTION_BUTTON_PRESS, MotionEvent.ACTION_BUTTON_RELEASE, MotionEvent.ACTION_UP); } @Test @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) public void sendClick_clickType_longPress_interruptCancelsLongPress() { MotionEventCaptor motionEventCaptor = new MotionEventCaptor(); mController.setNext(motionEventCaptor); injectFakeMouseActionHoverMoveEvent(); // Set delay to zero so click is scheduled to run immediately. mController.mClickScheduler.updateDelay(0); // Set click type to long press. mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LONG_PRESS); AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); mController.mAutoclickTypePanel = mockAutoclickTypePanel; // Send hover move event. injectFakeMouseMoveEvent(/* x= */ 100f, /* y= */ 0, MotionEvent.ACTION_HOVER_MOVE); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.downEvent).isNotNull(); assertThat(motionEventCaptor.downEvent.getButtonState()).isEqualTo( MotionEvent.BUTTON_PRIMARY); assertThat(motionEventCaptor.upEvent).isNull(); assertThat(mController.hasOngoingLongPressForTesting()).isTrue(); assertThat(motionEventCaptor.cancelEvent).isNull(); // Send another hover move event to interrupt the long press. mTestableLooper.moveTimeForward(mController.LONG_PRESS_TIMEOUT / 2); mController.clickPanelController.handleAutoclickTypeChange( AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK); injectFakeMouseMoveEvent(/* x= */ 0, /* y= */ 30f, MotionEvent.ACTION_HOVER_MOVE); mController.mClickScheduler.run(); mTestableLooper.processAllMessages(); assertThat(motionEventCaptor.cancelEvent).isNotNull(); assertThat(mController.hasOngoingLongPressForTesting()).isFalse(); } /** * ========================================================================= * Helper Functions Loading