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

Commit 06afbb65 authored by Ikram Gabiyev's avatar Ikram Gabiyev
Browse files

[PiP2] Clean up PiP if enter is aborted

Sometimes enter PiP might actually might actually
get applied on the Core side, make WM state changes, but
the transition might get aborted (e.g. due to screen going to sleep).

In such cases, we might end up with a WM Core <-> Shell inconsistency,
where Shell either gets a no-op transition or a transition without
a pinned task target.

We can try and resolve such inconsistencies on the Shell side by
removing the task that was resolved as the PiP candidate upon
transition request; this effectively cleans up the WM state to match
the Shell state.

Note: repro-ing this issue isn't easy and I could only do it 2/10 times
on average with the animation duration scaled down by 2x on the device.

Bug: 424294158
Flag: com.android.wm.shell.enable_pip2
Test: swipe-pip-to-home with auto-enter and lock the screen quickly
Change-Id: Ie977d6c80b2b7903ac1eee43b22877acc41c5c72
parent fcc1cbfe
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -309,7 +309,8 @@ public class PipTransition extends PipTransitionController implements
    @Override
    public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
            @Nullable SurfaceControl.Transaction finishT) {
        if ((transition == mBoundsChangeTransition || transition == mEnterTransition) && aborted) {
        if (aborted && (transition == mBoundsChangeTransition
                || mPipTransitionState.getState() == PipTransitionState.SCHEDULED_ENTER_PIP)) {
            onTransitionAborted();
        }
    }
@@ -327,7 +328,14 @@ public class PipTransition extends PipTransitionController implements
            TransitionInfo.Change pipChange = getPipChange(info);

            // If there is no PiP change, exit this transition handler and potentially try others.
            if (pipChange == null) return false;
            if (pipChange == null) {
                Log.wtf(TAG, String.format("""
                        PipTransition did not find a PiP change despite waiting for a scheduled
                        enter PiP transition.
                        callers=%s""", Debug.getCallers(4)));
                onTransitionAborted();
                return false;
            }

            // Other targets might have default transforms applied that are not relevant when
            // playing PiP transitions, so reset those transforms if needed.
@@ -864,6 +872,8 @@ public class PipTransition extends PipTransitionController implements
            @NonNull TransitionRequestInfo.PipChange pipChange) {
        // cache the original task token to check for multi-activity case later
        final ActivityManager.RunningTaskInfo pipTask = pipChange.getTaskInfo();
        mPipTransitionState.setPipCandidateTaskInfo(pipTask);

        PictureInPictureParams pipParams = pipTask.pictureInPictureParams;
        mPipTaskListener.setPictureInPictureParams(pipParams);
        mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo,
@@ -1120,6 +1130,7 @@ public class PipTransition extends PipTransitionController implements
                if (mPipTransitionState.getPipTaskToken() != null) {
                    nextState = PipTransitionState.ENTERED_PIP;
                } else {
                    removePipCandidateTaskIfNeeded();
                    nextState = PipTransitionState.EXITED_PIP;
                }
                break;
@@ -1134,6 +1145,22 @@ public class PipTransition extends PipTransitionController implements
        mPipTransitionState.setState(nextState);
    }

    private void removePipCandidateTaskIfNeeded() {
        if (mPipTransitionState.getState() != PipTransitionState.SCHEDULED_ENTER_PIP
                || mPipTransitionState.getPipCandidateTaskInfo() == null
                || mPipTransitionState.getPipCandidateTaskInfo().getToken() == null) {
            return;
        }

        // Enter PiP was scheduled but PiP handler didn't handle it properly.
        // So try to remove the PiP candidate we had received via transition request,
        // because Core might have put the activity in PiP and not resolved the task as a target
        // (this could happen if the display is asleep, which disqualifies PiP task as invisible).
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.removeTask(mPipTransitionState.getPipCandidateTaskInfo().getToken());
        mTransitions.startTransition(TRANSIT_CLOSE, wct, null);
    }

    @Override
    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
            @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
@@ -1155,6 +1182,7 @@ public class PipTransition extends PipTransitionController implements
            case PipTransitionState.EXITED_PIP:
                mPipTransitionState.setPinnedTaskLeash(null);
                mPipTransitionState.setPipTaskInfo(null);
                mPipTransitionState.setPipCandidateTaskInfo(null);
                mPendingRemoveWithFadeout = false;
                break;
        }
+13 −0
Original line number Diff line number Diff line
@@ -156,6 +156,11 @@ public class PipTransitionState {
    @Nullable
    private TaskInfo mPipTaskInfo;

    // PiP candidate task info sent to Shell during transition request;
    // this might not be the same as mPipTaskInfo, if in multi-activity case for example.
    @Nullable
    private TaskInfo mPipCandidateTaskInfo;

    // Overlay leash potentially used during swipe PiP to home transition;
    // if null while mInSwipePipToHomeTransition is true, then srcRectHint was invalid.
    @Nullable
@@ -358,6 +363,14 @@ public class PipTransitionState {
        mPipTaskInfo = pipTaskInfo;
    }

    @Nullable TaskInfo getPipCandidateTaskInfo() {
        return mPipCandidateTaskInfo;
    }

    void setPipCandidateTaskInfo(@Nullable TaskInfo pipCandidateTaskInfo) {
        mPipCandidateTaskInfo = pipCandidateTaskInfo;
    }

    /**
     * @return true if either in swipe or button-nav fixed rotation.
     */
+1 −1
Original line number Diff line number Diff line
@@ -1657,7 +1657,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                                    requestRes = mTransitions.dispatchRequest(mTransition,
                                            requestInfo, null /* skip */);
                            wct.merge(requestRes.second, true);
                            mTransitions.startTransition(TRANSIT_PIP, wct, null /* handler */);
                            mTransitions.startTransition(TRANSIT_PIP, wct, requestRes.first);
                            // We need to clear the WCT to send finishWCT=null for Recents.
                            wct.clear();