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

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

Merge changes I27530b15,Ic5d88cf3 into sc-v2-dev

* changes:
  Fixing the a11y floating menu could overlap the keyboard when rotated in a foldable device.
  Fixing the a11y floating menu could overlap the taskbar in a foldable device.
parents 11f14b1e 80929628
Loading
Loading
Loading
Loading
+55 −26
Original line number Diff line number Diff line
@@ -19,8 +19,9 @@ package com.android.systemui.accessibility.floatingmenu;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.util.MathUtils.constrain;
import static android.util.MathUtils.sq;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.systemBars;

import static java.util.Objects.requireNonNull;

@@ -41,7 +42,6 @@ import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -95,7 +95,6 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    private boolean mIsShowing;
    private boolean mIsDownInEnlargedTouchArea;
    private boolean mIsDragging = false;
    private boolean mImeVisibility;
    @Alignment
    private int mAlignment;
    @SizeType
@@ -108,8 +107,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    private int mRadiusType;
    private int mMargin;
    private int mPadding;
    private int mScreenHeight;
    private int mScreenWidth;
    // The display width excludes the window insets of the system bar and display cutout.
    private int mDisplayHeight;
    // The display Height excludes the window insets of the system bar and display cutout.
    private int mDisplayWidth;
    private int mIconWidth;
    private int mIconHeight;
    private int mInset;
@@ -118,6 +119,8 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    private int mRelativeToPointerDownX;
    private int mRelativeToPointerDownY;
    private float mRadius;
    private final Rect mDisplayInsetsRect = new Rect();
    private final Rect mImeInsetsRect = new Rect();
    private final Position mPosition;
    private float mSquareScaledTouchSlop;
    private final Configuration mLastConfiguration;
