Loading packages/SystemUI/aconfig/accessibility.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,16 @@ flag { bug: "297556899" } 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" Loading packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } Loading packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java +25 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) Loading @@ -219,12 +228,20 @@ class MenuAnimationController { createSpringForce(), finalPositionX); 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, float friction, SpringForce spring, Float finalPosition) { Loading packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java +2 −1 Original line number Diff line number Diff line Loading @@ -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(); } Loading packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java +34 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading Loading
packages/SystemUI/aconfig/accessibility.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,16 @@ flag { bug: "297556899" } 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" Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } Loading
packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java +25 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) Loading @@ -219,12 +228,20 @@ class MenuAnimationController { createSpringForce(), finalPositionX); 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, float friction, SpringForce spring, Float finalPosition) { Loading
packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandler.java +2 −1 Original line number Diff line number Diff line Loading @@ -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(); } Loading
packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java +34 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; } Loading