summaryrefslogtreecommitdiff
path: root/libs/WindowManager/Shell
diff options
context:
space:
mode:
author Chris Li <lihongyu@google.com> 2022-02-17 06:34:16 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-02-17 06:34:16 +0000
commit539e1349e829682670db79c6ca1f06b5065ad2bf (patch)
tree18f0aef553cb0e0a24e2587c09a6b4e96e794231 /libs/WindowManager/Shell
parent51ad2f17db5c25067c842f4d75f0612a2f24ad2d (diff)
parenteb8ca0d725e0840723cabab0192dcbfa126a1cb5 (diff)
Merge "Fixed rotation for entering PIP with Shell transition"
Diffstat (limited to 'libs/WindowManager/Shell')
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java175
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java4
3 files changed, 175 insertions, 34 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 13d9081bb3ba..1eb9501ac076 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -579,6 +579,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Log.d(TAG, "Alpha animation is expired. Use bounds animation.");
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
}
+
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ // For Shell transition, we will animate the window in PipTransition#startAnimation
+ // instead of #onTaskAppeared.
+ return;
+ }
+
if (mWaitForFixedRotation) {
onTaskAppearedWithFixedRotation();
return;
@@ -588,15 +595,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- mPipMenuController.attach(mLeash);
- } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
- }
- return;
- }
-
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
mPipMenuController.attach(mLeash);
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
@@ -829,6 +827,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mNextRotation = newRotation;
mWaitForFixedRotation = true;
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ // The fixed rotation will also be included in the transition info. However, if it is
+ // not a PIP transition (such as open another app to different orientation),
+ // PIP transition handler may not be aware of the fixed rotation start.
+ // Notify the PIP transition handler so that it can fade out the PIP window early for
+ // fixed transition of other windows.
+ mPipTransitionController.onFixedRotationStarted();
+ return;
+ }
+
if (mPipTransitionState.isInPip()) {
// Fade out the existing PiP to avoid jump cut during seamless rotation.
fadeExistingPip(false /* show */);
@@ -840,6 +848,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (!mWaitForFixedRotation) {
return;
}
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ clearWaitForFixedRotation();
+ return;
+ }
if (mPipTransitionState.getTransitionState() == PipTransitionState.TASK_APPEARED) {
if (mPipTransitionState.getInSwipePipToHomeTransition()) {
onEndOfSwipePipToHomeTransition();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 3e5d5f645725..60aac6806623 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
@@ -32,9 +33,11 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
+import static com.android.wm.shell.pip.PipTransitionState.ENTERED_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
@@ -47,6 +50,7 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.util.Log;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -86,6 +90,16 @@ public class PipTransition extends PipTransitionController {
/** The Task window that is currently in PIP windowing mode. */
@Nullable
private WindowContainerToken mCurrentPipTaskToken;
+ /** Whether display is in fixed rotation. */
+ private boolean mInFixedRotation;
+ /**
+ * The rotation that the display will apply after expanding PiP to fullscreen. This is only
+ * meaningful if {@link #mInFixedRotation} is true.
+ */
+ @Surface.Rotation
+ private int mFixedRotation;
+ /** Whether the PIP window has fade out for fixed rotation. */
+ private boolean mHasFadeOut;
public PipTransition(Context context,
PipBoundsState pipBoundsState,
@@ -136,35 +150,41 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
+ final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
+ final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
+ mInFixedRotation = fixedRotationChange != null;
+ mFixedRotation = mInFixedRotation
+ ? fixedRotationChange.getEndFixedRotation()
+ : ROTATION_UNDEFINED;
+
// Exiting PIP.
final int type = info.getType();
if (transition.equals(mExitTransition)) {
mExitDestinationBounds.setEmpty();
mExitTransition = null;
-
+ mHasFadeOut = false;
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(null, null);
mFinishCallback = null;
throw new RuntimeException("Previous callback not called, aborting exit PIP.");
}
- final TransitionInfo.Change exitPipChange = findCurrentPipChange(info);
- if (exitPipChange == null) {
+ if (currentPipChange == null) {
throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
}
switch (type) {
case TRANSIT_EXIT_PIP:
startExitAnimation(info, startTransaction, finishTransaction, finishCallback,
- exitPipChange);
+ currentPipChange);
break;
case TRANSIT_EXIT_PIP_TO_SPLIT:
startExitToSplitAnimation(info, startTransaction, finishTransaction,
- finishCallback, exitPipChange);
+ finishCallback, currentPipChange);
break;
case TRANSIT_REMOVE_PIP:
removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
- exitPipChange);
+ currentPipChange);
break;
default:
throw new IllegalStateException("mExitTransition with unexpected transit type="
@@ -177,7 +197,6 @@ public class PipTransition extends PipTransitionController {
// The previous PIP Task is no longer in PIP, but this is not an exit transition (This can
// happen when a new activity requests enter PIP). In this case, we just show this Task in
// its end state, and play other animation as normal.
- final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
if (currentPipChange != null
&& currentPipChange.getTaskInfo().getWindowingMode() != WINDOWING_MODE_PINNED) {
resetPrevPip(currentPipChange, startTransaction);
@@ -193,6 +212,12 @@ public class PipTransition extends PipTransitionController {
if (currentPipChange != null) {
updatePipForUnhandledTransition(currentPipChange, startTransaction, finishTransaction);
}
+
+ // Fade in the fadeout PIP when the fixed rotation is finished.
+ if (mPipTransitionState.isInPip() && !mInFixedRotation && mHasFadeOut) {
+ fadeExistingPip(true /* show */);
+ }
+
return false;
}
@@ -242,9 +267,8 @@ public class PipTransition extends PipTransitionController {
public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
@PipAnimationController.TransitionDirection int direction,
@Nullable SurfaceControl.Transaction tx) {
-
if (isInPipDirection(direction)) {
- mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP);
+ mPipTransitionState.setTransitionState(ENTERED_PIP);
}
// If there is an expected exit transition, then the exit will be "merged" into this
// transition so don't fire the finish-callback in that case.
@@ -268,6 +292,16 @@ public class PipTransition extends PipTransitionController {
mFinishCallback = null;
}
+ @Override
+ public void onFixedRotationStarted() {
+ // The transition with this fixed rotation may be handled by other handler before reaching
+ // PipTransition, so we cannot do this in #startAnimation.
+ if (mPipTransitionState.getTransitionState() == ENTERED_PIP && !mHasFadeOut) {
+ // Fade out the existing PiP to avoid jump cut during seamless rotation.
+ fadeExistingPip(false /* show */);
+ }
+ }
+
@Nullable
private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
if (mCurrentPipTaskToken == null) {
@@ -282,6 +316,17 @@ public class PipTransition extends PipTransitionController {
return null;
}
+ @Nullable
+ private TransitionInfo.Change findFixedRotationChange(@NonNull TransitionInfo info) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getEndFixedRotation() != ROTATION_UNDEFINED) {
+ return change;
+ }
+ }
+ return null;
+ }
+
private void startExitAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -453,6 +498,7 @@ public class PipTransition extends PipTransitionController {
}
// Keep track of the PIP task.
mCurrentPipTaskToken = enterPip.getContainer();
+ mHasFadeOut = false;
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
@@ -465,12 +511,25 @@ public class PipTransition extends PipTransitionController {
startTransaction.show(wallpaper.getLeash());
startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
}
+ // Make sure other open changes are visible as entering PIP. Some may be hidden in
+ // Transitions#setupStartState because the transition type is OPEN (such as auto-enter).
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change == enterPip || change == wallpaper) {
+ continue;
+ }
+ if (isOpeningType(change.getMode())) {
+ final SurfaceControl leash = change.getLeash();
+ startTransaction.show(leash).setAlpha(leash, 1.f);
+ }
+ }
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
+ final int endRotation = mInFixedRotation ? mFixedRotation : enterPip.getEndRotation();
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
startTransaction, finishTransaction, enterPip.getStartRotation(),
- enterPip.getEndRotation());
+ endRotation);
}
private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
@@ -481,25 +540,36 @@ public class PipTransition extends PipTransitionController {
taskInfo.topActivityInfo);
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
+ int rotationDelta = deltaRotation(startRotation, endRotation);
+ Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
+ taskInfo.pictureInPictureParams, currentBounds);
+ if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
+ // Need to get the bounds of new rotation in old rotation for fixed rotation,
+ sourceHintRect = computeRotatedBounds(rotationDelta, startRotation, endRotation,
+ taskInfo, TRANSITION_DIRECTION_TO_PIP, destinationBounds, sourceHintRect);
+ }
PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
+ mPipMenuController.attach(leash);
+
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
-
- // PiP menu is attached late in the process here to avoid any artifacts on the leash
- // caused by addShellRoot when in gesture navigation mode.
- mPipMenuController.attach(leash);
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
.setPosition(leash, destinationBounds.left, destinationBounds.top)
.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
startTransaction.merge(tx);
startTransaction.apply();
+ if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
+ // For fixed rotation, set the destination bounds to the new rotation coordinates
+ // at the end.
+ destinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ }
mPipBoundsState.setBounds(destinationBounds);
onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
@@ -507,17 +577,14 @@ public class PipTransition extends PipTransitionController {
return true;
}
- int rotationDelta = deltaRotation(endRotation, startRotation);
if (rotationDelta != Surface.ROTATION_0) {
Matrix tmpTransform = new Matrix();
- tmpTransform.postRotate(rotationDelta == Surface.ROTATION_90
- ? Surface.ROTATION_270 : Surface.ROTATION_90);
+ tmpTransform.postRotate(rotationDelta);
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- final Rect sourceHintRect =
- PipBoundsAlgorithm.getValidSourceHintRect(
- taskInfo.pictureInPictureParams, currentBounds);
+ // Reverse the rotation for Shell transition animation.
+ rotationDelta = deltaRotation(rotationDelta, 0);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, rotationDelta);
@@ -528,9 +595,6 @@ public class PipTransition extends PipTransitionController {
}
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
startTransaction.setAlpha(leash, 0f);
- // PiP menu is attached late in the process here to avoid any artifacts on the leash
- // caused by addShellRoot when in gesture navigation mode.
- mPipMenuController.attach(leash);
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
0f, 1f);
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -541,12 +605,47 @@ public class PipTransition extends PipTransitionController {
startTransaction.apply();
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
- .setDuration(mEnterExitAnimationDuration)
- .start();
+ .setDuration(mEnterExitAnimationDuration);
+ if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
+ // For fixed rotation, the animation destination bounds is in old rotation coordinates.
+ // Set the destination bounds to new coordinates after the animation is finished.
+ // ComputeRotatedBounds has changed the DisplayLayout without affecting the animation.
+ animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ }
+ animator.start();
return true;
}
+ /** Computes destination bounds in old rotation and returns source hint rect if available. */
+ @Nullable
+ private Rect computeRotatedBounds(int rotationDelta, int startRotation, int endRotation,
+ TaskInfo taskInfo, int direction, Rect outDestinationBounds,
+ @Nullable Rect sourceHintRect) {
+ if (direction == TRANSITION_DIRECTION_TO_PIP) {
+ mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ // Transform the destination bounds to current display coordinates.
+ rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (sourceHintRect != null && taskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ sourceHintRect.offset(taskInfo.displayCutoutInsets.left,
+ taskInfo.displayCutoutInsets.top);
+ }
+ }
+ } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
+ rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
+ rotationDelta);
+ return PipBoundsAlgorithm.getValidSourceHintRect(taskInfo.pictureInPictureParams,
+ rotatedDestinationBounds);
+ }
+ return sourceHintRect;
+ }
+
private void startExitToSplitAnimation(TransitionInfo info,
SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction,
@@ -595,6 +694,13 @@ public class PipTransition extends PipTransitionController {
startTransaction.setCornerRadius(leash, 0);
startTransaction.setPosition(leash, bounds.left, bounds.top);
+ if (mHasFadeOut && prevPipChange.getTaskInfo().isVisible()) {
+ if (mPipAnimationController.getCurrentAnimator() != null) {
+ mPipAnimationController.getCurrentAnimator().cancel();
+ }
+ startTransaction.setAlpha(leash, 1);
+ }
+ mHasFadeOut = false;
mCurrentPipTaskToken = null;
mPipOrganizer.onExitPipFinished(prevPipChange.getTaskInfo());
}
@@ -615,6 +721,25 @@ public class PipTransition extends PipTransitionController {
.round(finishTransaction, leash, isInPip);
}
+ /** Hides and shows the existing PIP during fixed rotation transition of other activities. */
+ private void fadeExistingPip(boolean show) {
+ final SurfaceControl leash = mPipOrganizer.getSurfaceControl();
+ final TaskInfo taskInfo = mPipOrganizer.getTaskInfo();
+ if (leash == null || !leash.isValid() || taskInfo == null) {
+ Log.w(TAG, "Invalid leash on fadeExistingPip: " + leash);
+ return;
+ }
+ final float alphaStart = show ? 0 : 1;
+ final float alphaEnd = show ? 1 : 0;
+ mPipAnimationController
+ .getAnimator(taskInfo, leash, mPipBoundsState.getBounds(), alphaStart, alphaEnd)
+ .setTransitionDirection(TRANSITION_DIRECTION_SAME)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration)
+ .start();
+ mHasFadeOut = !show;
+ }
+
private void finishResizeForMenu(Rect destinationBounds) {
mPipMenuController.movePipMenu(null, null, destinationBounds);
mPipMenuController.updateMenuBounds(destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 3403fb5aa940..02e713d2eaa3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -123,6 +123,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH
public void forceFinishTransition() {
}
+ /** Called when the fixed rotation started. */
+ public void onFixedRotationStarted() {
+ }
+
public PipTransitionController(PipBoundsState pipBoundsState,
PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
PipAnimationController pipAnimationController, Transitions transitions,