diff options
3 files changed, 132 insertions, 15 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java index db8441d2424b..5283df5ca7e1 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java @@ -17,11 +17,16 @@ package com.android.server.accessibility.autoclick; import static android.view.MotionEvent.BUTTON_PRIMARY; +import static android.view.MotionEvent.BUTTON_SECONDARY; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_DELAY_DEFAULT; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT; import static com.android.server.accessibility.autoclick.AutoclickIndicatorView.SHOW_INDICATOR_DELAY_TIME; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_RIGHT_CLICK; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface; import android.accessibilityservice.AccessibilityTrace; import android.annotation.NonNull; @@ -84,6 +89,23 @@ public class AutoclickController extends BaseEventStreamTransformation { @VisibleForTesting AutoclickTypePanel mAutoclickTypePanel; private WindowManager mWindowManager; + // Default click type is left-click. + private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; + + @VisibleForTesting + final ClickPanelControllerInterface clickPanelController = + new ClickPanelControllerInterface() { + @Override + public void handleAutoclickTypeChange(@AutoclickType int clickType) { + mActiveClickType = clickType; + } + + @Override + public void toggleAutoclickPause() { + // TODO(b/388872274): allows users to pause the autoclick. + } + }; + public AutoclickController(Context context, int userId, AccessibilityTraceManager trace) { mTrace = trace; mContext = context; @@ -124,7 +146,8 @@ public class AutoclickController extends BaseEventStreamTransformation { mAutoclickIndicatorView = new AutoclickIndicatorView(mContext); mWindowManager = mContext.getSystemService(WindowManager.class); - mAutoclickTypePanel = new AutoclickTypePanel(mContext, mWindowManager); + mAutoclickTypePanel = + new AutoclickTypePanel(mContext, mWindowManager, clickPanelController); mAutoclickTypePanel.show(); mWindowManager.addView(mAutoclickIndicatorView, mAutoclickIndicatorView.getLayoutParams()); @@ -644,6 +667,15 @@ public class AutoclickController extends BaseEventStreamTransformation { final long now = SystemClock.uptimeMillis(); + // TODO(b/395094903): 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 types. + final int actionButton = + mActiveClickType == AUTOCLICK_TYPE_RIGHT_CLICK + ? BUTTON_SECONDARY + : BUTTON_PRIMARY; + MotionEvent downEvent = MotionEvent.obtain( /* downTime= */ now, @@ -653,7 +685,7 @@ public class AutoclickController extends BaseEventStreamTransformation { mTempPointerProperties, mTempPointerCoords, mMetaState, - BUTTON_PRIMARY, + actionButton, /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, mLastMotionEvent.getDeviceId(), @@ -663,11 +695,11 @@ public class AutoclickController extends BaseEventStreamTransformation { MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); - pressEvent.setActionButton(BUTTON_PRIMARY); + pressEvent.setActionButton(actionButton); MotionEvent releaseEvent = MotionEvent.obtain(downEvent); releaseEvent.setAction(MotionEvent.ACTION_BUTTON_RELEASE); - releaseEvent.setActionButton(BUTTON_PRIMARY); + releaseEvent.setActionButton(actionButton); releaseEvent.setButtonState(0); MotionEvent upEvent = MotionEvent.obtain(downEvent); diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java index 2ef11f4b78e1..cf928e2f3fa4 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java @@ -18,6 +18,7 @@ package com.android.server.accessibility.autoclick; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import android.annotation.IntDef; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; @@ -39,12 +40,40 @@ public class AutoclickTypePanel { private final String TAG = AutoclickTypePanel.class.getSimpleName(); + public static final int AUTOCLICK_TYPE_LEFT_CLICK = 0; + public static final int AUTOCLICK_TYPE_RIGHT_CLICK = 1; + public static final int AUTOCLICK_TYPE_DOUBLE_CLICK = 2; + public static final int AUTOCLICK_TYPE_DRAG = 3; + public static final int AUTOCLICK_TYPE_SCROLL = 4; + + // Types of click the AutoclickTypePanel supports. + @IntDef({ + AUTOCLICK_TYPE_LEFT_CLICK, + AUTOCLICK_TYPE_RIGHT_CLICK, + AUTOCLICK_TYPE_DOUBLE_CLICK, + AUTOCLICK_TYPE_DRAG, + AUTOCLICK_TYPE_SCROLL, + }) + public @interface AutoclickType {} + + // 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. + void handleAutoclickTypeChange(@AutoclickType int clickType); + + // Allows users to pause/resume the autoclick. + void toggleAutoclickPause(); + } + private final Context mContext; private final View mContentView; private final WindowManager mWindowManager; + private final ClickPanelControllerInterface mClickPanelController; + // Whether the panel is expanded or not. private boolean mExpanded = false; @@ -56,9 +85,13 @@ public class AutoclickTypePanel { private LinearLayout mSelectedButton; - public AutoclickTypePanel(Context context, WindowManager windowManager) { + public AutoclickTypePanel( + Context context, + WindowManager windowManager, + ClickPanelControllerInterface clickPanelController) { mContext = context; mWindowManager = windowManager; + mClickPanelController = clickPanelController; mContentView = LayoutInflater.from(context) @@ -76,26 +109,35 @@ public class AutoclickTypePanel { } private void initializeButtonState() { - mLeftClickButton.setOnClickListener(v -> togglePanelExpansion(mLeftClickButton)); - mRightClickButton.setOnClickListener(v -> togglePanelExpansion(mRightClickButton)); - mDoubleClickButton.setOnClickListener(v -> togglePanelExpansion(mDoubleClickButton)); - mScrollButton.setOnClickListener(v -> togglePanelExpansion(mScrollButton)); - mDragButton.setOnClickListener(v -> togglePanelExpansion(mDragButton)); + mLeftClickButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_LEFT_CLICK)); + mRightClickButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_RIGHT_CLICK)); + mDoubleClickButton.setOnClickListener( + v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK)); + mScrollButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL)); + mDragButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG)); + + // TODO(b/388872274): registers listener for pause button and allows users to pause/resume + // the autoclick. + // TODO(b/388847771): registers listener for position button and allows users to move the + // panel to a different position. // Initializes panel as collapsed state and only displays the left click button. hideAllClickTypeButtons(); mLeftClickButton.setVisibility(View.VISIBLE); - setSelectedButton(/* selectedButton= */ mLeftClickButton); + setSelectedClickType(AUTOCLICK_TYPE_LEFT_CLICK); } /** Sets the selected button and updates the newly and previously selected button styling. */ - private void setSelectedButton(@NonNull LinearLayout selectedButton) { + private void setSelectedClickType(@AutoclickType int clickType) { + final LinearLayout selectedButton = getButtonFromClickType(clickType); + // Updates the previously selected button styling. if (mSelectedButton != null) { toggleSelectedButtonStyle(mSelectedButton, /* isSelected= */ false); } mSelectedButton = selectedButton; + mClickPanelController.handleAutoclickTypeChange(clickType); // Updates the newly selected button styling. toggleSelectedButtonStyle(selectedButton, /* isSelected= */ true); @@ -130,7 +172,9 @@ public class AutoclickTypePanel { } /** Toggles the panel expanded or collapsed state. */ - private void togglePanelExpansion(LinearLayout button) { + private void togglePanelExpansion(@AutoclickType int clickType) { + final LinearLayout button = getButtonFromClickType(clickType); + if (mExpanded) { // If the panel is already in expanded state, we should collapse it by hiding all // buttons except the one user selected. @@ -138,7 +182,7 @@ public class AutoclickTypePanel { button.setVisibility(View.VISIBLE); // Sets the newly selected button. - setSelectedButton(/* selectedButton= */ button); + setSelectedClickType(clickType); } else { // If the panel is already collapsed, we just need to expand it. showAllClickTypeButtons(); @@ -166,6 +210,17 @@ public class AutoclickTypePanel { mScrollButton.setVisibility(View.VISIBLE); } + private LinearLayout getButtonFromClickType(@AutoclickType int clickType) { + return switch (clickType) { + case AUTOCLICK_TYPE_LEFT_CLICK -> mLeftClickButton; + case AUTOCLICK_TYPE_RIGHT_CLICK -> mRightClickButton; + case AUTOCLICK_TYPE_DOUBLE_CLICK -> mDoubleClickButton; + case AUTOCLICK_TYPE_DRAG -> mDragButton; + case AUTOCLICK_TYPE_SCROLL -> mScrollButton; + default -> throw new IllegalArgumentException("Unknown clickType " + clickType); + }; + } + @VisibleForTesting boolean getExpansionStateForTesting() { return mExpanded; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java index 7b8824cb0e3d..00cc7264c1d0 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java @@ -18,6 +18,11 @@ package com.android.server.accessibility.autoclick; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_LEFT_CLICK; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AUTOCLICK_TYPE_SCROLL; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.AutoclickType; +import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; @@ -59,11 +64,25 @@ public class AutoclickTypePanelTest { private LinearLayout mDragButton; private LinearLayout mScrollButton; + private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; + + private final ClickPanelControllerInterface clickPanelController = + new ClickPanelControllerInterface() { + @Override + public void handleAutoclickTypeChange(@AutoclickType int clickType) { + mActiveClickType = clickType; + } + + @Override + public void toggleAutoclickPause() {} + }; + @Before public void setUp() { mTestableContext.addMockSystemService(Context.WINDOW_SERVICE, mMockWindowManager); - mAutoclickTypePanel = new AutoclickTypePanel(mTestableContext, mMockWindowManager); + mAutoclickTypePanel = + new AutoclickTypePanel(mTestableContext, mMockWindowManager, clickPanelController); View contentView = mAutoclickTypePanel.getContentViewForTesting(); mLeftClickButton = contentView.findViewById(R.id.accessibility_autoclick_left_click_layout); mRightClickButton = @@ -136,6 +155,17 @@ public class AutoclickTypePanelTest { verifyButtonHasSelectedStyle(mScrollButton); } + @Test + public void togglePanelExpansion_selectButton_correctActiveClickType() { + // By first click, the panel is expanded. + mLeftClickButton.callOnClick(); + + // Clicks any button in the expanded state to select a type button. + mScrollButton.callOnClick(); + + assertThat(mActiveClickType).isEqualTo(AUTOCLICK_TYPE_SCROLL); + } + private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) |