Loading services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +76 −9 Original line number Diff line number Diff line Loading @@ -46,6 +46,11 @@ public class AutoclickTypePanel { public static final int AUTOCLICK_TYPE_DRAG = 3; public static final int AUTOCLICK_TYPE_SCROLL = 4; public static final int CORNER_BOTTOM_RIGHT = 0; public static final int CORNER_BOTTOM_LEFT = 1; public static final int CORNER_TOP_LEFT = 2; public static final int CORNER_TOP_RIGHT = 3; // Types of click the AutoclickTypePanel supports. @IntDef({ AUTOCLICK_TYPE_LEFT_CLICK, Loading @@ -56,6 +61,21 @@ public class AutoclickTypePanel { }) public @interface AutoclickType {} @IntDef({ CORNER_BOTTOM_RIGHT, CORNER_BOTTOM_LEFT, CORNER_TOP_LEFT, CORNER_TOP_RIGHT }) public @interface Corner {} private static final @Corner int[] CORNER_ROTATION_ORDER = { CORNER_BOTTOM_RIGHT, CORNER_BOTTOM_LEFT, CORNER_TOP_LEFT, CORNER_TOP_RIGHT }; // An interface exposed to {@link AutoclickController) to handle different actions on the panel, // including changing autoclick type, pausing/resuming autoclick. public interface ClickPanelControllerInterface { Loading @@ -79,6 +99,10 @@ public class AutoclickTypePanel { // Whether autoclick is paused. private boolean mPaused = false; // Tracks the current corner position of the panel using an index into CORNER_ROTATION_ORDER // array. This allows the panel to cycle through screen corners in a defined sequence when // repositioned. private int mCurrentCornerIndex = 0; private final LinearLayout mLeftClickButton; private final LinearLayout mRightClickButton; Loading @@ -86,6 +110,7 @@ public class AutoclickTypePanel { private final LinearLayout mDragButton; private final LinearLayout mScrollButton; private final LinearLayout mPauseButton; private final LinearLayout mPositionButton; private LinearLayout mSelectedButton; Loading Loading @@ -117,6 +142,7 @@ public class AutoclickTypePanel { mScrollButton = mContentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = mContentView.findViewById(R.id.accessibility_autoclick_drag_layout); mPauseButton = mContentView.findViewById(R.id.accessibility_autoclick_pause_layout); mPositionButton = mContentView.findViewById(R.id.accessibility_autoclick_position_layout); initializeButtonState(); } Loading @@ -128,10 +154,8 @@ public class AutoclickTypePanel { v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK)); mScrollButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL)); mDragButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG)); mPositionButton.setOnClickListener(v -> moveToNextCorner()); mPauseButton.setOnClickListener(v -> togglePause()); // 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(); Loading Loading @@ -248,6 +272,46 @@ public class AutoclickTypePanel { }; } /** Moves the panel to the next corner in clockwise direction. */ private void moveToNextCorner() { @Corner int nextCornerIndex = (mCurrentCornerIndex + 1) % CORNER_ROTATION_ORDER.length; mCurrentCornerIndex = nextCornerIndex; // getLayoutParams() will update the panel position based on current corner. WindowManager.LayoutParams params = getLayoutParams(); mWindowManager.updateViewLayout(mContentView, params); } private void setPanelPositionForCorner(WindowManager.LayoutParams params, @Corner int corner) { // TODO(b/396402941): Replace hardcoded pixel values with proper dimension calculations, // Current values are experimental and may not work correctly across different device // resolutions and configurations. switch (corner) { case CORNER_BOTTOM_RIGHT: params.gravity = Gravity.END | Gravity.BOTTOM; params.x = 15; params.y = 90; break; case CORNER_BOTTOM_LEFT: params.gravity = Gravity.START | Gravity.BOTTOM; params.x = 15; params.y = 90; break; case CORNER_TOP_LEFT: params.gravity = Gravity.START | Gravity.TOP; params.x = 15; params.y = 30; break; case CORNER_TOP_RIGHT: params.gravity = Gravity.END | Gravity.TOP; params.x = 15; params.y = 30; break; default: throw new IllegalArgumentException("Invalid corner: " + corner); } } @VisibleForTesting boolean getExpansionStateForTesting() { return mExpanded; Loading @@ -259,12 +323,19 @@ public class AutoclickTypePanel { return mContentView; } @VisibleForTesting @Corner int getCurrentCornerIndexForTesting() { return mCurrentCornerIndex; } /** * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window * Manager. */ @VisibleForTesting @NonNull private WindowManager.LayoutParams getLayoutParams() { WindowManager.LayoutParams getLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -277,11 +348,7 @@ public class AutoclickTypePanel { mContext.getString(R.string.accessibility_autoclick_type_settings_panel_title); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; // TODO(b/388847771): Compute position based on user interaction. layoutParams.x = 15; layoutParams.y = 90; layoutParams.gravity = Gravity.END | Gravity.BOTTOM; setPanelPositionForCorner(layoutParams, mCurrentCornerIndex); return layoutParams; } } services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.drawable.GradientDrawable; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; Loading Loading @@ -64,6 +65,7 @@ public class AutoclickTypePanelTest { private LinearLayout mDragButton; private LinearLayout mScrollButton; private LinearLayout mPauseButton; private LinearLayout mPositionButton; private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; Loading Loading @@ -93,6 +95,7 @@ public class AutoclickTypePanelTest { mScrollButton = contentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = contentView.findViewById(R.id.accessibility_autoclick_drag_layout); mPauseButton = contentView.findViewById(R.id.accessibility_autoclick_pause_layout); mPositionButton = contentView.findViewById(R.id.accessibility_autoclick_position_layout); } @Test Loading Loading @@ -175,9 +178,39 @@ public class AutoclickTypePanelTest { assertThat(mActiveClickType).isEqualTo(AUTOCLICK_TYPE_SCROLL); } @Test public void moveToNextCorner_positionButton_rotatesThroughAllPositions() { // Define all positions in sequence int[][] expectedPositions = { {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, {1, Gravity.START | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, {2, Gravity.START | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, {3, Gravity.END | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90} }; // Check initial position verifyPanelPosition(expectedPositions[0]); // Move through all corners. for (int i = 1; i < expectedPositions.length; i++) { mPositionButton.callOnClick(); verifyPanelPosition(expectedPositions[i]); } } private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) .isEqualTo(mTestableContext.getColor(R.color.materialColorPrimary)); } private void verifyPanelPosition(int[] expectedPosition) { WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParams(); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo( expectedPosition[0]); assertThat(params.gravity).isEqualTo(expectedPosition[1]); assertThat(params.x).isEqualTo(expectedPosition[2]); assertThat(params.y).isEqualTo(expectedPosition[3]); } } Loading
services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +76 −9 Original line number Diff line number Diff line Loading @@ -46,6 +46,11 @@ public class AutoclickTypePanel { public static final int AUTOCLICK_TYPE_DRAG = 3; public static final int AUTOCLICK_TYPE_SCROLL = 4; public static final int CORNER_BOTTOM_RIGHT = 0; public static final int CORNER_BOTTOM_LEFT = 1; public static final int CORNER_TOP_LEFT = 2; public static final int CORNER_TOP_RIGHT = 3; // Types of click the AutoclickTypePanel supports. @IntDef({ AUTOCLICK_TYPE_LEFT_CLICK, Loading @@ -56,6 +61,21 @@ public class AutoclickTypePanel { }) public @interface AutoclickType {} @IntDef({ CORNER_BOTTOM_RIGHT, CORNER_BOTTOM_LEFT, CORNER_TOP_LEFT, CORNER_TOP_RIGHT }) public @interface Corner {} private static final @Corner int[] CORNER_ROTATION_ORDER = { CORNER_BOTTOM_RIGHT, CORNER_BOTTOM_LEFT, CORNER_TOP_LEFT, CORNER_TOP_RIGHT }; // An interface exposed to {@link AutoclickController) to handle different actions on the panel, // including changing autoclick type, pausing/resuming autoclick. public interface ClickPanelControllerInterface { Loading @@ -79,6 +99,10 @@ public class AutoclickTypePanel { // Whether autoclick is paused. private boolean mPaused = false; // Tracks the current corner position of the panel using an index into CORNER_ROTATION_ORDER // array. This allows the panel to cycle through screen corners in a defined sequence when // repositioned. private int mCurrentCornerIndex = 0; private final LinearLayout mLeftClickButton; private final LinearLayout mRightClickButton; Loading @@ -86,6 +110,7 @@ public class AutoclickTypePanel { private final LinearLayout mDragButton; private final LinearLayout mScrollButton; private final LinearLayout mPauseButton; private final LinearLayout mPositionButton; private LinearLayout mSelectedButton; Loading Loading @@ -117,6 +142,7 @@ public class AutoclickTypePanel { mScrollButton = mContentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = mContentView.findViewById(R.id.accessibility_autoclick_drag_layout); mPauseButton = mContentView.findViewById(R.id.accessibility_autoclick_pause_layout); mPositionButton = mContentView.findViewById(R.id.accessibility_autoclick_position_layout); initializeButtonState(); } Loading @@ -128,10 +154,8 @@ public class AutoclickTypePanel { v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK)); mScrollButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL)); mDragButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG)); mPositionButton.setOnClickListener(v -> moveToNextCorner()); mPauseButton.setOnClickListener(v -> togglePause()); // 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(); Loading Loading @@ -248,6 +272,46 @@ public class AutoclickTypePanel { }; } /** Moves the panel to the next corner in clockwise direction. */ private void moveToNextCorner() { @Corner int nextCornerIndex = (mCurrentCornerIndex + 1) % CORNER_ROTATION_ORDER.length; mCurrentCornerIndex = nextCornerIndex; // getLayoutParams() will update the panel position based on current corner. WindowManager.LayoutParams params = getLayoutParams(); mWindowManager.updateViewLayout(mContentView, params); } private void setPanelPositionForCorner(WindowManager.LayoutParams params, @Corner int corner) { // TODO(b/396402941): Replace hardcoded pixel values with proper dimension calculations, // Current values are experimental and may not work correctly across different device // resolutions and configurations. switch (corner) { case CORNER_BOTTOM_RIGHT: params.gravity = Gravity.END | Gravity.BOTTOM; params.x = 15; params.y = 90; break; case CORNER_BOTTOM_LEFT: params.gravity = Gravity.START | Gravity.BOTTOM; params.x = 15; params.y = 90; break; case CORNER_TOP_LEFT: params.gravity = Gravity.START | Gravity.TOP; params.x = 15; params.y = 30; break; case CORNER_TOP_RIGHT: params.gravity = Gravity.END | Gravity.TOP; params.x = 15; params.y = 30; break; default: throw new IllegalArgumentException("Invalid corner: " + corner); } } @VisibleForTesting boolean getExpansionStateForTesting() { return mExpanded; Loading @@ -259,12 +323,19 @@ public class AutoclickTypePanel { return mContentView; } @VisibleForTesting @Corner int getCurrentCornerIndexForTesting() { return mCurrentCornerIndex; } /** * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window * Manager. */ @VisibleForTesting @NonNull private WindowManager.LayoutParams getLayoutParams() { WindowManager.LayoutParams getLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -277,11 +348,7 @@ public class AutoclickTypePanel { mContext.getString(R.string.accessibility_autoclick_type_settings_panel_title); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; // TODO(b/388847771): Compute position based on user interaction. layoutParams.x = 15; layoutParams.y = 90; layoutParams.gravity = Gravity.END | Gravity.BOTTOM; setPanelPositionForCorner(layoutParams, mCurrentCornerIndex); return layoutParams; } }
services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.drawable.GradientDrawable; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; Loading Loading @@ -64,6 +65,7 @@ public class AutoclickTypePanelTest { private LinearLayout mDragButton; private LinearLayout mScrollButton; private LinearLayout mPauseButton; private LinearLayout mPositionButton; private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; Loading Loading @@ -93,6 +95,7 @@ public class AutoclickTypePanelTest { mScrollButton = contentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = contentView.findViewById(R.id.accessibility_autoclick_drag_layout); mPauseButton = contentView.findViewById(R.id.accessibility_autoclick_pause_layout); mPositionButton = contentView.findViewById(R.id.accessibility_autoclick_position_layout); } @Test Loading Loading @@ -175,9 +178,39 @@ public class AutoclickTypePanelTest { assertThat(mActiveClickType).isEqualTo(AUTOCLICK_TYPE_SCROLL); } @Test public void moveToNextCorner_positionButton_rotatesThroughAllPositions() { // Define all positions in sequence int[][] expectedPositions = { {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, {1, Gravity.START | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, {2, Gravity.START | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, {3, Gravity.END | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90} }; // Check initial position verifyPanelPosition(expectedPositions[0]); // Move through all corners. for (int i = 1; i < expectedPositions.length; i++) { mPositionButton.callOnClick(); verifyPanelPosition(expectedPositions[i]); } } private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) .isEqualTo(mTestableContext.getColor(R.color.materialColorPrimary)); } private void verifyPanelPosition(int[] expectedPosition) { WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParams(); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo( expectedPosition[0]); assertThat(params.gravity).isEqualTo(expectedPosition[1]); assertThat(params.x).isEqualTo(expectedPosition[2]); assertThat(params.y).isEqualTo(expectedPosition[3]); } }