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

Commit 817d5f1a authored by Riley Jones's avatar Riley Jones
Browse files

Added spring animations for tucking/untucking Floating Action Button

This change builds off of modifications from ag/24314702 to better suit animated tucking/untucking.
MenuViewLayer applies a clipBounds covering most of the screen excluding system/navigation bars
once the FAB begins a tucking animation. It does not remove the clip bounds until an untuck animation concludes.

Flag: ACONFIG com.android.systemui.Flags.floating_menu_animated_tuck ENABLED
Bug: 297556899
Test: adb sync system_ext && adb shell stop && adb shell start
Change-Id: Ic18e39486e24cd9080620174f9a3ecb298ebc515
parent 21e9eb45
Loading
Loading
Loading
Loading
+10 −3
Original line number Original line Diff line number Diff line
@@ -3,10 +3,10 @@ package: "com.android.systemui"
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.


flag {
flag {
    name: "floating_menu_overlaps_nav_bars_flag"
    name: "floating_menu_animated_tuck"
    namespace: "accessibility"
    namespace: "accessibility"
    description: "Adjusts bounds to allow the floating menu to render on top of navigation bars."
    description: "Sets up animations for tucking/untucking and adjusts clipbounds."
    bug: "283768342"
    bug: "24592044"
}
}


flag {
flag {
@@ -15,3 +15,10 @@ flag {
    description: "Adds an animation for when the FAB is displaced by an IME becoming visible."
    description: "Adds an animation for when the FAB is displaced by an IME becoming visible."
    bug: "281150010"
    bug: "281150010"
}
}

flag {
    name: "floating_menu_overlaps_nav_bars_flag"
    namespace: "accessibility"
    description: "Adjusts bounds to allow the floating menu to render on top of navigation bars."
    bug: "283768342"
}
 No newline at end of file
+34 −2
Original line number Original line Diff line number Diff line
@@ -341,7 +341,16 @@ class MenuAnimationController {
    void moveToEdgeAndHide() {
    void moveToEdgeAndHide() {
        mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ true);
        mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ true);
        final PointF position = mMenuView.getMenuPosition();
        final PointF position = mMenuView.getMenuPosition();
        moveToPosition(getTuckedMenuPosition());
        final PointF tuckedPosition = getTuckedMenuPosition();
        if (Flags.floatingMenuAnimatedTuck()) {
            flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
                    Math.signum(tuckedPosition.x - position.x) * ESCAPE_VELOCITY,
                    FLING_FRICTION_SCALAR,
                    createDefaultSpringForce(),
                    tuckedPosition.x);
        } else {
            moveToPosition(tuckedPosition);
        }


        // Keep the touch region let users could click extra space to pop up the menu view
        // Keep the touch region let users could click extra space to pop up the menu view
        // from the screen edge
        // from the screen edge
@@ -353,7 +362,24 @@ class MenuAnimationController {
    void moveOutEdgeAndShow() {
    void moveOutEdgeAndShow() {
        mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ false);
        mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ false);


        if (Flags.floatingMenuAnimatedTuck()) {
            PointF position = mMenuView.getMenuPosition();
            springMenuWith(DynamicAnimation.TRANSLATION_X,
                    createDefaultSpringForce(),
                    0,
                    position.x,
                    true
            );
            springMenuWith(DynamicAnimation.TRANSLATION_Y,
                    createDefaultSpringForce(),
                    0,
                    position.y,
                    true
            );
        } else {
            mMenuView.onPositionChanged();
            mMenuView.onPositionChanged();
        }

        mMenuView.onEdgeChangedIfNeeded();
        mMenuView.onEdgeChangedIfNeeded();
    }
    }


