Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java +24 −15 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.shared.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; Loading Loading @@ -170,26 +171,34 @@ public abstract class PipContentOverlay { private final Context mContext; private final int mAppIconSizePx; private final Rect mAppBounds; /** * The bounds of the application window relative to the task leash. */ private final Rect mRelativeAppBounds; private final int mOverlayHalfSize; private final Matrix mTmpTransform = new Matrix(); private final float[] mTmpFloat9 = new float[9]; private Bitmap mBitmap; public PipAppIconOverlay(Context context, Rect appBounds, Rect destinationBounds, Drawable appIcon, int appIconSizePx) { // TODO(b/356277166): add non-match_parent support on PIP2. /** * @param context the {@link Context} that contains the icon information * @param relativeAppBounds the bounds of the app window frame relative to the task leash * @param destinationBounds the bounds for rhe PIP task * @param appIcon the app icon {@link Drawable} * @param appIconSizePx the icon dimension in pixel */ public PipAppIconOverlay(@NonNull Context context, @NonNull Rect relativeAppBounds, @NonNull Rect destinationBounds, @NonNull Drawable appIcon, int appIconSizePx) { mContext = context; final int maxAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, MAX_APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics()); mAppIconSizePx = Math.min(maxAppIconSizePx, appIconSizePx); final int overlaySize = getOverlaySize(appBounds, destinationBounds); final int overlaySize = getOverlaySize(relativeAppBounds, 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, appBounds.width(), appBounds.height()); mRelativeAppBounds = relativeAppBounds; mBitmap = Bitmap.createBitmap(overlaySize, overlaySize, Bitmap.Config.ARGB_8888); prepareAppIconOverlay(appIcon); Loading @@ -206,9 +215,9 @@ public abstract class PipContentOverlay { * 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(); public static int getOverlaySize(Rect overlayBounds, Rect destinationBounds) { final int appWidth = overlayBounds.width(); final int appHeight = overlayBounds.height(); return Math.max(Math.max(appWidth, appHeight), Math.max(destinationBounds.width(), destinationBounds.height())) + 1; Loading @@ -230,15 +239,15 @@ public abstract class PipContentOverlay { mTmpTransform.reset(); // In order for the overlay to always cover the pip window, the overlay may have a // size larger than the pip window. Make sure that app icon is at the center. final int appBoundsCenterX = mAppBounds.centerX(); final int appBoundsCenterY = mAppBounds.centerY(); final int appBoundsCenterX = mRelativeAppBounds.centerX(); final int appBoundsCenterY = mRelativeAppBounds.centerY(); mTmpTransform.setTranslate( appBoundsCenterX - mOverlayHalfSize, appBoundsCenterY - mOverlayHalfSize); // Scale back the bitmap with the pivot point at center. final float scale = Math.min( (float) mAppBounds.width() / currentBounds.width(), (float) mAppBounds.height() / currentBounds.height()); (float) mRelativeAppBounds.width() / currentBounds.width(), (float) mRelativeAppBounds.height() / currentBounds.height()); mTmpTransform.postScale(scale, scale, appBoundsCenterX, appBoundsCenterY); atomicTx.setMatrix(mLeash, mTmpTransform, mTmpFloat9) .setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +61 −18 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.app.TaskInfo; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; import android.view.Surface; Loading Loading @@ -152,7 +153,6 @@ public class PipAnimationController { return mCurrentAnimator; } @SuppressWarnings("unchecked") /** * Construct and return an animator that animates from the {@param startBounds} to the * {@param endBounds} with the given {@param direction}. If {@param direction} is type Loading @@ -171,6 +171,7 @@ public class PipAnimationController { * leaving PiP to fullscreen, and the {@param endBounds} is the fullscreen bounds before the * rotation change. */ @SuppressWarnings("unchecked") @VisibleForTesting public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, Loading Loading @@ -566,7 +567,7 @@ public class PipAnimationController { } getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) .cropAndPosition(tx, leash, getDestinationBounds()) .round(tx, leash, true /* applyCornerRadius */) .shadow(tx, leash, shouldApplyShadowRadius()); tx.show(leash); Loading @@ -590,18 +591,50 @@ public class PipAnimationController { // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialSourceValue; final Rect mainWindowFrame = taskInfo.topActivityMainWindowFrame; final boolean hasNonMatchFrame = mainWindowFrame != null; final boolean changeOrientation = rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270; final Rect baseBounds = new Rect(baseValue); final Rect startBounds = new Rect(startValue); final Rect endBounds = new Rect(endValue); if (isOutPipDirection) { initialSourceValue = new Rect(endValue); // TODO(b/356277166): handle rotation change with activity that provides main window // frame. if (hasNonMatchFrame && !changeOrientation) { endBounds.set(mainWindowFrame); } initialSourceValue = new Rect(endBounds); } else if (isInPipDirection) { if (hasNonMatchFrame) { baseBounds.set(mainWindowFrame); if (startValue.equals(baseValue)) { // If the start value is at initial state as in PIP animation, also override // the start bounds with nonMatchParentBounds. startBounds.set(mainWindowFrame); } } initialSourceValue = new Rect(baseBounds); } else { initialSourceValue = new Rect(baseValue); // Note that we assume the window bounds always match task bounds in PIP mode. initialSourceValue = new Rect(baseBounds); } final Point leashOffset; if (isInPipDirection) { leashOffset = new Point(baseValue.left, baseValue.top); } else if (isOutPipDirection) { leashOffset = new Point(endValue.left, endValue.top); } else { leashOffset = new Point(baseValue.left, baseValue.top); } final Rect rotatedEndRect; final Rect lastEndRect; final Rect initialContainerRect; if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { lastEndRect = new Rect(endValue); rotatedEndRect = new Rect(endValue); if (changeOrientation) { lastEndRect = new Rect(endBounds); rotatedEndRect = new Rect(endBounds); // Rotate the end bounds according to the rotation delta because the display will // be rotated to the same orientation. rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); Loading @@ -617,9 +650,9 @@ public class PipAnimationController { // Crop a Rect matches the aspect ratio and pivots at the center point. // This is done for entering case only. if (isInPipDirection(direction)) { final float aspectRatio = endValue.width() / (float) endValue.height(); final float aspectRatio = endBounds.width() / (float) endBounds.height(); adjustedSourceRectHint.set(PipUtils.getEnterPipWithOverlaySrcRectHint( startValue, aspectRatio)); startBounds, aspectRatio)); } } else { adjustedSourceRectHint.set(sourceRectHint); Loading @@ -644,7 +677,7 @@ public class PipAnimationController { // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue)) { endBounds, new Rect(baseBounds), new Rect(startBounds), new Rect(endBounds)) { private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect()); Loading @@ -668,11 +701,22 @@ public class PipAnimationController { setCurrentValue(bounds); if (inScaleTransition() || adjustedSourceRectHint.isEmpty()) { if (isOutPipDirection) { getSurfaceTransactionHelper().crop(tx, leash, end) .scale(tx, leash, end, bounds); // Use the bounds relative to the task leash in case the leash does not // start from (0, 0). final Rect relativeEndBounds = new Rect(end); relativeEndBounds.offset(-leashOffset.x, -leashOffset.y); getSurfaceTransactionHelper() .crop(tx, leash, relativeEndBounds) .scale(tx, leash, relativeEndBounds, bounds, false /* shouldOffset */); } else { getSurfaceTransactionHelper().crop(tx, leash, base) .scale(tx, leash, base, bounds, angle) // TODO(b/356277166): add support to specify sourceRectHint with // non-match parent activity. // If there's a PIP resize animation, we should offset the bounds to // (0, 0) since the window bounds should match the leash bounds in PIP // mode. getSurfaceTransactionHelper().cropAndPosition(tx, leash, base) .scale(tx, leash, base, bounds, angle, inScaleTransition()) .round(tx, leash, base, bounds) .shadow(tx, leash, shouldApplyShadowRadius()); } Loading @@ -680,7 +724,7 @@ public class PipAnimationController { final Rect insets = computeInsets(fraction); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, adjustedSourceRectHint, initialSourceValue, bounds, insets, isInPipDirection, fraction); isInPipDirection, fraction, leashOffset); final Rect sourceBounds = new Rect(initialContainerRect); sourceBounds.inset(insets); getSurfaceTransactionHelper() Loading Loading @@ -733,8 +777,7 @@ public class PipAnimationController { getSurfaceTransactionHelper() .rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds, insets, degree, x, y, isOutPipDirection, rotationDelta == ROTATION_270 /* clockwise */); getSurfaceTransactionHelper() rotationDelta == ROTATION_270 /* clockwise */) .round(tx, leash, sourceBounds, bounds) .shadow(tx, leash, shouldApplyShadowRadius()); if (!handlePipTransaction(leash, tx, bounds, 1f /* alpha */)) { Loading Loading @@ -772,7 +815,7 @@ public class PipAnimationController { tx.setPosition(leash, 0, 0); tx.setWindowCrop(leash, 0, 0); } else { getSurfaceTransactionHelper().crop(tx, leash, destBounds); getSurfaceTransactionHelper().cropAndPosition(tx, leash, destBounds); } if (mContentOverlay != null) { clearContentOverlay(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +79 −25 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package com.android.wm.shell.pip; import android.annotation.NonNull; import android.content.Context; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.view.Choreographer; Loading Loading @@ -68,13 +70,28 @@ public class PipSurfaceTransactionHelper { * Operates the crop (and position) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds) { public PipSurfaceTransactionHelper cropAndPosition(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect destinationBounds) { tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height()) .setPosition(leash, destinationBounds.left, destinationBounds.top); return this; } /** * Operates {@link SurfaceControl.Transaction#setCrop} on a given transaction and leash. * * @param tx the transaction to apply * @param leash the leash to crop * @param relativeDestinationBounds the bounds to crop, which is relative to the leash * coordinate * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper crop(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect relativeDestinationBounds) { tx.setCrop(leash, relativeDestinationBounds); return this; } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining Loading @@ -82,38 +99,73 @@ public class PipSurfaceTransactionHelper { public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, RectF destinationBounds) { return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */); public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull RectF destinationBounds) { return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash * Operates the scale (setMatrix) on a given transaction and leash. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees) { public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, boolean shouldOffset) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */, shouldOffset); } /** * Operates the scale (setMatrix) on a given transaction and leash. * * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, float degrees) { return scale(tx, leash, sourceBounds, destinationBounds, degrees, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, float degrees, boolean shouldOffset) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees, shouldOffset); } /** * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, RectF destinationBounds, float degrees) { public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull RectF destinationBounds, float degrees, boolean shouldOffset) { mTmpSourceRectF.set(sourceBounds); // We want the matrix to position the surface relative to the screen coordinates so offset // the source to 0,0 // the source to (0, 0) if {@code shouldOffset} is true. if (shouldOffset) { mTmpSourceRectF.offsetTo(0, 0); } mTmpDestinationRectF.set(destinationBounds); mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); mTmpTransform.postRotate(degrees, Loading @@ -123,17 +175,19 @@ public class PipSurfaceTransactionHelper { } /** * Operates the scale (setMatrix) on a given transaction and leash * Operates the scale (setMatrix) on a given transaction and leash. * * @param leashOffset the offset of the leash bounds relative to the screen coordinate * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceRectHint, Rect sourceBounds, Rect destinationBounds, Rect insets, boolean isInPipDirection, float fraction) { public PipSurfaceTransactionHelper scaleAndCrop(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceRectHint, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, @NonNull Rect insets, boolean isInPipDirection, float fraction, @NonNull Point leashOffset) { mTmpDestinationRect.set(sourceBounds); // Similar to {@link #scale}, we want to position the surface relative to the screen // coordinates so offset the bounds to 0,0 mTmpDestinationRect.offsetTo(0, 0); // coordinates so offset the bounds relative to the leash. mTmpDestinationRect.offset(-leashOffset.x, -leashOffset.y); mTmpDestinationRect.inset(insets); // Scale to the bounds no smaller than the destination and offset such that the top/left // of the scaled inset source rect aligns with the top/left of the destination bounds Loading @@ -152,13 +206,13 @@ public class PipSurfaceTransactionHelper { scale = Math.max((float) destinationBounds.width() / sourceBounds.width(), (float) destinationBounds.height() / sourceBounds.height()); } float left = destinationBounds.left - insets.left * scale; float top = destinationBounds.top - insets.top * scale; float left = destinationBounds.left - mTmpDestinationRect.left * scale; float top = destinationBounds.top - mTmpDestinationRect.top * scale; if (scale == 1) { // Work around the 1 pixel off error by rounding the position down at very beginning. // We noticed such error from flicker tests, not visually. left = sourceBounds.left; top = sourceBounds.top; left = leashOffset.x; top = leashOffset.y; } mTmpTransform.setScale(scale, scale); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +4 −4 Original line number Diff line number Diff line Loading @@ -960,7 +960,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final SurfaceControl.Transaction boundsChangeTx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(boundsChangeTx, mLeash, destinationBounds) .cropAndPosition(boundsChangeTx, mLeash, destinationBounds) .round(boundsChangeTx, mLeash, true /* applyCornerRadius */); mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED); Loading Loading @@ -988,7 +988,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .resetScale(tx, mLeash, destinationBounds) .crop(tx, mLeash, destinationBounds) .cropAndPosition(tx, mLeash, destinationBounds) .round(tx, mLeash, isInPip()); // The animation is finished in the Launcher and here we directly apply the final touch. applyEnterPipSyncTransaction(destinationBounds, () -> { Loading Loading @@ -1525,7 +1525,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipBoundsState.setBounds(toBounds); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .cropAndPosition(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); Loading Loading @@ -1628,7 +1628,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, Rect destinationBounds) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(tx, mLeash, destinationBounds) .cropAndPosition(tx, mLeash, destinationBounds) .resetScale(tx, mLeash, destinationBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); return tx; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +16 −8 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/pip/PipContentOverlay.java +24 −15 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.shared.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; Loading Loading @@ -170,26 +171,34 @@ public abstract class PipContentOverlay { private final Context mContext; private final int mAppIconSizePx; private final Rect mAppBounds; /** * The bounds of the application window relative to the task leash. */ private final Rect mRelativeAppBounds; private final int mOverlayHalfSize; private final Matrix mTmpTransform = new Matrix(); private final float[] mTmpFloat9 = new float[9]; private Bitmap mBitmap; public PipAppIconOverlay(Context context, Rect appBounds, Rect destinationBounds, Drawable appIcon, int appIconSizePx) { // TODO(b/356277166): add non-match_parent support on PIP2. /** * @param context the {@link Context} that contains the icon information * @param relativeAppBounds the bounds of the app window frame relative to the task leash * @param destinationBounds the bounds for rhe PIP task * @param appIcon the app icon {@link Drawable} * @param appIconSizePx the icon dimension in pixel */ public PipAppIconOverlay(@NonNull Context context, @NonNull Rect relativeAppBounds, @NonNull Rect destinationBounds, @NonNull Drawable appIcon, int appIconSizePx) { mContext = context; final int maxAppIconSizePx = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, MAX_APP_ICON_SIZE_DP, context.getResources().getDisplayMetrics()); mAppIconSizePx = Math.min(maxAppIconSizePx, appIconSizePx); final int overlaySize = getOverlaySize(appBounds, destinationBounds); final int overlaySize = getOverlaySize(relativeAppBounds, 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, appBounds.width(), appBounds.height()); mRelativeAppBounds = relativeAppBounds; mBitmap = Bitmap.createBitmap(overlaySize, overlaySize, Bitmap.Config.ARGB_8888); prepareAppIconOverlay(appIcon); Loading @@ -206,9 +215,9 @@ public abstract class PipContentOverlay { * 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(); public static int getOverlaySize(Rect overlayBounds, Rect destinationBounds) { final int appWidth = overlayBounds.width(); final int appHeight = overlayBounds.height(); return Math.max(Math.max(appWidth, appHeight), Math.max(destinationBounds.width(), destinationBounds.height())) + 1; Loading @@ -230,15 +239,15 @@ public abstract class PipContentOverlay { mTmpTransform.reset(); // In order for the overlay to always cover the pip window, the overlay may have a // size larger than the pip window. Make sure that app icon is at the center. final int appBoundsCenterX = mAppBounds.centerX(); final int appBoundsCenterY = mAppBounds.centerY(); final int appBoundsCenterX = mRelativeAppBounds.centerX(); final int appBoundsCenterY = mRelativeAppBounds.centerY(); mTmpTransform.setTranslate( appBoundsCenterX - mOverlayHalfSize, appBoundsCenterY - mOverlayHalfSize); // Scale back the bitmap with the pivot point at center. final float scale = Math.min( (float) mAppBounds.width() / currentBounds.width(), (float) mAppBounds.height() / currentBounds.height()); (float) mRelativeAppBounds.width() / currentBounds.width(), (float) mRelativeAppBounds.height() / currentBounds.height()); mTmpTransform.postScale(scale, scale, appBoundsCenterX, appBoundsCenterY); atomicTx.setMatrix(mLeash, mTmpTransform, mTmpFloat9) .setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +61 −18 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.app.TaskInfo; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; import android.view.Surface; Loading Loading @@ -152,7 +153,6 @@ public class PipAnimationController { return mCurrentAnimator; } @SuppressWarnings("unchecked") /** * Construct and return an animator that animates from the {@param startBounds} to the * {@param endBounds} with the given {@param direction}. If {@param direction} is type Loading @@ -171,6 +171,7 @@ public class PipAnimationController { * leaving PiP to fullscreen, and the {@param endBounds} is the fullscreen bounds before the * rotation change. */ @SuppressWarnings("unchecked") @VisibleForTesting public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, Loading Loading @@ -566,7 +567,7 @@ public class PipAnimationController { } getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) .cropAndPosition(tx, leash, getDestinationBounds()) .round(tx, leash, true /* applyCornerRadius */) .shadow(tx, leash, shouldApplyShadowRadius()); tx.show(leash); Loading @@ -590,18 +591,50 @@ public class PipAnimationController { // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialSourceValue; final Rect mainWindowFrame = taskInfo.topActivityMainWindowFrame; final boolean hasNonMatchFrame = mainWindowFrame != null; final boolean changeOrientation = rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270; final Rect baseBounds = new Rect(baseValue); final Rect startBounds = new Rect(startValue); final Rect endBounds = new Rect(endValue); if (isOutPipDirection) { initialSourceValue = new Rect(endValue); // TODO(b/356277166): handle rotation change with activity that provides main window // frame. if (hasNonMatchFrame && !changeOrientation) { endBounds.set(mainWindowFrame); } initialSourceValue = new Rect(endBounds); } else if (isInPipDirection) { if (hasNonMatchFrame) { baseBounds.set(mainWindowFrame); if (startValue.equals(baseValue)) { // If the start value is at initial state as in PIP animation, also override // the start bounds with nonMatchParentBounds. startBounds.set(mainWindowFrame); } } initialSourceValue = new Rect(baseBounds); } else { initialSourceValue = new Rect(baseValue); // Note that we assume the window bounds always match task bounds in PIP mode. initialSourceValue = new Rect(baseBounds); } final Point leashOffset; if (isInPipDirection) { leashOffset = new Point(baseValue.left, baseValue.top); } else if (isOutPipDirection) { leashOffset = new Point(endValue.left, endValue.top); } else { leashOffset = new Point(baseValue.left, baseValue.top); } final Rect rotatedEndRect; final Rect lastEndRect; final Rect initialContainerRect; if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { lastEndRect = new Rect(endValue); rotatedEndRect = new Rect(endValue); if (changeOrientation) { lastEndRect = new Rect(endBounds); rotatedEndRect = new Rect(endBounds); // Rotate the end bounds according to the rotation delta because the display will // be rotated to the same orientation. rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); Loading @@ -617,9 +650,9 @@ public class PipAnimationController { // Crop a Rect matches the aspect ratio and pivots at the center point. // This is done for entering case only. if (isInPipDirection(direction)) { final float aspectRatio = endValue.width() / (float) endValue.height(); final float aspectRatio = endBounds.width() / (float) endBounds.height(); adjustedSourceRectHint.set(PipUtils.getEnterPipWithOverlaySrcRectHint( startValue, aspectRatio)); startBounds, aspectRatio)); } } else { adjustedSourceRectHint.set(sourceRectHint); Loading @@ -644,7 +677,7 @@ public class PipAnimationController { // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue)) { endBounds, new Rect(baseBounds), new Rect(startBounds), new Rect(endBounds)) { private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect()); Loading @@ -668,11 +701,22 @@ public class PipAnimationController { setCurrentValue(bounds); if (inScaleTransition() || adjustedSourceRectHint.isEmpty()) { if (isOutPipDirection) { getSurfaceTransactionHelper().crop(tx, leash, end) .scale(tx, leash, end, bounds); // Use the bounds relative to the task leash in case the leash does not // start from (0, 0). final Rect relativeEndBounds = new Rect(end); relativeEndBounds.offset(-leashOffset.x, -leashOffset.y); getSurfaceTransactionHelper() .crop(tx, leash, relativeEndBounds) .scale(tx, leash, relativeEndBounds, bounds, false /* shouldOffset */); } else { getSurfaceTransactionHelper().crop(tx, leash, base) .scale(tx, leash, base, bounds, angle) // TODO(b/356277166): add support to specify sourceRectHint with // non-match parent activity. // If there's a PIP resize animation, we should offset the bounds to // (0, 0) since the window bounds should match the leash bounds in PIP // mode. getSurfaceTransactionHelper().cropAndPosition(tx, leash, base) .scale(tx, leash, base, bounds, angle, inScaleTransition()) .round(tx, leash, base, bounds) .shadow(tx, leash, shouldApplyShadowRadius()); } Loading @@ -680,7 +724,7 @@ public class PipAnimationController { final Rect insets = computeInsets(fraction); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, adjustedSourceRectHint, initialSourceValue, bounds, insets, isInPipDirection, fraction); isInPipDirection, fraction, leashOffset); final Rect sourceBounds = new Rect(initialContainerRect); sourceBounds.inset(insets); getSurfaceTransactionHelper() Loading Loading @@ -733,8 +777,7 @@ public class PipAnimationController { getSurfaceTransactionHelper() .rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds, insets, degree, x, y, isOutPipDirection, rotationDelta == ROTATION_270 /* clockwise */); getSurfaceTransactionHelper() rotationDelta == ROTATION_270 /* clockwise */) .round(tx, leash, sourceBounds, bounds) .shadow(tx, leash, shouldApplyShadowRadius()); if (!handlePipTransaction(leash, tx, bounds, 1f /* alpha */)) { Loading Loading @@ -772,7 +815,7 @@ public class PipAnimationController { tx.setPosition(leash, 0, 0); tx.setWindowCrop(leash, 0, 0); } else { getSurfaceTransactionHelper().crop(tx, leash, destBounds); getSurfaceTransactionHelper().cropAndPosition(tx, leash, destBounds); } if (mContentOverlay != null) { clearContentOverlay(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +79 −25 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package com.android.wm.shell.pip; import android.annotation.NonNull; import android.content.Context; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.view.Choreographer; Loading Loading @@ -68,13 +70,28 @@ public class PipSurfaceTransactionHelper { * Operates the crop (and position) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds) { public PipSurfaceTransactionHelper cropAndPosition(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect destinationBounds) { tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height()) .setPosition(leash, destinationBounds.left, destinationBounds.top); return this; } /** * Operates {@link SurfaceControl.Transaction#setCrop} on a given transaction and leash. * * @param tx the transaction to apply * @param leash the leash to crop * @param relativeDestinationBounds the bounds to crop, which is relative to the leash * coordinate * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper crop(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect relativeDestinationBounds) { tx.setCrop(leash, relativeDestinationBounds); return this; } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining Loading @@ -82,38 +99,73 @@ public class PipSurfaceTransactionHelper { public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, RectF destinationBounds) { return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */); public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull RectF destinationBounds) { return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash * Operates the scale (setMatrix) on a given transaction and leash. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees) { public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, boolean shouldOffset) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */, shouldOffset); } /** * Operates the scale (setMatrix) on a given transaction and leash. * * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, float degrees) { return scale(tx, leash, sourceBounds, destinationBounds, degrees, true /* shouldOffset */); } /** * Operates the scale (setMatrix) on a given transaction and leash. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, float degrees, boolean shouldOffset) { mTmpDestinationRectF.set(destinationBounds); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees); return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees, shouldOffset); } /** * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation. * * @param shouldOffset {@code true} to offset the leash to (0, 0) * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, RectF destinationBounds, float degrees) { public PipSurfaceTransactionHelper scale(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceBounds, @NonNull RectF destinationBounds, float degrees, boolean shouldOffset) { mTmpSourceRectF.set(sourceBounds); // We want the matrix to position the surface relative to the screen coordinates so offset // the source to 0,0 // the source to (0, 0) if {@code shouldOffset} is true. if (shouldOffset) { mTmpSourceRectF.offsetTo(0, 0); } mTmpDestinationRectF.set(destinationBounds); mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); mTmpTransform.postRotate(degrees, Loading @@ -123,17 +175,19 @@ public class PipSurfaceTransactionHelper { } /** * Operates the scale (setMatrix) on a given transaction and leash * Operates the scale (setMatrix) on a given transaction and leash. * * @param leashOffset the offset of the leash bounds relative to the screen coordinate * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceRectHint, Rect sourceBounds, Rect destinationBounds, Rect insets, boolean isInPipDirection, float fraction) { public PipSurfaceTransactionHelper scaleAndCrop(@NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, @NonNull Rect sourceRectHint, @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, @NonNull Rect insets, boolean isInPipDirection, float fraction, @NonNull Point leashOffset) { mTmpDestinationRect.set(sourceBounds); // Similar to {@link #scale}, we want to position the surface relative to the screen // coordinates so offset the bounds to 0,0 mTmpDestinationRect.offsetTo(0, 0); // coordinates so offset the bounds relative to the leash. mTmpDestinationRect.offset(-leashOffset.x, -leashOffset.y); mTmpDestinationRect.inset(insets); // Scale to the bounds no smaller than the destination and offset such that the top/left // of the scaled inset source rect aligns with the top/left of the destination bounds Loading @@ -152,13 +206,13 @@ public class PipSurfaceTransactionHelper { scale = Math.max((float) destinationBounds.width() / sourceBounds.width(), (float) destinationBounds.height() / sourceBounds.height()); } float left = destinationBounds.left - insets.left * scale; float top = destinationBounds.top - insets.top * scale; float left = destinationBounds.left - mTmpDestinationRect.left * scale; float top = destinationBounds.top - mTmpDestinationRect.top * scale; if (scale == 1) { // Work around the 1 pixel off error by rounding the position down at very beginning. // We noticed such error from flicker tests, not visually. left = sourceBounds.left; top = sourceBounds.top; left = leashOffset.x; top = leashOffset.y; } mTmpTransform.setScale(scale, scale); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +4 −4 Original line number Diff line number Diff line Loading @@ -960,7 +960,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final SurfaceControl.Transaction boundsChangeTx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(boundsChangeTx, mLeash, destinationBounds) .cropAndPosition(boundsChangeTx, mLeash, destinationBounds) .round(boundsChangeTx, mLeash, true /* applyCornerRadius */); mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED); Loading Loading @@ -988,7 +988,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .resetScale(tx, mLeash, destinationBounds) .crop(tx, mLeash, destinationBounds) .cropAndPosition(tx, mLeash, destinationBounds) .round(tx, mLeash, isInPip()); // The animation is finished in the Launcher and here we directly apply the final touch. applyEnterPipSyncTransaction(destinationBounds, () -> { Loading Loading @@ -1525,7 +1525,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mPipBoundsState.setBounds(toBounds); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .cropAndPosition(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); Loading Loading @@ -1628,7 +1628,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, Rect destinationBounds) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper .crop(tx, mLeash, destinationBounds) .cropAndPosition(tx, mLeash, destinationBounds) .resetScale(tx, mLeash, destinationBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); return tx; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +16 −8 File changed.Preview size limit exceeded, changes collapsed. Show changes