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

Commit ae817912 authored by Peter_Liang's avatar Peter_Liang
Browse files

Add the new dock tooltip for accessibility floating menu.

Goal:
Pop up the tooltip to show how to move the menu and
hide after users move the Accessibility floating menu first.

Patch Action:
1. Create new SharedPrefernece for dock tooltip.

Bug: 182532449
Test: atest AccessibilityFloatingMenuViewTest AccessibilityFloatingMenuTest
AnnotationLinkSpanTest AccessibilityFloatingMenuTooltipViewTest
DockTooltipViewTest MigrationTooltipViewTest

Change-Id: I71d29761acd4e9d48f776e5c701149b3ed40fda4
parent 0ca995f3
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -22,6 +22,14 @@
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <View
        android:id="@+id/arrow_left"
        android:layout_width="@dimen/accessibility_floating_tooltip_arrow_width"
        android:layout_height="@dimen/accessibility_floating_tooltip_arrow_height"
        android:layout_marginRight="@dimen/accessibility_floating_tooltip_arrow_margin"
        android:visibility="gone"
        android:layout_gravity="center_vertical"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
@@ -35,9 +43,10 @@
        android:textSize="@dimen/accessibility_floating_tooltip_font_size"/>

    <View
        android:id="@+id/arrow"
        android:id="@+id/arrow_right"
        android:layout_width="@dimen/accessibility_floating_tooltip_arrow_width"
        android:layout_height="@dimen/accessibility_floating_tooltip_arrow_height"
        android:layout_marginLeft="@dimen/accessibility_floating_tooltip_arrow_margin"
        android:visibility="gone"
        android:layout_gravity="center_vertical"/>
</LinearLayout>
+4 −1
Original line number Diff line number Diff line
@@ -73,7 +73,8 @@ public final class Prefs {
            Key.TOUCHED_RINGER_TOGGLE,
            Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
            Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
            Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP
    })
    // TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
    public @interface Key {
@@ -122,6 +123,8 @@ public final class Prefs {
        String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
        String HAS_SEEN_REVERSE_BOTTOM_SHEET = "HasSeenReverseBottomSheet";
        String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
        String HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP =
                "HasSeenAccessibilityFloatingMenuDockTooltip";
    }

    public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
+21 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;

import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.systemui.Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP;
import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType;
import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType;

@@ -35,6 +36,7 @@ import android.os.UserHandle;
import android.provider.Settings;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;

/**
 * Contains logic for an accessibility floating menu view.
@@ -46,6 +48,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
    private final Context mContext;
    private final AccessibilityFloatingMenuView mMenuView;
    private final MigrationTooltipView mMigrationTooltipView;
    private final DockTooltipView mDockTooltipView;
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    private final ContentObserver mContentObserver =
@@ -90,6 +93,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
        mContext = context;
        mMenuView = menuView;
        mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView);
        mDockTooltipView = new DockTooltipView(mContext, mMenuView);
    }

    @Override
@@ -109,6 +113,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
                getOpacityValue(mContext));
        mMenuView.setSizeType(getSizeType(mContext));
        mMenuView.setShapeType(getShapeType(mContext));
        mMenuView.setOnDragEndListener(this::showDockTooltipIfNecessary);

        showMigrationTooltipIfNecessary();

@@ -123,6 +128,7 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {

        mMenuView.hide();
        mMigrationTooltipView.hide();
        mDockTooltipView.hide();

        unregisterContentObservers();
    }
@@ -144,6 +150,21 @@ public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
                DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED) == /* enabled */ 1;
    }

    /**
     * Shows tooltip when user drags accessibility floating menu for the first time.
     */
    private void showDockTooltipIfNecessary() {
        if (!Prefs.get(mContext).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);
        }
    }

    private static boolean isFadeEffectEnabled(Context context) {
        return Settings.Secure.getInt(
                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
+58 −6
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.accessibility.floatingmenu;
import static android.util.MathUtils.constrain;
import static android.util.MathUtils.sq;

import static java.util.Objects.requireNonNull;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -43,7 +45,9 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;

import androidx.annotation.DimenRes;
@@ -60,6 +64,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * Accessibility floating menu is used for the actions of accessibility features, it's also the
@@ -78,6 +83,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    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;
    private static final float ANIMATION_TO_X_VALUE = 0.5f;

    private boolean mIsFadeEffectEnabled;
    private boolean mIsShowing;
    private boolean mIsDownInEnlargedTouchArea;
@@ -107,6 +116,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    private float mPercentageY = LOCATION_Y_PERCENTAGE;
    private float mSquareScaledTouchSlop;
    private final Configuration mLastConfiguration;
    private Optional<OnDragEndListener> mOnDragEndListener = Optional.empty();
    private final RecyclerView mListView;
    private final AccessibilityTargetAdapter mAdapter;
    private float mFadeOutValue;
@@ -161,6 +171,17 @@ public class AccessibilityFloatingMenuView extends FrameLayout
        int RIGHT = 1;
    }

    /**
     * Interface for a callback to be invoked when the floating menu was dragging.
     */
    interface OnDragEndListener {

        /**
         * Invoked when the floating menu has dragged end.
         */
        void onDragEnd();
    }

    public AccessibilityFloatingMenuView(Context context) {
        this(context, new RecyclerView(context));
    }
@@ -201,6 +222,8 @@ public class AccessibilityFloatingMenuView extends FrameLayout
                updateRadiusWith(mSizeType, mRadiusType, mTargets.size());

                fadeOut();

                mOnDragEndListener.ifPresent(OnDragEndListener::onDragEnd);
            }
        });

