diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 5f68bdb4f0c60..9665c89cffba4 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -167,5 +167,11 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8dad40b0cd691..2299fd5e5cb6b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2693,6 +2693,14 @@
Accessibility button replaced the accessibility gesture\n\nView settings
Move button to the edge to hide it temporarily
+
+ Move top left
+
+ Move top right
+
+ Move bottom left
+
+ Move bottom right
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index ab05c2a273ad4..57be4e8477b27 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -31,6 +31,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
@@ -39,6 +40,8 @@ import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
@@ -284,6 +287,44 @@ public class AccessibilityFloatingMenuView extends FrameLayout
// Do Nothing
}
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ setupAccessibilityActions(info);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
+
+ fadeIn();
+
+ final Rect bounds = getAvailableBounds();
+ if (action == R.id.action_move_top_left) {
+ snapToLocation(bounds.left, bounds.top);
+ return true;
+ }
+
+ if (action == R.id.action_move_top_right) {
+ snapToLocation(bounds.right, bounds.top);
+ return true;
+ }
+
+ if (action == R.id.action_move_bottom_left) {
+ snapToLocation(bounds.left, bounds.bottom);
+ return true;
+ }
+
+ if (action == R.id.action_move_bottom_right) {
+ snapToLocation(bounds.right, bounds.bottom);
+ return true;
+ }
+
+ return false;
+ }
+
void show() {
if (isShowing()) {
return;
@@ -380,6 +421,33 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mUiHandler.postDelayed(() -> mFadeOutAnimator.start(), FADE_EFFECT_DURATION_MS);
}
+ private void setupAccessibilityActions(AccessibilityNodeInfo info) {
+ final Resources res = mContext.getResources();
+ final AccessibilityAction moveTopLeft =
+ new AccessibilityAction(R.id.action_move_top_left,
+ res.getString(
+ R.string.accessibility_floating_button_action_move_top_left));
+ info.addAction(moveTopLeft);
+
+ final AccessibilityAction moveTopRight =
+ new AccessibilityAction(R.id.action_move_top_right,
+ res.getString(
+ R.string.accessibility_floating_button_action_move_top_right));
+ info.addAction(moveTopRight);
+
+ final AccessibilityAction moveBottomLeft =
+ new AccessibilityAction(R.id.action_move_bottom_left,
+ res.getString(
+ R.string.accessibility_floating_button_action_move_bottom_left));
+ info.addAction(moveBottomLeft);
+
+ final AccessibilityAction moveBottomRight =
+ new AccessibilityAction(R.id.action_move_bottom_right,
+ res.getString(
+ R.string.accessibility_floating_button_action_move_bottom_right));
+ info.addAction(moveBottomRight);
+ }
+
private boolean onTouched(MotionEvent event) {
final int action = event.getAction();
final int currentX = (int) event.getX();
@@ -524,7 +592,8 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateLocationWith(mAlignment, mPercentageY);
}
- private void snapToLocation(int endX, int endY) {
+ @VisibleForTesting
+ void snapToLocation(int endX, int endY) {
mDragAnimator.cancel();
mDragAnimator.removeAllUpdateListeners();
mDragAnimator.addUpdateListener(anim -> onDragAnimationUpdate(anim, endX, endY));
@@ -662,6 +731,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
: R.dimen.accessibility_floating_menu_large_single_radius;
}
+ @VisibleForTesting
+ Rect getAvailableBounds() {
+ return new Rect(0, 0, mScreenWidth - getWindowWidth(), mScreenHeight - getWindowHeight());
+ }
+
private int getLayoutWidth() {
return mPadding * 2 + mIconWidth;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
index 8683dd6c33bd8..814f073edbb05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
@@ -40,6 +41,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
@@ -78,6 +80,8 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
private RecyclerView mListView;
+ private Rect mAvailableBounds = new Rect(100, 200, 300, 400);
+
private int mMenuHalfWidth;
private int mMenuHalfHeight;
private int mScreenHalfWidth;
@@ -339,6 +343,66 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
assertThat(mMenuView.mShapeType).isEqualTo(/* halfOval */ 1);
}
+ @Test
+ public void getAccessibilityActionList_matchResult() {
+ final AccessibilityNodeInfo infos = new AccessibilityNodeInfo();
+ mMenuView.onInitializeAccessibilityNodeInfo(infos);
+
+ assertThat(infos.getActionList().size()).isEqualTo(4);
+ }
+
+ @Test
+ public void accessibilityActionMove_moveTopLeft_success() {
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext));
+ doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+
+ final boolean isActionPerformed =
+ menuView.performAccessibilityAction(R.id.action_move_top_left, null);
+
+ assertThat(isActionPerformed).isTrue();
+ verify(menuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.top);
+ }
+
+ @Test
+ public void accessibilityActionMove_moveTopRight_success() {
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext));
+ doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+
+ final boolean isActionPerformed =
+ menuView.performAccessibilityAction(R.id.action_move_top_right, null);
+
+ assertThat(isActionPerformed).isTrue();
+ verify(menuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.top);
+ }
+
+ @Test
+ public void accessibilityActionMove_moveBottomLeft_success() {
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext));
+ doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+
+ final boolean isActionPerformed =
+ menuView.performAccessibilityAction(R.id.action_move_bottom_left, null);
+
+ assertThat(isActionPerformed).isTrue();
+ verify(menuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.bottom);
+ }
+
+ @Test
+ public void accessibilityActionMove_moveBottomRight_success() {
+ final AccessibilityFloatingMenuView menuView =
+ spy(new AccessibilityFloatingMenuView(mContext));
+ doReturn(mAvailableBounds).when(menuView).getAvailableBounds();
+
+ final boolean isActionPerformed =
+ menuView.performAccessibilityAction(R.id.action_move_bottom_right, null);
+
+ assertThat(isActionPerformed).isTrue();
+ verify(menuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.bottom);
+ }
+
@After
public void tearDown() {
mInterceptMotionEvent = null;