From 4f7be5bd52247f3f46a847945063ec0dc6e5d354 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Wed, 4 May 2022 16:23:54 -0700 Subject: [PATCH] Fix PiP transition ordering First, this cancels the existing pip animation if it is told to exit. Without this, an exit animation that starts before an enter animation finishes will have its state clobbered by the exit's finishTransition call. Next, make pip-enter transitions queue-up so that they don't interleave before other queued transitions (very common during CTS). Bug: 231150615 Test: atest PinnedStackTests Change-Id: I7f162c0b1f24ab845770b805c8fae2252814945e --- data/etc/services.core.protolog.json | 6 +++ .../android/wm/shell/pip/PipTransition.java | 5 +++ .../wm/shell/transition/Transitions.java | 2 + .../server/wm/ActivityTaskManagerService.java | 40 +++++++++++++++++-- .../server/wm/RootWindowContainer.java | 13 ++++-- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index ae913b07fd748..5ded2ccf86408 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -3061,6 +3061,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "898260097": { + "message": "Creating Pending Pip-Enter: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "898863925": { "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", "level": "WARN", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 195923c40c5d6..dfd34f8b7bc64 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -145,6 +145,11 @@ public class PipTransition extends PipTransitionController { if (destinationBounds != null) { mExitDestinationBounds.set(destinationBounds); } + final PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null && animator.isRunning()) { + animator.cancel(); + } mExitTransition = mTransitions.startTransition(type, out, this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index e4c94264be2c6..98eee7ba33a0e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -377,6 +377,7 @@ public class Transitions implements RemoteCallable { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Invalid root leash (%s): %s", transitionToken, info); t.apply(); + finishT.apply(); onAbort(transitionToken); return; } @@ -400,6 +401,7 @@ public class Transitions implements RemoteCallable { } if (nonTaskChange && transferStartingWindow) { t.apply(); + finishT.apply(); // Treat this as an abort since we are bypassing any merge logic and effectively // finishing immediately. onAbort(transitionToken); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 206cee802f9e1..7524825a998ac 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -65,6 +65,7 @@ import static android.provider.Settings.System.FONT_SCALE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT; +import static android.view.WindowManager.TRANSIT_PIP; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; @@ -237,6 +238,7 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.TransferPipe; import com.android.internal.policy.AttributeCache; import com.android.internal.policy.KeyguardDismissCallback; +import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; @@ -3463,6 +3465,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return false; } + // Create a transition for this pip entry. We guarantee that this gets its own transition + // by queueing this transition on SyncEngine. This is shared by all the entry paths. + final Transition transition = getTransitionController().isShellTransitionsEnabled() + ? new Transition(TRANSIT_PIP, 0 /* flags */, + getTransitionController(), mWindowManager.mSyncEngine) + : null; + final Runnable enterPipRunnable = () -> { synchronized (mGlobalLock) { if (r.getParent() == null) { @@ -3471,7 +3480,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } r.setPictureInPictureParams(params); mRootWindowContainer.moveActivityToPinnedRootTask(r, - null /* launchIntoPipHostActivity */, "enterPictureInPictureMode"); + null /* launchIntoPipHostActivity */, "enterPictureInPictureMode", + transition); final Task task = r.getTask(); // Continue the pausing process after entering pip. if (task.getPausingActivity() == r) { @@ -3488,12 +3498,36 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mActivityClientController.dismissKeyguard(r.token, new KeyguardDismissCallback() { @Override public void onDismissSucceeded() { - mH.post(enterPipRunnable); + if (mWindowManager.mSyncEngine.hasActiveSync()) { + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + "Creating Pending Pip-Enter: %s", transition); + mWindowManager.mSyncEngine.queueSyncSet( + () -> getTransitionController().moveToCollecting(transition), + enterPipRunnable); + } else { + // Move to collecting immediately to "claim" the sync-engine for this + // transition. + if (transition != null) { + getTransitionController().moveToCollecting(transition); + } + mH.post(enterPipRunnable); + } } }, null /* message */); } else { // Enter picture in picture immediately otherwise - enterPipRunnable.run(); + if (mWindowManager.mSyncEngine.hasActiveSync()) { + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + "Creating Pending Pip-Enter: %s", transition); + mWindowManager.mSyncEngine.queueSyncSet( + () -> getTransitionController().moveToCollecting(transition), + enterPipRunnable); + } else { + if (transition != null) { + getTransitionController().moveToCollecting(transition); + } + enterPipRunnable.run(); + } } return true; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index e79bb40709e81..ff18d681bee20 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1977,16 +1977,21 @@ class RootWindowContainer extends WindowContainer void moveActivityToPinnedRootTask(@NonNull ActivityRecord r, @Nullable ActivityRecord launchIntoPipHostActivity, String reason) { + moveActivityToPinnedRootTask(r, launchIntoPipHostActivity, reason, null /* transition */); + } + void moveActivityToPinnedRootTask(@NonNull ActivityRecord r, + @Nullable ActivityRecord launchIntoPipHostActivity, String reason, + @Nullable Transition transition) { final TaskDisplayArea taskDisplayArea = r.getDisplayArea(); final Task task = r.getTask(); final Task rootTask; - Transition newTransition = null; - // Create a transition now to collect the current pinned Task dismiss. Only do the - // create here as the Task (trigger) to enter PIP is not ready yet. + Transition newTransition = transition; + // Create a transition now (if not provided) to collect the current pinned Task dismiss. + // Only do the create here as the Task (trigger) to enter PIP is not ready yet. final TransitionController transitionController = task.mTransitionController; - if (!transitionController.isCollecting() + if (newTransition == null && !transitionController.isCollecting() && transitionController.getTransitionPlayer() != null) { newTransition = transitionController.createTransition(TRANSIT_PIP); }