Loading core/java/android/view/IRecentsAnimationController.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.view; import android.app.ActivityManager; import android.view.IRemoteAnimationFinishedCallback; import android.view.SurfaceControl; import android.graphics.GraphicBuffer; import android.window.PictureInPictureSurfaceTransaction; import android.window.TaskSnapshot; Loading @@ -43,9 +44,10 @@ interface IRecentsAnimationController { * updated accordingly. This should be called before `finish` * @param taskId for which the leash should be updated * @param finishTransaction leash operations for the final transform. * @param overlay the surface control for an overlay being shown above the pip (can be null) */ void setFinishTaskTransaction(int taskId, in PictureInPictureSurfaceTransaction finishTransaction); in PictureInPictureSurfaceTransaction finishTransaction, in SurfaceControl overlay); /** * Notifies to the system that the animation into Recents should end, and all leashes associated Loading libs/WindowManager/Shell/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ <!-- Animation duration for resizing of PIP. --> <integer name="config_pipResizeAnimationDuration">425</integer> <!-- Animation duration for crossfading of PIP (specifically to fade out the layer on top). --> <integer name="config_pipCrossfadeAnimationDuration">150</integer> <!-- Allow dragging the PIP to a location to close it --> <bool name="config_pipEnableDismissDragToEdge">true</bool> Loading libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java +29 −17 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private final SyncTransactionQueue mSyncQueue; private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>(); private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>(); public FullscreenTaskListener(SyncTransactionQueue syncQueue) { mSyncQueue = syncQueue; Loading @@ -50,14 +50,14 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { if (mLeashByTaskId.get(taskInfo.taskId) != null) { if (mDataByTaskId.get(taskInfo.taskId) != null) { throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId); } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d", taskInfo.taskId); mLeashByTaskId.put(taskInfo.taskId, leash); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; final Point positionInParent = taskInfo.positionInParent; mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent)); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; mSyncQueue.runInSync(t -> { // Reset several properties back to fullscreen (PiP, for example, leaves all these // properties in a bad state). Loading @@ -72,45 +72,57 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { if (Transitions.ENABLE_SHELL_TRANSITIONS) return; final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); final TaskData data = mDataByTaskId.get(taskInfo.taskId); final Point positionInParent = taskInfo.positionInParent; if (!positionInParent.equals(data.positionInParent)) { data.positionInParent.set(positionInParent.x, positionInParent.y); mSyncQueue.runInSync(t -> { // Reset several properties back. For instance, when an Activity enters PiP with // multiple activities in the same task, a new task will be created from that Activity // and we want reset the leash of the original task. t.setPosition(leash, positionInParent.x, positionInParent.y); t.setWindowCrop(leash, null); t.setPosition(data.surface, positionInParent.x, positionInParent.y); }); } } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { if (mLeashByTaskId.get(taskInfo.taskId) == null) { if (mDataByTaskId.get(taskInfo.taskId) == null) { Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); return; } mLeashByTaskId.remove(taskInfo.taskId); mDataByTaskId.remove(taskInfo.taskId); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d", taskInfo.taskId); } @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { if (!mLeashByTaskId.contains(taskId)) { if (!mDataByTaskId.contains(taskId)) { throw new IllegalArgumentException("There is no surface for taskId=" + taskId); } b.setParent(mLeashByTaskId.get(taskId)); b.setParent(mDataByTaskId.get(taskId).surface); } @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + this); pw.println(innerPrefix + mLeashByTaskId.size() + " Tasks"); pw.println(innerPrefix + mDataByTaskId.size() + " Tasks"); } @Override public String toString() { return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN); } /** * Per-task data for each managed task. */ private static class TaskData { public final SurfaceControl surface; public final Point positionInParent; public TaskData(SurfaceControl surface, Point positionInParent) { this.surface = surface; this.positionInParent = positionInParent; } } } libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.pip; import android.app.PictureInPictureParams; import android.view.SurfaceControl; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; Loading Loading @@ -48,8 +49,10 @@ interface IPip { * * @param componentName ComponentName represents the Activity * @param destinationBounds the destination bounds the PiP window lands into * @param overlay an optional overlay to fade out after entering PiP */ oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2; oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds, in SurfaceControl overlay) = 2; /** * Sets listener to get pinned stack animation callbacks. Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +49 −20 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private final PipUiEventLogger mPipUiEventLoggerLogger; private final int mEnterAnimationDuration; private final int mExitAnimationDuration; private final int mCrossFadeAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Optional<LegacySplitScreenController> mSplitScreenOptional; protected final ShellTaskOrganizer mTaskOrganizer; Loading Loading @@ -257,6 +258,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private boolean mInSwipePipToHomeTransition; /** * An optional overlay used to mask content changing between an app in/out of PiP, only set if * {@link #mInSwipePipToHomeTransition} is true. */ private SurfaceControl mSwipePipToHomeOverlay; public PipTaskOrganizer(Context context, @NonNull SyncTransactionQueue syncTransactionQueue, @NonNull PipBoundsState pipBoundsState, Loading @@ -280,6 +287,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, .getInteger(R.integer.config_pipEnterAnimationDuration); mExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipExitAnimationDuration); mCrossFadeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipCrossfadeAnimationDuration); mSurfaceTransactionHelper = surfaceTransactionHelper; mPipAnimationController = pipAnimationController; mPipUiEventLoggerLogger = pipUiEventLogger; Loading Loading @@ -350,10 +359,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, * Callback when launcher finishes swipe-pip-to-home operation. * Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards. */ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds, SurfaceControl overlay) { // do nothing if there is no startSwipePipToHome being called before if (mInSwipePipToHomeTransition) { mPipBoundsState.setBounds(destinationBounds); mSwipePipToHomeOverlay = overlay; } } Loading Loading @@ -599,6 +610,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private void onEndOfSwipePipToHomeTransition() { final Rect destinationBounds = mPipBoundsState.getBounds(); final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay; final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds); mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds); Loading @@ -607,8 +619,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Ensure menu's settled in its final bounds first. finishResizeForMenu(destinationBounds); sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); // Remove the swipe to home overlay if (swipeToHomeOverlay != null) { fadeOutAndRemoveOverlay(swipeToHomeOverlay); } }, tx); mInSwipePipToHomeTransition = false; mSwipePipToHomeOverlay = null; } private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable, Loading Loading @@ -1139,25 +1157,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); // Start animation to fade out the snapshot. final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mEnterAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction transaction = mSurfaceControlTransactionFactory.getTransaction(); transaction.setAlpha(snapshotSurface, alpha); transaction.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(snapshotSurface); tx.apply(); } }); animator.start(); fadeOutAndRemoveOverlay(snapshotSurface); }); } else { applyFinishBoundsResize(wct, direction); Loading Loading @@ -1300,6 +1300,35 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return true; } /** * Fades out and removes an overlay surface. */ private void fadeOutAndRemoveOverlay(SurfaceControl surface) { if (surface == null) { return; } final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mCrossFadeAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction transaction = mSurfaceControlTransactionFactory.getTransaction(); transaction.setAlpha(surface, alpha); transaction.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(surface); tx.apply(); } }); animator.start(); } /** * Dumps internal states. */ Loading Loading
core/java/android/view/IRecentsAnimationController.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.view; import android.app.ActivityManager; import android.view.IRemoteAnimationFinishedCallback; import android.view.SurfaceControl; import android.graphics.GraphicBuffer; import android.window.PictureInPictureSurfaceTransaction; import android.window.TaskSnapshot; Loading @@ -43,9 +44,10 @@ interface IRecentsAnimationController { * updated accordingly. This should be called before `finish` * @param taskId for which the leash should be updated * @param finishTransaction leash operations for the final transform. * @param overlay the surface control for an overlay being shown above the pip (can be null) */ void setFinishTaskTransaction(int taskId, in PictureInPictureSurfaceTransaction finishTransaction); in PictureInPictureSurfaceTransaction finishTransaction, in SurfaceControl overlay); /** * Notifies to the system that the animation into Recents should end, and all leashes associated Loading
libs/WindowManager/Shell/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ <!-- Animation duration for resizing of PIP. --> <integer name="config_pipResizeAnimationDuration">425</integer> <!-- Animation duration for crossfading of PIP (specifically to fade out the layer on top). --> <integer name="config_pipCrossfadeAnimationDuration">150</integer> <!-- Allow dragging the PIP to a location to close it --> <bool name="config_pipEnableDismissDragToEdge">true</bool> Loading
libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java +29 −17 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { private final SyncTransactionQueue mSyncQueue; private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>(); private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>(); public FullscreenTaskListener(SyncTransactionQueue syncQueue) { mSyncQueue = syncQueue; Loading @@ -50,14 +50,14 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { if (mLeashByTaskId.get(taskInfo.taskId) != null) { if (mDataByTaskId.get(taskInfo.taskId) != null) { throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId); } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d", taskInfo.taskId); mLeashByTaskId.put(taskInfo.taskId, leash); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; final Point positionInParent = taskInfo.positionInParent; mDataByTaskId.put(taskInfo.taskId, new TaskData(leash, positionInParent)); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; mSyncQueue.runInSync(t -> { // Reset several properties back to fullscreen (PiP, for example, leaves all these // properties in a bad state). Loading @@ -72,45 +72,57 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { if (Transitions.ENABLE_SHELL_TRANSITIONS) return; final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); final TaskData data = mDataByTaskId.get(taskInfo.taskId); final Point positionInParent = taskInfo.positionInParent; if (!positionInParent.equals(data.positionInParent)) { data.positionInParent.set(positionInParent.x, positionInParent.y); mSyncQueue.runInSync(t -> { // Reset several properties back. For instance, when an Activity enters PiP with // multiple activities in the same task, a new task will be created from that Activity // and we want reset the leash of the original task. t.setPosition(leash, positionInParent.x, positionInParent.y); t.setWindowCrop(leash, null); t.setPosition(data.surface, positionInParent.x, positionInParent.y); }); } } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { if (mLeashByTaskId.get(taskInfo.taskId) == null) { if (mDataByTaskId.get(taskInfo.taskId) == null) { Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId); return; } mLeashByTaskId.remove(taskInfo.taskId); mDataByTaskId.remove(taskInfo.taskId); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d", taskInfo.taskId); } @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { if (!mLeashByTaskId.contains(taskId)) { if (!mDataByTaskId.contains(taskId)) { throw new IllegalArgumentException("There is no surface for taskId=" + taskId); } b.setParent(mLeashByTaskId.get(taskId)); b.setParent(mDataByTaskId.get(taskId).surface); } @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + this); pw.println(innerPrefix + mLeashByTaskId.size() + " Tasks"); pw.println(innerPrefix + mDataByTaskId.size() + " Tasks"); } @Override public String toString() { return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN); } /** * Per-task data for each managed task. */ private static class TaskData { public final SurfaceControl surface; public final Point positionInParent; public TaskData(SurfaceControl surface, Point positionInParent) { this.surface = surface; this.positionInParent = positionInParent; } } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.pip; import android.app.PictureInPictureParams; import android.view.SurfaceControl; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; Loading Loading @@ -48,8 +49,10 @@ interface IPip { * * @param componentName ComponentName represents the Activity * @param destinationBounds the destination bounds the PiP window lands into * @param overlay an optional overlay to fade out after entering PiP */ oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2; oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds, in SurfaceControl overlay) = 2; /** * Sets listener to get pinned stack animation callbacks. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +49 −20 Original line number Diff line number Diff line Loading @@ -147,6 +147,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private final PipUiEventLogger mPipUiEventLoggerLogger; private final int mEnterAnimationDuration; private final int mExitAnimationDuration; private final int mCrossFadeAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Optional<LegacySplitScreenController> mSplitScreenOptional; protected final ShellTaskOrganizer mTaskOrganizer; Loading Loading @@ -257,6 +258,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private boolean mInSwipePipToHomeTransition; /** * An optional overlay used to mask content changing between an app in/out of PiP, only set if * {@link #mInSwipePipToHomeTransition} is true. */ private SurfaceControl mSwipePipToHomeOverlay; public PipTaskOrganizer(Context context, @NonNull SyncTransactionQueue syncTransactionQueue, @NonNull PipBoundsState pipBoundsState, Loading @@ -280,6 +287,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, .getInteger(R.integer.config_pipEnterAnimationDuration); mExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipExitAnimationDuration); mCrossFadeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipCrossfadeAnimationDuration); mSurfaceTransactionHelper = surfaceTransactionHelper; mPipAnimationController = pipAnimationController; mPipUiEventLoggerLogger = pipUiEventLogger; Loading Loading @@ -350,10 +359,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, * Callback when launcher finishes swipe-pip-to-home operation. * Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards. */ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds, SurfaceControl overlay) { // do nothing if there is no startSwipePipToHome being called before if (mInSwipePipToHomeTransition) { mPipBoundsState.setBounds(destinationBounds); mSwipePipToHomeOverlay = overlay; } } Loading Loading @@ -599,6 +610,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private void onEndOfSwipePipToHomeTransition() { final Rect destinationBounds = mPipBoundsState.getBounds(); final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay; final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds); mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds); Loading @@ -607,8 +619,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Ensure menu's settled in its final bounds first. finishResizeForMenu(destinationBounds); sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); // Remove the swipe to home overlay if (swipeToHomeOverlay != null) { fadeOutAndRemoveOverlay(swipeToHomeOverlay); } }, tx); mInSwipePipToHomeTransition = false; mSwipePipToHomeOverlay = null; } private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable, Loading Loading @@ -1139,25 +1157,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); // Start animation to fade out the snapshot. final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mEnterAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction transaction = mSurfaceControlTransactionFactory.getTransaction(); transaction.setAlpha(snapshotSurface, alpha); transaction.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(snapshotSurface); tx.apply(); } }); animator.start(); fadeOutAndRemoveOverlay(snapshotSurface); }); } else { applyFinishBoundsResize(wct, direction); Loading Loading @@ -1300,6 +1300,35 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return true; } /** * Fades out and removes an overlay surface. */ private void fadeOutAndRemoveOverlay(SurfaceControl surface) { if (surface == null) { return; } final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); animator.setDuration(mCrossFadeAnimationDuration); animator.addUpdateListener(animation -> { final float alpha = (float) animation.getAnimatedValue(); final SurfaceControl.Transaction transaction = mSurfaceControlTransactionFactory.getTransaction(); transaction.setAlpha(surface, alpha); transaction.apply(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(surface); tx.apply(); } }); animator.start(); } /** * Dumps internal states. */ Loading