summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
authorjasonwshsu <jasonwshsu@google.com>2021-05-05 01:22:51 +0800
committerjasonwshsu <jasonwshsu@google.com>2021-06-03 21:41:27 +0800
commitd2f7022ad153dafac494cc60c48e0df8a899d180 (patch)
tree643aca13e2c1afca88b1f281b89077e5e1b13c7d /packages/SystemUI/src
parentf142b5a368edaf8393d093393708b62fa4d87f94 (diff)
Maintain the position of accessibility floating menu
* Use percentage of X-aixs and Y-axis as last position, so it could be restored at approximately position when device screen size changed. * Fine-tune AccessibilityFloatingMenuViewTest Bug: 183342667 Test: atest AccessibilityFloatingMenuViewTest PositionTest Change-Id: I58ed608a03bc20f15a9d0852c95907107516c9ba
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java83
4 files changed, 178 insertions, 36 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index bf09975bb034..782cd29b0179 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -74,7 +74,8 @@ public final class Prefs {
Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
- Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP
+ Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP,
+ Key.ACCESSIBILITY_FLOATING_MENU_POSITION
})
// TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
public @interface Key {
@@ -125,6 +126,7 @@ public final class Prefs {
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
String HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP =
"HasSeenAccessibilityFloatingMenuDockTooltip";
+ String ACCESSIBILITY_FLOATING_MENU_POSITION = "AccessibilityFloatingMenuPosition";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index ee6276813512..47f373920b90 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -28,12 +28,16 @@ import static com.android.systemui.Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MEN
import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType;
import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType;
+import android.annotation.FloatRange;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
@@ -44,7 +48,13 @@ import com.android.systemui.Prefs;
public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
private static final int DEFAULT_FADE_EFFECT_IS_ENABLED = 1;
private static final int DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED = 0;
+ @FloatRange(from = 0.0, to = 1.0)
private static final float DEFAULT_OPACITY_VALUE = 0.55f;
+ @FloatRange(from = 0.0, to = 1.0)
+ private static final float DEFAULT_POSITION_X_PERCENT = 1.0f;
+ @FloatRange(from = 0.0, to = 1.0)
+ private static final float DEFAULT_POSITION_Y_PERCENT = 0.8f;
+
private final Context mContext;
private final AccessibilityFloatingMenuView mMenuView;
private final MigrationTooltipView mMigrationTooltipView;
@@ -85,7 +95,10 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
};
public AccessibilityFloatingMenu(Context context) {
- this(context, new AccessibilityFloatingMenuView(context));
+ mContext = context;
+ mMenuView = new AccessibilityFloatingMenuView(context, getPosition(context));
+ mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView);
+ mDockTooltipView = new DockTooltipView(mContext, mMenuView);
}
@VisibleForTesting
@@ -113,7 +126,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
getOpacityValue(mContext));
mMenuView.setSizeType(getSizeType(mContext));
mMenuView.setShapeType(getShapeType(mContext));
- mMenuView.setOnDragEndListener(this::showDockTooltipIfNecessary);
+ mMenuView.setOnDragEndListener(this::onDragEnd);
showMigrationTooltipIfNecessary();
@@ -127,12 +140,25 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
}
mMenuView.hide();
+ mMenuView.setOnDragEndListener(null);
mMigrationTooltipView.hide();
mDockTooltipView.hide();
unregisterContentObservers();
}
+ @NonNull
+ private Position getPosition(Context context) {
+ final String absolutePositionString = Prefs.getString(context,
+ Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
+
+ if (TextUtils.isEmpty(absolutePositionString)) {
+ return new Position(DEFAULT_POSITION_X_PERCENT, DEFAULT_POSITION_Y_PERCENT);
+ } else {
+ return Position.fromString(absolutePositionString);
+ }
+ }
+
// Migration tooltip was the android S feature. It's just used on the Android version from R
// to S. In addition, it only shows once.
private void showMigrationTooltipIfNecessary() {
@@ -150,18 +176,28 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED) == /* enabled */ 1;
}
+ private void onDragEnd(Position position) {
+ savePosition(mContext, position);
+ showDockTooltipIfNecessary(mContext);
+ }
+
+ private void savePosition(Context context, Position position) {
+ Prefs.putString(context, Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION,
+ position.toString());
+ }
+
/**
* Shows tooltip when user drags accessibility floating menu for the first time.
*/
- private void showDockTooltipIfNecessary() {
- if (!Prefs.get(mContext).getBoolean(
+ private void showDockTooltipIfNecessary(Context context) {
+ if (!Prefs.get(context).getBoolean(
HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, false)) {
// if the menu is an oval, the user has already dragged it out, so show the tooltip.
if (mMenuView.isOvalShape()) {
mDockTooltipView.show();
}
- Prefs.putBoolean(mContext, HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, true);
+ Prefs.putBoolean(context, HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, true);
}
}
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 259a9f7c6f3b..5bb55222e09b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -26,6 +26,7 @@ import static java.util.Objects.requireNonNull;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -85,7 +86,6 @@ public class AccessibilityFloatingMenuView extends FrameLayout
private static final int FADE_EFFECT_DURATION_MS = 3000;
private static final int SNAP_TO_LOCATION_DURATION_MS = 150;
private static final int MIN_WINDOW_Y = 0;
- private static final float LOCATION_Y_PERCENTAGE = 0.8f;
private static final int ANIMATION_START_OFFSET = 600;
private static final int ANIMATION_DURATION_MS = 600;
@@ -97,7 +97,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
private boolean mIsDragging = false;
private boolean mImeVisibility;
@Alignment
- private int mAlignment = Alignment.RIGHT;
+ private int mAlignment;
@SizeType
private int mSizeType = SizeType.SMALL;
@VisibleForTesting
@@ -105,7 +105,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
int mShapeType = ShapeType.OVAL;
private int mTemporaryShapeType;
@RadiusType
- private int mRadiusType = RadiusType.LEFT_HALF_OVAL;
+ private int mRadiusType;
private int mMargin;
private int mPadding;
private int mScreenHeight;
@@ -118,7 +118,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
private int mRelativeToPointerDownX;
private int mRelativeToPointerDownY;
private float mRadius;
- private float mPercentageY = LOCATION_Y_PERCENTAGE;
+ private final Position mPosition;
private float mSquareScaledTouchSlop;
private final Configuration mLastConfiguration;
private Optional<OnDragEndListener> mOnDragEndListener = Optional.empty();
@@ -182,25 +182,35 @@ public class AccessibilityFloatingMenuView extends FrameLayout
interface OnDragEndListener {
/**
- * Invoked when the floating menu has dragged end.
+ * Called when a drag is completed.
+ *
+ * @param position Stores information about the position
*/
- void onDragEnd();
+ void onDragEnd(Position position);
}
- public AccessibilityFloatingMenuView(Context context) {
- this(context, new RecyclerView(context));
+ public AccessibilityFloatingMenuView(Context context, @NonNull Position position) {
+ this(context, position, new RecyclerView(context));
}
@VisibleForTesting
- AccessibilityFloatingMenuView(Context context,
+ AccessibilityFloatingMenuView(Context context, @NonNull Position position,
RecyclerView listView) {
super(context);
mListView = listView;
mWindowManager = context.getSystemService(WindowManager.class);
- mCurrentLayoutParams = createDefaultLayoutParams();
mAdapter = new AccessibilityTargetAdapter(mTargets);
mUiHandler = createUiHandler();
+ mPosition = position;
+ mAlignment = transformToAlignment(mPosition.getPercentageX());
+ mRadiusType = (mAlignment == Alignment.RIGHT)
+ ? RadiusType.LEFT_HALF_OVAL
+ : RadiusType.RIGHT_HALF_OVAL;
+
+ updateDimensions();
+
+ mCurrentLayoutParams = createDefaultLayoutParams();
mFadeOutAnimator = ValueAnimator.ofFloat(1.0f, mFadeOutValue);
mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS);
@@ -213,10 +223,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mDragAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mAlignment = calculateCurrentAlignment();
- mPercentageY = calculateCurrentPercentageY();
+ mPosition.update(transformCurrentPercentageXToEdge(),
+ calculateCurrentPercentageY());
+ mAlignment = transformToAlignment(mPosition.getPercentageX());
- updateLocationWith(mAlignment, mPercentageY);
+ updateLocationWith(mPosition);
updateInsetWith(getResources().getConfiguration().uiMode, mAlignment);
@@ -227,13 +238,13 @@ public class AccessibilityFloatingMenuView extends FrameLayout
fadeOut();
- mOnDragEndListener.ifPresent(OnDragEndListener::onDragEnd);
+ mOnDragEndListener.ifPresent(
+ onDragEndListener -> onDragEndListener.onDragEnd(mPosition));
}
});
mLastConfiguration = new Configuration(getResources().getConfiguration());
- updateDimensions();
initListView();
updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment);
}
@@ -423,7 +434,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateRadiusWith(newSizeType, mRadiusType, mTargets.size());
// When the icon sized changed, the menu size and location will be impacted.
- updateLocationWith(mAlignment, mPercentageY);
+ updateLocationWith(mPosition);
updateScrollModeWith(hasExceededMaxLayoutHeight());
updateOffsetWith(mShapeType, mAlignment);
setSystemGestureExclusion();
@@ -446,14 +457,14 @@ public class AccessibilityFloatingMenuView extends FrameLayout
fadeOut();
}
- public void setOnDragEndListener(OnDragEndListener onDragListener) {
- mOnDragEndListener = Optional.ofNullable(onDragListener);
+ public void setOnDragEndListener(OnDragEndListener onDragEndListener) {
+ mOnDragEndListener = Optional.ofNullable(onDragEndListener);
}
void startTranslateXAnimation() {
fadeIn();
- final float toXValue = mAlignment == Alignment.RIGHT
+ final float toXValue = (mAlignment == Alignment.RIGHT)
? ANIMATION_TO_X_VALUE
: -ANIMATION_TO_X_VALUE;
final TranslateAnimation animation =
@@ -581,7 +592,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
final boolean currentImeVisibility = insets.isVisible(ime());
if (currentImeVisibility != mImeVisibility) {
mImeVisibility = currentImeVisibility;
- updateLocationWith(mAlignment, mPercentageY);
+ updateLocationWith(mPosition);
}
return insets;
@@ -697,8 +708,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
params.receiveInsetsIgnoringZOrder = true;
params.windowAnimations = android.R.style.Animation_Translucent;
params.gravity = Gravity.START | Gravity.TOP;
- params.x = getMaxWindowX();
- params.y = (int) (getMaxWindowY() * mPercentageY);
+ params.x = (mAlignment == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX();
+// params.y = (int) (mPosition.getPercentageY() * getMaxWindowY());
+ final int currentLayoutY = (int) (mPosition.getPercentageY() * getMaxWindowY());
+ params.y = Math.max(MIN_WINDOW_Y, currentLayoutY - getInterval());
updateAccessibilityTitle(params);
return params;
}
@@ -716,7 +729,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateItemViewWith(mSizeType);
updateColor();
updateStrokeWith(newConfig.uiMode, mAlignment);
- updateLocationWith(mAlignment, mPercentageY);
+ updateLocationWith(mPosition);
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
updateScrollModeWith(hasExceededMaxLayoutHeight());
setSystemGestureExclusion();
@@ -765,9 +778,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
/**
* Updates the floating menu to be fixed at the side of the screen.
*/
- private void updateLocationWith(@Alignment int side, float percentageCurrentY) {
- mCurrentLayoutParams.x = (side == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX();
- final int currentLayoutY = (int) (percentageCurrentY * getMaxWindowY());
+ private void updateLocationWith(Position position) {
+ final @Alignment int alignment = transformToAlignment(position.getPercentageX());
+ mCurrentLayoutParams.x = (alignment == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX();
+ final int currentLayoutY = (int) (position.getPercentageY() * getMaxWindowY());
mCurrentLayoutParams.y = Math.max(MIN_WINDOW_Y, currentLayoutY - getInterval());
mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
}
@@ -861,10 +875,17 @@ public class AccessibilityFloatingMenuView extends FrameLayout
}
@Alignment
- private int calculateCurrentAlignment() {
- return mCurrentLayoutParams.x >= ((getMinWindowX() + getMaxWindowX()) / 2)
- ? Alignment.RIGHT
- : Alignment.LEFT;
+ private int transformToAlignment(@FloatRange(from = 0.0, to = 1.0) float percentageX) {
+ return (percentageX < 0.5f) ? Alignment.LEFT : Alignment.RIGHT;
+ }
+
+ private float transformCurrentPercentageXToEdge() {
+ final float percentageX = calculateCurrentPercentageX();
+ return (percentageX < 0.5) ? 0.0f : 1.0f;
+ }
+
+ private float calculateCurrentPercentageX() {
+ return mCurrentLayoutParams.x / (float) getMaxWindowX();
}
private float calculateCurrentPercentageY() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java
new file mode 100644
index 000000000000..7b7eda84df4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/Position.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import android.annotation.FloatRange;
+import android.text.TextUtils;
+
+/**
+ * Stores information about the position, which includes percentage of X-axis of the screen,
+ * percentage of Y-axis of the screen.
+ */
+public class Position {
+
+ private static final char STRING_SEPARATOR = ',';
+ private static final TextUtils.SimpleStringSplitter sStringCommaSplitter =
+ new TextUtils.SimpleStringSplitter(STRING_SEPARATOR);
+
+ private float mPercentageX;
+ private float mPercentageY;
+
+ /**
+ * Creates a {@link Position} from a encoded string described in {@link #toString()}.
+ *
+ * @param positionString A string conform to the format described in {@link #toString()}
+ * @return A {@link Position} with the given value retrieved from {@code absolutePositionString}
+ * @throws IllegalArgumentException If {@code positionString} does not conform to the format
+ * described in {@link #toString()}
+ */
+ public static Position fromString(String positionString) {
+ sStringCommaSplitter.setString(positionString);
+ if (sStringCommaSplitter.hasNext()) {
+ final float percentageX = Float.parseFloat(sStringCommaSplitter.next());
+ final float percentageY = Float.parseFloat(sStringCommaSplitter.next());
+ return new Position(percentageX, percentageY);
+ }
+
+ throw new IllegalArgumentException(
+ "Invalid Position string: " + positionString);
+ }
+
+ Position(float percentageX, float percentageY) {
+ update(percentageX, percentageY);
+ }
+
+ @Override
+ public String toString() {
+ return mPercentageX + ", " + mPercentageY;
+ }
+
+ /**
+ * Updates the position with {@code percentageX} and {@code percentageY}.
+ *
+ * @param percentageX the new percentage of X-axis of the screen, from 0.0 to 1.0.
+ * @param percentageY the new percentage of Y-axis of the screen, from 0.0 to 1.0.
+ */
+ public void update(@FloatRange(from = 0.0, to = 1.0) float percentageX,
+ @FloatRange(from = 0.0, to = 1.0) float percentageY) {
+ mPercentageX = percentageX;
+ mPercentageY = percentageY;
+ }
+
+ public float getPercentageX() {
+ return mPercentageX;
+ }
+
+ public float getPercentageY() {
+ return mPercentageY;
+ }
+}