Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java +6 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,12 @@ public class PipDisplayLayoutState { mDisplayLayout.rotateTo(mContext.getResources(), targetRotation); } /** Returns the current display rotation of this layout state. */ @Surface.Rotation public int getRotation() { return mDisplayLayout.rotation(); } /** Get the current display id */ public int getDisplayId() { return mDisplayId; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +49 −13 Original line number Diff line number Diff line Loading @@ -287,6 +287,12 @@ public class PipTransition extends PipTransitionController { // Entering PIP. if (isEnteringPip(info)) { if (handleEnteringPipWithDisplayChange(transition, info, startTransaction, finishTransaction, finishCallback)) { // The destination position is applied directly and let default transition handler // run the display change animation. return true; } startEnterAnimation(info, startTransaction, finishTransaction, finishCallback); return true; } Loading @@ -301,6 +307,25 @@ public class PipTransition extends PipTransitionController { return false; } private boolean handleEnteringPipWithDisplayChange(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, @NonNull Transitions.TransitionFinishCallback finishCallback) { if (mFixedRotationState != FIXED_ROTATION_UNDEFINED || !TransitionUtil.hasDisplayChange(info)) { return false; } final TransitionInfo.Change pipChange = getPipChange(info); if (pipChange == null) { return false; } ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: handle entering PiP with display change", TAG); mMixedHandler.animateEnteringPipWithDisplayChange(transition, info, pipChange, startT, finishT, finishCallback); return true; } @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, Loading Loading @@ -825,8 +850,11 @@ public class PipTransition extends PipTransitionController { @NonNull Transitions.TransitionFinishCallback finishCallback, @NonNull TaskInfo taskInfo) { startTransaction.apply(); finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(), mPipDisplayLayoutState.getDisplayBounds()); final TransitionInfo.Change pipChange = findCurrentPipTaskChange(info); if (pipChange == null) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "removePipImmediately is called without pip change"); } mPipOrganizer.onExitPipFinished(taskInfo); finishCallback.onTransitionFinished(null); } Loading Loading @@ -873,19 +901,24 @@ public class PipTransition extends PipTransitionController { mEnterAnimationType = type; } private void startEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Search for an Enter PiP transition TransitionInfo.Change enterPip = null; @Nullable private static TransitionInfo.Change getPipChange(@NonNull TransitionInfo info) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) { enterPip = change; return change; } } return null; } private void startEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Search for an Enter PiP transition final TransitionInfo.Change enterPip = getPipChange(info); if (enterPip == null) { throw new IllegalStateException("Trying to start PiP animation without a pip" + "participant"); Loading Loading @@ -959,8 +992,8 @@ public class PipTransition extends PipTransitionController { Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( taskInfo.pictureInPictureParams, currentBounds, destinationBounds); if (rotationDelta != Surface.ROTATION_0 && mFixedRotationState == FIXED_ROTATION_TRANSITION) { // Need to get the bounds of new rotation in old rotation for fixed rotation, && endRotation != mPipDisplayLayoutState.getRotation()) { // Computes the destination bounds in new rotation. computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo, destinationBounds, sourceHintRect); } Loading Loading @@ -1052,8 +1085,11 @@ public class PipTransition extends PipTransitionController { final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); if (mFixedRotationState == FIXED_ROTATION_TRANSITION) { // Transform the destination bounds to current display coordinates. // With fixed rotation, the bounds of new rotation shows in old rotation. rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation); } // When entering PiP (from button navigation mode), adjust the source rect hint by // display cutout if applicable. if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +10 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import com.android.wm.shell.common.pip.PipMenuController; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; Loading @@ -68,6 +69,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final Transitions mTransitions; private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>(); protected PipTaskOrganizer mPipOrganizer; protected DefaultMixedHandler mMixedHandler; protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback = new PipAnimationController.PipAnimationCallback() { Loading Loading @@ -173,6 +175,14 @@ public abstract class PipTransitionController implements Transitions.TransitionH mPipOrganizer = pto; } public void setMixedHandler(DefaultMixedHandler mixedHandler) { mMixedHandler = mixedHandler; } public void applyTransaction(WindowContainerTransaction wct) { mShellTaskOrganizer.applyTransaction(wct); } /** * Registers {@link PipTransitionCallback} to receive transition callbacks. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +45 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, /** Entering Pip from split, but replace the Pip stage instead of breaking split. */ static final int TYPE_ENTER_PIP_REPLACE_FROM_SPLIT = 10; /** The display changes when pip is entering. */ static final int TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE = 11; /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; Loading Loading @@ -232,6 +235,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, // Add after dependencies because it is higher priority shellInit.addInitCallback(() -> { mPipHandler = pipTransitionController; pipTransitionController.setMixedHandler(this); mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler(); mPlayer.addHandler(this); if (mSplitHandler != null) { Loading Loading @@ -549,6 +553,47 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, return true; } /** * For example: pip is entering in rotation 0, and then the display changes to rotation 90 * before the pip transition is ready. So the info contains both the entering pip and display * change. In this case, the pip can go to the end state in new rotation directly, and let the * display level animation cover all changed participates. */ public void animateEnteringPipWithDisplayChange(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull TransitionInfo.Change pipChange, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, @NonNull Transitions.TransitionFinishCallback finishCallback) { // In order to play display level animation, force the type to CHANGE (it could be PIP). final TransitionInfo changeInfo = info.getType() != TRANSIT_CHANGE ? subCopy(info, TRANSIT_CHANGE, true /* withChanges */) : info; final MixedTransition mixed = createDefaultMixedTransition( MixedTransition.TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE, transition); mActiveTransitions.add(mixed); mixed.mInFlightSubAnimations = 2; final Transitions.TransitionFinishCallback finishCB = wct -> { --mixed.mInFlightSubAnimations; mixed.joinFinishArgs(wct); if (mixed.mInFlightSubAnimations > 0) return; mActiveTransitions.remove(mixed); finishCallback.onTransitionFinished(mixed.mFinishWCT); }; // Perform the display animation first. mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, changeInfo, startT, finishT, finishCB, mPipHandler); // Use a standalone finish transaction for pip because it will apply immediately. final SurfaceControl.Transaction pipFinishT = new SurfaceControl.Transaction(); mPipHandler.startEnterAnimation(pipChange, startT, pipFinishT, wct -> { // Apply immediately to avoid potential flickering by bounds change at the end of // display animation. mPipHandler.applyTransaction(wct); finishCB.onTransitionFinished(null /* wct */); }); // Jump to the pip end state directly and make sure the real finishT have the latest state. mPipHandler.end(); mPipHandler.syncPipSurfaceState(info, startT, finishT); } private static boolean animateKeyguard(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java +2 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { return switch (mType) { case TYPE_DISPLAY_AND_SPLIT_CHANGE -> false; case TYPE_DISPLAY_AND_SPLIT_CHANGE, TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE -> false; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING -> animateEnterPipFromActivityEmbedding( info, startTransaction, finishTransaction, finishCallback); Loading Loading @@ -253,6 +253,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull Transitions.TransitionFinishCallback finishCallback) { switch (mType) { case TYPE_DISPLAY_AND_SPLIT_CHANGE: case TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE: // queue since no actual animation. return; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDisplayLayoutState.java +6 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,12 @@ public class PipDisplayLayoutState { mDisplayLayout.rotateTo(mContext.getResources(), targetRotation); } /** Returns the current display rotation of this layout state. */ @Surface.Rotation public int getRotation() { return mDisplayLayout.rotation(); } /** Get the current display id */ public int getDisplayId() { return mDisplayId; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +49 −13 Original line number Diff line number Diff line Loading @@ -287,6 +287,12 @@ public class PipTransition extends PipTransitionController { // Entering PIP. if (isEnteringPip(info)) { if (handleEnteringPipWithDisplayChange(transition, info, startTransaction, finishTransaction, finishCallback)) { // The destination position is applied directly and let default transition handler // run the display change animation. return true; } startEnterAnimation(info, startTransaction, finishTransaction, finishCallback); return true; } Loading @@ -301,6 +307,25 @@ public class PipTransition extends PipTransitionController { return false; } private boolean handleEnteringPipWithDisplayChange(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, @NonNull Transitions.TransitionFinishCallback finishCallback) { if (mFixedRotationState != FIXED_ROTATION_UNDEFINED || !TransitionUtil.hasDisplayChange(info)) { return false; } final TransitionInfo.Change pipChange = getPipChange(info); if (pipChange == null) { return false; } ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: handle entering PiP with display change", TAG); mMixedHandler.animateEnteringPipWithDisplayChange(transition, info, pipChange, startT, finishT, finishCallback); return true; } @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, Loading Loading @@ -825,8 +850,11 @@ public class PipTransition extends PipTransitionController { @NonNull Transitions.TransitionFinishCallback finishCallback, @NonNull TaskInfo taskInfo) { startTransaction.apply(); finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(), mPipDisplayLayoutState.getDisplayBounds()); final TransitionInfo.Change pipChange = findCurrentPipTaskChange(info); if (pipChange == null) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "removePipImmediately is called without pip change"); } mPipOrganizer.onExitPipFinished(taskInfo); finishCallback.onTransitionFinished(null); } Loading Loading @@ -873,19 +901,24 @@ public class PipTransition extends PipTransitionController { mEnterAnimationType = type; } private void startEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Search for an Enter PiP transition TransitionInfo.Change enterPip = null; @Nullable private static TransitionInfo.Change getPipChange(@NonNull TransitionInfo info) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) { enterPip = change; return change; } } return null; } private void startEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Search for an Enter PiP transition final TransitionInfo.Change enterPip = getPipChange(info); if (enterPip == null) { throw new IllegalStateException("Trying to start PiP animation without a pip" + "participant"); Loading Loading @@ -959,8 +992,8 @@ public class PipTransition extends PipTransitionController { Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( taskInfo.pictureInPictureParams, currentBounds, destinationBounds); if (rotationDelta != Surface.ROTATION_0 && mFixedRotationState == FIXED_ROTATION_TRANSITION) { // Need to get the bounds of new rotation in old rotation for fixed rotation, && endRotation != mPipDisplayLayoutState.getRotation()) { // Computes the destination bounds in new rotation. computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo, destinationBounds, sourceHintRect); } Loading Loading @@ -1052,8 +1085,11 @@ public class PipTransition extends PipTransitionController { final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); if (mFixedRotationState == FIXED_ROTATION_TRANSITION) { // Transform the destination bounds to current display coordinates. // With fixed rotation, the bounds of new rotation shows in old rotation. rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation); } // When entering PiP (from button navigation mode), adjust the source rect hint by // display cutout if applicable. if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +10 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import com.android.wm.shell.common.pip.PipMenuController; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; Loading @@ -68,6 +69,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final Transitions mTransitions; private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>(); protected PipTaskOrganizer mPipOrganizer; protected DefaultMixedHandler mMixedHandler; protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback = new PipAnimationController.PipAnimationCallback() { Loading Loading @@ -173,6 +175,14 @@ public abstract class PipTransitionController implements Transitions.TransitionH mPipOrganizer = pto; } public void setMixedHandler(DefaultMixedHandler mixedHandler) { mMixedHandler = mixedHandler; } public void applyTransaction(WindowContainerTransaction wct) { mShellTaskOrganizer.applyTransaction(wct); } /** * Registers {@link PipTransitionCallback} to receive transition callbacks. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +45 −0 Original line number Diff line number Diff line Loading @@ -106,6 +106,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, /** Entering Pip from split, but replace the Pip stage instead of breaking split. */ static final int TYPE_ENTER_PIP_REPLACE_FROM_SPLIT = 10; /** The display changes when pip is entering. */ static final int TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE = 11; /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; Loading Loading @@ -232,6 +235,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, // Add after dependencies because it is higher priority shellInit.addInitCallback(() -> { mPipHandler = pipTransitionController; pipTransitionController.setMixedHandler(this); mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler(); mPlayer.addHandler(this); if (mSplitHandler != null) { Loading Loading @@ -549,6 +553,47 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, return true; } /** * For example: pip is entering in rotation 0, and then the display changes to rotation 90 * before the pip transition is ready. So the info contains both the entering pip and display * change. In this case, the pip can go to the end state in new rotation directly, and let the * display level animation cover all changed participates. */ public void animateEnteringPipWithDisplayChange(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull TransitionInfo.Change pipChange, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT, @NonNull Transitions.TransitionFinishCallback finishCallback) { // In order to play display level animation, force the type to CHANGE (it could be PIP). final TransitionInfo changeInfo = info.getType() != TRANSIT_CHANGE ? subCopy(info, TRANSIT_CHANGE, true /* withChanges */) : info; final MixedTransition mixed = createDefaultMixedTransition( MixedTransition.TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE, transition); mActiveTransitions.add(mixed); mixed.mInFlightSubAnimations = 2; final Transitions.TransitionFinishCallback finishCB = wct -> { --mixed.mInFlightSubAnimations; mixed.joinFinishArgs(wct); if (mixed.mInFlightSubAnimations > 0) return; mActiveTransitions.remove(mixed); finishCallback.onTransitionFinished(mixed.mFinishWCT); }; // Perform the display animation first. mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, changeInfo, startT, finishT, finishCB, mPipHandler); // Use a standalone finish transaction for pip because it will apply immediately. final SurfaceControl.Transaction pipFinishT = new SurfaceControl.Transaction(); mPipHandler.startEnterAnimation(pipChange, startT, pipFinishT, wct -> { // Apply immediately to avoid potential flickering by bounds change at the end of // display animation. mPipHandler.applyTransaction(wct); finishCB.onTransitionFinished(null /* wct */); }); // Jump to the pip end state directly and make sure the real finishT have the latest state. mPipHandler.end(); mPipHandler.syncPipSurfaceState(info, startT, finishT); } private static boolean animateKeyguard(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java +2 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { return switch (mType) { case TYPE_DISPLAY_AND_SPLIT_CHANGE -> false; case TYPE_DISPLAY_AND_SPLIT_CHANGE, TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE -> false; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING -> animateEnterPipFromActivityEmbedding( info, startTransaction, finishTransaction, finishCallback); Loading Loading @@ -253,6 +253,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull Transitions.TransitionFinishCallback finishCallback) { switch (mType) { case TYPE_DISPLAY_AND_SPLIT_CHANGE: case TYPE_ENTER_PIP_WITH_DISPLAY_CHANGE: // queue since no actual animation. return; case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: Loading