diff options
4 files changed, 73 insertions, 48 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt index 579a7943829e..a09720dd6a70 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt @@ -22,6 +22,7 @@ import android.app.WindowConfiguration import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager +import android.graphics.Rect import android.os.RemoteException import android.os.SystemProperties import android.util.DisplayMetrics @@ -138,6 +139,30 @@ object PipUtils { } } + + /** + * Returns a fake source rect hint for animation purposes when app-provided one is invalid. + * Resulting adjusted source rect hint lets the app icon in the content overlay to stay visible. + */ + @JvmStatic + fun getEnterPipWithOverlaySrcRectHint(appBounds: Rect, aspectRatio: Float): Rect { + val appBoundsAspRatio = appBounds.width().toFloat() / appBounds.height() + val width: Int + val height: Int + var left = 0 + var top = 0 + if (appBoundsAspRatio < aspectRatio) { + width = appBounds.width() + height = Math.round(width / aspectRatio) + top = (appBounds.height() - height) / 2 + } else { + height = appBounds.height() + width = Math.round(height * aspectRatio) + left = (appBounds.width() - width) / 2 + } + return Rect(left, top, left + width, top + height) + } + private var isPip2ExperimentEnabled: Boolean? = null /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 57c07323d1bb..0a3c15b6057f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -40,6 +40,7 @@ import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.animation.Interpolators; +import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.transition.Transitions; @@ -619,19 +620,8 @@ public class PipAnimationController { // This is done for entering case only. if (isInPipDirection(direction)) { final float aspectRatio = endValue.width() / (float) endValue.height(); - if ((startValue.width() / (float) startValue.height()) > aspectRatio) { - // use the full height. - adjustedSourceRectHint.set(0, 0, - (int) (startValue.height() * aspectRatio), startValue.height()); - adjustedSourceRectHint.offset( - (startValue.width() - adjustedSourceRectHint.width()) / 2, 0); - } else { - // use the full width. - adjustedSourceRectHint.set(0, 0, - startValue.width(), (int) (startValue.width() / aspectRatio)); - adjustedSourceRectHint.offset( - 0, (startValue.height() - adjustedSourceRectHint.height()) / 2); - } + adjustedSourceRectHint.set(PipUtils.getEnterPipWithOverlaySrcRectHint( + startValue, aspectRatio)); } } else { adjustedSourceRectHint.set(sourceRectHint); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java index 3e298e530415..895c2aeba9ef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java @@ -19,11 +19,13 @@ package com.android.wm.shell.pip2.animation; import android.animation.Animator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.content.Context; import android.view.SurfaceControl; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.wm.shell.R; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import java.lang.annotation.Retention; @@ -45,6 +47,7 @@ public class PipAlphaAnimator extends ValueAnimator implements ValueAnimator.Ani public static final int FADE_IN = 0; public static final int FADE_OUT = 1; + private final int mEnterAnimationDuration; private final SurfaceControl mLeash; private final SurfaceControl.Transaction mStartTransaction; @@ -55,7 +58,8 @@ public class PipAlphaAnimator extends ValueAnimator implements ValueAnimator.Ani private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; - public PipAlphaAnimator(SurfaceControl leash, + public PipAlphaAnimator(Context context, + SurfaceControl leash, SurfaceControl.Transaction tx, @Fade int direction) { mLeash = leash; @@ -67,6 +71,9 @@ public class PipAlphaAnimator extends ValueAnimator implements ValueAnimator.Ani } mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); + mEnterAnimationDuration = context.getResources() + .getInteger(R.integer.config_pipEnterAnimationDuration); + setDuration(mEnterAnimationDuration); addListener(this); addUpdateListener(this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 3e215d9bfa34..0b2db6cf3dd1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -293,37 +293,32 @@ public class PipTransition extends PipTransitionController implements return false; } + SurfaceControl overlayLeash = mPipTransitionState.getSwipePipToHomeOverlay(); PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams; - Rect srcRectHint = params.getSourceRectHint(); - Rect startBounds = pipChange.getStartAbsBounds(); + + Rect appBounds = mPipTransitionState.getSwipePipToHomeAppBounds(); Rect destinationBounds = pipChange.getEndAbsBounds(); + float aspectRatio = pipChange.getTaskInfo().pictureInPictureParams.getAspectRatioFloat(); + + // We fake the source rect hint when the one prvided by the app is invalid for + // the animation with an app icon overlay. + Rect animationSrcRectHint = overlayLeash == null ? params.getSourceRectHint() + : PipUtils.getEnterPipWithOverlaySrcRectHint(appBounds, aspectRatio); + WindowContainerTransaction finishWct = new WindowContainerTransaction(); SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); - if (PipBoundsAlgorithm.isSourceRectHintValidForEnterPip(srcRectHint, destinationBounds)) { - final float scale = (float) destinationBounds.width() / srcRectHint.width(); - startTransaction.setWindowCrop(pipLeash, srcRectHint); - startTransaction.setPosition(pipLeash, - destinationBounds.left - srcRectHint.left * scale, - destinationBounds.top - srcRectHint.top * scale); - - // Reset the scale in case we are in the multi-activity case. - // TO_FRONT transition already scales down the task in single-activity case, but - // in multi-activity case, reparenting yields new reset scales coming from pinned task. - startTransaction.setScale(pipLeash, scale, scale); - } else { - final float scaleX = (float) destinationBounds.width() / startBounds.width(); - final float scaleY = (float) destinationBounds.height() / startBounds.height(); + final float scale = (float) destinationBounds.width() / animationSrcRectHint.width(); + startTransaction.setWindowCrop(pipLeash, animationSrcRectHint); + startTransaction.setPosition(pipLeash, + destinationBounds.left - animationSrcRectHint.left * scale, + destinationBounds.top - animationSrcRectHint.top * scale); + startTransaction.setScale(pipLeash, scale, scale); + + if (overlayLeash != null) { final int overlaySize = PipContentOverlay.PipAppIconOverlay.getOverlaySize( mPipTransitionState.getSwipePipToHomeAppBounds(), destinationBounds); - SurfaceControl overlayLeash = mPipTransitionState.getSwipePipToHomeOverlay(); - - startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top) - .setScale(pipLeash, scaleX, scaleY) - .setWindowCrop(pipLeash, startBounds) - .reparent(overlayLeash, pipLeash) - .setLayer(overlayLeash, Integer.MAX_VALUE); // Overlay needs to be adjusted once a new draw comes in resetting surface transform. tx.setScale(overlayLeash, 1f, 1f); @@ -390,15 +385,23 @@ public class PipTransition extends PipTransitionController implements if (pipChange == null) { return false; } - // cache the PiP task token and leash - WindowContainerToken pipTaskToken = pipChange.getContainer(); - Preconditions.checkNotNull(mPipLeash, "Leash is null for alpha transition."); - // start transition with 0 alpha - startTransaction.setAlpha(mPipLeash, 0f); - PipAlphaAnimator animator = new PipAlphaAnimator(mPipLeash, - startTransaction, PipAlphaAnimator.FADE_IN); - animator.setAnimationEndCallback(() -> finishCallback.onTransitionFinished(null)); + Rect destinationBounds = pipChange.getEndAbsBounds(); + SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash; + Preconditions.checkNotNull(pipLeash, "Leash is null for alpha transition."); + + // Start transition with 0 alpha at the entry bounds. + startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top) + .setWindowCrop(pipLeash, destinationBounds.width(), destinationBounds.height()) + .setAlpha(pipLeash, 0f); + + PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction, + PipAlphaAnimator.FADE_IN); + animator.setAnimationEndCallback(() -> { + finishCallback.onTransitionFinished(null); + // This should update the pip transition state accordingly after we stop playing. + onClientDrawAtTransitionEnd(); + }); animator.start(); return true; @@ -480,10 +483,10 @@ public class PipTransition extends PipTransitionController implements private boolean isLegacyEnter(@NonNull TransitionInfo info) { TransitionInfo.Change pipChange = getPipChange(info); - // If the only change in the changes list is a TO_FRONT mode PiP task, + // If the only change in the changes list is a opening type PiP task, // then this is legacy-enter PiP. - return pipChange != null && pipChange.getMode() == TRANSIT_TO_FRONT - && info.getChanges().size() == 1; + return pipChange != null && info.getChanges().size() == 1 + && (pipChange.getMode() == TRANSIT_TO_FRONT || pipChange.getMode() == TRANSIT_OPEN); } private boolean isRemovePipTransition(@NonNull TransitionInfo info) { |