Transfer PipContentOverlay when swipe to home with Shell transition
Swipe to home animation is played by launcher, but the entering PIP transition will finished by PipTransition. As a result, we need to reparent the overlay and fade out the overlay in PipTransition when enter PIP is finalized, otherwise the overlay will be removed with the remote transition leash and cause flicker. Bug: 222030101 Test: verify with swipe to home with Shell transition Change-Id: Idde3414e3cc5e8193cf7d4da9818e59dc6b4b1c5
This commit is contained in:
@@ -98,16 +98,22 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
||||
default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
|
||||
default void onTaskVanished(RunningTaskInfo taskInfo) {}
|
||||
default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
|
||||
/** Whether this task listener supports compat UI. */
|
||||
/** Whether this task listener supports compat UI. */
|
||||
default boolean supportCompatUI() {
|
||||
// All TaskListeners should support compat UI except PIP.
|
||||
return true;
|
||||
}
|
||||
/** Attaches the a child window surface to the task surface. */
|
||||
/** Attaches a child window surface to the task surface. */
|
||||
default void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
throw new IllegalStateException(
|
||||
"This task listener doesn't support child surface attachment.");
|
||||
}
|
||||
/** Reparents a child window surface to the task surface. */
|
||||
default void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
throw new IllegalStateException(
|
||||
"This task listener doesn't support child surface reparent.");
|
||||
}
|
||||
default void dump(@NonNull PrintWriter pw, String prefix) {};
|
||||
}
|
||||
|
||||
@@ -620,6 +626,23 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
||||
updateCameraCompatControlState(info.getTaskInfo().token, state);
|
||||
}
|
||||
|
||||
/** Reparents a child window surface to the task surface. */
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
final TaskListener taskListener;
|
||||
synchronized (mLock) {
|
||||
taskListener = mTasks.contains(taskId)
|
||||
? getTaskListener(mTasks.get(taskId).getTaskInfo())
|
||||
: null;
|
||||
}
|
||||
if (taskListener == null) {
|
||||
ProtoLog.w(WM_SHELL_TASK_ORG, "Failed to find Task to reparent surface taskId=%d",
|
||||
taskId);
|
||||
return;
|
||||
}
|
||||
taskListener.reparentChildSurfaceToTask(taskId, sc, t);
|
||||
}
|
||||
|
||||
private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
|
||||
int event) {
|
||||
ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
|
||||
|
||||
@@ -367,10 +367,20 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
if (mTaskInfo.taskId != taskId) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (mTaskInfo == null || mTaskLeash == null || mTaskInfo.taskId != taskId) {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
b.setParent(mTaskLeash);
|
||||
return mTaskLeash;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -275,12 +275,22 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (getRootTaskId() == taskId) {
|
||||
b.setParent(mRootTaskLeash);
|
||||
return mRootTaskLeash;
|
||||
} else if (getTaskId1() == taskId) {
|
||||
b.setParent(mTaskLeash1);
|
||||
return mTaskLeash1;
|
||||
} else if (getTaskId2() == taskId) {
|
||||
b.setParent(mTaskLeash2);
|
||||
return mTaskLeash2;
|
||||
} else {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
|
||||
@@ -109,6 +109,24 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (!mTasks.contains(taskId)) {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
return mTasks.get(taskId).mLeash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
|
||||
@@ -133,10 +133,20 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (!mDataByTaskId.contains(taskId)) {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
b.setParent(mDataByTaskId.get(taskId).surface);
|
||||
return mDataByTaskId.get(taskId).surface;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -343,10 +343,20 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (!mLeashByTaskId.contains(taskId)) {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
b.setParent(mLeashByTaskId.get(taskId));
|
||||
return mLeashByTaskId.get(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,12 +47,13 @@ interface IPip {
|
||||
/**
|
||||
* Notifies the swiping Activity to PiP onto home transition is finished
|
||||
*
|
||||
* @param taskId the Task id that the Activity and overlay are currently in.
|
||||
* @param componentName ComponentName represents the Activity
|
||||
* @param destinationBounds the destination bounds the PiP window lands into
|
||||
* @param overlay an optional overlay to fade out after entering PiP
|
||||
*/
|
||||
oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds,
|
||||
in SurfaceControl overlay) = 2;
|
||||
oneway void stopSwipePipToHome(int taskId, in ComponentName componentName,
|
||||
in Rect destinationBounds, in SurfaceControl overlay) = 2;
|
||||
|
||||
/**
|
||||
* Sets listener to get pinned stack animation callbacks.
|
||||
|
||||
@@ -249,7 +249,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
* An optional overlay used to mask content changing between an app in/out of PiP, only set if
|
||||
* {@link PipTransitionState#getInSwipePipToHomeTransition()} is true.
|
||||
*/
|
||||
private SurfaceControl mSwipePipToHomeOverlay;
|
||||
@Nullable
|
||||
SurfaceControl mSwipePipToHomeOverlay;
|
||||
|
||||
public PipTaskOrganizer(Context context,
|
||||
@NonNull SyncTransactionQueue syncTransactionQueue,
|
||||
@@ -356,12 +357,24 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
* Callback when launcher finishes swipe-pip-to-home operation.
|
||||
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
|
||||
*/
|
||||
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
|
||||
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
|
||||
SurfaceControl overlay) {
|
||||
// do nothing if there is no startSwipePipToHome being called before
|
||||
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
|
||||
mPipBoundsState.setBounds(destinationBounds);
|
||||
mSwipePipToHomeOverlay = overlay;
|
||||
if (!mPipTransitionState.getInSwipePipToHomeTransition()) {
|
||||
return;
|
||||
}
|
||||
mPipBoundsState.setBounds(destinationBounds);
|
||||
mSwipePipToHomeOverlay = overlay;
|
||||
if (ENABLE_SHELL_TRANSITIONS) {
|
||||
// With Shell transition, the overlay was attached to the remote transition leash, which
|
||||
// will be removed when the current transition is finished, so we need to reparent it
|
||||
// to the actual Task surface now.
|
||||
// PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
|
||||
// transition.
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
mTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, t);
|
||||
t.setLayer(overlay, Integer.MAX_VALUE);
|
||||
t.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,7 +684,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
private void onEndOfSwipePipToHomeTransition() {
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
mSwipePipToHomeOverlay = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -822,6 +834,24 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (mTaskInfo == null || mLeash == null || mTaskInfo.taskId != taskId) {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
return mLeash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFixedRotationStarted(int displayId, int newRotation) {
|
||||
mNextRotation = newRotation;
|
||||
@@ -877,9 +907,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
clearWaitForFixedRotation();
|
||||
}
|
||||
|
||||
/** Called when exiting PIP tranisiton is finished to do the state cleanup. */
|
||||
/** Called when exiting PIP transition is finished to do the state cleanup. */
|
||||
void onExitPipFinished(TaskInfo info) {
|
||||
clearWaitForFixedRotation();
|
||||
if (mSwipePipToHomeOverlay != null) {
|
||||
removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
|
||||
mSwipePipToHomeOverlay = null;
|
||||
}
|
||||
mPipTransitionState.setInSwipePipToHomeTransition(false);
|
||||
mPictureInPictureParams = null;
|
||||
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
|
||||
|
||||
@@ -603,11 +603,18 @@ public class PipTransition extends PipTransitionController {
|
||||
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
|
||||
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
|
||||
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
|
||||
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
|
||||
tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
|
||||
final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
|
||||
startTransaction.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
|
||||
.setPosition(leash, destinationBounds.left, destinationBounds.top)
|
||||
.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
|
||||
startTransaction.merge(tx);
|
||||
if (swipePipToHomeOverlay != null) {
|
||||
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
|
||||
// reparent the PIP activity to a new PIP task (in case there are other activities
|
||||
// in the original Task), so we should also reparent the overlay to the PIP task.
|
||||
startTransaction.reparent(swipePipToHomeOverlay, leash)
|
||||
.setLayer(swipePipToHomeOverlay, Integer.MAX_VALUE);
|
||||
mPipOrganizer.mSwipePipToHomeOverlay = null;
|
||||
}
|
||||
startTransaction.apply();
|
||||
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
|
||||
// For fixed rotation, set the destination bounds to the new rotation coordinates
|
||||
@@ -617,6 +624,10 @@ public class PipTransition extends PipTransitionController {
|
||||
mPipBoundsState.setBounds(destinationBounds);
|
||||
onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
|
||||
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
|
||||
if (swipePipToHomeOverlay != null) {
|
||||
mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
|
||||
null /* callback */, false /* withStartDelay */);
|
||||
}
|
||||
mPipTransitionState.setInSwipePipToHomeTransition(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -592,9 +592,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
return entryBounds;
|
||||
}
|
||||
|
||||
private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
|
||||
private void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
|
||||
SurfaceControl overlay) {
|
||||
mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds, overlay);
|
||||
mPipTaskOrganizer.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
|
||||
}
|
||||
|
||||
private String getTransitionTag(int direction) {
|
||||
@@ -923,11 +923,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
|
||||
SurfaceControl overlay) {
|
||||
public void stopSwipePipToHome(int taskId, ComponentName componentName,
|
||||
Rect destinationBounds, SurfaceControl overlay) {
|
||||
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
|
||||
(controller) -> {
|
||||
controller.stopSwipePipToHome(componentName, destinationBounds, overlay);
|
||||
controller.stopSwipePipToHome(taskId, componentName, destinationBounds,
|
||||
overlay);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -280,10 +280,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (mRootTaskInfo.taskId == taskId) {
|
||||
b.setParent(mRootLeash);
|
||||
return mRootLeash;
|
||||
} else if (mChildrenLeashes.contains(taskId)) {
|
||||
b.setParent(mChildrenLeashes.get(taskId));
|
||||
return mChildrenLeashes.get(taskId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
|
||||
@@ -227,10 +227,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
|
||||
@Override
|
||||
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
|
||||
b.setParent(findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
|
||||
SurfaceControl.Transaction t) {
|
||||
t.reparent(sc, findTaskSurface(taskId));
|
||||
}
|
||||
|
||||
private SurfaceControl findTaskSurface(int taskId) {
|
||||
if (mRootTaskInfo.taskId == taskId) {
|
||||
b.setParent(mRootLeash);
|
||||
return mRootLeash;
|
||||
} else if (mChildrenLeashes.contains(taskId)) {
|
||||
b.setParent(mChildrenLeashes.get(taskId));
|
||||
return mChildrenLeashes.get(taskId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user