@@ -506,9 +509,21 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    }

    private WindowInsets onWindowInsetsApplied(WindowInsets insets) {
        final boolean currentImeVisibility = insets.isVisible(ime());
        if (currentImeVisibility != mImeVisibility) {
            mImeVisibility = currentImeVisibility;
        final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        final Rect displayWindowInsetsRect = getDisplayInsets(windowMetrics).toRect();
        if (!displayWindowInsetsRect.equals(mDisplayInsetsRect)) {
            updateDisplaySizeWith(windowMetrics);
            updateLocationWith(mPosition);
        }

        final Rect imeInsetsRect = windowMetrics.getWindowInsets().getInsets(ime()).toRect();
        if (!imeInsetsRect.equals(mImeInsetsRect)) {
            if (isImeVisible(imeInsetsRect)) {
                mImeInsetsRect.set(imeInsetsRect);
            } else {
                mImeInsetsRect.setEmpty();
            }

            updateLocationWith(mPosition);
        }

@@ -520,6 +535,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
                || (side == Alignment.LEFT && downX > currentRawX);
    }

    private boolean isImeVisible(Rect imeInsetsRect) {
        return imeInsetsRect.left != 0 || imeInsetsRect.top != 0 || imeInsetsRect.right != 0
                || imeInsetsRect.bottom != 0;
    }

    private boolean hasExceededTouchSlop(int startX, int startY, int endX, int endY) {
        return (sq(endX - startX) + sq(endY - startY)) > mSquareScaledTouchSlop;
    }
@@ -546,9 +566,9 @@ public class AccessibilityFloatingMenuView extends FrameLayout

    private void updateDimensions() {
        final Resources res = getResources();
        final DisplayMetrics dm = res.getDisplayMetrics();
        mScreenWidth = dm.widthPixels;
        mScreenHeight = dm.heightPixels;

        updateDisplaySizeWith(mWindowManager.getCurrentWindowMetrics());

        mMargin =
                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin);
        mInset =
@@ -560,6 +580,15 @@ public class AccessibilityFloatingMenuView extends FrameLayout
        updateItemViewDimensionsWith(mSizeType);
    }

    private void updateDisplaySizeWith(WindowMetrics metrics) {
        final Rect displayBounds = metrics.getBounds();
        final Insets displayInsets = getDisplayInsets(metrics);
        mDisplayInsetsRect.set(displayInsets.toRect());
        displayBounds.inset(displayInsets);
        mDisplayWidth = displayBounds.width();
        mDisplayHeight = displayBounds.height();
    }

    private void updateItemViewDimensionsWith(@SizeType int sizeType) {
        final Resources res = getResources();
        final int paddingResId =
@@ -684,11 +713,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    }

    private int getMaxWindowX() {
        return mScreenWidth - getMarginStartEndWith(mLastConfiguration) - getLayoutWidth();
        return mDisplayWidth - getMarginStartEndWith(mLastConfiguration) - getLayoutWidth();
    }

    private int getMaxWindowY() {
        return mScreenHeight - getWindowHeight();
        return mDisplayHeight - getWindowHeight();
    }

    private InstantInsetLayerDrawable getMenuLayerDrawable() {
@@ -699,8 +728,13 @@ public class AccessibilityFloatingMenuView extends FrameLayout
        return (GradientDrawable) getMenuLayerDrawable().getDrawable(INDEX_MENU_ITEM);
    }

    private Insets getDisplayInsets(WindowMetrics metrics) {
        return metrics.getWindowInsets().getInsetsIgnoringVisibility(
                systemBars() | displayCutout());
    }

    /**
     * Updates the floating menu to be fixed at the side of the screen.
     * Updates the floating menu to be fixed at the side of the display.
     */
    private void updateLocationWith(Position position) {
        final @Alignment int alignment = transformToAlignment(position.getPercentageX());
@@ -716,15 +750,9 @@ public class AccessibilityFloatingMenuView extends FrameLayout
     * @return the moving interval if they overlap each other, otherwise 0.
     */
    private int getInterval() {
        if (!mImeVisibility) {
            return 0;
        }

        final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        final Insets imeInsets = windowMetrics.getWindowInsets().getInsets(
                ime() | navigationBars());
        final int imeY = mScreenHeight - imeInsets.bottom;
        final int layoutBottomY = mCurrentLayoutParams.y + getWindowHeight();
        final int currentLayoutY = (int) (mPosition.getPercentageY() * getMaxWindowY());
        final int imeY = mDisplayHeight - mImeInsetsRect.bottom;
        final int layoutBottomY = currentLayoutY + getWindowHeight();

        return layoutBottomY > imeY ? (layoutBottomY - imeY) : 0;
    }
@@ -855,11 +883,12 @@ public class AccessibilityFloatingMenuView extends FrameLayout

    @VisibleForTesting
    Rect getAvailableBounds() {
        return new Rect(0, 0, mScreenWidth - getWindowWidth(), mScreenHeight - getWindowHeight());
        return new Rect(0, 0, mDisplayWidth - getWindowWidth(),
                mDisplayHeight - getWindowHeight());
    }

    private int getMaxLayoutHeight() {
        return mScreenHeight - mMargin * 2;
        return mDisplayHeight - mMargin * 2;
    }

    private int getLayoutWidth() {
@@ -875,7 +904,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
    }

    private int getWindowHeight() {
        return Math.min(mScreenHeight, mMargin * 2 + getLayoutHeight());
        return Math.min(mDisplayHeight, mMargin * 2 + getLayoutHeight());
    }

    private void setSystemGestureExclusion() {
+46 −31
Original line number Diff line number Diff line
@@ -19,8 +19,9 @@ package com.android.systemui.accessibility.floatingmenu;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.View.OVER_SCROLL_ALWAYS;
import static android.view.View.OVER_SCROLL_NEVER;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.systemBars;

import static com.google.common.truth.Truth.assertThat;

@@ -39,6 +40,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.testing.AndroidTestingRunner;
@@ -98,14 +100,15 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
    private AccessibilityFloatingMenuView mMenuView;
    private RecyclerView mListView = new RecyclerView(mContext);

    private int mScreenHeight;
    private int mMenuWindowHeight;
    private int mMenuHalfWidth;
    private int mMenuHalfHeight;
    private int mScreenHalfWidth;
    private int mScreenHalfHeight;
    private int mDisplayHalfWidth;
    private int mDisplayHalfHeight;
    private int mMaxWindowX;
    private int mMaxWindowY;
    private final int mDisplayWindowWidth = 1080;
    private final int mDisplayWindowHeight = 2340;

    @Before
    public void initMenuView() {
@@ -113,7 +116,10 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
                mWindowManager).getMaximumWindowMetrics();
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);

        when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
        when(mWindowMetrics.getBounds()).thenReturn(new Rect(0, 0, mDisplayWindowWidth,
                mDisplayWindowHeight));
        when(mWindowMetrics.getWindowInsets()).thenReturn(fakeDisplayInsets());
        mMenuView = spy(
                new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition, mListView));
    }
