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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user