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

Commit a0e43e71 authored by PETER LIANG's avatar PETER LIANG Committed by Android (Google) Code Review
Browse files

Merge "Add the new dock tooltip for accessibility floating menu." into sc-dev

parents d5325f9f ae817912
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