Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +55 −0 Original line number Diff line number Diff line Loading @@ -26,10 +26,14 @@ import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.app.TaskInfo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; import android.view.Choreographer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; Loading Loading @@ -253,6 +257,7 @@ public class PipAnimationController { mSurfaceControlTransactionFactory; private PipSurfaceTransactionHelper mSurfaceTransactionHelper; private @TransitionDirection int mTransitionDirection; protected SurfaceControl mContentOverlay; private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, Loading Loading @@ -331,6 +336,53 @@ public class PipAnimationController { return false; } SurfaceControl getContentOverlay() { return mContentOverlay; } PipTransitionAnimator<T> setUseContentOverlay(Context context) { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); if (mContentOverlay != null) { // remove existing content overlay if there is any. tx.remove(mContentOverlay); tx.apply(); } mContentOverlay = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite("PipAnimation") .setName("PipContentOverlay") .setColorLayer() .build(); tx.show(mContentOverlay); tx.setLayer(mContentOverlay, Integer.MAX_VALUE); tx.setColor(mContentOverlay, getContentOverlayColor(context)); tx.setAlpha(mContentOverlay, 0f); tx.reparent(mContentOverlay, mLeash); tx.apply(); return this; } private float[] getContentOverlayColor(Context context) { final TypedArray ta = context.obtainStyledAttributes(new int[] { android.R.attr.colorBackground }); try { int colorAccent = ta.getColor(0, 0); return new float[] { Color.red(colorAccent) / 255f, Color.green(colorAccent) / 255f, Color.blue(colorAccent) / 255f }; } finally { ta.recycle(); } } /** * Clears the {@link #mContentOverlay}, this should be done after the content overlay is * faded out, such as in {@link PipTaskOrganizer#fadeOutAndRemoveOverlay} */ void clearContentOverlay() { mContentOverlay = null; } @VisibleForTesting @TransitionDirection public int getTransitionDirection() { return mTransitionDirection; Loading Loading @@ -517,6 +569,9 @@ public class PipAnimationController { final Rect base = getBaseValue(); final Rect start = getStartValue(); final Rect end = getEndValue(); if (mContentOverlay != null) { tx.setAlpha(mContentOverlay, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); } if (rotatedEndRect != null) { // Animate the bounds in a different orientation. It only happens when // switching between PiP and fullscreen. Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +54 −18 Original line number Diff line number Diff line Loading @@ -107,6 +107,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000; /** * The fixed start delay in ms when fading out the content overlay from bounds animation. * This is to overcome the flicker caused by configuration change when rotating from landscape * to portrait PiP in button navigation mode. */ private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 500; // Not a complete set of states but serves what we want right now. private enum State { UNDEFINED(0), Loading Loading @@ -176,6 +183,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final int direction = animator.getTransitionDirection(); final int animationType = animator.getAnimationType(); final Rect destinationBounds = animator.getDestinationBounds(); if (isInPipDirection(direction) && animator.getContentOverlay() != null) { fadeOutAndRemoveOverlay(animator.getContentOverlay(), animator::clearContentOverlay, true /* withStartDelay*/); } if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS && direction == TRANSITION_DIRECTION_TO_PIP) { // Notify the display to continue the deferred orientation change. Loading @@ -199,17 +210,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, finishResize(tx, destinationBounds, direction, animationType); sendOnPipTransitionFinished(direction); } if (direction == TRANSITION_DIRECTION_TO_PIP) { // TODO (b//169221267): Add jank listener for transactions without buffer updates. //InteractionJankMonitor.getInstance().end( // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP); } } @Override public void onPipAnimationCancel(TaskInfo taskInfo, PipAnimationController.PipTransitionAnimator animator) { sendOnPipTransitionCancelled(animator.getTransitionDirection()); final int direction = animator.getTransitionDirection(); if (isInPipDirection(direction) && animator.getContentOverlay() != null) { fadeOutAndRemoveOverlay(animator.getContentOverlay(), animator::clearContentOverlay, true /* withStartDelay */); } sendOnPipTransitionCancelled(direction); } }; Loading Loading @@ -640,7 +651,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Remove the swipe to home overlay if (swipeToHomeOverlay != null) { fadeOutAndRemoveOverlay(swipeToHomeOverlay); fadeOutAndRemoveOverlay(swipeToHomeOverlay, null /* callback */, false /* withStartDelay */); } }, tx); mInSwipePipToHomeTransition = false; Loading Loading @@ -723,9 +735,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY); } final PipAnimationController.PipTransitionAnimator animator = final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController.getCurrentAnimator(); if (animator != null) { if (animator.getContentOverlay() != null) { removeContentOverlay(animator.getContentOverlay(), animator::clearContentOverlay); } animator.removeAllUpdateListeners(); animator.removeAllListeners(); animator.cancel(); Loading Loading @@ -1196,7 +1211,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, snapshotDest); // Start animation to fade out the snapshot. fadeOutAndRemoveOverlay(snapshotSurface); fadeOutAndRemoveOverlay(snapshotSurface, null /* callback */, false /* withStartDelay */); }); } else { applyFinishBoundsResize(wct, direction); Loading Loading @@ -1287,15 +1303,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, animator.setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setPipTransactionHandler(mPipTransactionHandler) .setDuration(durationMs) .start(); if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) { .setDuration(durationMs); if (isInPipDirection(direction)) { // Similar to auto-enter-pip transition, we use content overlay when there is no // source rect hint to enter PiP use bounds animation. if (sourceHintRect == null) animator.setUseContentOverlay(mContext); // The destination bounds are used for the end rect of animation and the final bounds // after animation finishes. So after the animation is started, the destination bounds // can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout // without affecting the animation. if (rotationDelta != Surface.ROTATION_0) { animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds()); } } animator.start(); return animator; } Loading @@ -1308,6 +1329,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); // Transform the destination bounds to current display coordinates. rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation); // When entering PiP (from button navigation mode), adjust the source rect hint by // display cutout if applicable. if (sourceHintRect != null && mTaskInfo.displayCutoutInsets != null) { if (rotationDelta == Surface.ROTATION_270) { sourceHintRect.offset(mTaskInfo.displayCutoutInsets.left, mTaskInfo.displayCutoutInsets.top); } } } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) { final Rect rotatedDestinationBounds = new Rect(outDestinationBounds); rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(), Loading Loading @@ -1346,7 +1375,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, /** * Fades out and removes an overlay surface. */ private void fadeOutAndRemoveOverlay(SurfaceControl surface) { private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback, boolean withStartDelay) { if (surface == null) { return; } Loading @@ -1363,13 +1393,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { removeContentOverlay(surface, callback); } }); animator.setStartDelay(withStartDelay ? CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0); animator.start(); } private void removeContentOverlay(SurfaceControl surface, Runnable callback) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(surface); tx.apply(); } }); animator.start(); if (callback != null) callback.run(); } /** Loading services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -1884,7 +1884,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp forAllWindows(w -> { w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly); }, true /* traverseTopToBottom */); mPinnedTaskController.startSeamlessRotationIfNeeded(transaction); mPinnedTaskController.startSeamlessRotationIfNeeded(transaction, oldRotation, rotation); } mWmService.mDisplayManagerInternal.performTraversal(transaction); Loading services/core/java/com/android/server/wm/PinnedTaskController.java +15 −1 Original line number Diff line number Diff line Loading @@ -27,13 +27,16 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.RotationUtils; import android.util.Slog; import android.view.IPinnedTaskListener; import android.view.Surface; import android.view.SurfaceControl; import android.window.PictureInPictureSurfaceTransaction; Loading Loading @@ -237,7 +240,8 @@ class PinnedTaskController { * rotation of display. The final surface matrix will be replaced by PiPTaskOrganizer after it * receives the callback of fixed rotation completion. */ void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t) { void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t, int oldRotation, int newRotation) { final Rect bounds = mDestRotatedBounds; final PictureInPictureSurfaceTransaction pipTx = mPipTransaction; if (bounds == null && pipTx == null) { Loading Loading @@ -280,6 +284,16 @@ class PinnedTaskController { ? params.getSourceRectHint() : null; Slog.i(TAG, "Seamless rotation PiP bounds=" + bounds + " hintRect=" + sourceHintRect); final int rotationDelta = RotationUtils.deltaRotation(oldRotation, newRotation); // Adjust for display cutout if applicable. if (sourceHintRect != null && rotationDelta == Surface.ROTATION_270) { if (pinnedTask.getDisplayCutoutInsets() != null) { final int rotationBackDelta = RotationUtils.deltaRotation(newRotation, oldRotation); final Rect displayCutoutInsets = RotationUtils.rotateInsets( Insets.of(pinnedTask.getDisplayCutoutInsets()), rotationBackDelta).toRect(); sourceHintRect.offset(displayCutoutInsets.left, displayCutoutInsets.top); } } final Rect contentBounds = sourceHintRect != null && areaBounds.contains(sourceHintRect) ? sourceHintRect : areaBounds; final int w = contentBounds.width(); Loading services/core/java/com/android/server/wm/Task.java +5 −6 Original line number Diff line number Diff line Loading @@ -4105,7 +4105,7 @@ class Task extends WindowContainer<WindowContainer> { info.positionInParent = getRelativePosition(); info.pictureInPictureParams = getPictureInPictureParams(top); info.displayCutoutInsets = getDisplayCutoutInsets(top); info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null; info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; Loading Loading @@ -4140,16 +4140,15 @@ class Task extends WindowContainer<WindowContainer> { ? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs); } private Rect getDisplayCutoutInsets(Task top) { if (top == null || top.mDisplayContent == null || top.getDisplayInfo().displayCutout == null) return null; final WindowState w = top.getTopVisibleAppMainWindow(); Rect getDisplayCutoutInsets() { if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null; final WindowState w = getTopVisibleAppMainWindow(); final int displayCutoutMode = w == null ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT : w.getAttrs().layoutInDisplayCutoutMode; return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) ? null : top.getDisplayInfo().displayCutout.getSafeInsets(); ? null : getDisplayInfo().displayCutout.getSafeInsets(); } /** Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +55 −0 Original line number Diff line number Diff line Loading @@ -26,10 +26,14 @@ import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.app.TaskInfo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Rect; import android.view.Choreographer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; Loading Loading @@ -253,6 +257,7 @@ public class PipAnimationController { mSurfaceControlTransactionFactory; private PipSurfaceTransactionHelper mSurfaceTransactionHelper; private @TransitionDirection int mTransitionDirection; protected SurfaceControl mContentOverlay; private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, Loading Loading @@ -331,6 +336,53 @@ public class PipAnimationController { return false; } SurfaceControl getContentOverlay() { return mContentOverlay; } PipTransitionAnimator<T> setUseContentOverlay(Context context) { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); if (mContentOverlay != null) { // remove existing content overlay if there is any. tx.remove(mContentOverlay); tx.apply(); } mContentOverlay = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite("PipAnimation") .setName("PipContentOverlay") .setColorLayer() .build(); tx.show(mContentOverlay); tx.setLayer(mContentOverlay, Integer.MAX_VALUE); tx.setColor(mContentOverlay, getContentOverlayColor(context)); tx.setAlpha(mContentOverlay, 0f); tx.reparent(mContentOverlay, mLeash); tx.apply(); return this; } private float[] getContentOverlayColor(Context context) { final TypedArray ta = context.obtainStyledAttributes(new int[] { android.R.attr.colorBackground }); try { int colorAccent = ta.getColor(0, 0); return new float[] { Color.red(colorAccent) / 255f, Color.green(colorAccent) / 255f, Color.blue(colorAccent) / 255f }; } finally { ta.recycle(); } } /** * Clears the {@link #mContentOverlay}, this should be done after the content overlay is * faded out, such as in {@link PipTaskOrganizer#fadeOutAndRemoveOverlay} */ void clearContentOverlay() { mContentOverlay = null; } @VisibleForTesting @TransitionDirection public int getTransitionDirection() { return mTransitionDirection; Loading Loading @@ -517,6 +569,9 @@ public class PipAnimationController { final Rect base = getBaseValue(); final Rect start = getStartValue(); final Rect end = getEndValue(); if (mContentOverlay != null) { tx.setAlpha(mContentOverlay, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); } if (rotatedEndRect != null) { // Animate the bounds in a different orientation. It only happens when // switching between PiP and fullscreen. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +54 −18 Original line number Diff line number Diff line Loading @@ -107,6 +107,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000; /** * The fixed start delay in ms when fading out the content overlay from bounds animation. * This is to overcome the flicker caused by configuration change when rotating from landscape * to portrait PiP in button navigation mode. */ private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 500; // Not a complete set of states but serves what we want right now. private enum State { UNDEFINED(0), Loading Loading @@ -176,6 +183,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final int direction = animator.getTransitionDirection(); final int animationType = animator.getAnimationType(); final Rect destinationBounds = animator.getDestinationBounds(); if (isInPipDirection(direction) && animator.getContentOverlay() != null) { fadeOutAndRemoveOverlay(animator.getContentOverlay(), animator::clearContentOverlay, true /* withStartDelay*/); } if (mWaitForFixedRotation && animationType == ANIM_TYPE_BOUNDS && direction == TRANSITION_DIRECTION_TO_PIP) { // Notify the display to continue the deferred orientation change. Loading @@ -199,17 +210,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, finishResize(tx, destinationBounds, direction, animationType); sendOnPipTransitionFinished(direction); } if (direction == TRANSITION_DIRECTION_TO_PIP) { // TODO (b//169221267): Add jank listener for transactions without buffer updates. //InteractionJankMonitor.getInstance().end( // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP); } } @Override public void onPipAnimationCancel(TaskInfo taskInfo, PipAnimationController.PipTransitionAnimator animator) { sendOnPipTransitionCancelled(animator.getTransitionDirection()); final int direction = animator.getTransitionDirection(); if (isInPipDirection(direction) && animator.getContentOverlay() != null) { fadeOutAndRemoveOverlay(animator.getContentOverlay(), animator::clearContentOverlay, true /* withStartDelay */); } sendOnPipTransitionCancelled(direction); } }; Loading Loading @@ -640,7 +651,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Remove the swipe to home overlay if (swipeToHomeOverlay != null) { fadeOutAndRemoveOverlay(swipeToHomeOverlay); fadeOutAndRemoveOverlay(swipeToHomeOverlay, null /* callback */, false /* withStartDelay */); } }, tx); mInSwipePipToHomeTransition = false; Loading Loading @@ -723,9 +735,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY); } final PipAnimationController.PipTransitionAnimator animator = final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController.getCurrentAnimator(); if (animator != null) { if (animator.getContentOverlay() != null) { removeContentOverlay(animator.getContentOverlay(), animator::clearContentOverlay); } animator.removeAllUpdateListeners(); animator.removeAllListeners(); animator.cancel(); Loading Loading @@ -1196,7 +1211,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, snapshotDest); // Start animation to fade out the snapshot. fadeOutAndRemoveOverlay(snapshotSurface); fadeOutAndRemoveOverlay(snapshotSurface, null /* callback */, false /* withStartDelay */); }); } else { applyFinishBoundsResize(wct, direction); Loading Loading @@ -1287,15 +1303,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, animator.setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setPipTransactionHandler(mPipTransactionHandler) .setDuration(durationMs) .start(); if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) { .setDuration(durationMs); if (isInPipDirection(direction)) { // Similar to auto-enter-pip transition, we use content overlay when there is no // source rect hint to enter PiP use bounds animation. if (sourceHintRect == null) animator.setUseContentOverlay(mContext); // The destination bounds are used for the end rect of animation and the final bounds // after animation finishes. So after the animation is started, the destination bounds // can be updated to new rotation (computeRotatedBounds has changed the DisplayLayout // without affecting the animation. if (rotationDelta != Surface.ROTATION_0) { animator.setDestinationBounds(mPipBoundsAlgorithm.getEntryDestinationBounds()); } } animator.start(); return animator; } Loading @@ -1308,6 +1329,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); // Transform the destination bounds to current display coordinates. rotateBounds(outDestinationBounds, displayBounds, mNextRotation, mCurrentRotation); // When entering PiP (from button navigation mode), adjust the source rect hint by // display cutout if applicable. if (sourceHintRect != null && mTaskInfo.displayCutoutInsets != null) { if (rotationDelta == Surface.ROTATION_270) { sourceHintRect.offset(mTaskInfo.displayCutoutInsets.left, mTaskInfo.displayCutoutInsets.top); } } } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) { final Rect rotatedDestinationBounds = new Rect(outDestinationBounds); rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(), Loading Loading @@ -1346,7 +1375,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, /** * Fades out and removes an overlay surface. */ private void fadeOutAndRemoveOverlay(SurfaceControl surface) { private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback, boolean withStartDelay) { if (surface == null) { return; } Loading @@ -1363,13 +1393,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { removeContentOverlay(surface, callback); } }); animator.setStartDelay(withStartDelay ? CONTENT_OVERLAY_FADE_OUT_DELAY_MS : 0); animator.start(); } private void removeContentOverlay(SurfaceControl surface, Runnable callback) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.remove(surface); tx.apply(); } }); animator.start(); if (callback != null) callback.run(); } /** Loading
services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -1884,7 +1884,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp forAllWindows(w -> { w.seamlesslyRotateIfAllowed(transaction, oldRotation, rotation, rotateSeamlessly); }, true /* traverseTopToBottom */); mPinnedTaskController.startSeamlessRotationIfNeeded(transaction); mPinnedTaskController.startSeamlessRotationIfNeeded(transaction, oldRotation, rotation); } mWmService.mDisplayManagerInternal.performTraversal(transaction); Loading
services/core/java/com/android/server/wm/PinnedTaskController.java +15 −1 Original line number Diff line number Diff line Loading @@ -27,13 +27,16 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.RotationUtils; import android.util.Slog; import android.view.IPinnedTaskListener; import android.view.Surface; import android.view.SurfaceControl; import android.window.PictureInPictureSurfaceTransaction; Loading Loading @@ -237,7 +240,8 @@ class PinnedTaskController { * rotation of display. The final surface matrix will be replaced by PiPTaskOrganizer after it * receives the callback of fixed rotation completion. */ void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t) { void startSeamlessRotationIfNeeded(SurfaceControl.Transaction t, int oldRotation, int newRotation) { final Rect bounds = mDestRotatedBounds; final PictureInPictureSurfaceTransaction pipTx = mPipTransaction; if (bounds == null && pipTx == null) { Loading Loading @@ -280,6 +284,16 @@ class PinnedTaskController { ? params.getSourceRectHint() : null; Slog.i(TAG, "Seamless rotation PiP bounds=" + bounds + " hintRect=" + sourceHintRect); final int rotationDelta = RotationUtils.deltaRotation(oldRotation, newRotation); // Adjust for display cutout if applicable. if (sourceHintRect != null && rotationDelta == Surface.ROTATION_270) { if (pinnedTask.getDisplayCutoutInsets() != null) { final int rotationBackDelta = RotationUtils.deltaRotation(newRotation, oldRotation); final Rect displayCutoutInsets = RotationUtils.rotateInsets( Insets.of(pinnedTask.getDisplayCutoutInsets()), rotationBackDelta).toRect(); sourceHintRect.offset(displayCutoutInsets.left, displayCutoutInsets.top); } } final Rect contentBounds = sourceHintRect != null && areaBounds.contains(sourceHintRect) ? sourceHintRect : areaBounds; final int w = contentBounds.width(); Loading
services/core/java/com/android/server/wm/Task.java +5 −6 Original line number Diff line number Diff line Loading @@ -4105,7 +4105,7 @@ class Task extends WindowContainer<WindowContainer> { info.positionInParent = getRelativePosition(); info.pictureInPictureParams = getPictureInPictureParams(top); info.displayCutoutInsets = getDisplayCutoutInsets(top); info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null; info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; Loading Loading @@ -4140,16 +4140,15 @@ class Task extends WindowContainer<WindowContainer> { ? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs); } private Rect getDisplayCutoutInsets(Task top) { if (top == null || top.mDisplayContent == null || top.getDisplayInfo().displayCutout == null) return null; final WindowState w = top.getTopVisibleAppMainWindow(); Rect getDisplayCutoutInsets() { if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null; final WindowState w = getTopVisibleAppMainWindow(); final int displayCutoutMode = w == null ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT : w.getAttrs().layoutInDisplayCutoutMode; return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) ? null : top.getDisplayInfo().displayCutout.getSafeInsets(); ? null : getDisplayInfo().displayCutout.getSafeInsets(); } /** Loading