Merge "Dismiss PiP to split screen if applicable" into rvc-dev

This commit is contained in:
Hongwei Wang
2020-04-22 21:58:15 +00:00
committed by Android (Google) Code Review
6 changed files with 75 additions and 31 deletions

View File

@@ -53,16 +53,23 @@ public class PipAnimationController {
public static final int TRANSITION_DIRECTION_SAME = 1; public static final int TRANSITION_DIRECTION_SAME = 1;
public static final int TRANSITION_DIRECTION_TO_PIP = 2; 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_FULLSCREEN = 3;
public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
@IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = { @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
TRANSITION_DIRECTION_NONE, TRANSITION_DIRECTION_NONE,
TRANSITION_DIRECTION_SAME, TRANSITION_DIRECTION_SAME,
TRANSITION_DIRECTION_TO_PIP, TRANSITION_DIRECTION_TO_PIP,
TRANSITION_DIRECTION_TO_FULLSCREEN TRANSITION_DIRECTION_TO_FULLSCREEN,
TRANSITION_DIRECTION_TO_SPLIT_SCREEN
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface TransitionDirection {} 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 Interpolator mFastOutSlowInInterpolator;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
@@ -253,14 +260,13 @@ public class PipAnimationController {
} }
boolean shouldApplyCornerRadius() { boolean shouldApplyCornerRadius() {
return mTransitionDirection != TRANSITION_DIRECTION_TO_FULLSCREEN; return !isOutPipDirection(mTransitionDirection);
} }
boolean inScaleTransition() { boolean inScaleTransition() {
if (mAnimationType != ANIM_TYPE_BOUNDS) return false; if (mAnimationType != ANIM_TYPE_BOUNDS) return false;
final int direction = getTransitionDirection(); final int direction = getTransitionDirection();
return direction != TRANSITION_DIRECTION_TO_FULLSCREEN return !isOutPipDirection(direction) && direction != TRANSITION_DIRECTION_TO_PIP;
&& direction != TRANSITION_DIRECTION_TO_PIP;
} }
/** /**

View File

@@ -16,7 +16,6 @@
package com.android.systemui.pip; package com.android.systemui.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA; 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_SAME;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; 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_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.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -48,6 +49,7 @@ import android.window.WindowOrganizer;
import com.android.internal.os.SomeArgs; import com.android.internal.os.SomeArgs;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.pip.phone.PipUpdateThread; import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.stackdivider.Divider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -85,6 +87,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
private final int mEnterExitAnimationDuration; private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>(); private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
private final Divider mSplitDivider;
// These callbacks are called on the update thread // These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback = private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -189,7 +192,8 @@ public class PipTaskOrganizer extends TaskOrganizer {
mSurfaceControlTransactionFactory; mSurfaceControlTransactionFactory;
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper) { @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@Nullable Divider divider) {
mMainHandler = new Handler(Looper.getMainLooper()); mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler; mPipBoundsHandler = boundsHandler;
@@ -198,6 +202,7 @@ public class PipTaskOrganizer extends TaskOrganizer {
mSurfaceTransactionHelper = surfaceTransactionHelper; mSurfaceTransactionHelper = surfaceTransactionHelper;
mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper); mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper);
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
mSplitDivider = divider;
} }
public Handler getUpdateHandler() { public Handler getUpdateHandler() {
@@ -226,20 +231,21 @@ public class PipTaskOrganizer extends TaskOrganizer {
/** /**
* Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction} * Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction}
* - setActivityWindowingMode to fullscreen at beginning of the transaction. without changing * - 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 fullscreen * the windowing mode of the Task itself. This makes sure the activity render it's final
* configuration while the Task is still in PiP. * 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 * @param animationDurationMs duration in millisecond for the exiting PiP transition
*/ */
public void dismissPip(int animationDurationMs) { public void dismissPip(int animationDurationMs) {
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN); wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
WindowOrganizer.applyTransaction(wct); WindowOrganizer.applyTransaction(wct);
final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder()); final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder());
final int direction = syncWithSplitScreenBounds(destinationBounds)
? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN;
scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
TRANSITION_DIRECTION_TO_FULLSCREEN, animationDurationMs, direction, animationDurationMs, null /* updateBoundsCallback */);
null /* updateBoundsCallback */);
mInPip = false; mInPip = false;
} }
@@ -282,6 +288,9 @@ public class PipTaskOrganizer extends TaskOrganizer {
*/ */
@Override @Override
public void onTaskVanished(ActivityManager.RunningTaskInfo info) { public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
if (!mInPip) {
return;
}
final WindowContainerToken token = info.token; final WindowContainerToken token = info.token;
Objects.requireNonNull(token, "Requires valid WindowContainerToken"); Objects.requireNonNull(token, "Requires valid WindowContainerToken");
if (token.asBinder() != mToken.asBinder()) { if (token.asBinder() != mToken.asBinder()) {
@@ -519,14 +528,13 @@ public class PipTaskOrganizer extends TaskOrganizer {
mLastReportedBounds.set(destinationBounds); mLastReportedBounds.set(destinationBounds);
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect taskBounds; 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 // 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 // on the task to ensure that the task "matches" the parent's bounds.
// also to the final windowing mode, which should be reset to undefined rather than taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN)
// fullscreen. ? null : destinationBounds;
taskBounds = null; // As for the final windowing mode, simply reset it to undefined.
wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED) wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
} else { } else {
taskBounds = destinationBounds; taskBounds = destinationBounds;
} }
@@ -577,6 +585,24 @@ public class PipTaskOrganizer extends TaskOrganizer {
: params.getAspectRatio(); : params.getAspectRatio();
} }
/**
* 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) * Callback interface for PiP transitions (both from and to PiP mode)
*/ */

View File

@@ -19,7 +19,7 @@ package com.android.systemui.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 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.annotation.Nullable;
import android.app.ActivityManager; 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.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.wm.DisplayChangeController; import com.android.systemui.wm.DisplayChangeController;
@@ -199,7 +200,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
DeviceConfigProxy deviceConfig, DeviceConfigProxy deviceConfig,
PipBoundsHandler pipBoundsHandler, PipBoundsHandler pipBoundsHandler,
PipSnapAlgorithm pipSnapAlgorithm, PipSnapAlgorithm pipSnapAlgorithm,
PipSurfaceTransactionHelper surfaceTransactionHelper) { PipSurfaceTransactionHelper surfaceTransactionHelper,
Divider divider) {
mContext = context; mContext = context;
mActivityManager = ActivityManager.getService(); mActivityManager = ActivityManager.getService();
@@ -214,7 +216,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService(); final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
mPipBoundsHandler = pipBoundsHandler; mPipBoundsHandler = pipBoundsHandler;
mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler, mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler,
surfaceTransactionHelper); surfaceTransactionHelper, divider);
mPipTaskOrganizer.registerPipTransitionCallback(this); mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer(); mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher); mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -312,7 +314,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Override @Override
public void onPipTransitionStarted(ComponentName activity, int direction) { 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 // 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 // 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, // bounds. We want to restore to the unexpanded bounds when re-entering pip,

View File

@@ -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.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -232,7 +233,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
@Inject @Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
PipBoundsHandler pipBoundsHandler, PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper surfaceTransactionHelper) { PipSurfaceTransactionHelper surfaceTransactionHelper,
Divider divider) {
if (mInitialized) { if (mInitialized) {
return; return;
} }
@@ -249,7 +251,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mResizeAnimationDuration = context.getResources() mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration); .getInteger(R.integer.config_pipResizeAnimationDuration);
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
surfaceTransactionHelper); surfaceTransactionHelper, divider);
mPipTaskOrganizer.registerPipTransitionCallback(this); mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService(); mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);

