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

Commit 813ef9b6 authored by Winson Chung's avatar Winson Chung
Browse files

Fix issue with relaunch of transiently-hiding task

- When a previously-pausing task is relaunched (initiated from Core)
  during a recents transition, we should only consider it to be a
  NEW_TASK state only if there are tasks that are new.  Otherwise,
  launcher will attempt to return to the app, but the recents transition
  will not consider it a return-to-app due to the NEW_TASK state
- Separately, the visibilty of the relaunched tasks needs to be updated
  in the finish transactions of the merged transition otherwise the
  visibility set by setupStartState() will clobber the merged transition
  when the original transition is finished.

  ie.
  Start Home from A (T1, setupStartState() will hide pausing task A
      (TO_BACK) in the finish transition)
  Start A (T2, since A is transiently hiding and is technically visible,
      this results in a CHANGE+MOVE_TO_TOP and setupStartState() will
      only show() task A in the start transition)
  T2 merges into T1
  T1 finishes (this applies T1's finishT followed by T2's finishT)

Bug: 386877383
Flag: EXEMPT bugfix
Test: atest WMShellUnitTests:ShellTransitionTests
Test: Open split pair of A|B, enter overview, re-launch A (or B)
      from taskbar
Change-Id: Ic9ed3371f064bfb0d0d206a8ecfcbb0d8cc4719f
parent 9118e512
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -1135,6 +1135,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                if (openingLeafCount > 0) {
                    appearedTargets = new RemoteAnimationTarget[openingLeafCount];
                }
                boolean onlyOpeningPausedTasks = true;
                int nextTargetIdx = 0;
                for (int i = 0; i < openingTasks.size(); ++i) {
                    final TransitionInfo.Change change = openingTasks.get(i);
@@ -1188,6 +1189,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                                "  opening new leaf taskId=%d wasClosing=%b",
                                target.taskId, wasClosing);
                        mOpeningTasks.add(new TaskState(change, target.leash));
                        onlyOpeningPausedTasks = false;
                    } else {
                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                                "  opening new taskId=%d", change.getTaskInfo().taskId);
@@ -1196,11 +1198,18 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                        // is only animating the leafs.
                        startT.show(change.getLeash());
                        mOpeningTasks.add(new TaskState(change, null));
                        onlyOpeningPausedTasks = false;
                    }
                }
                didMergeThings = true;
                if (!onlyOpeningPausedTasks) {
                    // If we are only opening paused leaf tasks, then we aren't actually quick
                    // switching or launching a new task from overview, and if Launcher requests to
                    // finish(toHome=false) as a response to the pausing tasks being opened again,
                    // we should allow that to be considered returningToApp
                    mState = STATE_NEW_TASK;
                }
            }
            if (mPausingTasks.isEmpty()) {
                // The pausing tasks may be removed by the incoming closing tasks.
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
@@ -1368,8 +1377,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,

            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "[%d] RecentsController.finishInner: toHome=%b userLeave=%b "
                            + "willFinishToHome=%b state=%d reason=%s",
                    mInstanceId, toHome, sendUserLeaveHint, mWillFinishToHome, mState, reason);
                            + "willFinishToHome=%b state=%d hasPausingTasks=%b reason=%s",
                    mInstanceId, toHome, sendUserLeaveHint, mWillFinishToHome, mState,
                    mPausingTasks != null, reason);

            final SurfaceControl.Transaction t = mFinishTransaction;
            final WindowContainerTransaction wct = new WindowContainerTransaction();
+5 −0
Original line number Diff line number Diff line
@@ -602,6 +602,11 @@ public class Transitions implements RemoteCallable<Transitions>,
                // Just in case there is a race with another animation (eg. recents finish()).
                // Changes are visible->visible so it's a problem if it isn't visible.
                t.show(leash);
                // If there is a transient launch followed by a launch of one of the pausing tasks,
                // we may end up with TRANSIT_TO_BACK followed by a CHANGE (w/ flag MOVE_TO_TOP),
                // but since we are hiding the leash in the finish transaction above, we should also
                // update the finish transaction here to reflect the change in visibility
                finishT.show(leash);
            }
        }
    }
+48 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_SYNC;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;

@@ -1742,6 +1743,53 @@ public class ShellTransitionTests extends ShellTestCase {
                eq(R.styleable.WindowAnimation_activityCloseEnterAnimation), anyBoolean());
    }

    @Test
    public void testTransientHideWithMoveToTop() {
        Transitions transitions = createTestTransitions();
        transitions.replaceDefaultHandlerForTest(mDefaultHandler);
        final TransitionAnimation transitionAnimation = new TransitionAnimation(mContext, false,
                Transitions.TAG);
        spyOn(transitionAnimation);

        // Prepare for a TO_BACK transition
        final RunningTaskInfo taskInfo = createTaskInfo(1);
        final IBinder closeTransition = new Binder();
        final SurfaceControl.Transaction closeTransitionFinishT =
                mock(SurfaceControl.Transaction.class);

        // Start a TO_BACK transition
        transitions.requestStartTransition(closeTransition,
                new TransitionRequestInfo(TRANSIT_TO_BACK, null /* trigger */, null /* remote */));
        TransitionInfo closeInfo = new TransitionInfoBuilder(TRANSIT_TO_BACK)
                .addChange(TRANSIT_TO_BACK, taskInfo)
                .build();
        transitions.onTransitionReady(closeTransition, closeInfo, new StubTransaction(),
                closeTransitionFinishT);

        // Verify that the transition hides the task surface in the finish transaction
        verify(closeTransitionFinishT).hide(any());

        // Prepare for a CHANGE transition
        final IBinder changeTransition = new Binder();
        final SurfaceControl.Transaction changeTransitionFinishT =
                mock(SurfaceControl.Transaction.class);

        // Start a CHANGE transition w/ MOVE_TO_FRONT that is merged into the TO_BACK
        mDefaultHandler.setShouldMerge(changeTransition);
        transitions.requestStartTransition(changeTransition,
                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
        TransitionInfo changeInfo = new TransitionInfoBuilder(TRANSIT_OPEN)
                .addChange(TRANSIT_CHANGE, FLAG_MOVED_TO_TOP, taskInfo)
                .build();
        transitions.onTransitionReady(changeTransition, changeInfo, new StubTransaction(),
                changeTransitionFinishT);

        // Verify that the transition shows the task surface in the finish transaction so that the
        // when the original transition finishes, the finish transaction does not clobber the
        // visibility of the merged transition
        verify(changeTransitionFinishT).show(any());
    }

    class TestTransitionHandler implements Transitions.TransitionHandler {
        ArrayList<Pair<IBinder, Transitions.TransitionFinishCallback>> mFinishes =
                new ArrayList<>();