From 69a8b77741d02723ab3df2f370c5b15f378e78e6 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Tue, 22 Mar 2022 14:30:50 -0700 Subject: [PATCH] Pass through Recent's finish-but-not-really intent There are a few situations where recents will tell WMCore that it is finishing (going home), but then actually doesn't finish. In these cases, we need to tell WMCore not to enter PiP even when it normally would. This functionality is added to shell-transitions by adding a signal to WindowContainerTransaction. Bug: 223317893 Bug: 223317556 Test: open pipable, go to recents, swipe pipable to close. Change-Id: I969ae8b562aa54fc06e35164e676205682f24994 --- .../window/WindowContainerTransaction.java | 15 +++++++++++++++ .../shared/system/RemoteTransitionCompat.java | 15 ++++++++++----- .../java/com/android/server/wm/Transition.java | 14 +++++++++++++- .../server/wm/WindowOrganizerController.java | 8 ++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 35c959493f230..f2db5648a75f0 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -268,6 +268,20 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + /** + * Used in conjunction with a shell-transition call (usually finishTransition). This is + * basically a message to the transition system that a particular task should NOT go into + * PIP even though it normally would. This is to deal with some edge-case situations where + * Recents will "commit" the transition to go home, but then not actually go-home. + * @hide + */ + @NonNull + public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { + Change chg = getOrCreateChange(container.asBinder()); + chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; + return this; + } + /** * Reparents a container into another one. The effect of a {@code null} parent can vary. For * example, reparenting a stack to {@code null} will reparent it to its display. @@ -790,6 +804,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_HIDDEN = 1 << 3; public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5; + public static final int CHANGE_FORCE_NO_PIP = 1 << 6; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index b61827a0212c4..51001a7a4c8eb 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -331,13 +331,12 @@ public class RemoteTransitionCompat implements Parcelable { } if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - final WindowContainerTransaction wct; + final WindowContainerTransaction wct = new WindowContainerTransaction(); if (!toHome && mPausingTasks != null && mOpeningLeashes == null) { // The gesture went back to opening the app rather than continuing with // recents, so end the transition by moving the app back to the top (and also // re-showing it's task). - wct = new WindowContainerTransaction(); for (int i = mPausingTasks.size() - 1; i >= 0; --i) { // reverse order so that index 0 ends up on top wct.reorder(mPausingTasks.get(i), true /* onTop */); @@ -347,8 +346,14 @@ public class RemoteTransitionCompat implements Parcelable { wct.restoreTransientOrder(mRecentsTask); } } else { - wct = null; - if (mPipTask != null && mPipTransaction != null) { + if (!sendUserLeaveHint) { + for (int i = 0; i < mPausingTasks.size(); ++i) { + // This means recents is not *actually* finishing, so of course we gotta + // do special stuff in WMCore to accommodate. + wct.setDoNotPip(mPausingTasks.get(i)); + } + } + if (mPipTask != null && mPipTransaction != null && sendUserLeaveHint) { t.show(mInfo.getChange(mPipTask).getLeash()); PictureInPictureSurfaceTransaction.apply(mPipTransaction, mInfo.getChange(mPipTask).getLeash(), t); @@ -363,7 +368,7 @@ public class RemoteTransitionCompat implements Parcelable { t.remove(mLeashMap.valueAt(i)); } try { - mFinishCB.onTransitionFinished(wct, t); + mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t); } catch (RemoteException e) { Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e); t.apply(); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 21ca4bb6038bf..bb1a8182d46e7 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -189,6 +189,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe private boolean mNavBarAttachedToApp = false; private int mRecentsDisplayId = INVALID_DISPLAY; + /** @see #setCanPipOnFinish */ + private boolean mCanPipOnFinish = true; + Transition(@TransitionType int type, @TransitionFlags int flags, TransitionController controller, BLASTSyncEngine syncEngine) { mType = type; @@ -447,6 +450,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } + /** + * Set whether this transition can start a pip-enter transition when finished. This is usually + * true, but gets set to false when recents decides that it wants to finish its animation but + * not actually finish its animation (yeah...). + */ + void setCanPipOnFinish(boolean canPipOnFinish) { + mCanPipOnFinish = canPipOnFinish; + } + /** * The transition has finished animating and is ready to finalize WM state. This should not * be called directly; use {@link TransitionController#finishTransition} instead. @@ -475,7 +487,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // activity in a bad state. if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) { boolean commitVisibility = true; - if (ar.isVisible() && ar.getTask() != null) { + if (mCanPipOnFinish && ar.isVisible() && ar.getTask() != null) { if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) { if (mTransientLaunches != null) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 044da3982e268..f3507366cfaaf 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -428,6 +428,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } if (transition != null) transition.collect(wc); + if (finishTransition != null) { + // Deal with edge-cases in recents where it pretends to finish itself. + if ((entry.getValue().getChangeMask() + & WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) { + finishTransition.setCanPipOnFinish(false /* canPipOnFinish */); + } + } + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect;