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_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;
}
/**

View File

@@ -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;
}
@@ -577,6 +585,24 @@ public class PipTaskOrganizer extends TaskOrganizer {
: 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)
*/

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.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,

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.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);

View File

@@ -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);
}
}
}

View File

@@ -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);
}