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

Commit ea7d2af3 authored by Ikram Gabiyev's avatar Ikram Gabiyev Committed by Android (Google) Code Review
Browse files

Merge "[2/2][PiP2] Block duplicate exit PiP calls" into main

parents 1254733e 91584da3
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -128,6 +128,20 @@ public abstract class PipTransitionController implements Transitions.TransitionH
        // Default implementation does nothing.
    }

    /**
     * Called when the Shell wants to start an exit-via-expand from Pip transition/animation.
     */
    public void startExpandTransition(WindowContainerTransaction out) {
        // Default implementation does nothing.
    }

    /**
     * Called when the Shell wants to start a remove Pip transition/animation.
     */
    public void startRemoveTransition(boolean withFadeout) {
        // Default implementation does nothing.
    }

    /**
     * Called when the Shell wants to start resizing Pip transition/animation.
     *
+11 −3
Original line number Diff line number Diff line
@@ -344,13 +344,22 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
     */
    @Override
    public void dismissPip() {
        dismissPip(true /* withFadeout */);
    }

    /**
     * Dismisses the pinned stack.
     *
     * @param withFadeout should animate with fadeout for the removal
     */
    public void dismissPip(boolean withFadeout) {
        if (DEBUG) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: removePip: callers=\n%s", TAG, Debug.getCallers(5, "    "));
        }
        cancelPhysicsAnimation();
        mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
        mPipScheduler.scheduleRemovePip();
        mPipScheduler.scheduleRemovePip(withFadeout);
    }

    /** Sets the movement bounds to use to constrain PIP position animations. */
@@ -473,7 +482,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
                        mPipBoundsState.getMovementBounds().bottom + getBounds().height() * 2,
                        0,
                        mSpringConfig)
                .withEndActions(this::dismissPip);
                .withEndActions(() -> dismissPip(false /* withFadeout */));

        startBoundsAnimator(
                getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */);
@@ -772,7 +781,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
            case PipTransitionState.EXITING_PIP:
                // We need to force finish any local animators if about to leave PiP, to avoid
                // breaking the state (e.g. leashes are cleaned up upon exit).
                if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break;
                cancelPhysicsAnimation();
                settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
                break;
+7 −26
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@ package com.android.wm.shell.pip2.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -112,19 +109,6 @@ public class PipScheduler {
        return wct;
    }

    @Nullable
    private WindowContainerTransaction getRemovePipTransaction() {
        WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
        if (pipTaskToken == null) {
            return null;
        }
        WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.setBounds(pipTaskToken, null);
        wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
        wct.reorder(pipTaskToken, false);
        return wct;
    }

    /**
     * Schedules exit PiP via expand transition.
     */
@@ -133,21 +117,16 @@ public class PipScheduler {
            if (!mPipTransitionState.isInPip()) return;
            WindowContainerTransaction wct = getExitPipViaExpandTransaction();
            if (wct != null) {
                mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct,
                        null /* destinationBounds */);
                mPipTransitionController.startExpandTransition(wct);
            }
        });
    }

    /** Schedules remove PiP transition. */
    public void scheduleRemovePip() {
    public void scheduleRemovePip(boolean withFadeout) {
        mMainExecutor.execute(() -> {
            if (!mPipTransitionState.isInPip()) return;
            WindowContainerTransaction wct = getRemovePipTransaction();
            if (wct != null) {
                mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
                        null /* destinationBounds */);
            }
            mPipTransitionController.startRemoveTransition(withFadeout);
        });
    }