@@ -266,7 +289,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout

                // 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) {
                if (!isOvalShape()) {
                    setShapeType(ShapeType.OVAL);

                    return true;
@@ -363,6 +386,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
        return mIsShowing;
    }

    boolean isOvalShape() {
        return mShapeType == ShapeType.OVAL;
    }

    void onTargetsChanged(List<AccessibilityTarget> newTargets) {
        fadeIn();

@@ -407,6 +434,35 @@ public class AccessibilityFloatingMenuView extends FrameLayout
        fadeOut();
    }

    public void setOnDragEndListener(OnDragEndListener onDragListener) {
        mOnDragEndListener = Optional.ofNullable(onDragListener);
    }

    void startTranslateXAnimation() {
        fadeIn();

        final float toXValue = mAlignment == Alignment.RIGHT
                ? ANIMATION_TO_X_VALUE
                : -ANIMATION_TO_X_VALUE;
        final TranslateAnimation animation =
                new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, toXValue,
                        Animation.RELATIVE_TO_SELF, 0,
                        Animation.RELATIVE_TO_SELF, 0);
        animation.setDuration(ANIMATION_DURATION_MS);
        animation.setRepeatMode(Animation.REVERSE);
        animation.setInterpolator(new OvershootInterpolator());
        animation.setRepeatCount(Animation.INFINITE);
        animation.setStartOffset(ANIMATION_START_OFFSET);
        mListView.startAnimation(animation);
    }

    void stopTranslateXAnimation() {
        mListView.clearAnimation();

        fadeOut();
    }

    Rect getWindowLocationOnScreen() {
        final int left = mCurrentLayoutParams.x;
        final int top = mCurrentLayoutParams.y;
@@ -536,11 +592,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    }

    private Handler createUiHandler() {
        final Looper looper = Looper.myLooper();
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }
        return new Handler(looper);
        return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
    }

    private void updateDimensions() {
+26 −18
Original line number Diff line number Diff line
@@ -66,7 +66,6 @@ class BaseTooltipView extends FrameLayout {
    private int mArrowCornerRadius;
    private int mScreenWidth;
    private boolean mIsShowing;
    private View mArrowView;
    private TextView mTextView;
    private final WindowManager.LayoutParams mCurrentLayoutParams;
    private final WindowManager mWindowManager;
@@ -87,12 +86,11 @@ class BaseTooltipView extends FrameLayout {
        super.onConfigurationChanged(newConfig);

        updateDimensions();

        updateTextView();
        updateArrow();

        mAnchorView.onConfigurationChanged(newConfig);
        final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
        updateArrowWith(anchorViewLocation);
        updateWidthWith(anchorViewLocation);
        updateLocationWith(anchorViewLocation);

@@ -132,6 +130,7 @@ class BaseTooltipView extends FrameLayout {

        mIsShowing = true;
        final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
        updateArrowWith(anchorViewLocation);
        updateWidthWith(anchorViewLocation);
        updateLocationWith(anchorViewLocation);

@@ -164,9 +163,6 @@ class BaseTooltipView extends FrameLayout {
                LayoutInflater.from(getContext()).inflate(
                        R.layout.accessibility_floating_menu_tooltip, this, false);

        mArrowView = contentView.findViewById(R.id.arrow);
        drawArrow(mArrowView);

        mTextView = contentView.findViewById(R.id.text);

        addView(contentView);
@@ -220,17 +216,23 @@ class BaseTooltipView extends FrameLayout {
        gradientDrawable.setCornerRadius(mTextViewCornerRadius);
    }

    private void updateArrow() {
        final ShapeDrawable shapeDrawable = (ShapeDrawable) mArrowView.getBackground();
        final Paint paint = shapeDrawable.getPaint();
        paint.setPathEffect(new CornerPathEffect(mArrowCornerRadius));
    private void updateArrowWith(Rect anchorViewLocation) {
        final boolean isAnchorViewOnLeft = isAnchorViewOnLeft(anchorViewLocation);
        final View arrowView = findViewById(isAnchorViewOnLeft
                ? R.id.arrow_left
                : R.id.arrow_right);
        arrowView.setVisibility(VISIBLE);
        drawArrow(arrowView, isAnchorViewOnLeft);

        final LinearLayout.LayoutParams layoutParams =
                (LinearLayout.LayoutParams) mArrowView.getLayoutParams();
                (LinearLayout.LayoutParams) arrowView.getLayoutParams();
        layoutParams.width = mArrowWidth;
        layoutParams.height = mArrowHeight;
        layoutParams.setMargins(mArrowMargin, 0, 0, 0);
        mArrowView.setLayoutParams(layoutParams);

        final int leftMargin = isAnchorViewOnLeft ? 0 : mArrowMargin;
        final int rightMargin = isAnchorViewOnLeft ? mArrowMargin : 0;
        layoutParams.setMargins(leftMargin, 0, rightMargin, 0);
        arrowView.setLayoutParams(layoutParams);
    }

    private void updateWidthWith(Rect anchorViewLocation) {
@@ -240,17 +242,19 @@ class BaseTooltipView extends FrameLayout {
    }

    private void updateLocationWith(Rect anchorViewLocation) {
        mCurrentLayoutParams.x =
                mScreenWidth - getWindowWidthWith(anchorViewLocation) - anchorViewLocation.width();
        mCurrentLayoutParams.x = isAnchorViewOnLeft(anchorViewLocation)
                ? anchorViewLocation.width()
                : mScreenWidth - getWindowWidthWith(anchorViewLocation)
                        - anchorViewLocation.width();
        mCurrentLayoutParams.y =
                anchorViewLocation.centerY() - (getTextHeightWith(anchorViewLocation) / 2);
    }

    private void drawArrow(View view) {
    private void drawArrow(View view, boolean isPointingLeft) {
        final ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        final TriangleShape triangleShape =
                TriangleShape.createHorizontal(layoutParams.width, layoutParams.height,
                        false);
                        isPointingLeft);
        final ShapeDrawable arrowDrawable = new ShapeDrawable(triangleShape);
        final Paint arrowPaint = arrowDrawable.getPaint();
        arrowPaint.setColor(Utils.getColorAttrDefaultColor(getContext(),
@@ -260,6 +264,10 @@ class BaseTooltipView extends FrameLayout {
        view.setBackground(arrowDrawable);
    }

    private boolean isAnchorViewOnLeft(Rect anchorViewLocation) {
        return anchorViewLocation.left < (mScreenWidth / 2);
    }

    private int getTextWidthWith(Rect anchorViewLocation) {
        final int widthSpec =
                MeasureSpec.makeMeasureSpec(getAvailableTextWidthWith(anchorViewLocation), AT_MOST);
Loading