diff options
| author | Hongwei Wang <hwwang@google.com> | 2020-04-20 16:02:30 -0700 |
|---|---|---|
| committer | Hongwei Wang <hwwang@google.com> | 2020-04-22 11:14:00 -0700 |
| commit | 5c52ff8ca5b0bed1ebdcd2bbdbeac6aa6835aa91 (patch) | |
| tree | 014f2ea70b9391be7c9e27c36ca7a8b6dca33468 | |
| parent | 5ff2b3ce04e6530f996e63f78a60fb4e79d5d918 (diff) | |
Dismiss PiP to split screen if applicable
When splt screen is present, dismiss PiP should result in
split-secondary instead of fullscreen mode.
Fixed also in this CL that when a PiP window transitions to split
screen, a picture-in-picture mode change event should be dispatched to
client.
Video: http://go/recall/-/aaaaaabFQoRHlzixHdtY/dP7U1AtIBXPvLwMp7fFXN
Bug: 154284314
Test: atest PinnedStackTests
Test: manually dismiss PiP when split screen is present
Change-Id: I99b33c1be37d13572e540d7d30b96ed75d00323d
6 files changed, 75 insertions, 31 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index dba43430b490..f322489b8dc2 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -53,16 +53,23 @@ public class PipAnimationController { public static final int TRANSITION_DIRECTION_SAME = 1; public static final int TRANSITION_DIRECTION_TO_PIP = 2; public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3; + public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4; @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = { TRANSITION_DIRECTION_NONE, TRANSITION_DIRECTION_SAME, TRANSITION_DIRECTION_TO_PIP, - TRANSITION_DIRECTION_TO_FULLSCREEN + TRANSITION_DIRECTION_TO_FULLSCREEN, + TRANSITION_DIRECTION_TO_SPLIT_SCREEN }) @Retention(RetentionPolicy.SOURCE) public @interface TransitionDirection {} + public static boolean isOutPipDirection(@TransitionDirection int direction) { + return direction == TRANSITION_DIRECTION_TO_FULLSCREEN + || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN; + } + private final Interpolator mFastOutSlowInInterpolator; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; @@ -253,14 +260,13 @@ public class PipAnimationController { } boolean shouldApplyCornerRadius() { - return mTransitionDirection != TRANSITION_DIRECTION_TO_FULLSCREEN; + return !isOutPipDirection(mTransitionDirection); } boolean inScaleTransition() { if (mAnimationType != ANIM_TYPE_BOUNDS) return false; final int direction = getTransitionDirection(); - return direction != TRANSITION_DIRECTION_TO_FULLSCREEN - && direction != TRANSITION_DIRECTION_TO_PIP; + return !isOutPipDirection(direction) && direction != TRANSITION_DIRECTION_TO_PIP; } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 0125153542c1..9eae3ca232ff 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -16,7 +16,6 @@ package com.android.systemui.pip; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -25,6 +24,8 @@ import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; +import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN; +import static com.android.systemui.pip.PipAnimationController.isOutPipDirection; import android.annotation.NonNull; import android.annotation.Nullable; @@ -48,6 +49,7 @@ import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; import com.android.systemui.R; import com.android.systemui.pip.phone.PipUpdateThread; +import com.android.systemui.stackdivider.Divider; import java.util.ArrayList; import java.util.HashMap; @@ -85,6 +87,7 @@ public class PipTaskOrganizer extends TaskOrganizer { private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>(); + private final Divider mSplitDivider; // These callbacks are called on the update thread private final PipAnimationController.PipAnimationCallback mPipAnimationCallback = @@ -189,7 +192,8 @@ public class PipTaskOrganizer extends TaskOrganizer { mSurfaceControlTransactionFactory; public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, - @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper) { + @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, + @Nullable Divider divider) { mMainHandler = new Handler(Looper.getMainLooper()); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); mPipBoundsHandler = boundsHandler; @@ -198,6 +202,7 @@ public class PipTaskOrganizer extends TaskOrganizer { mSurfaceTransactionHelper = surfaceTransactionHelper; mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; + mSplitDivider = divider; } public Handler getUpdateHandler() { @@ -226,20 +231,21 @@ public class PipTaskOrganizer extends TaskOrganizer { /** * Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction} - * - setActivityWindowingMode to fullscreen at beginning of the transaction. without changing - * the windowing mode of the Task itself. This makes sure the activity render it's fullscreen + * - setActivityWindowingMode to undefined at beginning of the transaction. without changing + * the windowing mode of the Task itself. This makes sure the activity render it's final * configuration while the Task is still in PiP. - * - setWindowingMode to fullscreen at the end of transition + * - setWindowingMode to undefined at the end of transition * @param animationDurationMs duration in millisecond for the exiting PiP transition */ public void dismissPip(int animationDurationMs) { final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN); + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); WindowOrganizer.applyTransaction(wct); final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder()); + final int direction = syncWithSplitScreenBounds(destinationBounds) + ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN; scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, - TRANSITION_DIRECTION_TO_FULLSCREEN, animationDurationMs, - null /* updateBoundsCallback */); + direction, animationDurationMs, null /* updateBoundsCallback */); mInPip = false; } @@ -282,6 +288,9 @@ public class PipTaskOrganizer extends TaskOrganizer { */ @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { + if (!mInPip) { + return; + } final WindowContainerToken token = info.token; Objects.requireNonNull(token, "Requires valid WindowContainerToken"); if (token.asBinder() != mToken.asBinder()) { @@ -519,14 +528,13 @@ public class PipTaskOrganizer extends TaskOrganizer { mLastReportedBounds.set(destinationBounds); final WindowContainerTransaction wct = new WindowContainerTransaction(); final Rect taskBounds; - if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) { + if (isOutPipDirection(direction)) { // If we are animating to fullscreen, then we need to reset the override bounds - // on the task to ensure that the task "matches" the parent's bounds, this applies - // also to the final windowing mode, which should be reset to undefined rather than - // fullscreen. - taskBounds = null; - wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED) - .setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + // on the task to ensure that the task "matches" the parent's bounds. + taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) + ? null : destinationBounds; + // As for the final windowing mode, simply reset it to undefined. + wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); } else { taskBounds = destinationBounds; } @@ -578,6 +586,24 @@ public class PipTaskOrganizer extends TaskOrganizer { } /** + * Sync with {@link #mSplitDivider} on destination bounds if PiP is going to split screen. + * + * @param destinationBoundsOut contain the updated destination bounds if applicable + * @return {@code true} if destinationBounds is altered for split screen + */ + private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) { + if (mSplitDivider == null || !mSplitDivider.inSplitMode()) { + // bail early if system is not in split screen mode + return false; + } + // PiP window will go to split-secondary mode instead of fullscreen, populates the + // split screen bounds here. + destinationBoundsOut.set( + mSplitDivider.getView().getNonMinimizedSplitScreenSecondaryBounds()); + return true; + } + + /** * Callback interface for PiP transitions (both from and to PiP mode) */ public interface PipTransitionCallback { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index ba9a30fb554f..78975735ef0f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -19,7 +19,7 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; +import static com.android.systemui.pip.PipAnimationController.isOutPipDirection; import android.annotation.Nullable; import android.app.ActivityManager; @@ -53,6 +53,7 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.stackdivider.Divider; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.wm.DisplayChangeController; @@ -199,7 +200,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio DeviceConfigProxy deviceConfig, PipBoundsHandler pipBoundsHandler, PipSnapAlgorithm pipSnapAlgorithm, - PipSurfaceTransactionHelper surfaceTransactionHelper) { + PipSurfaceTransactionHelper surfaceTransactionHelper, + Divider divider) { mContext = context; mActivityManager = ActivityManager.getService(); @@ -214,7 +216,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService(); mPipBoundsHandler = pipBoundsHandler; mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler, - surfaceTransactionHelper); + surfaceTransactionHelper, divider); mPipTaskOrganizer.registerPipTransitionCallback(this); mInputConsumerController = InputConsumerController.getPipInputConsumer(); mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher); @@ -312,7 +314,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Override public void onPipTransitionStarted(ComponentName activity, int direction) { - if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) { + if (isOutPipDirection(direction)) { // On phones, the expansion animation that happens on pip tap before restoring // to fullscreen makes it so that the bounds received here are the expanded // bounds. We want to restore to the unexpanded bounds when re-entering pip, diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 3a2d786cebe4..6c5312d57b2a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -57,6 +57,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.stackdivider.Divider; import java.util.ArrayList; import java.util.List; @@ -232,7 +233,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Inject public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, PipBoundsHandler pipBoundsHandler, - PipSurfaceTransactionHelper surfaceTransactionHelper) { + PipSurfaceTransactionHelper surfaceTransactionHelper, + Divider divider) { if (mInitialized) { return; } @@ -249,7 +251,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mResizeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, - surfaceTransactionHelper); + surfaceTransactionHelper, divider); mPipTaskOrganizer.registerPipTransitionCallback(this); mActivityTaskManager = ActivityTaskManager.getService(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 2648c86d3c6a..ac76ad6ea1f8 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1188,12 +1188,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { - // Picture-in-picture mode changes also trigger a multi-window mode change as well, so - // update that here in order. Set the last reported MW state to the same as the PiP - // state since we haven't yet actually resized the task (these callbacks need to - // preceed the configuration change from the resiez. + // Picture-in-picture mode change normal triggers also multi-window mode change + // except transitions between pip and split screen mode, so update that here in order. + // Set the last reported MW state to the same as the PiP state since we haven't yet + // actually resized the task (these callbacks need to proceed the configuration change + // from the resize). // TODO(110009072): Once we move these callbacks to the client, remove all logic related // to forcing the update of the picture-in-picture mode as a part of the PiP animation. + final boolean shouldScheduleMultiWindowModeChange = + mLastReportedMultiWindowMode != inMultiWindowMode(); mLastReportedPictureInPictureMode = inPictureInPictureMode; mLastReportedMultiWindowMode = inPictureInPictureMode; final Configuration newConfig = new Configuration(); @@ -1204,7 +1207,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); } schedulePictureInPictureModeChanged(newConfig); - scheduleMultiWindowModeChanged(newConfig); + if (shouldScheduleMultiWindowModeChange) { + scheduleMultiWindowModeChanged(newConfig); + } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 66e1b1758d85..4b3c7a25d2ce 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1943,12 +1943,15 @@ class Task extends WindowContainer<WindowContainer> { final int prevWinMode = getWindowingMode(); mTmpPrevBounds.set(getBounds()); final boolean wasInMultiWindowMode = inMultiWindowMode(); + final boolean wasInPictureInPicture = inPinnedWindowingMode(); super.onConfigurationChanged(newParentConfig); // Only need to update surface size here since the super method will handle updating // surface position. updateSurfaceSize(getPendingTransaction()); - if (wasInMultiWindowMode != inMultiWindowMode()) { + if (wasInPictureInPicture != inPinnedWindowingMode()) { + mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack()); + } else if (wasInMultiWindowMode != inMultiWindowMode()) { mStackSupervisor.scheduleUpdateMultiWindowMode(this); } |
