Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8243eb53 authored by Gavin Williams's avatar Gavin Williams
Browse files

a11y: Pause auto click with pause button

Pause autoclick when the pause button is clicked by canceling
any pending clicks and preventing scheduling of new clicks.

Demo: http://b/388872274#comment4

Bug: b/388872274
Test: AutoclickTypePanelTest
Flag: com.android.server.accessibility.enable_autoclick_indicator
Change-Id: I1cabc63a2656ea4e962a5565b84e5db70eb115ae
parent 1be4df13
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -101,8 +101,15 @@ public class AutoclickController extends BaseEventStreamTransformation {
                }

                @Override
                public void toggleAutoclickPause() {
                    // TODO(b/388872274): allows users to pause the autoclick.
                public void toggleAutoclickPause(boolean paused) {
                    if (paused) {
                        if (mClickScheduler != null) {
                            mClickScheduler.cancel();
                        }
                        if (mAutoclickIndicatorScheduler != null) {
                            mAutoclickIndicatorScheduler.cancel();
                        }
                    }
                }
            };

@@ -133,7 +140,9 @@ public class AutoclickController extends BaseEventStreamTransformation {
                        mAutoclickIndicatorScheduler);
            }

            if (!isPaused()) {
                handleMouseMotion(event, policyFlags);
            }
        } else if (mClickScheduler != null) {
            mClickScheduler.cancel();
        }
@@ -216,6 +225,11 @@ public class AutoclickController extends BaseEventStreamTransformation {
        }
    }

    private boolean isPaused() {
        // TODO (b/397460424): Unpause when hovering over panel.
        return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused();
    }

    /**
     * Observes autoclick setting values, and updates ClickScheduler delay and indicator size
     * whenever the setting value changes.
+17 −3
Original line number Diff line number Diff line
@@ -79,11 +79,20 @@ public class AutoclickTypePanel {
    // An interface exposed to {@link AutoclickController) to handle different actions on the panel,
    // including changing autoclick type, pausing/resuming autoclick.
    public interface ClickPanelControllerInterface {
        // Allows users to change a different autoclick type.
        /**
         * Allows users to change a different autoclick type.
         *
         * @param clickType The new autoclick type to use. Should be one of the values defined in
         *                  {@link AutoclickType}.
         */
        void handleAutoclickTypeChange(@AutoclickType int clickType);

        // Allows users to pause/resume the autoclick.
        void toggleAutoclickPause();
        /**
         * Allows users to pause or resume autoclick.
         *
         * @param paused {@code true} to pause autoclick, {@code false} to resume.
         */
        void toggleAutoclickPause(boolean paused);
    }

    private final Context mContext;
@@ -211,6 +220,10 @@ public class AutoclickTypePanel {
        mWindowManager.removeView(mContentView);
    }

    public boolean isPaused() {
        return mPaused;
    }

    /** Toggles the panel expanded or collapsed state. */
    private void togglePanelExpansion(@AutoclickType int clickType) {
        final LinearLayout button = getButtonFromClickType(clickType);
@@ -234,6 +247,7 @@ public class AutoclickTypePanel {

    private void togglePause() {
        mPaused = !mPaused;
        mClickPanelController.toggleAutoclickPause(mPaused);

        ImageButton imageButton = (ImageButton) mPauseButton.getChildAt(/* index= */ 0);
        if (mPaused) {
+41 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.platform.test.annotations.DisableFlags;
@@ -400,6 +401,46 @@ public class AutoclickControllerTest {
                .isNotEqualTo(initialScheduledTime);
    }

    @Test
    @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
    public void pauseButton_flagOn_clickNotTriggeredWhenPaused() {
        injectFakeMouseActionHoverMoveEvent();

        // Pause autoclick.
        AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class);
        when(mockAutoclickTypePanel.isPaused()).thenReturn(true);
        mController.mAutoclickTypePanel = mockAutoclickTypePanel;

        // Send hover move event.
        MotionEvent hoverMove = MotionEvent.obtain(
                /* downTime= */ 0,
                /* eventTime= */ 100,
                /* action= */ MotionEvent.ACTION_HOVER_MOVE,
                /* x= */ 30f,
                /* y= */ 0f,
                /* metaState= */ 0);
        hoverMove.setSource(InputDevice.SOURCE_MOUSE);
        mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);

        // Verify there is not a pending click.
        assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
        assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1);

        // Resume autoclick.
        when(mockAutoclickTypePanel.isPaused()).thenReturn(false);

        // Send initial move event again. Because this is the first recorded move, a click won't be
        // scheduled.
        injectFakeMouseActionHoverMoveEvent();
        assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse();
        assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1);

        // Send move again to trigger click and verify there is now a pending click.
        mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0);
        assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue();
        assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1);
    }

    private void injectFakeMouseActionHoverMoveEvent() {
        MotionEvent event = getFakeMotionHoverMoveEvent();
        event.setSource(InputDevice.SOURCE_MOUSE);
+15 −1
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ public class AutoclickTypePanelTest {
    private LinearLayout mPositionButton;

    private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK;
    private boolean mPaused;

    private final ClickPanelControllerInterface clickPanelController =
            new ClickPanelControllerInterface() {
@@ -77,7 +78,9 @@ public class AutoclickTypePanelTest {
                }

                @Override
                public void toggleAutoclickPause() {}
                public void toggleAutoclickPause(boolean paused) {
                    mPaused = paused;
                }
            };

    @Before
@@ -199,6 +202,17 @@ public class AutoclickTypePanelTest {
        }
    }

    @Test
    public void pauseButton_onClick() {
        mPauseButton.callOnClick();
        assertThat(mPaused).isTrue();
        assertThat(mAutoclickTypePanel.isPaused()).isTrue();

        mPauseButton.callOnClick();
        assertThat(mPaused).isFalse();
        assertThat(mAutoclickTypePanel.isPaused()).isFalse();
    }

    private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) {
        GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
        assertThat(gradientDrawable.getColor().getDefaultColor())