Loading packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +36 −26 Original line number Diff line number Diff line Loading @@ -18,16 +18,16 @@ package com.android.systemui.pip; import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.Interpolators; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -76,7 +76,6 @@ public class PipAnimationController { || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN; } private final Interpolator mFastOutSlowInInterpolator; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private PipTransitionAnimator mCurrentAnimator; Loading @@ -90,8 +89,6 @@ public class PipAnimationController { @Inject PipAnimationController(Context context, PipSurfaceTransactionHelper helper) { mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); mSurfaceTransactionHelper = helper; } Loading @@ -113,10 +110,11 @@ public class PipAnimationController { } @SuppressWarnings("unchecked") PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) { PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds, Rect sourceHintRect) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure Loading @@ -131,7 +129,7 @@ public class PipAnimationController { } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); } return mCurrentAnimator; } Loading @@ -142,7 +140,7 @@ public class PipAnimationController { private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) { animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper); animator.setInterpolator(mFastOutSlowInInterpolator); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); animator.setFloatValues(FRACTION_START, FRACTION_END); animator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get()); return animator; Loading Loading @@ -341,6 +339,7 @@ public class PipAnimationController { @Override void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) .round(tx, leash, shouldApplyCornerRadius()); tx.show(leash); Loading @@ -356,35 +355,46 @@ public class PipAnimationController { } static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, Rect startValue, Rect endValue) { Rect startValue, Rect endValue, Rect sourceHintRect) { // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialStartValue = new Rect(startValue); final Rect sourceHintRectInsets = sourceHintRect != null ? new Rect(sourceHintRect.left - startValue.left, sourceHintRect.top - startValue.top, startValue.right - sourceHintRect.right, startValue.bottom - sourceHintRect.bottom) : null; final Rect sourceInsets = new Rect(0, 0, 0, 0); // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS, endValue, new Rect(startValue), new Rect(endValue)) { private final Rect mTmpRect = new Rect(); private int getCastedFractionValue(float start, float end, float fraction) { return (int) (start * (1 - fraction) + end * fraction + .5f); } private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect()); @Override void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction) { final Rect start = getStartValue(); final Rect end = getEndValue(); mTmpRect.set( getCastedFractionValue(start.left, end.left, fraction), getCastedFractionValue(start.top, end.top, fraction), getCastedFractionValue(start.right, end.right, fraction), getCastedFractionValue(start.bottom, end.bottom, fraction)); setCurrentValue(mTmpRect); Rect bounds = mRectEvaluator.evaluate(fraction, start, end); setCurrentValue(bounds); if (inScaleTransition()) { if (isOutPipDirection(getTransitionDirection())) { getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect); getSurfaceTransactionHelper().scale(tx, leash, end, bounds); } else { getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect); getSurfaceTransactionHelper().scale(tx, leash, start, bounds); } } else { getSurfaceTransactionHelper().crop(tx, leash, mTmpRect); if (sourceHintRectInsets != null) { Rect insets = mInsetsEvaluator.evaluate(fraction, sourceInsets, sourceHintRectInsets); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialStartValue, bounds, insets); } else { getSurfaceTransactionHelper().scale(tx, leash, start, bounds); } } tx.apply(); } Loading @@ -400,11 +410,11 @@ public class PipAnimationController { @Override void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { if (!inScaleTransition()) return; // NOTE: intentionally does not apply the transaction here. // this end transaction should get executed synchronously with the final // WindowContainerTransaction in task organizer getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds()) getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()); } Loading packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +18 −0 Original line number Diff line number Diff line Loading @@ -288,6 +288,24 @@ public class PipBoundsHandler { return mDefaultAspectRatio; } /** * Updatest the display info and display layout on rotation change. This is needed even when we * aren't in PIP because the rotation layout is used to calculate the proper insets for the * next enter animation into PIP. */ public void onDisplayRotationChangedNotInPip(int toRotation) { // Update the display layout, note that we have to do this on every rotation even if we // aren't in PIP since we need to update the display layout to get the right resources mDisplayLayout.rotateTo(mContext.getResources(), toRotation); // Populate the new {@link #mDisplayInfo}. // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation, // therefore, the width/height may require a swap first. // Moving forward, we should get the new dimensions after rotation from DisplayLayout. mDisplayInfo.rotation = toRotation; updateDisplayInfoIfNeeded(); } /** * Updates the display info, calculating and returning the new stack and movement bounds in the * new orientation of the device if necessary. Loading packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java +25 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf private final float[] mTmpFloat9 = new float[9]; private final RectF mTmpSourceRectF = new RectF(); private final RectF mTmpDestinationRectF = new RectF(); private final Rect mTmpDestinationRect = new Rect(); @Inject public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) { Loading Loading @@ -90,7 +91,30 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf mTmpDestinationRectF.set(destinationBounds); mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setPosition(leash, destinationBounds.left, destinationBounds.top); .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top); return this; } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets) { mTmpSourceRectF.set(sourceBounds); mTmpDestinationRect.set(sourceBounds); mTmpDestinationRect.inset(insets); // Scale by the shortest edge and offset such that the top/left of the scaled inset source // rect aligns with the top/left of the destination bounds final float scale = sourceBounds.width() <= sourceBounds.height() ? (float) destinationBounds.width() / sourceBounds.width() : (float) destinationBounds.height() / sourceBounds.height(); final float left = destinationBounds.left - insets.left * scale; final float top = destinationBounds.top - insets.top * scale; mTmpTransform.setScale(scale, scale); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setWindowCrop(leash, mTmpDestinationRect) .setPosition(leash, left, top); return this; } Loading packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +31 −9 Original line number Diff line number Diff line Loading @@ -143,8 +143,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements case MSG_RESIZE_ANIMATE: { Rect currentBounds = (Rect) args.arg2; Rect toBounds = (Rect) args.arg3; Rect sourceHintRect = (Rect) args.arg4; int duration = args.argi2; animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration); animateResizePip(currentBounds, toBounds, sourceHintRect, args.argi1 /* direction */, duration); if (updateBoundsCallback != null) { updateBoundsCallback.accept(toBounds); } Loading Loading @@ -307,7 +309,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements public void onTransactionReady(int id, SurfaceControl.Transaction t) { t.apply(); scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, direction, animationDurationMs, null /* updateBoundsCallback */); null /* sourceHintRect */, direction, animationDurationMs, null /* updateBoundsCallback */); mInPip = false; } }); Loading Loading @@ -380,7 +383,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, final Rect sourceHintRect = getValidSourceHintRect(info, currentBounds); scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { Loading @@ -391,6 +395,21 @@ public class PipTaskOrganizer extends TaskOrganizer implements } } /** * Returns the source hint rect if it is valid (if provided and is contained by the current * task bounds). */ private Rect getValidSourceHintRect(ActivityManager.RunningTaskInfo info, Rect sourceBounds) { final Rect sourceHintRect = info.pictureInPictureParams != null && info.pictureInPictureParams.hasSourceBoundsHint() ? info.pictureInPictureParams.getSourceRectHint() : null; if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) { return sourceHintRect; } return null; } private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) { // If we are fading the PIP in, then we should move the pip to the final location as // soon as possible, but set the alpha immediately since the transaction can take a Loading Loading @@ -611,13 +630,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mLastReportedBounds, toBounds, scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); } private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer<Rect> updateBoundsCallback) { Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer<Rect> updateBoundsCallback) { if (!mInPip) { // TODO: tend to use shouldBlockResizeRequest here as well but need to consider // the fact that when in exitPip, scheduleAnimateResizePip is executed in the window Loading @@ -629,6 +648,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements args.arg1 = updateBoundsCallback; args.arg2 = currentBounds; args.arg3 = destinationBounds; args.arg4 = sourceHintRect; args.argi1 = direction; args.argi2 = durationMs; mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); Loading Loading @@ -732,7 +752,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements } final Rect destinationBounds = new Rect(originalBounds); destinationBounds.offset(xOffset, yOffset); animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs); animateResizePip(originalBounds, destinationBounds, null /* sourceHintRect */, TRANSITION_DIRECTION_SAME, durationMs); } private void resizePip(Rect destinationBounds) { Loading Loading @@ -838,7 +859,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements return WINDOWING_MODE_UNDEFINED; } private void animateResizePip(Rect currentBounds, Rect destinationBounds, private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, int durationMs) { if (Looper.myLooper() != mUpdateHandler.getLooper()) { throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of " Loading @@ -850,7 +872,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements return; } mPipAnimationController .getAnimator(mLeash, currentBounds, destinationBounds) .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect) .setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -96,7 +96,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) { // Skip if we aren't in PIP or haven't actually entered PIP yet // Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update // the display layout in the bounds handler in this case. mPipBoundsHandler.onDisplayRotationChangedNotInPip(toRotation); return; } // If there is an animation running (ie. from a shelf offset), then ensure that we calculate Loading Loading
packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +36 −26 Original line number Diff line number Diff line Loading @@ -18,16 +18,16 @@ package com.android.systemui.pip; import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.Interpolators; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -76,7 +76,6 @@ public class PipAnimationController { || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN; } private final Interpolator mFastOutSlowInInterpolator; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private PipTransitionAnimator mCurrentAnimator; Loading @@ -90,8 +89,6 @@ public class PipAnimationController { @Inject PipAnimationController(Context context, PipSurfaceTransactionHelper helper) { mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); mSurfaceTransactionHelper = helper; } Loading @@ -113,10 +110,11 @@ public class PipAnimationController { } @SuppressWarnings("unchecked") PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) { PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds, Rect sourceHintRect) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure Loading @@ -131,7 +129,7 @@ public class PipAnimationController { } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); } return mCurrentAnimator; } Loading @@ -142,7 +140,7 @@ public class PipAnimationController { private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) { animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper); animator.setInterpolator(mFastOutSlowInInterpolator); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); animator.setFloatValues(FRACTION_START, FRACTION_END); animator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get()); return animator; Loading Loading @@ -341,6 +339,7 @@ public class PipAnimationController { @Override void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) .round(tx, leash, shouldApplyCornerRadius()); tx.show(leash); Loading @@ -356,35 +355,46 @@ public class PipAnimationController { } static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, Rect startValue, Rect endValue) { Rect startValue, Rect endValue, Rect sourceHintRect) { // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialStartValue = new Rect(startValue); final Rect sourceHintRectInsets = sourceHintRect != null ? new Rect(sourceHintRect.left - startValue.left, sourceHintRect.top - startValue.top, startValue.right - sourceHintRect.right, startValue.bottom - sourceHintRect.bottom) : null; final Rect sourceInsets = new Rect(0, 0, 0, 0); // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS, endValue, new Rect(startValue), new Rect(endValue)) { private final Rect mTmpRect = new Rect(); private int getCastedFractionValue(float start, float end, float fraction) { return (int) (start * (1 - fraction) + end * fraction + .5f); } private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect()); @Override void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction) { final Rect start = getStartValue(); final Rect end = getEndValue(); mTmpRect.set( getCastedFractionValue(start.left, end.left, fraction), getCastedFractionValue(start.top, end.top, fraction), getCastedFractionValue(start.right, end.right, fraction), getCastedFractionValue(start.bottom, end.bottom, fraction)); setCurrentValue(mTmpRect); Rect bounds = mRectEvaluator.evaluate(fraction, start, end); setCurrentValue(bounds); if (inScaleTransition()) { if (isOutPipDirection(getTransitionDirection())) { getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect); getSurfaceTransactionHelper().scale(tx, leash, end, bounds); } else { getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect); getSurfaceTransactionHelper().scale(tx, leash, start, bounds); } } else { getSurfaceTransactionHelper().crop(tx, leash, mTmpRect); if (sourceHintRectInsets != null) { Rect insets = mInsetsEvaluator.evaluate(fraction, sourceInsets, sourceHintRectInsets); getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialStartValue, bounds, insets); } else { getSurfaceTransactionHelper().scale(tx, leash, start, bounds); } } tx.apply(); } Loading @@ -400,11 +410,11 @@ public class PipAnimationController { @Override void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { if (!inScaleTransition()) return; // NOTE: intentionally does not apply the transaction here. // this end transaction should get executed synchronously with the final // WindowContainerTransaction in task organizer getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds()) getSurfaceTransactionHelper() .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()); } Loading
packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +18 −0 Original line number Diff line number Diff line Loading @@ -288,6 +288,24 @@ public class PipBoundsHandler { return mDefaultAspectRatio; } /** * Updatest the display info and display layout on rotation change. This is needed even when we * aren't in PIP because the rotation layout is used to calculate the proper insets for the * next enter animation into PIP. */ public void onDisplayRotationChangedNotInPip(int toRotation) { // Update the display layout, note that we have to do this on every rotation even if we // aren't in PIP since we need to update the display layout to get the right resources mDisplayLayout.rotateTo(mContext.getResources(), toRotation); // Populate the new {@link #mDisplayInfo}. // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation, // therefore, the width/height may require a swap first. // Moving forward, we should get the new dimensions after rotation from DisplayLayout. mDisplayInfo.rotation = toRotation; updateDisplayInfoIfNeeded(); } /** * Updates the display info, calculating and returning the new stack and movement bounds in the * new orientation of the device if necessary. Loading
packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java +25 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf private final float[] mTmpFloat9 = new float[9]; private final RectF mTmpSourceRectF = new RectF(); private final RectF mTmpDestinationRectF = new RectF(); private final Rect mTmpDestinationRect = new Rect(); @Inject public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) { Loading Loading @@ -90,7 +91,30 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf mTmpDestinationRectF.set(destinationBounds); mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setPosition(leash, destinationBounds.left, destinationBounds.top); .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top); return this; } /** * Operates the scale (setMatrix) on a given transaction and leash * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets) { mTmpSourceRectF.set(sourceBounds); mTmpDestinationRect.set(sourceBounds); mTmpDestinationRect.inset(insets); // Scale by the shortest edge and offset such that the top/left of the scaled inset source // rect aligns with the top/left of the destination bounds final float scale = sourceBounds.width() <= sourceBounds.height() ? (float) destinationBounds.width() / sourceBounds.width() : (float) destinationBounds.height() / sourceBounds.height(); final float left = destinationBounds.left - insets.left * scale; final float top = destinationBounds.top - insets.top * scale; mTmpTransform.setScale(scale, scale); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) .setWindowCrop(leash, mTmpDestinationRect) .setPosition(leash, left, top); return this; } Loading
packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +31 −9 Original line number Diff line number Diff line Loading @@ -143,8 +143,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements case MSG_RESIZE_ANIMATE: { Rect currentBounds = (Rect) args.arg2; Rect toBounds = (Rect) args.arg3; Rect sourceHintRect = (Rect) args.arg4; int duration = args.argi2; animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration); animateResizePip(currentBounds, toBounds, sourceHintRect, args.argi1 /* direction */, duration); if (updateBoundsCallback != null) { updateBoundsCallback.accept(toBounds); } Loading Loading @@ -307,7 +309,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements public void onTransactionReady(int id, SurfaceControl.Transaction t) { t.apply(); scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, direction, animationDurationMs, null /* updateBoundsCallback */); null /* sourceHintRect */, direction, animationDurationMs, null /* updateBoundsCallback */); mInPip = false; } }); Loading Loading @@ -380,7 +383,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, final Rect sourceHintRect = getValidSourceHintRect(info, currentBounds); scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { Loading @@ -391,6 +395,21 @@ public class PipTaskOrganizer extends TaskOrganizer implements } } /** * Returns the source hint rect if it is valid (if provided and is contained by the current * task bounds). */ private Rect getValidSourceHintRect(ActivityManager.RunningTaskInfo info, Rect sourceBounds) { final Rect sourceHintRect = info.pictureInPictureParams != null && info.pictureInPictureParams.hasSourceBoundsHint() ? info.pictureInPictureParams.getSourceRectHint() : null; if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) { return sourceHintRect; } return null; } private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) { // If we are fading the PIP in, then we should move the pip to the final location as // soon as possible, but set the alpha immediately since the transaction can take a Loading Loading @@ -611,13 +630,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mLastReportedBounds, toBounds, scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); } private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer<Rect> updateBoundsCallback) { Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer<Rect> updateBoundsCallback) { if (!mInPip) { // TODO: tend to use shouldBlockResizeRequest here as well but need to consider // the fact that when in exitPip, scheduleAnimateResizePip is executed in the window Loading @@ -629,6 +648,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements args.arg1 = updateBoundsCallback; args.arg2 = currentBounds; args.arg3 = destinationBounds; args.arg4 = sourceHintRect; args.argi1 = direction; args.argi2 = durationMs; mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); Loading Loading @@ -732,7 +752,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements } final Rect destinationBounds = new Rect(originalBounds); destinationBounds.offset(xOffset, yOffset); animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs); animateResizePip(originalBounds, destinationBounds, null /* sourceHintRect */, TRANSITION_DIRECTION_SAME, durationMs); } private void resizePip(Rect destinationBounds) { Loading Loading @@ -838,7 +859,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements return WINDOWING_MODE_UNDEFINED; } private void animateResizePip(Rect currentBounds, Rect destinationBounds, private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, int durationMs) { if (Looper.myLooper() != mUpdateHandler.getLooper()) { throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of " Loading @@ -850,7 +872,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements return; } mPipAnimationController .getAnimator(mLeash, currentBounds, destinationBounds) .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect) .setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -96,7 +96,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) { // Skip if we aren't in PIP or haven't actually entered PIP yet // Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update // the display layout in the bounds handler in this case. mPipBoundsHandler.onDisplayRotationChangedNotInPip(toRotation); return; } // If there is an animation running (ie. from a shelf offset), then ensure that we calculate Loading