Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +5 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ public class PipAnimationController { public static final int TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN = 4; public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5; public static final int TRANSITION_DIRECTION_SNAP_AFTER_RESIZE = 6; public static final int TRANSITION_DIRECTION_USER_RESIZE = 7; public static final int TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND = 8; @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = { TRANSITION_DIRECTION_NONE, Loading @@ -64,7 +66,9 @@ public class PipAnimationController { TRANSITION_DIRECTION_LEAVE_PIP, TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN, TRANSITION_DIRECTION_REMOVE_STACK, TRANSITION_DIRECTION_SNAP_AFTER_RESIZE TRANSITION_DIRECTION_SNAP_AFTER_RESIZE, TRANSITION_DIRECTION_USER_RESIZE, TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND }) @Retention(RetentionPolicy.SOURCE) public @interface TransitionDirection {} Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +12 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,18 @@ public class PipSurfaceTransactionHelper { return this; } /** * Re-parents the snapshot to the parent's surface control and shows it. */ public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot( SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) { t.reparent(snapshot, parent); t.setLayer(snapshot, Integer.MAX_VALUE); t.show(snapshot); t.apply(); return this; } public interface SurfaceControlTransactionFactory { SurfaceControl.Transaction getTransaction(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +79 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_NONE; Loading @@ -32,9 +33,13 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SNAP_AFTER_RESIZE; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; Loading Loading @@ -820,13 +825,22 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ public void scheduleAnimateResizePip(Rect toBounds, int duration, Consumer<Rect> updateBoundsCallback) { scheduleAnimateResizePip(toBounds, duration, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } /** * Animates resizing of the pinned stack given the duration. */ public void scheduleAnimateResizePip(Rect toBounds, int duration, @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { if (mWaitForFixedRotation) { Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mPipBoundsState.getBounds(), toBounds, 0 /* startingAngle */, null /* sourceHintRect */, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); null /* sourceHintRect */, direction, duration, updateBoundsCallback); } /** Loading Loading @@ -919,7 +933,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, scheduleFinishResizePip(destinationBounds, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } private void scheduleFinishResizePip(Rect destinationBounds, /** * Finish an intermediate resize operation. This is expected to be called after * {@link #scheduleResizePip}. * * @param destinationBounds the final bounds of the PIP after resizing * @param direction the transition direction * @param updateBoundsCallback a callback to invoke after finishing the resize */ public void scheduleFinishResizePip(Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { if (mState.shouldBlockResizeRequest()) { Loading Loading @@ -1049,7 +1071,60 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, WindowContainerTransaction wct = new WindowContainerTransaction(); prepareFinishResizeTransaction(destinationBounds, direction, tx, wct); // Only corner drag, pinch or expand/un-expand resizing may lead to animating the finish // resize operation. final boolean mayAnimateFinishResize = direction == TRANSITION_DIRECTION_USER_RESIZE || direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE || direction == TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; // Animate with a cross-fade if enabled and seamless resize is disables by the app. final boolean animateCrossFadeResize = mayAnimateFinishResize && !mPictureInPictureParams.isSeamlessResizeEnabled(); if (animateCrossFadeResize) { // Take a snapshot of the PIP task and hide it. We'll show it and fade it out after // the wct transaction is applied and the activity is laid out again. final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken); mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot( mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface); mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() { @Override public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) { // Scale the snapshot from its pre-resize bounds to the post-resize bounds. final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(), snapshotSurface.getHeight()); final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(), destinationBounds.height()); mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); t.apply(); mUpdateHandler.post(() -> { // Start animation to fade out the snapshot. final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mEnterExitAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(snapshotSurface, alpha); tx.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(snapshotSurface); tx.apply(); } }); animator.start(); }); } }); } else { applyFinishBoundsResize(wct, direction); } finishResizeForMenu(destinationBounds); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip.phone; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT; import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT; Loading Loading @@ -624,7 +625,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Intentionally resize here even if the current bounds match the destination bounds. // This is so all the proper callbacks are performed. mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback); mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, mUpdateBoundsCallback); setAnimatingToBounds(toBounds); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.wm.shell.R; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipTaskOrganizer; Loading Loading @@ -542,6 +543,7 @@ public class PipResizeGestureHandler { }); } else { mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE, (Rect bounds) -> { mHandler.post(callback); }); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +5 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ public class PipAnimationController { public static final int TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN = 4; public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5; public static final int TRANSITION_DIRECTION_SNAP_AFTER_RESIZE = 6; public static final int TRANSITION_DIRECTION_USER_RESIZE = 7; public static final int TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND = 8; @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = { TRANSITION_DIRECTION_NONE, Loading @@ -64,7 +66,9 @@ public class PipAnimationController { TRANSITION_DIRECTION_LEAVE_PIP, TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN, TRANSITION_DIRECTION_REMOVE_STACK, TRANSITION_DIRECTION_SNAP_AFTER_RESIZE TRANSITION_DIRECTION_SNAP_AFTER_RESIZE, TRANSITION_DIRECTION_USER_RESIZE, TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND }) @Retention(RetentionPolicy.SOURCE) public @interface TransitionDirection {} Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +12 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,18 @@ public class PipSurfaceTransactionHelper { return this; } /** * Re-parents the snapshot to the parent's surface control and shows it. */ public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot( SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) { t.reparent(snapshot, parent); t.setLayer(snapshot, Integer.MAX_VALUE); t.show(snapshot); t.apply(); return this; } public interface SurfaceControlTransactionFactory { SurfaceControl.Transaction getTransaction(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +79 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_NONE; Loading @@ -32,9 +33,13 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SNAP_AFTER_RESIZE; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; Loading Loading @@ -820,13 +825,22 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ public void scheduleAnimateResizePip(Rect toBounds, int duration, Consumer<Rect> updateBoundsCallback) { scheduleAnimateResizePip(toBounds, duration, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } /** * Animates resizing of the pinned stack given the duration. */ public void scheduleAnimateResizePip(Rect toBounds, int duration, @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { if (mWaitForFixedRotation) { Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mPipBoundsState.getBounds(), toBounds, 0 /* startingAngle */, null /* sourceHintRect */, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); null /* sourceHintRect */, direction, duration, updateBoundsCallback); } /** Loading Loading @@ -919,7 +933,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, scheduleFinishResizePip(destinationBounds, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } private void scheduleFinishResizePip(Rect destinationBounds, /** * Finish an intermediate resize operation. This is expected to be called after * {@link #scheduleResizePip}. * * @param destinationBounds the final bounds of the PIP after resizing * @param direction the transition direction * @param updateBoundsCallback a callback to invoke after finishing the resize */ public void scheduleFinishResizePip(Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { if (mState.shouldBlockResizeRequest()) { Loading Loading @@ -1049,7 +1071,60 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, WindowContainerTransaction wct = new WindowContainerTransaction(); prepareFinishResizeTransaction(destinationBounds, direction, tx, wct); // Only corner drag, pinch or expand/un-expand resizing may lead to animating the finish // resize operation. final boolean mayAnimateFinishResize = direction == TRANSITION_DIRECTION_USER_RESIZE || direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE || direction == TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; // Animate with a cross-fade if enabled and seamless resize is disables by the app. final boolean animateCrossFadeResize = mayAnimateFinishResize && !mPictureInPictureParams.isSeamlessResizeEnabled(); if (animateCrossFadeResize) { // Take a snapshot of the PIP task and hide it. We'll show it and fade it out after // the wct transaction is applied and the activity is laid out again. final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken); mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot( mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface); mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() { @Override public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) { // Scale the snapshot from its pre-resize bounds to the post-resize bounds. final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(), snapshotSurface.getHeight()); final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(), destinationBounds.height()); mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); t.apply(); mUpdateHandler.post(() -> { // Start animation to fade out the snapshot. final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mEnterExitAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(snapshotSurface, alpha); tx.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(snapshotSurface); tx.apply(); } }); animator.start(); }); } }); } else { applyFinishBoundsResize(wct, direction); } finishResizeForMenu(destinationBounds); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip.phone; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT; import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT; Loading Loading @@ -624,7 +625,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Intentionally resize here even if the current bounds match the destination bounds. // This is so all the proper callbacks are performed. mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback); mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, mUpdateBoundsCallback); setAnimatingToBounds(toBounds); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.wm.shell.R; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsAlgorithm; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipTaskOrganizer; Loading Loading @@ -542,6 +543,7 @@ public class PipResizeGestureHandler { }); } else { mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE, (Rect bounds) -> { mHandler.post(callback); }); Loading