Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java +52 −6 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.view.Surface; import android.view.SurfaceControl; import androidx.annotation.NonNull; Loading Loading @@ -51,8 +52,10 @@ public class PipEnterExitAnimator extends ValueAnimator @NonNull private final SurfaceControl mLeash; private final SurfaceControl.Transaction mStartTransaction; private final int mEnterAnimationDuration; private final SurfaceControl.Transaction mFinishTransaction; private final int mEnterExitAnimationDuration; private final @BOUNDS int mDirection; private final @Surface.Rotation int mRotation; // optional callbacks for tracking animation start and end @Nullable private Runnable mAnimationStartCallback; Loading @@ -62,37 +65,59 @@ public class PipEnterExitAnimator extends ValueAnimator private final Rect mStartBounds = new Rect(); private final Rect mEndBounds = new Rect(); @Nullable private final Rect mSourceRectHint; private final Rect mSourceRectHintInsets = new Rect(); private final Rect mZeroInsets = new Rect(0, 0, 0, 0); // Bounds updated by the evaluator as animator is running. private final Rect mAnimatedRect = new Rect(); private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; private final RectEvaluator mRectEvaluator; private final RectEvaluator mInsetEvaluator; private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; public PipEnterExitAnimator(Context context, @NonNull SurfaceControl leash, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, @NonNull Rect baseBounds, @NonNull Rect startBounds, @NonNull Rect endBounds, @BOUNDS int direction) { @Nullable Rect sourceRectHint, @BOUNDS int direction, @Surface.Rotation int rotation) { mLeash = leash; mStartTransaction = startTransaction; mFinishTransaction = finishTransaction; mBaseBounds.set(baseBounds); mStartBounds.set(startBounds); mAnimatedRect.set(startBounds); mEndBounds.set(endBounds); mRectEvaluator = new RectEvaluator(mAnimatedRect); mInsetEvaluator = new RectEvaluator(new Rect()); mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context); mDirection = direction; mRotation = rotation; mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null; if (mSourceRectHint != null) { mSourceRectHintInsets.set( mSourceRectHint.left - mBaseBounds.left, mSourceRectHint.top - mBaseBounds.top, mBaseBounds.right - mSourceRectHint.right, mBaseBounds.bottom - mSourceRectHint.bottom ); } mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); mEnterAnimationDuration = context.getResources() mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipEnterAnimationDuration); setDuration(mEnterAnimationDuration); setObjectValues(startBounds, endBounds); setDuration(mEnterExitAnimationDuration); setEvaluator(mRectEvaluator); addListener(this); addUpdateListener(this); Loading @@ -118,6 +143,14 @@ public class PipEnterExitAnimator extends ValueAnimator @Override public void onAnimationEnd(@NonNull Animator animation) { if (mFinishTransaction != null) { // finishTransaction might override some state (eg. corner radii) so we want to // manually set the state to the end of the animation mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash, mSourceRectHint, mBaseBounds, mAnimatedRect, getInsets(1f), isInPipDirection(), 1f) .round(mFinishTransaction, mLeash, isInPipDirection()) .shadow(mFinishTransaction, mLeash, isInPipDirection()); } if (mAnimationEndCallback != null) { mAnimationEndCallback.run(); } Loading @@ -127,19 +160,32 @@ public class PipEnterExitAnimator extends ValueAnimator public void onAnimationUpdate(@NonNull ValueAnimator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); final float fraction = getAnimatedFraction(); Rect insets = getInsets(fraction); // TODO (b/350801661): implement fixed rotation mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, null, mBaseBounds, mAnimatedRect, null, isInPipDirection(), fraction) mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint, mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction) .round(tx, mLeash, isInPipDirection()) .shadow(tx, mLeash, isInPipDirection()); tx.apply(); } private Rect getInsets(float fraction) { Rect startInsets = isInPipDirection() ? mZeroInsets : mSourceRectHintInsets; Rect endInsets = isInPipDirection() ? mSourceRectHintInsets : mZeroInsets; return mInsetEvaluator.evaluate(fraction, startInsets, endInsets); } private boolean isInPipDirection() { return mDirection == BOUNDS_ENTER; } private boolean isOutPipDirection() { return mDirection == BOUNDS_EXIT; } // no-ops @Override Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java +6 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.view.SurfaceControl; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.util.Preconditions; Loading Loading @@ -88,6 +89,11 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener, : new PictureInPictureParams.Builder().build()); } @NonNull public PictureInPictureParams getPictureInPictureParams() { return mPictureInPictureParams; } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { PictureInPictureParams params = taskInfo.pictureInPictureParams; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +49 −9 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.Context; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.view.Surface; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; Loading Loading @@ -398,17 +399,22 @@ public class PipTransition extends PipTransitionController implements SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash; Preconditions.checkNotNull(pipLeash, "Leash is null for bounds transition."); Rect sourceRectHint = null; if (pipChange.getTaskInfo() != null && pipChange.getTaskInfo().pictureInPictureParams != null) { sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint(); } PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash, startTransaction, startBounds, startBounds, endBounds, PipEnterExitAnimator.BOUNDS_ENTER); startTransaction, finishTransaction, startBounds, startBounds, endBounds, sourceRectHint, PipEnterExitAnimator.BOUNDS_ENTER, Surface.ROTATION_0); tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(), this::onClientDrawAtTransitionEnd); finishWct.setBoundsChangeTransaction(pipTaskToken, tx); animator.setAnimationEndCallback(() -> { finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct); }); animator.setAnimationEndCallback(() -> finishCallback.onTransitionFinished(finishWct)); animator.start(); return true; Loading Loading @@ -451,20 +457,54 @@ public class PipTransition extends PipTransitionController implements WindowContainerToken pipToken = mPipTransitionState.mPipTaskToken; TransitionInfo.Change pipChange = getChangeByToken(info, pipToken); if (pipChange == null) { // pipChange is null, check to see if we've reparented the PIP activity for // the multi activity case. If so we should use the activity leash instead for (TransitionInfo.Change change : info.getChanges()) { if (change.getTaskInfo() == null && change.getLastParent() != null && change.getLastParent().equals(pipToken)) { pipChange = change; break; } } // failsafe if (pipChange == null) { return false; } } // for multi activity, we need to manually set the leash layer if (pipChange.getTaskInfo() == null) { TransitionInfo.Change parent = getChangeByToken(info, pipChange.getParent()); if (parent != null) { startTransaction.setLayer(parent.getLeash(), Integer.MAX_VALUE - 1); } } Rect startBounds = pipChange.getStartAbsBounds(); Rect endBounds = pipChange.getEndAbsBounds(); SurfaceControl pipLeash = pipChange.getLeash(); Preconditions.checkNotNull(pipLeash, "Leash is null for exit transition."); Rect sourceRectHint = null; if (pipChange.getTaskInfo() != null && pipChange.getTaskInfo().pictureInPictureParams != null) { // single activity sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint(); } else if (mPipTaskListener.getPictureInPictureParams().hasSourceBoundsHint()) { // multi activity sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint(); } PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash, startTransaction, startBounds, startBounds, endBounds, PipEnterExitAnimator.BOUNDS_EXIT); startTransaction, finishTransaction, endBounds, startBounds, endBounds, sourceRectHint, PipEnterExitAnimator.BOUNDS_EXIT, Surface.ROTATION_0); animator.setAnimationEndCallback(() -> { finishCallback.onTransitionFinished(null); mPipTransitionState.setState(PipTransitionState.EXITED_PIP); finishCallback.onTransitionFinished(null); }); animator.start(); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterExitAnimator.java +52 −6 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.content.Context; import android.graphics.Rect; import android.view.Surface; import android.view.SurfaceControl; import androidx.annotation.NonNull; Loading Loading @@ -51,8 +52,10 @@ public class PipEnterExitAnimator extends ValueAnimator @NonNull private final SurfaceControl mLeash; private final SurfaceControl.Transaction mStartTransaction; private final int mEnterAnimationDuration; private final SurfaceControl.Transaction mFinishTransaction; private final int mEnterExitAnimationDuration; private final @BOUNDS int mDirection; private final @Surface.Rotation int mRotation; // optional callbacks for tracking animation start and end @Nullable private Runnable mAnimationStartCallback; Loading @@ -62,37 +65,59 @@ public class PipEnterExitAnimator extends ValueAnimator private final Rect mStartBounds = new Rect(); private final Rect mEndBounds = new Rect(); @Nullable private final Rect mSourceRectHint; private final Rect mSourceRectHintInsets = new Rect(); private final Rect mZeroInsets = new Rect(0, 0, 0, 0); // Bounds updated by the evaluator as animator is running. private final Rect mAnimatedRect = new Rect(); private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; private final RectEvaluator mRectEvaluator; private final RectEvaluator mInsetEvaluator; private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; public PipEnterExitAnimator(Context context, @NonNull SurfaceControl leash, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, @NonNull Rect baseBounds, @NonNull Rect startBounds, @NonNull Rect endBounds, @BOUNDS int direction) { @Nullable Rect sourceRectHint, @BOUNDS int direction, @Surface.Rotation int rotation) { mLeash = leash; mStartTransaction = startTransaction; mFinishTransaction = finishTransaction; mBaseBounds.set(baseBounds); mStartBounds.set(startBounds); mAnimatedRect.set(startBounds); mEndBounds.set(endBounds); mRectEvaluator = new RectEvaluator(mAnimatedRect); mInsetEvaluator = new RectEvaluator(new Rect()); mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context); mDirection = direction; mRotation = rotation; mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null; if (mSourceRectHint != null) { mSourceRectHintInsets.set( mSourceRectHint.left - mBaseBounds.left, mSourceRectHint.top - mBaseBounds.top, mBaseBounds.right - mSourceRectHint.right, mBaseBounds.bottom - mSourceRectHint.bottom ); } mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); mEnterAnimationDuration = context.getResources() mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipEnterAnimationDuration); setDuration(mEnterAnimationDuration); setObjectValues(startBounds, endBounds); setDuration(mEnterExitAnimationDuration); setEvaluator(mRectEvaluator); addListener(this); addUpdateListener(this); Loading @@ -118,6 +143,14 @@ public class PipEnterExitAnimator extends ValueAnimator @Override public void onAnimationEnd(@NonNull Animator animation) { if (mFinishTransaction != null) { // finishTransaction might override some state (eg. corner radii) so we want to // manually set the state to the end of the animation mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash, mSourceRectHint, mBaseBounds, mAnimatedRect, getInsets(1f), isInPipDirection(), 1f) .round(mFinishTransaction, mLeash, isInPipDirection()) .shadow(mFinishTransaction, mLeash, isInPipDirection()); } if (mAnimationEndCallback != null) { mAnimationEndCallback.run(); } Loading @@ -127,19 +160,32 @@ public class PipEnterExitAnimator extends ValueAnimator public void onAnimationUpdate(@NonNull ValueAnimator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); final float fraction = getAnimatedFraction(); Rect insets = getInsets(fraction); // TODO (b/350801661): implement fixed rotation mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, null, mBaseBounds, mAnimatedRect, null, isInPipDirection(), fraction) mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint, mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction) .round(tx, mLeash, isInPipDirection()) .shadow(tx, mLeash, isInPipDirection()); tx.apply(); } private Rect getInsets(float fraction) { Rect startInsets = isInPipDirection() ? mZeroInsets : mSourceRectHintInsets; Rect endInsets = isInPipDirection() ? mSourceRectHintInsets : mZeroInsets; return mInsetEvaluator.evaluate(fraction, startInsets, endInsets); } private boolean isInPipDirection() { return mDirection == BOUNDS_ENTER; } private boolean isOutPipDirection() { return mDirection == BOUNDS_EXIT; } // no-ops @Override Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java +6 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.view.SurfaceControl; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.util.Preconditions; Loading Loading @@ -88,6 +89,11 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener, : new PictureInPictureParams.Builder().build()); } @NonNull public PictureInPictureParams getPictureInPictureParams() { return mPictureInPictureParams; } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { PictureInPictureParams params = taskInfo.pictureInPictureParams; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +49 −9 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.Context; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.view.Surface; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; Loading Loading @@ -398,17 +399,22 @@ public class PipTransition extends PipTransitionController implements SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash; Preconditions.checkNotNull(pipLeash, "Leash is null for bounds transition."); Rect sourceRectHint = null; if (pipChange.getTaskInfo() != null && pipChange.getTaskInfo().pictureInPictureParams != null) { sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint(); } PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash, startTransaction, startBounds, startBounds, endBounds, PipEnterExitAnimator.BOUNDS_ENTER); startTransaction, finishTransaction, startBounds, startBounds, endBounds, sourceRectHint, PipEnterExitAnimator.BOUNDS_ENTER, Surface.ROTATION_0); tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(), this::onClientDrawAtTransitionEnd); finishWct.setBoundsChangeTransaction(pipTaskToken, tx); animator.setAnimationEndCallback(() -> { finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct); }); animator.setAnimationEndCallback(() -> finishCallback.onTransitionFinished(finishWct)); animator.start(); return true; Loading Loading @@ -451,20 +457,54 @@ public class PipTransition extends PipTransitionController implements WindowContainerToken pipToken = mPipTransitionState.mPipTaskToken; TransitionInfo.Change pipChange = getChangeByToken(info, pipToken); if (pipChange == null) { // pipChange is null, check to see if we've reparented the PIP activity for // the multi activity case. If so we should use the activity leash instead for (TransitionInfo.Change change : info.getChanges()) { if (change.getTaskInfo() == null && change.getLastParent() != null && change.getLastParent().equals(pipToken)) { pipChange = change; break; } } // failsafe if (pipChange == null) { return false; } } // for multi activity, we need to manually set the leash layer if (pipChange.getTaskInfo() == null) { TransitionInfo.Change parent = getChangeByToken(info, pipChange.getParent()); if (parent != null) { startTransaction.setLayer(parent.getLeash(), Integer.MAX_VALUE - 1); } } Rect startBounds = pipChange.getStartAbsBounds(); Rect endBounds = pipChange.getEndAbsBounds(); SurfaceControl pipLeash = pipChange.getLeash(); Preconditions.checkNotNull(pipLeash, "Leash is null for exit transition."); Rect sourceRectHint = null; if (pipChange.getTaskInfo() != null && pipChange.getTaskInfo().pictureInPictureParams != null) { // single activity sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint(); } else if (mPipTaskListener.getPictureInPictureParams().hasSourceBoundsHint()) { // multi activity sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint(); } PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash, startTransaction, startBounds, startBounds, endBounds, PipEnterExitAnimator.BOUNDS_EXIT); startTransaction, finishTransaction, endBounds, startBounds, endBounds, sourceRectHint, PipEnterExitAnimator.BOUNDS_EXIT, Surface.ROTATION_0); animator.setAnimationEndCallback(() -> { finishCallback.onTransitionFinished(null); mPipTransitionState.setState(PipTransitionState.EXITED_PIP); finishCallback.onTransitionFinished(null); }); animator.start(); Loading