@@ -216,9 +195,11 @@ public class PipScheduler {
     * @param degrees the angle to rotate the bounds to.
     */
    public void scheduleUserResizePip(Rect toBounds, float degrees) {
        if (toBounds.isEmpty()) {
        if (toBounds.isEmpty() || !mPipTransitionState.isInPip()) {
            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG);
                    "%s: Attempted to user resize PIP in invalid state, aborting;"
                            + "toBounds=%s, mPipTransitionState=%s",
                    TAG, toBounds, mPipTransitionState);
            return;
        }
        SurfaceControl leash = mPipTransitionState.getPinnedTaskLeash();
+41 −14
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.pip2.phone;

import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -126,6 +127,7 @@ public class PipTransition extends PipTransitionController implements
    @Nullable
    private IBinder mResizeTransition;
    private int mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
    private boolean mPendingRemoveWithFadeout;


    //
@@ -184,15 +186,19 @@ public class PipTransition extends PipTransitionController implements
    //

    @Override
    public void startExitTransition(int type, WindowContainerTransaction out,
            @Nullable Rect destinationBounds) {
        if (out == null) {
            return;
        }
        IBinder transition = mTransitions.startTransition(type, out, this);
        if (type == TRANSIT_EXIT_PIP) {
            mExitViaExpandTransition = transition;
    public void startExpandTransition(WindowContainerTransaction out) {
        if (out == null) return;
        mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
        mExitViaExpandTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
    }

    @Override
    public void startRemoveTransition(boolean withFadeout) {
        final WindowContainerTransaction wct = getRemovePipTransaction();
        if (wct == null) return;
        mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
        mPendingRemoveWithFadeout = withFadeout;
        mTransitions.startTransition(TRANSIT_REMOVE_PIP, wct, this);
    }

    @Override
@@ -284,7 +290,6 @@ public class PipTransition extends PipTransitionController implements
                    finishCallback);
        } else if (transition == mExitViaExpandTransition) {
            mExitViaExpandTransition = null;
            mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
            return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
        } else if (transition == mResizeTransition) {
            mResizeTransition = null;
@@ -690,11 +695,19 @@ public class PipTransition extends PipTransitionController implements
        TransitionInfo.Change pipChange = getChangeByToken(info,
                mPipTransitionState.getPipTaskToken());
        mFinishCallback = finishCallback;

        finishTransaction.setAlpha(pipChange.getLeash(), 0f);
        if (mPendingRemoveWithFadeout) {
            PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
                    startTransaction, PipAlphaAnimator.FADE_OUT);
        finishTransaction.setAlpha(pipChange.getLeash(), 0f);
            animator.setAnimationEndCallback(this::finishTransition);
            animator.start();
        } else {
            // Jumpcut to a faded-out PiP if no fadeout animation was requested.
            startTransaction.setAlpha(pipChange.getLeash(), 0f);
            startTransaction.apply();
            finishTransition();
        }
        return true;
    }

@@ -824,6 +837,19 @@ public class PipTransition extends PipTransitionController implements
        return wct;
    }

    @Nullable
    private WindowContainerTransaction getRemovePipTransaction() {
        WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken();
        if (pipTaskToken == null) {
            return null;
        }
        WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.setBounds(pipTaskToken, null);
        wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED);
        wct.reorder(pipTaskToken, false);
        return wct;
    }

    private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) {
        final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipChange() != null
                ? requestInfo.getPipChange().getTaskInfo() : null;
@@ -1000,6 +1026,7 @@ public class PipTransition extends PipTransitionController implements
                }
                mPipTransitionState.setPinnedTaskLeash(null);
                mPipTransitionState.setPipTaskInfo(null);
                mPendingRemoveWithFadeout = false;
                break;
        }
    }
+20 −0
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@ import android.window.WindowContainerToken;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.annotations.ShellMainThread;

import java.io.PrintWriter;
@@ -201,6 +203,13 @@ public class PipTransitionState {
            Preconditions.checkArgument(extra != null && !extra.isEmpty(),
                    "No extra bundle for " + stateToString(state) + " state.");
        }
        if (!shouldTransitionToState(state)) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Attempted to transition to an invalid state=%s, while in %s",
                    TAG, stateToString(state), this);
            return;
        }

        if (mState != state) {
            final int prevState = mState;
            mState = state;
@@ -374,6 +383,17 @@ public class PipTransitionState {
        return ++mPrevCustomState;
    }

    private boolean shouldTransitionToState(@TransitionState int newState) {
        switch (newState) {
            case SCHEDULED_BOUNDS_CHANGE:
                // Allow scheduling bounds change only while in PiP, except for if another bounds
                // change was scheduled but hasn't started playing yet.
                return isInPip();
            default:
                return true;
        }
    }

    private static String stateToString(int state) {
        switch (state) {
            case UNDEFINED: return "undefined";
Loading