Add new floating action menu for Accessibility targets. (5/n)

Action:
AccessibilityFloatingMenu has two shape types, one is oval style, the other is half oval style.
- Half oval shape when dragging.
- Oval shape when dropping.
The patch will provide the capability of switch shape type by dragging into the screen edge or out.

Cherry picked from commit 0a2e8f9a56

Bug: 173958541
Test: atest AccessibilityFloatingMenuTest
AccessibilityFloatingMenuViewTest AccessibilityTargetAdapterTest

Change-Id: Ib86713cd6a48e102cb9088beb6353391caeadc83
Merged-In: Ib86713cd6a48e102cb9088beb6353391caeadc83
This commit is contained in:
Peter_Liang
2021-03-10 20:53:59 +08:00
parent 2f5db39366
commit 1b682704fd
3 changed files with 59 additions and 19 deletions

View File

@@ -43,9 +43,10 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
private static final float DEFAULT_OPACITY_VALUE = 0.55f;
private final Context mContext;
private final AccessibilityFloatingMenuView mMenuView;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ContentObserver mContentObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
@@ -53,23 +54,15 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
};
private final ContentObserver mSizeContentObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
mMenuView.setSizeType(getSizeType(mContext));
}
};
private final ContentObserver mShapeContentObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
mMenuView.setShapeType(getShapeType(mContext));
}
};
private final ContentObserver mFadeOutContentObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
@@ -152,10 +145,6 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
/* notifyForDescendants */ false, mSizeContentObserver,
UserHandle.USER_CURRENT);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE),
/* notifyForDescendants */ false, mShapeContentObserver,
UserHandle.USER_CURRENT);
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
/* notifyForDescendants */ false, mFadeOutContentObserver,
@@ -169,7 +158,6 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
private void unregisterContentObservers() {
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
mContext.getContentResolver().unregisterContentObserver(mSizeContentObserver);
mContext.getContentResolver().unregisterContentObserver(mShapeContentObserver);
mContext.getContentResolver().unregisterContentObserver(mFadeOutContentObserver);
}
}

View File

@@ -82,8 +82,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
private int mAlignment = Alignment.RIGHT;
@SizeType
private int mSizeType = SizeType.SMALL;
@VisibleForTesting
@ShapeType
private int mShapeType = ShapeType.OVAL;
int mShapeType = ShapeType.OVAL;
private int mTemporaryShapeType;
@RadiusType
private int mRadiusType = RadiusType.LEFT_HALF_OVAL;
private int mMargin;
@@ -185,7 +187,6 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateLocationWith(mAlignment, mPercentageY);
updateMarginsWith(mAlignment);
updateOffsetWith(mShapeType, mAlignment);
updateInsetWith(getResources().getConfiguration().uiMode, mAlignment);
@@ -228,6 +229,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
setInset(0, 0);
}
mTemporaryShapeType =
isMovingTowardsScreenEdge(mAlignment, currentRawX, mDownX)
? ShapeType.HALF_OVAL
: ShapeType.OVAL;
final int newWindowX = currentRawX + mRelativeToPointerDownX;
final int newWindowY = currentRawY + mRelativeToPointerDownY;
mCurrentLayoutParams.x = constrain(newWindowX, MIN_WINDOW_X, getMaxWindowX());
@@ -246,10 +251,19 @@ public class AccessibilityFloatingMenuView extends FrameLayout
final int endY = mCurrentLayoutParams.y;
snapToLocation(endX, endY);
setShapeType(mTemporaryShapeType);
// Avoid triggering the listener of the item.
return true;
}
updateOffsetWith(mShapeType, mAlignment);
// Must switch the oval shape type before tapping the corresponding item in the
// list view, otherwise it can't work on it.
if (mShapeType == ShapeType.HALF_OVAL) {
setShapeType(ShapeType.OVAL);
return true;
}
fadeOut();
break;
@@ -393,6 +407,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
return mListView.dispatchTouchEvent(event);
}
private boolean isMovingTowardsScreenEdge(@Alignment int side, int currentRawX, int downX) {
return (side == Alignment.RIGHT && currentRawX > downX)
|| (side == Alignment.LEFT && downX > currentRawX);
}
private boolean hasExceededTouchSlop(int startX, int startY, int endX, int endY) {
return (sq(endX - startX) + sq(endY - startY)) > mSquareScaledTouchSlop;
}

View File

@@ -306,6 +306,39 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
/* newWindowY = screenCenterY - offsetY */ mScreenHalfHeight - mMenuHalfHeight);
}
@Test
public void tapOnAndDragMenuToScreenSide_transformShapeHalfOval() {
mMenuView.show();
mMenuView.onTargetsChanged(mTargets);
mMenuView.setSizeType(0);
mMenuView.setShapeType(/* oval */ 0);
final int currentWindowX = mMenuView.mCurrentLayoutParams.x;
final int currentWindowY = mMenuView.mCurrentLayoutParams.y;
final MotionEvent downEvent =
mMotionEventHelper.obtainMotionEvent(0, 1,
MotionEvent.ACTION_DOWN,
currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth,
currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight);
final MotionEvent moveEvent =
mMotionEventHelper.obtainMotionEvent(2, 3,
MotionEvent.ACTION_MOVE,
/* downX */(currentWindowX + mMenuHalfWidth)
+ /* offsetXToScreenRightSide */ mMenuHalfWidth,
/* downY */ (currentWindowY + mMenuHalfHeight));
final MotionEvent upEvent =
mMotionEventHelper.obtainMotionEvent(4, 5,
MotionEvent.ACTION_UP,
/* downX */(currentWindowX + mMenuHalfWidth)
+ /* offsetXToScreenRightSide */ mMenuHalfWidth,
/* downY */ (currentWindowY + mMenuHalfHeight));
mListView.dispatchTouchEvent(downEvent);
mListView.dispatchTouchEvent(moveEvent);
mListView.dispatchTouchEvent(upEvent);
assertThat(mMenuView.mShapeType).isEqualTo(/* halfOval */ 1);
}
@After
public void tearDown() {
mInterceptMotionEvent = null;