@@ -489,6 +515,12 @@ class MenuAnimationController {
        return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
        return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
    }
    }


    private static SpringForce createDefaultSpringForce() {
        return new SpringForce()
                .setStiffness(SPRING_STIFFNESS)
                .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO);
    }

    static class MenuPositionProperty
    static class MenuPositionProperty
            extends FloatPropertyCompat<MenuView> {
            extends FloatPropertyCompat<MenuView> {
        private final DynamicAnimation.ViewProperty mProperty;
        private final DynamicAnimation.ViewProperty mProperty;
+16 −1
Original line number Original line Diff line number Diff line
@@ -71,6 +71,7 @@ class MenuView extends FrameLayout implements


    private final MenuAnimationController mMenuAnimationController;
    private final MenuAnimationController mMenuAnimationController;
    private OnTargetFeaturesChangeListener mFeaturesChangeListener;
    private OnTargetFeaturesChangeListener mFeaturesChangeListener;
    private OnMoveToTuckedListener mMoveToTuckedListener;


    MenuView(Context context, MenuViewModel menuViewModel, MenuViewAppearance menuViewAppearance) {
    MenuView(Context context, MenuViewModel menuViewModel, MenuViewAppearance menuViewAppearance) {
        super(context);
        super(context);
@@ -138,6 +139,10 @@ class MenuView extends FrameLayout implements
        mFeaturesChangeListener = listener;
        mFeaturesChangeListener = listener;
    }
    }


    void setMoveToTuckedListener(OnMoveToTuckedListener listener) {
        mMoveToTuckedListener = listener;
    }

    void addOnItemTouchListenerToList(RecyclerView.OnItemTouchListener listener) {
    void addOnItemTouchListenerToList(RecyclerView.OnItemTouchListener listener) {
        mTargetFeaturesView.addOnItemTouchListener(listener);
        mTargetFeaturesView.addOnItemTouchListener(listener);
    }
    }
@@ -307,8 +312,11 @@ class MenuView extends FrameLayout implements
    void updateMenuMoveToTucked(boolean isMoveToTucked) {
    void updateMenuMoveToTucked(boolean isMoveToTucked) {
        mIsMoveToTucked = isMoveToTucked;
        mIsMoveToTucked = isMoveToTucked;
        mMenuViewModel.updateMenuMoveToTucked(isMoveToTucked);
        mMenuViewModel.updateMenuMoveToTucked(isMoveToTucked);
        if (mMoveToTuckedListener != null) {
            mMoveToTuckedListener.onMoveToTuckedChanged(isMoveToTucked);
        }


        if (Flags.floatingMenuOverlapsNavBarsFlag()) {
        if (Flags.floatingMenuOverlapsNavBarsFlag() && !Flags.floatingMenuAnimatedTuck()) {
            if (isMoveToTucked) {
            if (isMoveToTucked) {
                final float halfWidth = getMenuWidth() / 2.0f;
                final float halfWidth = getMenuWidth() / 2.0f;
                final boolean isOnLeftSide = mMenuAnimationController.isOnLeftSide();
                final boolean isOnLeftSide = mMenuAnimationController.isOnLeftSide();
@@ -428,4 +436,11 @@ class MenuView extends FrameLayout implements
         */
         */
        void onChange(List<AccessibilityTarget> newTargetFeatures);
        void onChange(List<AccessibilityTarget> newTargetFeatures);
    }
    }

    /**
     * Interface containing a callback for when MoveToTucked changes.
     */
    interface OnMoveToTuckedListener {
        void onMoveToTuckedChanged(boolean moveToTucked);
    }
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -281,7 +281,7 @@ class MenuViewAppearance {
                : new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
                : new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius};
    }
    }


    private Rect getWindowAvailableBounds() {
    public Rect getWindowAvailableBounds() {
        final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        final WindowInsets windowInsets = windowMetrics.getWindowInsets();
        final WindowInsets windowInsets = windowMetrics.getWindowInsets();
        final Insets insets = windowInsets.getInsetsIgnoringVisibility(
        final Insets insets = windowInsets.getInsetsIgnoringVisibility(
+30 −1
Original line number Original line Diff line number Diff line
@@ -79,7 +79,8 @@ import java.util.Optional;
 */
 */
@SuppressLint("ViewConstructor")
@SuppressLint("ViewConstructor")
class MenuViewLayer extends FrameLayout implements
class MenuViewLayer extends FrameLayout implements
        ViewTreeObserver.OnComputeInternalInsetsListener, View.OnClickListener, ComponentCallbacks {
        ViewTreeObserver.OnComputeInternalInsetsListener, View.OnClickListener, ComponentCallbacks,
        MenuView.OnMoveToTuckedListener {
    private static final int SHOW_MESSAGE_DELAY_MS = 3000;
    private static final int SHOW_MESSAGE_DELAY_MS = 3000;


    private final WindowManager mWindowManager;
    private final WindowManager mWindowManager;
@@ -211,6 +212,7 @@ class MenuViewLayer extends FrameLayout implements
        mMenuListViewTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController,
        mMenuListViewTouchHandler = new MenuListViewTouchHandler(mMenuAnimationController,
                mDismissAnimationController);
                mDismissAnimationController);
        mMenuView.addOnItemTouchListenerToList(mMenuListViewTouchHandler);
        mMenuView.addOnItemTouchListenerToList(mMenuListViewTouchHandler);
        mMenuView.setMoveToTuckedListener(this);


        mMessageView = new MenuMessageView(context);
        mMessageView = new MenuMessageView(context);


@@ -232,6 +234,10 @@ class MenuViewLayer extends FrameLayout implements
        addView(mMenuView, LayerIndex.MENU_VIEW);
        addView(mMenuView, LayerIndex.MENU_VIEW);
        addView(mDismissView, LayerIndex.DISMISS_VIEW);
        addView(mDismissView, LayerIndex.DISMISS_VIEW);
        addView(mMessageView, LayerIndex.MESSAGE_VIEW);
        addView(mMessageView, LayerIndex.MESSAGE_VIEW);

        if (Flags.floatingMenuAnimatedTuck()) {
            setClipChildren(true);
        }
    }
    }


    @Override
    @Override
@@ -354,6 +360,24 @@ class MenuViewLayer extends FrameLayout implements
        mShouldShowDockTooltip = !hasSeenTooltip;
        mShouldShowDockTooltip = !hasSeenTooltip;
    }
    }


    public void onMoveToTuckedChanged(boolean moveToTuck) {
        if (Flags.floatingMenuOverlapsNavBarsFlag()) {
            if (moveToTuck) {
                final Rect bounds = mMenuViewAppearance.getWindowAvailableBounds();
                final int[] location = getLocationOnScreen();
                bounds.offset(
                        location[0],
                        location[1]
                );

                setClipBounds(bounds);
            }
            // Instead of clearing clip bounds when moveToTuck is false,
            // wait until the spring animation finishes.
        }
        // Function is a no-operation if flag is disabled.
    }

    private void onSpringAnimationsEndAction() {
    private void onSpringAnimationsEndAction() {
        if (mShouldShowDockTooltip) {
        if (mShouldShowDockTooltip) {
            mEduTooltipView = Optional.of(new MenuEduTooltipView(mContext, mMenuViewAppearance));
            mEduTooltipView = Optional.of(new MenuEduTooltipView(mContext, mMenuViewAppearance));
@@ -364,6 +388,11 @@ class MenuViewLayer extends FrameLayout implements
            mMenuAnimationController.startTuckedAnimationPreview();
            mMenuAnimationController.startTuckedAnimationPreview();
        }
        }


        if (Flags.floatingMenuAnimatedTuck()) {
            if (!mMenuView.isMoveToTucked()) {
                setClipBounds(null);
            }
        }
        if (Flags.floatingMenuImeDisplacementAnimation()) {
        if (Flags.floatingMenuImeDisplacementAnimation()) {
            mMenuView.onArrivalAtPosition();
            mMenuView.onArrivalAtPosition();
        }
        }
Loading