@@ -129,18 +135,16 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
                res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_width_height);
        final int menuWidth = padding * 2 + iconWidthHeight;
        final int menuHeight = (padding + iconWidthHeight) * mTargets.size() + padding;
        final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
        mScreenHeight = mContext.getResources().getDisplayMetrics().heightPixels;
        mMenuHalfWidth = menuWidth / 2;
        mMenuHalfHeight = menuHeight / 2;
        mScreenHalfWidth = screenWidth / 2;
        mScreenHalfHeight = mScreenHeight / 2;
        mDisplayHalfWidth = mDisplayWindowWidth / 2;
        mDisplayHalfHeight = mDisplayWindowHeight / 2;
        int marginStartEnd =
                mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT
                        ? margin : 0;
        mMaxWindowX = screenWidth - marginStartEnd - menuWidth;
        mMaxWindowX = mDisplayWindowWidth - marginStartEnd - menuWidth;
        mMenuWindowHeight = menuHeight + margin * 2;
        mMaxWindowY = mScreenHeight - mMenuWindowHeight;
        mMaxWindowY = mDisplayWindowHeight - mMenuWindowHeight;
    }

    @Test
@@ -279,15 +283,15 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
        final MotionEvent moveEvent =
                mMotionEventHelper.obtainMotionEvent(2, 3,
                        MotionEvent.ACTION_MOVE,
                        /* screenCenterX */mScreenHalfWidth
                                - /* offsetXToScreenLeftHalfRegion */ 10,
                        /* screenCenterY */ mScreenHalfHeight);
                        /* displayCenterX */mDisplayHalfWidth
                                - /* offsetXToDisplayLeftHalfRegion */ 10,
                        /* displayCenterY */ mDisplayHalfHeight);
        final MotionEvent upEvent =
                mMotionEventHelper.obtainMotionEvent(4, 5,
                        MotionEvent.ACTION_UP,
                        /* screenCenterX */ mScreenHalfWidth
                                - /* offsetXToScreenLeftHalfRegion */ 10,
                        /* screenCenterY */ mScreenHalfHeight);
                        /* displayCenterX */ mDisplayHalfWidth
                                - /* offsetXToDisplayLeftHalfRegion */ 10,
                        /* displayCenterY */ mDisplayHalfHeight);

        listView.dispatchTouchEvent(downEvent);
        listView.dispatchTouchEvent(moveEvent);
@@ -315,15 +319,15 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
        final MotionEvent moveEvent =
                mMotionEventHelper.obtainMotionEvent(2, 3,
                        MotionEvent.ACTION_MOVE,
                        /* screenCenterX */mScreenHalfWidth
                                + /* offsetXToScreenRightHalfRegion */ 10,
                        /* screenCenterY */ mScreenHalfHeight);
                        /* displayCenterX */mDisplayHalfWidth
                                + /* offsetXToDisplayRightHalfRegion */ 10,
                        /* displayCenterY */ mDisplayHalfHeight);
        final MotionEvent upEvent =
                mMotionEventHelper.obtainMotionEvent(4, 5,
                        MotionEvent.ACTION_UP,
                        /* screenCenterX */ mScreenHalfWidth
                                + /* offsetXToScreenRightHalfRegion */ 10,
                        /* screenCenterY */ mScreenHalfHeight);
                        /* displayCenterX */ mDisplayHalfWidth
                                + /* offsetXToDisplayRightHalfRegion */ 10,
                        /* displayCenterY */ mDisplayHalfHeight);

        listView.dispatchTouchEvent(downEvent);
        listView.dispatchTouchEvent(moveEvent);
