Loading services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickIndicatorView.java +1 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ public class AutoclickIndicatorView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Get the screen dimensions. // TODO(b/397944891): Handle device rotation case. DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int screenWidth = displayMetrics.widthPixels; int screenHeight = displayMetrics.heightPixels; Loading services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +118 −11 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; Loading @@ -51,6 +52,16 @@ public class AutoclickTypePanel { public static final int CORNER_TOP_LEFT = 2; public static final int CORNER_TOP_RIGHT = 3; // Distance between panel and screen edge. // TODO(b/396402941): Finalize edge margin. private static final int PANEL_EDGE_MARGIN = 15; // Touch point when drag starts, it can be anywhere inside the panel. private float mTouchStartX, mTouchStartY; // Initial panel position in screen coordinates. private int mPanelStartX, mPanelStartY; private boolean mIsDragging = false; // Types of click the AutoclickTypePanel supports. @IntDef({ AUTOCLICK_TYPE_LEFT_CLICK, Loading Loading @@ -101,6 +112,8 @@ public class AutoclickTypePanel { private final WindowManager mWindowManager; private WindowManager.LayoutParams mParams; private final ClickPanelControllerInterface mClickPanelController; // Whether the panel is expanded or not. Loading Loading @@ -133,6 +146,7 @@ public class AutoclickTypePanel { mContext = context; mWindowManager = windowManager; mClickPanelController = clickPanelController; mParams = getDefaultLayoutParams(); mPauseButtonDrawable = mContext.getDrawable( R.drawable.accessibility_autoclick_pause); Loading @@ -154,6 +168,91 @@ public class AutoclickTypePanel { mPositionButton = mContentView.findViewById(R.id.accessibility_autoclick_position_layout); initializeButtonState(); // Set up touch event handling for the panel to allow the user to drag and reposition the // panel by touching and moving it. mContentView.setOnTouchListener(this::onPanelTouch); } /** * Handles touch events on the panel, enabling the user to drag and reposition it. * This function supports the draggable panel feature, allowing users to move the panel * to different screen locations for better usability and customization. */ private boolean onPanelTouch(View v, MotionEvent event) { // TODO(b/397681794): Make sure this works on multiple screens. switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // Store initial touch positions. mTouchStartX = event.getRawX(); mTouchStartY = event.getRawY(); // Store initial panel position relative to screen's top-left corner. // getLocationOnScreen provides coordinates relative to the top-left corner of the // screen's display. We are using this coordinate system to consistently track the // panel's position during drag operations. int[] location = new int[2]; v.getLocationOnScreen(location); mPanelStartX = location[0]; mPanelStartY = location[1]; return true; case MotionEvent.ACTION_MOVE: mIsDragging = true; // Set panel gravity to TOP|LEFT to match getLocationOnScreen's coordinate system mParams.gravity = Gravity.LEFT | Gravity.TOP; if (mIsDragging) { // Calculate touch distance moved from start position. float deltaX = event.getRawX() - mTouchStartX; float deltaY = event.getRawY() - mTouchStartY; // Update panel position, based on Top-Left absolute positioning. mParams.x = mPanelStartX + (int) deltaX; mParams.y = mPanelStartY + (int) deltaY; mWindowManager.updateViewLayout(mContentView, mParams); } return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsDragging) { // When drag ends, snap panel to nearest edge. snapToNearestEdge(mParams); } mIsDragging = false; return true; } return false; } private void snapToNearestEdge(WindowManager.LayoutParams params) { // Get screen width to determine which side to snap to. // TODO(b/397944891): Handle device rotation case. int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; int yPosition = params.y; // Determine which half of the screen the panel is on. boolean isOnLeftHalf = params.x < screenWidth / 2; if (isOnLeftHalf) { // Snap to left edge. Set params.gravity to make sure x, y offsets from correct anchor. params.gravity = Gravity.START | Gravity.TOP; // Set the current corner to be bottom-left to ensure that the subsequent reposition // action rotates the panel clockwise from bottom-left towards top-left. mCurrentCornerIndex = 1; } else { // Snap to right edge. Set params.gravity to make sure x, y offsets from correct anchor. params.gravity = Gravity.END | Gravity.TOP; // Set the current corner to be top-right to ensure that the subsequent reposition // action rotates the panel clockwise from top-right towards bottom-right. mCurrentCornerIndex = 3; } // Apply final position: set params.x to be edge margin, params.y to maintain vertical // position. params.x = PANEL_EDGE_MARGIN; params.y = yPosition; mWindowManager.updateViewLayout(mContentView, params); } private void initializeButtonState() { Loading Loading @@ -209,7 +308,7 @@ public class AutoclickTypePanel { } public void show() { mWindowManager.addView(mContentView, getLayoutParams()); mWindowManager.addView(mContentView, mParams); } public void hide() { Loading Loading @@ -291,9 +390,8 @@ public class AutoclickTypePanel { @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); setPanelPositionForCorner(mParams, mCurrentCornerIndex); mWindowManager.updateViewLayout(mContentView, mParams); } private void setPanelPositionForCorner(WindowManager.LayoutParams params, @Corner int corner) { Loading @@ -303,22 +401,22 @@ public class AutoclickTypePanel { switch (corner) { case CORNER_BOTTOM_RIGHT: params.gravity = Gravity.END | Gravity.BOTTOM; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 90; break; case CORNER_BOTTOM_LEFT: params.gravity = Gravity.START | Gravity.BOTTOM; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 90; break; case CORNER_TOP_LEFT: params.gravity = Gravity.START | Gravity.TOP; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 30; break; case CORNER_TOP_RIGHT: params.gravity = Gravity.END | Gravity.TOP; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 30; break; default: Loading @@ -343,13 +441,22 @@ public class AutoclickTypePanel { return mCurrentCornerIndex; } @VisibleForTesting WindowManager.LayoutParams getLayoutParamsForTesting() { return mParams; } @VisibleForTesting boolean getIsDraggingForTesting() { return mIsDragging; } /** * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window * Manager. */ @VisibleForTesting @NonNull WindowManager.LayoutParams getLayoutParams() { private WindowManager.LayoutParams getDefaultLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -362,7 +469,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; setPanelPositionForCorner(layoutParams, mCurrentCornerIndex); setPanelPositionForCorner(layoutParams, CORNER_BOTTOM_RIGHT); return layoutParams; } } services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +104 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat 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.CORNER_BOTTOM_LEFT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.CORNER_BOTTOM_RIGHT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.CORNER_TOP_RIGHT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface; import static com.google.common.truth.Truth.assertThat; Loading @@ -31,6 +34,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; Loading Loading @@ -213,6 +217,105 @@ public class AutoclickTypePanelTest { assertThat(mAutoclickTypePanel.isPaused()).isFalse(); } @Test public void onTouch_dragMove_updatesPosition() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); // Define movement delta for both x and y directions. int delta = 15; // Dispatch initial down event. float touchX = panelLocation[0] + 10; float touchY = panelLocation[1] + 10; MotionEvent downEvent = MotionEvent.obtain( 0, 0, MotionEvent.ACTION_DOWN, touchX, touchY, 0); contentView.dispatchTouchEvent(downEvent); // Create move event with delta, move from (x, y) to (x + delta, y + delta) MotionEvent moveEvent = MotionEvent.obtain( 0, 0, MotionEvent.ACTION_MOVE, touchX + delta, touchY + delta, 0); contentView.dispatchTouchEvent(moveEvent); // Verify position update. assertThat(mAutoclickTypePanel.getIsDraggingForTesting()).isTrue(); assertThat(params.gravity).isEqualTo(Gravity.LEFT | Gravity.TOP); assertThat(params.x).isEqualTo(panelLocation[0] + delta); assertThat(params.y).isEqualTo(panelLocation[1] + delta); } @Test public void dragAndEndAtRight_snapsToRightSide() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels; // Verify initial corner is bottom-right. assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_RIGHT); dispatchDragSequence(contentView, /* startX =*/ panelLocation[0] + 10, /* startY =*/ panelLocation[1] + 10, /* endX =*/ (float) (screenWidth * 3) / 4, /* endY =*/ panelLocation[1] + 10); // Verify snapping to the right. assertThat(params.gravity).isEqualTo(Gravity.END | Gravity.TOP); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_TOP_RIGHT); } @Test public void dragAndEndAtLeft_snapsToLeftSide() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels; // Verify initial corner is bottom-right. assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_RIGHT); dispatchDragSequence(contentView, /* startX =*/ panelLocation[0] + 10, /* startY =*/ panelLocation[1] + 10, /* endX =*/ (float) screenWidth / 4, /* endY =*/ panelLocation[1] + 10); // Verify snapping to the left. assertThat(params.gravity).isEqualTo(Gravity.START | Gravity.TOP); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_LEFT); } // Helper method to handle drag event sequences private void dispatchDragSequence(View view, float startX, float startY, float endX, float endY) { // Down event MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, startX, startY, 0); view.dispatchTouchEvent(downEvent); // Move event MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, endX, endY, 0); view.dispatchTouchEvent(moveEvent); // Up event MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, endX, endY, 0); view.dispatchTouchEvent(upEvent); // Clean up downEvent.recycle(); moveEvent.recycle(); upEvent.recycle(); } private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) Loading @@ -220,7 +323,7 @@ public class AutoclickTypePanelTest { } private void verifyPanelPosition(int[] expectedPosition) { WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParams(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo( expectedPosition[0]); assertThat(params.gravity).isEqualTo(expectedPosition[1]); Loading Loading
services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickIndicatorView.java +1 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ public class AutoclickIndicatorView extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Get the screen dimensions. // TODO(b/397944891): Handle device rotation case. DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int screenWidth = displayMetrics.widthPixels; int screenHeight = displayMetrics.heightPixels; Loading
services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +118 −11 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; Loading @@ -51,6 +52,16 @@ public class AutoclickTypePanel { public static final int CORNER_TOP_LEFT = 2; public static final int CORNER_TOP_RIGHT = 3; // Distance between panel and screen edge. // TODO(b/396402941): Finalize edge margin. private static final int PANEL_EDGE_MARGIN = 15; // Touch point when drag starts, it can be anywhere inside the panel. private float mTouchStartX, mTouchStartY; // Initial panel position in screen coordinates. private int mPanelStartX, mPanelStartY; private boolean mIsDragging = false; // Types of click the AutoclickTypePanel supports. @IntDef({ AUTOCLICK_TYPE_LEFT_CLICK, Loading Loading @@ -101,6 +112,8 @@ public class AutoclickTypePanel { private final WindowManager mWindowManager; private WindowManager.LayoutParams mParams; private final ClickPanelControllerInterface mClickPanelController; // Whether the panel is expanded or not. Loading Loading @@ -133,6 +146,7 @@ public class AutoclickTypePanel { mContext = context; mWindowManager = windowManager; mClickPanelController = clickPanelController; mParams = getDefaultLayoutParams(); mPauseButtonDrawable = mContext.getDrawable( R.drawable.accessibility_autoclick_pause); Loading @@ -154,6 +168,91 @@ public class AutoclickTypePanel { mPositionButton = mContentView.findViewById(R.id.accessibility_autoclick_position_layout); initializeButtonState(); // Set up touch event handling for the panel to allow the user to drag and reposition the // panel by touching and moving it. mContentView.setOnTouchListener(this::onPanelTouch); } /** * Handles touch events on the panel, enabling the user to drag and reposition it. * This function supports the draggable panel feature, allowing users to move the panel * to different screen locations for better usability and customization. */ private boolean onPanelTouch(View v, MotionEvent event) { // TODO(b/397681794): Make sure this works on multiple screens. switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // Store initial touch positions. mTouchStartX = event.getRawX(); mTouchStartY = event.getRawY(); // Store initial panel position relative to screen's top-left corner. // getLocationOnScreen provides coordinates relative to the top-left corner of the // screen's display. We are using this coordinate system to consistently track the // panel's position during drag operations. int[] location = new int[2]; v.getLocationOnScreen(location); mPanelStartX = location[0]; mPanelStartY = location[1]; return true; case MotionEvent.ACTION_MOVE: mIsDragging = true; // Set panel gravity to TOP|LEFT to match getLocationOnScreen's coordinate system mParams.gravity = Gravity.LEFT | Gravity.TOP; if (mIsDragging) { // Calculate touch distance moved from start position. float deltaX = event.getRawX() - mTouchStartX; float deltaY = event.getRawY() - mTouchStartY; // Update panel position, based on Top-Left absolute positioning. mParams.x = mPanelStartX + (int) deltaX; mParams.y = mPanelStartY + (int) deltaY; mWindowManager.updateViewLayout(mContentView, mParams); } return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsDragging) { // When drag ends, snap panel to nearest edge. snapToNearestEdge(mParams); } mIsDragging = false; return true; } return false; } private void snapToNearestEdge(WindowManager.LayoutParams params) { // Get screen width to determine which side to snap to. // TODO(b/397944891): Handle device rotation case. int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels; int yPosition = params.y; // Determine which half of the screen the panel is on. boolean isOnLeftHalf = params.x < screenWidth / 2; if (isOnLeftHalf) { // Snap to left edge. Set params.gravity to make sure x, y offsets from correct anchor. params.gravity = Gravity.START | Gravity.TOP; // Set the current corner to be bottom-left to ensure that the subsequent reposition // action rotates the panel clockwise from bottom-left towards top-left. mCurrentCornerIndex = 1; } else { // Snap to right edge. Set params.gravity to make sure x, y offsets from correct anchor. params.gravity = Gravity.END | Gravity.TOP; // Set the current corner to be top-right to ensure that the subsequent reposition // action rotates the panel clockwise from top-right towards bottom-right. mCurrentCornerIndex = 3; } // Apply final position: set params.x to be edge margin, params.y to maintain vertical // position. params.x = PANEL_EDGE_MARGIN; params.y = yPosition; mWindowManager.updateViewLayout(mContentView, params); } private void initializeButtonState() { Loading Loading @@ -209,7 +308,7 @@ public class AutoclickTypePanel { } public void show() { mWindowManager.addView(mContentView, getLayoutParams()); mWindowManager.addView(mContentView, mParams); } public void hide() { Loading Loading @@ -291,9 +390,8 @@ public class AutoclickTypePanel { @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); setPanelPositionForCorner(mParams, mCurrentCornerIndex); mWindowManager.updateViewLayout(mContentView, mParams); } private void setPanelPositionForCorner(WindowManager.LayoutParams params, @Corner int corner) { Loading @@ -303,22 +401,22 @@ public class AutoclickTypePanel { switch (corner) { case CORNER_BOTTOM_RIGHT: params.gravity = Gravity.END | Gravity.BOTTOM; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 90; break; case CORNER_BOTTOM_LEFT: params.gravity = Gravity.START | Gravity.BOTTOM; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 90; break; case CORNER_TOP_LEFT: params.gravity = Gravity.START | Gravity.TOP; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 30; break; case CORNER_TOP_RIGHT: params.gravity = Gravity.END | Gravity.TOP; params.x = 15; params.x = PANEL_EDGE_MARGIN; params.y = 30; break; default: Loading @@ -343,13 +441,22 @@ public class AutoclickTypePanel { return mCurrentCornerIndex; } @VisibleForTesting WindowManager.LayoutParams getLayoutParamsForTesting() { return mParams; } @VisibleForTesting boolean getIsDraggingForTesting() { return mIsDragging; } /** * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window * Manager. */ @VisibleForTesting @NonNull WindowManager.LayoutParams getLayoutParams() { private WindowManager.LayoutParams getDefaultLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -362,7 +469,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; setPanelPositionForCorner(layoutParams, mCurrentCornerIndex); setPanelPositionForCorner(layoutParams, CORNER_BOTTOM_RIGHT); return layoutParams; } }
services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +104 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat 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.CORNER_BOTTOM_LEFT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.CORNER_BOTTOM_RIGHT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.CORNER_TOP_RIGHT; import static com.android.server.accessibility.autoclick.AutoclickTypePanel.ClickPanelControllerInterface; import static com.google.common.truth.Truth.assertThat; Loading @@ -31,6 +34,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; Loading Loading @@ -213,6 +217,105 @@ public class AutoclickTypePanelTest { assertThat(mAutoclickTypePanel.isPaused()).isFalse(); } @Test public void onTouch_dragMove_updatesPosition() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); // Define movement delta for both x and y directions. int delta = 15; // Dispatch initial down event. float touchX = panelLocation[0] + 10; float touchY = panelLocation[1] + 10; MotionEvent downEvent = MotionEvent.obtain( 0, 0, MotionEvent.ACTION_DOWN, touchX, touchY, 0); contentView.dispatchTouchEvent(downEvent); // Create move event with delta, move from (x, y) to (x + delta, y + delta) MotionEvent moveEvent = MotionEvent.obtain( 0, 0, MotionEvent.ACTION_MOVE, touchX + delta, touchY + delta, 0); contentView.dispatchTouchEvent(moveEvent); // Verify position update. assertThat(mAutoclickTypePanel.getIsDraggingForTesting()).isTrue(); assertThat(params.gravity).isEqualTo(Gravity.LEFT | Gravity.TOP); assertThat(params.x).isEqualTo(panelLocation[0] + delta); assertThat(params.y).isEqualTo(panelLocation[1] + delta); } @Test public void dragAndEndAtRight_snapsToRightSide() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels; // Verify initial corner is bottom-right. assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_RIGHT); dispatchDragSequence(contentView, /* startX =*/ panelLocation[0] + 10, /* startY =*/ panelLocation[1] + 10, /* endX =*/ (float) (screenWidth * 3) / 4, /* endY =*/ panelLocation[1] + 10); // Verify snapping to the right. assertThat(params.gravity).isEqualTo(Gravity.END | Gravity.TOP); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_TOP_RIGHT); } @Test public void dragAndEndAtLeft_snapsToLeftSide() { View contentView = mAutoclickTypePanel.getContentViewForTesting(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); int[] panelLocation = new int[2]; contentView.getLocationOnScreen(panelLocation); int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels; // Verify initial corner is bottom-right. assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_RIGHT); dispatchDragSequence(contentView, /* startX =*/ panelLocation[0] + 10, /* startY =*/ panelLocation[1] + 10, /* endX =*/ (float) screenWidth / 4, /* endY =*/ panelLocation[1] + 10); // Verify snapping to the left. assertThat(params.gravity).isEqualTo(Gravity.START | Gravity.TOP); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()) .isEqualTo(CORNER_BOTTOM_LEFT); } // Helper method to handle drag event sequences private void dispatchDragSequence(View view, float startX, float startY, float endX, float endY) { // Down event MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, startX, startY, 0); view.dispatchTouchEvent(downEvent); // Move event MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, endX, endY, 0); view.dispatchTouchEvent(moveEvent); // Up event MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, endX, endY, 0); view.dispatchTouchEvent(upEvent); // Clean up downEvent.recycle(); moveEvent.recycle(); upEvent.recycle(); } private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) Loading @@ -220,7 +323,7 @@ public class AutoclickTypePanelTest { } private void verifyPanelPosition(int[] expectedPosition) { WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParams(); WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting(); assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo( expectedPosition[0]); assertThat(params.gravity).isEqualTo(expectedPosition[1]); Loading