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

Commit b2f5a2f9 authored by jorgegil@google.com's avatar jorgegil@google.com
Browse files

Synchronize PIP menu fade out with task dismiss

This CL addreses two issues:
1. PipMenuView.dismissPip was previously fading out the PIP
menu, waiting for that to complete, then notifying the task
organizer to remove and fade out the window, and then it would
fade the menu out again even though it was already hidden.
This resulted in a quick flash because the menu and the window
are not faded out in sync.
2. The menu fade out animation had a fixed duration of 150ms,
meaning that even if it starting fading out at the same time
as the PIP window, it would not finish at the same time because
the PIP exit anim duration is longer.

To fix both of them, the X button now hides the menu and starts
dismissing the task at the same time (once), and the dismiss
animation duration is equal to the task fade out animation
duration.

Previous: http://recall/-/e8RgaQ0dFlwFuh0c7GRpyy/g7XMbvBGMyAOKZMuFlYpW0
With CL: http://recall/-/e8RgaQ0dFlwFuh0c7GRpyy/g7XMbvBGMyAOKZMuFlYpW0

Bug: 182727923
Test: Tap X to dismiss PIP, no flashes seen
Change-Id: If9bdda8d0fd8b819c00ec4a592d1b2441d642d00
parent a2bbcf95
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.wm.shell.pip.phone;

import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;

import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_HIDE;

