From 6a55435011eeb759ad87a6b33d3fa4d0efc3123c Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Tue, 25 May 2021 19:04:08 -0700 Subject: [PATCH] PiP: Move enter-PiP on-pause logic. Previously, we rely on #makeInvisible in other situations as the last place to enter PIP before activity gets put to stopped (e.g. ARC++). However with Shell transitions, #makeInvisible is now immediately called as user starts the transition into Recents, which would cause app to enter PIP right away. Thus, removing this part of the code, and instead we will wait until the Recents transition is finished and try to pause the app with userLeaveHint before visibility is committed. Also, when shell transition is enabled, make an explicit transition when dmissing PIP to properly commit the necessary window container changes to WM. The tranition will just have no animation. Bug: 165793917 Test: Enable Shell transition, enter PIP via gesture (non-auto enter case) Test: Enable Shell transition, dismiss PIP via dismiss bubble Change-Id: Ic2c8691f5a1f359b822b1874b16a327bc689f34d --- core/java/android/view/WindowManager.java | 8 +++- .../wm/shell/pip/PipTaskOrganizer.java | 11 +++++ .../android/wm/shell/pip/PipTransition.java | 47 +++++++++++++++++-- .../wm/shell/pip/PipTransitionController.java | 9 ++++ .../wm/shell/pip/phone/PipController.java | 3 ++ .../wm/shell/transition/Transitions.java | 5 +- .../com/android/server/wm/ActivityRecord.java | 11 ++--- .../server/wm/RootWindowContainer.java | 4 +- .../com/android/server/wm/Transition.java | 7 +++ 9 files changed, 91 insertions(+), 14 deletions(-) diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 52812efd4aa6a..eaeade0f37715 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -393,6 +393,11 @@ public interface WindowManager extends ViewManager { * @hide */ int TRANSIT_KEYGUARD_UNOCCLUDE = 9; + /** + * A window is starting to enter PiP. + * @hide + */ + int TRANSIT_PIP = 10; /** * The first slot for custom transition types. Callers (like Shell) can make use of custom * transition types for dealing with special cases. These types are effectively ignored by @@ -402,7 +407,7 @@ public interface WindowManager extends ViewManager { * implementation. * @hide */ - int TRANSIT_FIRST_CUSTOM = 10; + int TRANSIT_FIRST_CUSTOM = 11; /** * @hide @@ -418,6 +423,7 @@ public interface WindowManager extends ViewManager { TRANSIT_KEYGUARD_GOING_AWAY, TRANSIT_KEYGUARD_OCCLUDE, TRANSIT_KEYGUARD_UNOCCLUDE, + TRANSIT_PIP, TRANSIT_FIRST_CUSTOM }) @Retention(RetentionPolicy.SOURCE) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 27707a4132599..25b68d590037a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -463,6 +463,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } private void removePipImmediately() { + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setBounds(mToken, null); + wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.reorder(mToken, false); + mPipTransitionController.startTransition(null, wct); + return; + } + try { // Reset the task bounds first to ensure the activity configuration is reset as well final WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -524,6 +533,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, if (Transitions.ENABLE_SHELL_TRANSITIONS) { if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { mPipMenuController.attach(mLeash); + } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { + mOneShotAnimationType = ANIM_TYPE_BOUNDS; } return; } 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 93b0fcfcd9d78..b75cde099bcbb 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 @@ -18,6 +18,7 @@ package com.android.wm.shell.pip; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.view.WindowManager.TRANSIT_PIP; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -27,6 +28,7 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; +import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP; import android.app.TaskInfo; import android.content.Context; @@ -73,10 +75,28 @@ public class PipTransition extends PipTransitionController { .getInteger(R.integer.config_pipResizeAnimationDuration); } + @Override + public void setIsFullAnimation(boolean isFullAnimation) { + setOneShotAnimationType(isFullAnimation ? ANIM_TYPE_BOUNDS : ANIM_TYPE_ALPHA); + } + + /** + * Sets the preferred animation type for one time. + * This is typically used to set the animation type to + * {@link PipAnimationController#ANIM_TYPE_ALPHA}. + */ + private void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) { + mOneShotAnimationType = animationType; + } + @Override public void startTransition(Rect destinationBounds, WindowContainerTransaction out) { - mExitDestinationBounds.set(destinationBounds); - mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); + if (destinationBounds != null) { + mExitDestinationBounds.set(destinationBounds); + mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); + } else { + mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this); + } } @Override @@ -96,6 +116,14 @@ public class PipTransition extends PipTransitionController { return success; } + if (info.getType() == TRANSIT_REMOVE_PIP) { + startTransaction.apply(); + finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(), + mPipBoundsState.getDisplayBounds()); + finishCallback.onTransitionFinished(null, null); + return true; + } + // Search for an Enter PiP transition (along with a show wallpaper one) TransitionInfo.Change enterPip = null; TransitionInfo.Change wallpaper = null; @@ -129,13 +157,23 @@ public class PipTransition extends PipTransitionController { @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { - return null; + if (request.getType() == TRANSIT_PIP) { + WindowContainerTransaction wct = new WindowContainerTransaction(); + mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED); + final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); + wct.setActivityWindowingMode(request.getTriggerTask().token, WINDOWING_MODE_UNDEFINED); + wct.setBounds(request.getTriggerTask().token, destinationBounds); + return wct; + } else { + return null; + } } @Override public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx) { + if (isInPipDirection(direction)) { mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP); } @@ -185,6 +223,9 @@ public class PipTransition extends PipTransitionController { 0 /* startingAngle */, Surface.ROTATION_0); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { startTransaction.setAlpha(leash, 0f); + // PiP menu is attached late in the process here to avoid any artifacts on the leash + // caused by addShellRoot when in gesture navigation mode. + mPipMenuController.attach(leash); animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds, 0f, 1f); mOneShotAnimationType = ANIM_TYPE_BOUNDS; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index bc262560844df..dedc56678ef17 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -100,6 +100,15 @@ public abstract class PipTransitionController implements Transitions.TransitionH SurfaceControl.Transaction tx) { } + /** + * Called to inform the transition that the animation should start with the assumption that + * PiP is not animating from its original bounds, but rather a continuation of another + * animation. For example, gesture navigation would first fade out the PiP activity, and the + * transition should be responsible to animate in (such as fade in) the PiP. + */ + public void setIsFullAnimation(boolean isFullAnimation) { + } + /** * Called when the Shell wants to starts a transition/animation. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 4f3ec96968b29..62b50c55e77cf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -67,6 +67,7 @@ import com.android.wm.shell.pip.IPip; import com.android.wm.shell.pip.IPipAnimationListener; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; @@ -528,6 +529,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void setPinnedStackAnimationType(int animationType) { mPipTaskOrganizer.setOneShotAnimationType(animationType); + mPipTransitionController.setIsFullAnimation( + animationType == PipAnimationController.ANIM_TYPE_BOUNDS); } private void setPinnedStackAnimationListener(IPipAnimationListener callback) { 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 64faed2061091..8ed92dfb39c67 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 @@ -77,9 +77,12 @@ public class Transitions implements RemoteCallable { /** Transition type for launching 2 tasks simultaneously. */ public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 2; - /** Transition type for exiting PIP via the Shell, either via Expand or Dismiss. */ + /** Transition type for exiting PIP via the Shell, via pressing the expand button. */ public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 3; + /** Transition type for removing PIP via the Shell, either via Dismiss bubble or Close. */ + public static final int TRANSIT_REMOVE_PIP = TRANSIT_FIRST_CUSTOM + 4; + private final WindowOrganizer mOrganizer; private final Context mContext; private final ShellExecutor mMainExecutor; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 1652cc91d6cef..e47856af4d259 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4433,6 +4433,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + boolean getDeferHidingClient() { + return mDeferHidingClient; + } + @Override boolean isVisible() { // If the activity isn't hidden then it is considered visible and there is no need to check @@ -5151,13 +5155,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A supportsEnterPipOnTaskSwitch = false; break; case RESUMED: - // If the app is capable of entering PIP, we should try pausing it now - // so it can PIP correctly. - if (deferHidingClient) { - getTaskFragment().startPausing(false /* uiSleeping */, - null /* resuming */, "makeInvisible"); - break; - } case INITIALIZING: case PAUSING: case PAUSED: diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f8cae6b0e7210..4414db3bc2d01 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -36,10 +36,10 @@ import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; -import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; import static android.view.WindowManager.TRANSIT_NONE; +import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; @@ -2177,7 +2177,7 @@ class RootWindowContainer extends WindowContainer // display area, so reparent. rootTask.reparent(taskDisplayArea, true /* onTop */); } - mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CHANGE, rootTask); + mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_PIP, rootTask); // Defer the windowing mode change until after the transition to prevent the activity // from doing work and changing the activity visuals while animating diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index de3af2cb058cc..7169988f10f68 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -300,6 +300,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe for (int i = 0; i < mParticipants.size(); ++i) { final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); if (ar != null && !ar.isVisibleRequested()) { + // If activity is capable of entering PiP, give it a chance to enter it now. + if (ar.getDeferHidingClient() && ar.getTask() != null) { + mController.mAtm.mTaskSupervisor.mUserLeaving = true; + ar.getTaskFragment().startPausing(false /* uiSleeping */, null /* resuming */, + "finishTransition"); + mController.mAtm.mTaskSupervisor.mUserLeaving = false; + } ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Commit activity becoming invisible: %s", ar); ar.commitVisibility(false /* visible */, false /* performLayout */);