@@ -332,12 +336,12 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {

        assertThat((float) menuView.mCurrentLayoutParams.x).isWithin(1.0f).of(mMaxWindowX);
        assertThat((float) menuView.mCurrentLayoutParams.y).isWithin(1.0f).of(
                /* newWindowY = screenCenterY - offsetY */ mScreenHalfHeight - mMenuHalfHeight);
                /* newWindowY = displayCenterY - offsetY */ mDisplayHalfHeight - mMenuHalfHeight);
    }


    @Test
    public void tapOnAndDragMenuToScreenSide_transformShapeHalfOval() {
    public void tapOnAndDragMenuToDisplaySide_transformShapeHalfOval() {
        final Position alignRightPosition = new Position(1.0f, 0.8f);
        final RecyclerView listView = new RecyclerView(mContext);
        final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext,
@@ -355,13 +359,13 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
                mMotionEventHelper.obtainMotionEvent(2, 3,
                        MotionEvent.ACTION_MOVE,
                        /* downX */(currentWindowX + mMenuHalfWidth)
                                + /* offsetXToScreenRightSide */ mMenuHalfWidth,
                                + /* offsetXToDisplayRightSide */ mMenuHalfWidth,
                        /* downY */ (currentWindowY +  mMenuHalfHeight));
        final MotionEvent upEvent =
                mMotionEventHelper.obtainMotionEvent(4, 5,
                        MotionEvent.ACTION_UP,
                        /* downX */(currentWindowX + mMenuHalfWidth)
                                + /* offsetXToScreenRightSide */ mMenuHalfWidth,
                                + /* offsetXToDisplayRightSide */ mMenuHalfWidth,
                        /* downY */ (currentWindowY +  mMenuHalfHeight));

        listView.dispatchTouchEvent(downEvent);
@@ -423,7 +427,7 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
    }

    @Test
    public void showMenuAndIme_withHigherIme_alignScreenTopEdge() {
    public void showMenuAndIme_withHigherIme_alignDisplayTopEdge() {
        final int offset = 99999;

        setupBasicMenuView(mMenuView);
@@ -475,10 +479,21 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
    private WindowInsets fakeImeInsetWith(AccessibilityFloatingMenuView menuView, int offset) {
        // Ensure the keyboard has overlapped on the menu view.
        final int fakeImeHeight =
                mScreenHeight - (menuView.mCurrentLayoutParams.y + mMenuWindowHeight) + offset;
                mDisplayWindowHeight - (menuView.mCurrentLayoutParams.y + mMenuWindowHeight)
                        + offset;
        return new WindowInsets.Builder()
                .setVisible(ime(), true)
                .setInsets(ime(), Insets.of(0, 0, 0, fakeImeHeight))
                .build();
    }

    private WindowInsets fakeDisplayInsets() {
        final int fakeStatusBarHeight = 75;
        final int fakeNavigationBarHeight = 125;
        return new WindowInsets.Builder()
                .setVisible(ime() | navigationBars(), true)
                .setInsets(ime() | navigationBars(), Insets.of(0, 0, 0, fakeImeHeight))
                .setVisible(systemBars() | displayCutout(), true)
                .setInsets(systemBars() | displayCutout(),
                        Insets.of(0, fakeStatusBarHeight, 0, fakeNavigationBarHeight))
                .build();
    }

+10 −0
Original line number Diff line number Diff line
@@ -23,12 +23,16 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.test.filters.SmallTest;
@@ -52,6 +56,9 @@ public class BaseTooltipViewTest extends SysuiTestCase {
    @Mock
    private WindowManager mWindowManager;

    @Mock
    private WindowMetrics mWindowMetrics;

    private AccessibilityFloatingMenuView mMenuView;
    private BaseTooltipView mToolTipView;

@@ -66,6 +73,9 @@ public class BaseTooltipViewTest extends SysuiTestCase {
        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
                mWindowManager).getMaximumWindowMetrics();
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
        when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
        when(mWindowMetrics.getBounds()).thenReturn(new Rect());
        when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build());

        mMenuView = new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition);
        mToolTipView = new BaseTooltipView(mContext, mMenuView);
+10 −0
Original line number Diff line number Diff line
@@ -21,12 +21,16 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;

import androidx.test.filters.SmallTest;

@@ -49,6 +53,9 @@ public class DockTooltipViewTest extends SysuiTestCase {
    @Mock
    private WindowManager mWindowManager;

    @Mock
    private WindowMetrics mWindowMetrics;

    private AccessibilityFloatingMenuView mMenuView;
    private DockTooltipView mDockTooltipView;
    private final Position mPlaceholderPosition = new Position(0.0f, 0.0f);
@@ -62,6 +69,9 @@ public class DockTooltipViewTest extends SysuiTestCase {
        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
                mWindowManager).getMaximumWindowMetrics();
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
        when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
        when(mWindowMetrics.getBounds()).thenReturn(new Rect());
        when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build());

        mMenuView = spy(new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition));
        mDockTooltipView = new DockTooltipView(mContext, mMenuView);
+8 −0
Original line number Diff line number Diff line
@@ -22,12 +22,15 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
@@ -57,6 +60,8 @@ public class ItemDelegateCompatTest extends SysuiTestCase {
    @Mock
    private WindowManager mWindowManager;

    @Mock
    private WindowMetrics mWindowMetrics;
    private RecyclerView mListView;
    private AccessibilityFloatingMenuView mMenuView;
    private ItemDelegateCompat mItemDelegateCompat;
@@ -69,6 +74,9 @@ public class ItemDelegateCompatTest extends SysuiTestCase {
        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
                mWindowManager).getMaximumWindowMetrics();
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
        when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
        when(mWindowMetrics.getBounds()).thenReturn(new Rect());
        when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build());

        mListView = new RecyclerView(mContext);
        mMenuView =