From cbf6b7ef03e10570e699c8cb4467965445a5f199 Mon Sep 17 00:00:00 2001 From: Peter_Liang Date: Tue, 30 Mar 2021 17:46:16 +0800 Subject: [PATCH] Fix the GAR issue of the Switch Access user can not move. Root cause: Not set and export the corresponding Accessibility actions. Solution: Exported the four Accessibility actions used to move the floating menu to the screen corners like a system bubble. Bug: 178433098 Test: atest AccessibilityFloatingMenuViewTest Change-Id: Ic2e205a1ed2e8c1ea8794e25835f56444271b9df --- packages/SystemUI/res/values/ids.xml | 6 ++ packages/SystemUI/res/values/strings.xml | 8 ++ .../AccessibilityFloatingMenuView.java | 76 ++++++++++++++++++- .../AccessibilityFloatingMenuViewTest.java | 64 ++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) 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 3ca885a2c6b7c..f5357d7a2ec96 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2681,6 +2681,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;