View File

@@ -1188,12 +1188,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so // Picture-in-picture mode change normal triggers also multi-window mode change
// update that here in order. Set the last reported MW state to the same as the PiP // except transitions between pip and split screen mode, so update that here in order.
// state since we haven't yet actually resized the task (these callbacks need to // Set the last reported MW state to the same as the PiP state since we haven't yet
// preceed the configuration change from the resiez. // 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 // 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. // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
final boolean shouldScheduleMultiWindowModeChange =
mLastReportedMultiWindowMode != inMultiWindowMode();
mLastReportedPictureInPictureMode = inPictureInPictureMode; mLastReportedPictureInPictureMode = inPictureInPictureMode;
mLastReportedMultiWindowMode = inPictureInPictureMode; mLastReportedMultiWindowMode = inPictureInPictureMode;
final Configuration newConfig = new Configuration(); final Configuration newConfig = new Configuration();
@@ -1204,7 +1207,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration());
} }
schedulePictureInPictureModeChanged(newConfig); schedulePictureInPictureModeChanged(newConfig);
scheduleMultiWindowModeChanged(newConfig); if (shouldScheduleMultiWindowModeChange) {
scheduleMultiWindowModeChanged(newConfig);
}
} }
} }

View File

@@ -1943,12 +1943,15 @@ class Task extends WindowContainer<WindowContainer> {
final int prevWinMode = getWindowingMode(); final int prevWinMode = getWindowingMode();
mTmpPrevBounds.set(getBounds()); mTmpPrevBounds.set(getBounds());
final boolean wasInMultiWindowMode = inMultiWindowMode(); final boolean wasInMultiWindowMode = inMultiWindowMode();
final boolean wasInPictureInPicture = inPinnedWindowingMode();
super.onConfigurationChanged(newParentConfig); super.onConfigurationChanged(newParentConfig);
// Only need to update surface size here since the super method will handle updating // Only need to update surface size here since the super method will handle updating
// surface position. // surface position.
updateSurfaceSize(getPendingTransaction()); updateSurfaceSize(getPendingTransaction());
if (wasInMultiWindowMode != inMultiWindowMode()) { if (wasInPictureInPicture != inPinnedWindowingMode()) {
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack());
} else if (wasInMultiWindowMode != inMultiWindowMode()) {
mStackSupervisor.scheduleUpdateMultiWindowMode(this); mStackSupervisor.scheduleUpdateMultiWindowMode(this);
} }