Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1e1887e authored by Peter Liang's avatar Peter Liang
Browse files

Refactor the design and improve the animations of Accessibility Floating Menu(9/n).

Actions:
1) Support the feature to avoid overlapping on the keyboard.
2) Fix the issue overlapping on primary action on the bottom.

Bug: 227715451
Bug: 252913008
Test: manual test
Change-Id: Ie3404276c56c9fb1e3d18d348cfc5a7b4815c905
parent 41752009
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1341,6 +1341,7 @@
    <dimen name="accessibility_floating_menu_large_width_height">56dp</dimen>
    <dimen name="accessibility_floating_menu_large_single_radius">35dp</dimen>
    <dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen>
    <dimen name="accessibility_floating_menu_ime_shifting_space">48dp</dimen>

    <dimen name="accessibility_floating_menu_message_container_horizontal_padding">15dp</dimen>
    <dimen name="accessibility_floating_menu_message_text_vertical_padding">8dp</dimen>
+1 −1
Original line number Diff line number Diff line
@@ -345,7 +345,7 @@ class MenuAnimationController {
    }

    private void constrainPositionAndUpdate(PointF position) {
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        final Rect draggableBounds = mMenuView.getMenuDraggableBoundsExcludeIme();
        // Have the space gap margin between the top bound and the menu view, so actually the
        // position y range needs to cut the margin.
        position.offset(-draggableBounds.left, -draggableBounds.top);
+8 −0
Original line number Diff line number Diff line
@@ -219,6 +219,14 @@ class MenuView extends FrameLayout implements
        return mMenuViewAppearance.getMenuDraggableBounds();
    }

    Rect getMenuDraggableBoundsExcludeIme() {
        return mMenuViewAppearance.getMenuDraggableBoundsExcludeIme();
    }

    int getMenuHeight() {
        return mMenuViewAppearance.getMenuHeight();
    }

    void persistPositionAndUpdateEdge(Position percentagePosition) {
        mMenuViewModel.updateMenuSavingPosition(percentagePosition);
        mMenuViewAppearance.setPercentagePosition(percentagePosition);
+44 −11
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@ class MenuViewAppearance {
    private final Resources mRes;
    private final Position mPercentagePosition = new Position(/* percentageX= */
            0f, /* percentageY= */ 0f);
    private boolean mIsImeShowing;
    // Avoid the menu view overlapping on the primary action button under the bottom as possible.
    private int mImeShiftingSpace;
    private int mTargetFeaturesSize;
    private int mSizeType;
    private int mMargin;
@@ -62,6 +65,7 @@ class MenuViewAppearance {
    private int mStrokeColor;
    private int mInset;
    private int mElevation;
    private float mImeTop;
    private float[] mRadii;
    private Drawable mBackgroundDrawable;
    private String mContentDescription;
@@ -106,6 +110,8 @@ class MenuViewAppearance {
        mStrokeColor = mRes.getColor(R.color.accessibility_floating_menu_stroke_dark);
        mInset = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset);
        mElevation = mRes.getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
        mImeShiftingSpace = mRes.getDimensionPixelSize(
                R.dimen.accessibility_floating_menu_ime_shifting_space);
        final Drawable drawable =
                mRes.getDrawable(R.drawable.accessibility_floating_menu_background);
        mBackgroundDrawable = new InstantInsetLayerDrawable(new Drawable[]{drawable});
@@ -131,29 +137,56 @@ class MenuViewAppearance {
        mRadii = createRadii(isMenuOnLeftSide(), getMenuRadius(mTargetFeaturesSize));
    }

    void onImeVisibilityChanged(boolean imeShowing, float imeTop) {
        mIsImeShowing = imeShowing;
        mImeTop = imeTop;
    }

    Rect getMenuDraggableBounds() {
        return getMenuDraggableBoundsWith(/* includeIme= */ true);
    }

    Rect getMenuDraggableBoundsExcludeIme() {
        return getMenuDraggableBoundsWith(/* includeIme= */ false);
    }

    private Rect getMenuDraggableBoundsWith(boolean includeIme) {
        final int margin = getMenuMargin();
        final Rect draggableBounds = getWindowAvailableBounds();
        final Rect draggableBounds = new Rect(getWindowAvailableBounds());

        // Initializes start position for mapping the translation of the menu view.
        draggableBounds.offsetTo(/* newLeft= */ 0, /* newTop= */ 0);

        draggableBounds.top += margin;
        draggableBounds.right -= getMenuWidth();
        draggableBounds.bottom -= Math.min(
                getWindowAvailableBounds().height() - draggableBounds.top,
                calculateActualMenuHeight() + margin);

        if (includeIme && mIsImeShowing) {
            final int imeHeight = (int) (draggableBounds.bottom - mImeTop);
            draggableBounds.bottom -= (imeHeight + mImeShiftingSpace);
        }
        draggableBounds.bottom -= (calculateActualMenuHeight() + margin);
        draggableBounds.bottom = Math.max(draggableBounds.top, draggableBounds.bottom);

        return draggableBounds;
    }

    PointF getMenuPosition() {
        final Rect draggableBounds = getMenuDraggableBounds();
        final Rect draggableBounds = getMenuDraggableBoundsExcludeIme();
        final float x = draggableBounds.left
                + draggableBounds.width() * mPercentagePosition.getPercentageX();

        float y = draggableBounds.top
                + draggableBounds.height() * mPercentagePosition.getPercentageY();

        // If the bottom of the menu view and overlap on the ime, its position y will be
        // overridden with new y.
        final float menuBottom = y + getMenuHeight() + mMargin;
        if (mIsImeShowing && (menuBottom >= mImeTop)) {
            y = Math.max(draggableBounds.top,
                    mImeTop - getMenuHeight() - mMargin - mImeShiftingSpace);
        }

        return new PointF(
                draggableBounds.left
                        + draggableBounds.width() * mPercentagePosition.getPercentageX(),
                draggableBounds.top
                        + draggableBounds.height() * mPercentagePosition.getPercentageY());
        return new PointF(x, y);
    }

    String getContentDescription() {
+39 −3
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.systemui.accessibility.floatingmenu;

import static android.view.WindowInsets.Type.ime;

import static androidx.core.view.WindowInsetsCompat.Type;

import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
@@ -26,13 +30,16 @@ import android.annotation.IntDef;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.PluralsMessageFormatter;
import android.view.MotionEvent;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -62,14 +69,17 @@ import java.util.Map;
class MenuViewLayer extends FrameLayout {
    private static final int SHOW_MESSAGE_DELAY_MS = 3000;

    private final WindowManager mWindowManager;
    private final MenuView mMenuView;
    private final MenuMessageView mMessageView;
    private final DismissView mDismissView;
    private final MenuViewAppearance mMenuViewAppearance;
    private final MenuAnimationController mMenuAnimationController;
    private final AccessibilityManager mAccessibilityManager;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final IAccessibilityFloatingMenu mFloatingMenu;
    private final DismissAnimationController mDismissAnimationController;
    private final Rect mImeInsetsRect = new Rect();

    @IntDef({
            LayerIndex.MENU_VIEW,
@@ -111,13 +121,13 @@ class MenuViewLayer extends FrameLayout {
            AccessibilityManager accessibilityManager, IAccessibilityFloatingMenu floatingMenu) {
        super(context);

        mWindowManager = windowManager;
        mAccessibilityManager = accessibilityManager;
        mFloatingMenu = floatingMenu;

        final MenuViewModel menuViewModel = new MenuViewModel(context);
        final MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context,
                windowManager);
        mMenuView = new MenuView(context, menuViewModel, menuViewAppearance);
        mMenuViewAppearance = new MenuViewAppearance(context, windowManager);
        mMenuView = new MenuView(context, menuViewModel, mMenuViewAppearance);
        mMenuAnimationController = mMenuView.getMenuAnimationController();
        mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage);

@@ -200,6 +210,7 @@ class MenuViewLayer extends FrameLayout {
        super.onAttachedToWindow();

        mMenuView.show();
        setOnApplyWindowInsetsListener((view, insets) -> onWindowInsetsApplied(insets));
        mMessageView.setUndoListener(view -> undo());
        mContext.registerComponentCallbacks(mDismissAnimationController);
    }
@@ -209,10 +220,35 @@ class MenuViewLayer extends FrameLayout {
        super.onDetachedFromWindow();

        mMenuView.hide();
        setOnApplyWindowInsetsListener(null);
        mHandler.removeCallbacksAndMessages(/* token= */ null);
        mContext.unregisterComponentCallbacks(mDismissAnimationController);
    }

    private WindowInsets onWindowInsetsApplied(WindowInsets insets) {
        final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        final WindowInsets windowInsets = windowMetrics.getWindowInsets();
        final Rect imeInsetsRect = windowInsets.getInsets(ime()).toRect();
        if (!imeInsetsRect.equals(mImeInsetsRect)) {
            final Rect windowBounds = new Rect(windowMetrics.getBounds());
            final Rect systemBarsAndDisplayCutoutInsetsRect =
                    windowInsets.getInsetsIgnoringVisibility(
                            Type.systemBars() | Type.displayCutout()).toRect();
            final float imeTop =
                    windowBounds.height() - systemBarsAndDisplayCutoutInsetsRect.top
                            - imeInsetsRect.bottom;

            mMenuViewAppearance.onImeVisibilityChanged(windowInsets.isVisible(ime()), imeTop);

            mMenuView.onEdgeChanged();
            mMenuView.onPositionChanged();

            mImeInsetsRect.set(imeInsetsRect);
        }

        return insets;
    }

    private void hideMenuAndShowMessage() {
        final int delayTime = mAccessibilityManager.getRecommendedTimeoutMillis(
                SHOW_MESSAGE_DELAY_MS,
Loading