Merge "Reset the pip icon overlay scale and offset" into main
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index 850b06a0..a70a072 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -193,19 +193,12 @@
MAX_APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics());
mAppIconSizePx = Math.min(maxAppIconSizePx, appIconSizePx);
- final int appWidth = appBounds.width();
- final int appHeight = appBounds.height();
-
- // In order to have the overlay always cover the pip window during the transition, the
- // overlay will be drawn with the max size of the start and end bounds in different
- // rotation.
- final int overlaySize = Math.max(Math.max(appWidth, appHeight),
- Math.max(destinationBounds.width(), destinationBounds.height())) + 1;
+ final int overlaySize = getOverlaySize(appBounds, destinationBounds);
mOverlayHalfSize = overlaySize >> 1;
// When the activity is in the secondary split, make sure the scaling center is not
// offset.
- mAppBounds = new Rect(0, 0, appWidth, appHeight);
+ mAppBounds = new Rect(0, 0, appBounds.width(), appBounds.height());
mBitmap = Bitmap.createBitmap(overlaySize, overlaySize, Bitmap.Config.ARGB_8888);
prepareAppIconOverlay(appIcon);
@@ -215,6 +208,21 @@
.build();
}
+ /**
+ * Returns the size of the app icon overlay.
+ *
+ * In order to have the overlay always cover the pip window during the transition,
+ * the overlay will be drawn with the max size of the start and end bounds in different
+ * rotation.
+ */
+ public static int getOverlaySize(Rect appBounds, Rect destinationBounds) {
+ final int appWidth = appBounds.width();
+ final int appHeight = appBounds.height();
+
+ return Math.max(Math.max(appWidth, appHeight),
+ Math.max(destinationBounds.width(), destinationBounds.height())) + 1;
+ }
+
@Override
public void attach(SurfaceControl.Transaction tx, SurfaceControl parentLeash) {
tx.show(mLeash);
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 fe4980a..395db68 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
@@ -43,6 +43,7 @@
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import android.animation.Animator;
+import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.Context;
@@ -76,6 +77,8 @@
import com.android.wm.shell.util.TransitionUtil;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Optional;
/**
@@ -86,6 +89,18 @@
private static final String TAG = PipTransition.class.getSimpleName();
+ /** No fixed rotation, or fixed rotation state is undefined. */
+ private static final int FIXED_ROTATION_UNDEFINED = 0;
+ /**
+ * Fixed rotation detected via callbacks (see PipController#startSwipePipToHome());
+ * this is used in the swipe PiP to home case, since the transitions itself isn't supposed to
+ * see the fixed rotation.
+ */
+ private static final int FIXED_ROTATION_CALLBACK = 1;
+
+ /** Fixed rotation detected in the incoming transition. */
+ private static final int FIXED_ROTATION_TRANSITION = 2;
+
private final Context mContext;
private final PipTransitionState mPipTransitionState;
private final PipDisplayLayoutState mPipDisplayLayoutState;
@@ -106,17 +121,28 @@
/** The Task window that is currently in PIP windowing mode. */
@Nullable
private WindowContainerToken mCurrentPipTaskToken;
- /** Whether display is in fixed rotation. */
- private boolean mInFixedRotation;
+
+ @IntDef(prefix = { "FIXED_ROTATION_" }, value = {
+ FIXED_ROTATION_UNDEFINED,
+ FIXED_ROTATION_CALLBACK,
+ FIXED_ROTATION_TRANSITION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FixedRotationState {}
+
+ /** Fixed rotation state of the display. */
+ private @FixedRotationState int mFixedRotationState = FIXED_ROTATION_UNDEFINED;
/**
* The rotation that the display will apply after expanding PiP to fullscreen. This is only
- * meaningful if {@link #mInFixedRotation} is true.
+ * meaningful if {@link #mFixedRotationState} is {@link #FIXED_ROTATION_TRANSITION}.
*/
@Surface.Rotation
private int mEndFixedRotation;
/** Whether the PIP window has fade out for fixed rotation. */
private boolean mHasFadeOut;
+ private Rect mInitBounds = new Rect();
+
/** Used for setting transform to a transaction from animator. */
private final PipAnimationController.PipTransactionHandler mTransactionConsumer =
new PipAnimationController.PipTransactionHandler() {
@@ -181,8 +207,16 @@
@NonNull Transitions.TransitionFinishCallback finishCallback) {
final TransitionInfo.Change currentPipTaskChange = findCurrentPipTaskChange(info);
final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
- mInFixedRotation = fixedRotationChange != null;
- mEndFixedRotation = mInFixedRotation
+ if (mFixedRotationState == FIXED_ROTATION_TRANSITION) {
+ // If we are just about to process potential fixed rotation information,
+ // then fixed rotation state should either be UNDEFINED or CALLBACK.
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "%s: startAnimation() should start with clear fixed rotation state", TAG);
+ mFixedRotationState = FIXED_ROTATION_UNDEFINED;
+ }
+ mFixedRotationState = fixedRotationChange != null
+ ? FIXED_ROTATION_TRANSITION : mFixedRotationState;
+ mEndFixedRotation = mFixedRotationState == FIXED_ROTATION_TRANSITION
? fixedRotationChange.getEndFixedRotation()
: ROTATION_UNDEFINED;
@@ -347,6 +381,10 @@
@Override
public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
@Nullable SurfaceControl.Transaction finishT) {
+ // Transition either finished pre-emptively, got merged, or aborted,
+ // so update fixed rotation state to default.
+ mFixedRotationState = FIXED_ROTATION_UNDEFINED;
+
if (transition != mExitTransition) {
return;
}
@@ -408,7 +446,8 @@
// done at the start. But if it is running fixed rotation, there will be a seamless
// display transition later. So the last rotation transform needs to be kept to
// avoid flickering, and then the display transition will reset the transform.
- if (!mInFixedRotation && mFinishTransaction != null) {
+ if (mFixedRotationState != FIXED_ROTATION_TRANSITION
+ && mFinishTransaction != null) {
mFinishTransaction.merge(tx);
}
} else {
@@ -426,12 +465,27 @@
mSurfaceTransactionHelper.crop(tx, leash, destinationBounds)
.resetScale(tx, leash, destinationBounds)
.round(tx, leash, true /* applyCornerRadius */);
+ if (mPipOrganizer.mSwipePipToHomeOverlay != null && !mInitBounds.isEmpty()) {
+ // Resetting the scale for pinned task while re-adjusting its crop,
+ // also scales the overlay. So we need to update the overlay leash too.
+ Rect overlayBounds = new Rect(destinationBounds);
+ final int overlaySize = PipContentOverlay.PipAppIconOverlay
+ .getOverlaySize(mInitBounds, destinationBounds);
+
+ overlayBounds.offsetTo(
+ (destinationBounds.width() - overlaySize) / 2,
+ (destinationBounds.height() - overlaySize) / 2);
+ mSurfaceTransactionHelper.resetScale(tx,
+ mPipOrganizer.mSwipePipToHomeOverlay, overlayBounds);
+ }
}
+ mInitBounds.setEmpty();
wct.setBoundsChangeTransaction(taskInfo.token, tx);
}
final int displayRotation = taskInfo.getConfiguration().windowConfiguration
.getDisplayRotation();
- if (enteringPip && mInFixedRotation && mEndFixedRotation != displayRotation
+ if (enteringPip && mFixedRotationState == FIXED_ROTATION_TRANSITION
+ && mEndFixedRotation != displayRotation
&& hasValidLeash) {
// Launcher may update the Shelf height during the animation, which will update the
// destination bounds. Because this is in fixed rotation, We need to make sure the
@@ -451,6 +505,8 @@
mFinishTransaction = null;
callFinishCallback(wct);
}
+ // This is the end of transition on the Shell side so update the fixed rotation state.
+ mFixedRotationState = FIXED_ROTATION_UNDEFINED;
finishResizeForMenu(destinationBounds);
}
@@ -467,6 +523,7 @@
// mFinishCallback might be null with an outdated mCurrentPipTaskToken
// for example, when app crashes while in PiP and exit transition has not started
mCurrentPipTaskToken = null;
+ mFixedRotationState = FIXED_ROTATION_UNDEFINED;
if (mFinishCallback == null) return;
mFinishCallback.onTransitionFinished(null /* wct */);
mFinishCallback = null;
@@ -475,6 +532,9 @@
@Override
public void onFixedRotationStarted() {
+ if (mFixedRotationState == FIXED_ROTATION_UNDEFINED) {
+ mFixedRotationState = FIXED_ROTATION_CALLBACK;
+ }
fadeEnteredPipIfNeed(false /* show */);
}
@@ -656,7 +716,7 @@
// Check if it is fixed rotation.
final int rotationDelta;
- if (mInFixedRotation) {
+ if (mFixedRotationState == FIXED_ROTATION_TRANSITION) {
final int startRotation = pipChange.getStartRotation();
final int endRotation = mEndFixedRotation;
rotationDelta = deltaRotation(startRotation, endRotation);
@@ -873,11 +933,13 @@
final int startRotation = pipChange.getStartRotation();
// Check again in case some callers use startEnterAnimation directly so the flag was not
// set in startAnimation, e.g. from DefaultMixedHandler.
- if (!mInFixedRotation) {
+ if (mFixedRotationState != FIXED_ROTATION_TRANSITION) {
mEndFixedRotation = pipChange.getEndFixedRotation();
- mInFixedRotation = mEndFixedRotation != ROTATION_UNDEFINED;
+ mFixedRotationState = mEndFixedRotation != ROTATION_UNDEFINED
+ ? FIXED_ROTATION_TRANSITION : mFixedRotationState;
}
- final int endRotation = mInFixedRotation ? mEndFixedRotation : pipChange.getEndRotation();
+ final int endRotation = mFixedRotationState == FIXED_ROTATION_TRANSITION
+ ? mEndFixedRotation : pipChange.getEndRotation();
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
@@ -888,10 +950,15 @@
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final Rect currentBounds = pipChange.getStartAbsBounds();
+
+ // Cache the start bounds for overlay manipulations as a part of finishCallback.
+ mInitBounds.set(currentBounds);
+
int rotationDelta = deltaRotation(startRotation, endRotation);
Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, currentBounds, destinationBounds);
- if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
+ if (rotationDelta != Surface.ROTATION_0
+ && mFixedRotationState == FIXED_ROTATION_TRANSITION) {
// Need to get the bounds of new rotation in old rotation for fixed rotation,
computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
destinationBounds, sourceHintRect);
@@ -958,7 +1025,8 @@
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration);
- if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
+ if (rotationDelta != Surface.ROTATION_0
+ && mFixedRotationState == FIXED_ROTATION_TRANSITION) {
// 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.
@@ -997,13 +1065,17 @@
@NonNull SurfaceControl leash, @Nullable Rect sourceHintRect,
@NonNull Rect destinationBounds,
@NonNull ActivityManager.RunningTaskInfo pipTaskInfo) {
- if (mInFixedRotation) {
+ if (mFixedRotationState == FIXED_ROTATION_TRANSITION) {
// If rotation changes when returning to home, the transition should contain both the
// entering PiP and the display change (PipController#startSwipePipToHome has updated
// the display layout to new rotation). So it is not expected to see fixed rotation.
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"%s: SwipePipToHome should not use fixed rotation %d", TAG, mEndFixedRotation);
}
+ Rect appBounds = pipTaskInfo.configuration.windowConfiguration.getAppBounds();
+ if (mFixedRotationState == FIXED_ROTATION_CALLBACK && appBounds != null) {
+ mInitBounds.set(appBounds);
+ }
final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we