import android.annotation.Nullable;
import android.app.RemoteAction;
import android.content.Context;
@@ -397,26 +399,26 @@ public class PhonePipMenuController implements PipMenuController {
     * Hides the menu view.
     */
    public void hideMenu() {
        hideMenu(true /* animate */, true /* resize */);
        hideMenu(ANIM_TYPE_HIDE, true /* resize */);
    }

    /**
     * Hides the menu view.
     *
     * @param animate whether to animate the menu fadeout
     * @param animationType the animation type to use upon hiding the menu
     * @param resize whether or not to resize the PiP with the state change
     */
    public void hideMenu(boolean animate, boolean resize) {
    public void hideMenu(@PipMenuView.AnimationType int animationType, boolean resize) {
        final boolean isMenuVisible = isMenuVisible();
        if (DEBUG) {
            Log.d(TAG, "hideMenu() state=" + mMenuState
                    + " isMenuVisible=" + isMenuVisible
                    + " animate=" + animate
                    + " animationType=" + animationType
                    + " resize=" + resize
                    + " callers=\n" + Debug.getCallers(5, "    "));
        }
        if (isMenuVisible) {
            mPipMenuView.hideMenu(animate, resize);
            mPipMenuView.hideMenu(resize, animationType);
        }
    }

+55 −20
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteAction;
import android.content.ComponentName;
@@ -64,6 +65,8 @@ import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PipUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

@@ -74,9 +77,26 @@ public class PipMenuView extends FrameLayout {

    private static final String TAG = "PipMenuView";

    private static final int ANIMATION_NONE_DURATION_MS = 0;
    private static final int ANIMATION_HIDE_DURATION_MS = 125;

    /** No animation performed during menu hide. */
    public static final int ANIM_TYPE_NONE = 0;
    /** Fade out the menu until it's invisible. Used when the PIP window remains visible.  */
    public static final int ANIM_TYPE_HIDE = 1;
    /** Fade out the menu in sync with the PIP window. */
    public static final int ANIM_TYPE_DISMISS = 2;

    @IntDef(prefix = { "ANIM_TYPE_" }, value = {
            ANIM_TYPE_NONE,
            ANIM_TYPE_HIDE,
            ANIM_TYPE_DISMISS
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface AnimationType {}

    private static final int INITIAL_DISMISS_DELAY = 3500;
    private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
    private static final long MENU_FADE_DURATION = 125;
    private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;

    private static final float MENU_BACKGROUND_ALPHA = 0.3f;
@@ -87,6 +107,7 @@ public class PipMenuView extends FrameLayout {
    private int mMenuState;
    private boolean mAllowMenuTimeout = true;
    private boolean mAllowTouches = true;
    private int mDismissFadeOutDurationMs;

    private final List<RemoteAction> mActions = new ArrayList<>();

@@ -167,6 +188,8 @@ public class PipMenuView extends FrameLayout {
        mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
        mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
                mResizeHandle, mSettingsButton, mDismissButton);
        mDismissFadeOutDurationMs = context.getResources()
                .getInteger(R.integer.config_pipExitAnimationDuration);

        initAccessibility();
    }
@@ -258,7 +281,7 @@ public class PipMenuView extends FrameLayout {
                mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
            }
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
            mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
            mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
            if (allowMenuTimeout) {
                mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
@@ -320,17 +343,18 @@ public class PipMenuView extends FrameLayout {
        hideMenu(null);
    }

    void hideMenu(boolean animate, boolean resize) {
        hideMenu(null, true /* notifyMenuVisibility */, animate, resize);
    void hideMenu(Runnable animationEndCallback) {
        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, true /* resize */,
                ANIM_TYPE_HIDE);
    }

    void hideMenu(Runnable animationEndCallback) {
        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, true /* animate */,
                true /* resize */);
    void hideMenu(boolean resize, @AnimationType int animationType) {
        hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */, resize,
                animationType);
    }

    private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
            boolean animate, boolean resize) {
    void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
            boolean resize, @AnimationType int animationType) {
        if (mMenuState != MENU_STATE_NONE) {
            cancelDelayedHide();
            if (notifyMenuVisibility) {
@@ -348,7 +372,7 @@ public class PipMenuView extends FrameLayout {
                    mResizeHandle.getAlpha(), 0f);
            mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
            mMenuContainerAnimator.setDuration(animate ? MENU_FADE_DURATION : 0);
            mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
            mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
@@ -478,19 +502,17 @@ public class PipMenuView extends FrameLayout {
    private void expandPip() {
        // Do not notify menu visibility when hiding the menu, the controller will do this when it
        // handles the message
        hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* animate */,
                true /* resize */);
        hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* resize */,
                ANIM_TYPE_HIDE);
    }

    private void dismissPip() {
        // Since tapping on the close-button invokes a double-tap wait callback in PipTouchHandler,
        // we want to disable animating the fadeout animation of the buttons in order to call on
        // PipTouchHandler#onPipDismiss fast enough.
        final boolean animate = mMenuState != MENU_STATE_CLOSE;
        // Do not notify menu visibility when hiding the menu, the controller will do this when it
        // handles the message
        hideMenu(mController::onPipDismiss, false /* notifyMenuVisibility */, animate,
                true /* resize */);
        if (mMenuState != MENU_STATE_NONE) {
            // Do not call hideMenu() directly. Instead, let the menu controller handle it just as
            // any other dismissal that will update the touch state and fade out the PIP task
            // and the menu view at the same time.
            mController.onPipDismiss();
        }
    }

    private void showSettings() {
@@ -514,4 +536,17 @@ public class PipMenuView extends FrameLayout {
        mMainExecutor.removeCallbacks(mHideMenuRunnable);
        mMainExecutor.executeDelayed(mHideMenuRunnable, recommendedTimeout);
    }

    private long getFadeOutDuration(@AnimationType int animationType) {
        switch (animationType) {
            case ANIM_TYPE_NONE:
                return ANIMATION_NONE_DURATION_MS;
            case ANIM_TYPE_HIDE:
                return ANIMATION_HIDE_DURATION_MS;
            case ANIM_TYPE_DISMISS:
                return mDismissFadeOutDurationMs;
            default:
                throw new IllegalStateException("Invalid animation type " + animationType);
        }
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;

import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_DISMISS;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -336,7 +338,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
                    + " callers=\n" + Debug.getCallers(5, "    "));
        }
        cancelPhysicsAnimation();
        mMenuController.hideMenu(false /* animate */, false /* resize */);
        mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
        mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION);
    }

@@ -349,7 +351,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
            Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, "    "));
        }
        cancelPhysicsAnimation();
        mMenuController.hideMenu(true /* animate*/, false /* resize */);
        mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
        mPipTaskOrganizer.removePip();
    }

+2 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;

import android.content.Context;
import android.content.res.Resources;
@@ -471,7 +472,7 @@ public class PipResizeGestureHandler {
                    }
                    if (mThresholdCrossed) {
                        if (mPhonePipMenuController.isMenuVisible()) {
                            mPhonePipMenuController.hideMenu(false /* animate */,
                            mPhonePipMenuController.hideMenu(ANIM_TYPE_NONE,
                                    false /* resize */);
                        }
                        final Rect currentPipBounds = mPipBoundsState.getBounds();
+2 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;

import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -881,7 +882,7 @@ public class PipTouchHandler {
                            && mPipBoundsState.getBounds().height()
                            < mPipBoundsState.getMaxSize().y;
                    if (mMenuController.isMenuVisible()) {
                        mMenuController.hideMenu(false /* animate */, false /* resize */);
                        mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
                    }
                    if (toExpand) {
                        mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());