summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riley Jones <jonesriley@google.com> 2025-01-08 01:07:55 +0000
committer Riley Jones <jonesriley@google.com> 2025-01-10 13:13:57 -0800
commit0912c28ad74946f8545732a6989e88ba6bade096 (patch)
tree4df6a365507510712daf5dff6901e975db5e750b
parente64e000f2a17c399fcaba2c8d8e2f802465920d8 (diff)
Handling DisplayCutouts more granularly to allow the FAB to occupy more space
Flag: com.android.systemui.floating_menu_display_cutout_support Bug: 384399408 Test: atest com.android.systemup.floatingmenu Change-Id: I37095dffc48cb653a44d8be1986667f7c282844e
-rw-r--r--packages/SystemUI/aconfig/accessibility.aconfig10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java72
8 files changed, 148 insertions, 14 deletions
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index b5eba08c8f87..585d021baa98 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -38,6 +38,16 @@ flag {
}
flag {
+ name: "floating_menu_display_cutout_support"
+ namespace: "accessibility"
+ description: "Makes FAB properly react to and avoid DisplayCutouts."
+ bug: "384399408"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "floating_menu_drag_to_hide"
namespace: "accessibility"
description: "Allows users to hide the FAB then use notification to dismiss or bring it back."
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 56a97bb34172..fff6def52803 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.graphics.PointF;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
@@ -210,7 +211,7 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase {
mTouchHandler.onInterceptTouchEvent(mStubListView, stubMoveEvent);
mTouchHandler.onInterceptTouchEvent(mStubListView, stubUpEvent);
- verify(mMenuAnimationController).flingMenuThenSpringToEdge(anyFloat(), anyFloat(),
+ verify(mMenuAnimationController).flingMenuThenSpringToEdge(any(PointF.class), anyFloat(),
anyFloat());
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 030d147e21c3..edbede8fa865 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import android.view.DisplayCutout;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
@@ -197,7 +198,7 @@ class MenuAnimationController {
constrainPositionAndUpdate(position, /* writeToPosition = */ true);
}
- void flingMenuThenSpringToEdge(float x, float velocityX, float velocityY) {
+ void flingMenuThenSpringToEdge(PointF position, float velocityX, float velocityY) {
final boolean shouldMenuFlingLeft = isOnLeftSide()
? velocityX < ESCAPE_VELOCITY
: velocityX < -ESCAPE_VELOCITY;
@@ -205,9 +206,17 @@ class MenuAnimationController {
final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
final float finalPositionX = shouldMenuFlingLeft
? draggableBounds.left : draggableBounds.right;
-
+ final DisplayCutout displayCutout = mMenuViewAppearance.getDisplayCutout();
+ final float finalPositionY =
+ (displayCutout == null) ? position.y
+ : mMenuViewAppearance.avoidVerticalDisplayCutout(
+ position.y, draggableBounds,
+ shouldMenuFlingLeft
+ ? displayCutout.getBoundingRectLeft()
+ : displayCutout.getBoundingRectRight()
+ );
final float minimumVelocityToReachEdge =
- (finalPositionX - x) * (FLING_FRICTION_SCALAR * DEFAULT_FRICTION);
+ (finalPositionX - position.x) * (FLING_FRICTION_SCALAR * DEFAULT_FRICTION);
final float startXVelocity = shouldMenuFlingLeft
? Math.min(minimumVelocityToReachEdge, velocityX)
@@ -219,11 +228,19 @@ class MenuAnimationController {
createSpringForce(),
finalPositionX);
- flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
- velocityY,
- FLING_FRICTION_SCALAR,
- createSpringForce(),
- /* finalPosition= */ null);
+ if (com.android.systemui.Flags.floatingMenuDisplayCutoutSupport()) {
+ flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
+ velocityY,
+ FLING_FRICTION_SCALAR,
+ createSpringForce(),
+ (finalPositionY != position.y) ? finalPositionY : null);
+ } else {
+ flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
+ velocityY,
+ FLING_FRICTION_SCALAR,
+ createSpringForce(),
+ /* finalPosition= */ null);
+ }
}
private void flingThenSpringMenuWith(DynamicAnimation.ViewProperty property, float velocity,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
index 9511e3769a8d..aca020d235be 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java
@@ -105,7 +105,8 @@ class MenuListViewTouchHandler implements RecyclerView.OnItemTouchListener {
if (mDragToInteractAnimationController.maybeConsumeUpMotionEvent(motionEvent)
== empty) {
mVelocityTracker.computeCurrentVelocity(VELOCITY_UNIT_SECONDS);
- mMenuAnimationController.flingMenuThenSpringToEdge(endX,
+ mMenuAnimationController.flingMenuThenSpringToEdge(
+ new PointF(endX, mMenuTranslationDown.y + dy),
mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
mMenuAnimationController.fadeOutIfEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
index a700cbef2e16..bd3dfe049587 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
@@ -28,12 +28,14 @@ import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.view.DisplayCutout;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.DimenRes;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.res.R;
import java.lang.annotation.Retention;
@@ -291,7 +293,7 @@ class MenuViewAppearance {
final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();
final Insets insets = windowInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
+ WindowInsets.Type.systemBars());
final Rect bounds = new Rect(windowMetrics.getBounds());
bounds.left += insets.left;
@@ -302,6 +304,37 @@ class MenuViewAppearance {
return bounds;
}
+ DisplayCutout getDisplayCutout() {
+ return mWindowManager.getCurrentWindowMetrics().getWindowInsets().getDisplayCutout();
+ }
+
+ float avoidVerticalDisplayCutout(float y, Rect bounds, Rect cutout) {
+ int menuHeight = calculateActualMenuHeight();
+ return avoidVerticalDisplayCutout(y, menuHeight, bounds, cutout);
+ }
+
+ @VisibleForTesting
+ public static float avoidVerticalDisplayCutout(
+ float y, float menuHeight, Rect bounds, Rect cutout) {
+ if (cutout.top > y + menuHeight || cutout.bottom < y) {
+ return y;
+ }
+
+ boolean topAvailable = cutout.top - bounds.top >= menuHeight;
+ boolean bottomAvailable = bounds.bottom - cutout.bottom >= menuHeight;
+ boolean topOrBottom;
+ if (!topAvailable && !bottomAvailable) {
+ return y;
+ } else if (topAvailable && !bottomAvailable) {
+ topOrBottom = true;
+ } else if (!topAvailable && bottomAvailable) {
+ topOrBottom = false;
+ } else {
+ topOrBottom = y + menuHeight * 0.5f < cutout.centerY();
+ }
+ return (topOrBottom) ? cutout.top - menuHeight : cutout.bottom;
+ }
+
boolean isMenuOnLeftSide() {
return mPercentagePosition.getPercentageX() < 0.5f;
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 7a674e2fa6f1..2ee9de4f49d8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -516,7 +516,7 @@ class MenuViewLayer extends FrameLayout implements
return;
}
mMenuAnimationController.flingMenuThenSpringToEdge(
- mMenuView.getMenuPosition().x, 100f, 0f);
+ mMenuView.getMenuPosition(), 100f, 0f);
Intent intent = getIntentForEditScreen();
PackageManager packageManager = getContext().getPackageManager();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index 9f6ad56335d7..c14cb87064ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -194,7 +194,7 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
- mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ mMenuAnimationController.flingMenuThenSpringToEdge(new PointF(), /* velocityX= */
100, /* velocityY= */ 100);
mMenuAnimationController.mPositionAnimations.values()
.forEach(animation -> verify((FlingAnimation) animation).addEndListener(
@@ -212,7 +212,7 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
final Runnable onSpringAnimationsEndCallback = mock(Runnable.class);
mMenuAnimationController.setSpringAnimationsEndAction(onSpringAnimationsEndCallback);
- mMenuAnimationController.flingMenuThenSpringToEdge(/* x= */ 0, /* velocityX= */
+ mMenuAnimationController.flingMenuThenSpringToEdge(new PointF(), /* velocityX= */
200, /* velocityY= */ 200);
mMenuAnimationController.mPositionAnimations.values()
.forEach(animation -> verify((FlingAnimation) animation).addEndListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java
new file mode 100644
index 000000000000..146488b523ad
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearanceTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2025 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 static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Rect;
+import android.testing.TestableLooper;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for {@link MenuViewAppearanceTest}. */
+@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class MenuViewAppearanceTest extends SysuiTestCase {
+ static final Rect DRAGGABLE_BOUNDS = new Rect(0, 0, 10, 10);
+ static final int MENU_HEIGHT = 1;
+
+ @Test
+ public void avoidVerticalDisplayCutout_roomAbove_placesAbove() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 3, 0, 10);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y + MENU_HEIGHT).isAtMost(cutout.top);
+ }
+
+ @Test
+ public void avoidVerticalDisplayCutout_roomBelow_placesBelow() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 0, 0, 5);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y).isAtLeast(cutout.bottom);
+ }
+
+ @Test
+ public void avoidVerticalDisplayCutout_noRoom_noChange() {
+ final int y = 2;
+ final Rect cutout = new Rect(0, 0, 0, 10);
+
+ final float end_y = MenuViewAppearance.avoidVerticalDisplayCutout(
+ y, MENU_HEIGHT, DRAGGABLE_BOUNDS, cutout);
+
+ assertThat(end_y).isEqualTo(end_y);
+ }
+}