Loading core/java/android/view/IDisplayWindowListener.aidl +9 −0 Original line number Diff line number Diff line Loading @@ -46,4 +46,13 @@ oneway interface IDisplayWindowListener { */ void onDisplayRemoved(int displayId); /** * Called when fixed rotation is started on a display. */ void onFixedRotationStarted(int displayId, int newRotation); /** * Called when the previous fixed rotation on a display is finished. */ void onFixedRotationFinished(int displayId); } packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +84 −32 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.os.SomeArgs; import com.android.systemui.R; import com.android.systemui.pip.phone.PipUpdateThread; import com.android.systemui.stackdivider.Divider; import com.android.systemui.wm.DisplayController; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -82,8 +83,10 @@ import javax.inject.Singleton; * see also {@link com.android.systemui.pip.phone.PipMotionHelper}. */ @Singleton public class PipTaskOrganizer extends TaskOrganizer { public class PipTaskOrganizer extends TaskOrganizer implements DisplayController.OnDisplaysChangedListener { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final boolean DEBUG = false; private static final int MSG_RESIZE_IMMEDIATE = 1; private static final int MSG_RESIZE_ANIMATE = 2; Loading Loading @@ -206,10 +209,17 @@ public class PipTaskOrganizer extends TaskOrganizer { mSurfaceControlTransactionFactory; private PictureInPictureParams mPictureInPictureParams; /** * If set to {@code true}, the entering animation will be skipped and we will wait for * {@link #onFixedRotationFinished(int)} callback to actually enter PiP. */ private boolean mShouldDeferEnteringPip; @Inject public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @Nullable Divider divider) { @Nullable Divider divider, @NonNull DisplayController displayController) { mMainHandler = new Handler(Looper.getMainLooper()); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); mPipBoundsHandler = boundsHandler; Loading @@ -219,6 +229,7 @@ public class PipTaskOrganizer extends TaskOrganizer { mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; mSplitDivider = divider; displayController.addDisplayWindowListener(this); } public Handler getUpdateHandler() { Loading Loading @@ -281,7 +292,8 @@ public class PipTaskOrganizer extends TaskOrganizer { final int direction = syncWithSplitScreenBounds(destinationBounds) ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN; final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, mLastReportedBounds); tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height()); Loading Loading @@ -325,29 +337,47 @@ public class PipTaskOrganizer extends TaskOrganizer { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) { Objects.requireNonNull(info, "Requires RunningTaskInfo"); mPictureInPictureParams = info.pictureInPictureParams; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( info.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); mTaskInfo = info; mToken = mTaskInfo.token; mInPip = true; mLeash = leash; mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); mPictureInPictureParams = mTaskInfo.pictureInPictureParams; // TODO: Skip enter animation when entering pip from another orientation if (mShouldDeferEnteringPip) { if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing"); // if deferred, hide the surface till fixed rotation is completed final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(mLeash, 0f); tx.apply(); return; } final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { enterPipWithAlphaAnimation(destinationBounds, mEnterExitAnimationDuration); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } } 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 // while to process final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(mLeash, 0f); tx.apply(); final WindowContainerTransaction wct = new WindowContainerTransaction(); Loading @@ -362,14 +392,10 @@ public class PipTaskOrganizer extends TaskOrganizer { .getAnimator(mLeash, destinationBounds, 0f, 1f) .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .setDuration(durationMs) .start()); } }); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } } /** Loading @@ -391,6 +417,7 @@ public class PipTaskOrganizer extends TaskOrganizer { Log.wtf(TAG, "Unrecognized token: " + token); return; } mShouldDeferEnteringPip = false; mPictureInPictureParams = null; mInPip = false; } Loading @@ -416,6 +443,23 @@ public class PipTaskOrganizer extends TaskOrganizer { // Do nothing } @Override public void onFixedRotationStarted(int displayId, int newRotation) { mShouldDeferEnteringPip = true; } @Override public void onFixedRotationFinished(int displayId) { if (mShouldDeferEnteringPip && mInPip) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); // schedule a regular animation to ensure all the callbacks are still being sent enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */); } mShouldDeferEnteringPip = false; } /** * TODO(b/152809058): consolidate the display info handling logic in SysUI * Loading Loading @@ -476,6 +520,10 @@ public class PipTaskOrganizer extends TaskOrganizer { */ public void scheduleAnimateResizePip(Rect toBounds, int duration, Consumer<Rect> updateBoundsCallback) { if (mShouldDeferEnteringPip) { Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mLastReportedBounds, toBounds, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); } Loading Loading @@ -567,6 +615,10 @@ public class PipTaskOrganizer extends TaskOrganizer { // can be initiated in other component, ignore if we are no longer in PIP return; } if (mShouldDeferEnteringPip) { Log.d(TAG, "skip scheduleOffsetPip, entering pip deferred"); return; } SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = originalBounds; Loading packages/SystemUI/src/com/android/systemui/wm/DisplayController.java +43 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,39 @@ public class DisplayController { } }); } @Override public void onFixedRotationStarted(int displayId, int newRotation) { mHandler.post(() -> { synchronized (mDisplays) { if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) { Slog.w(TAG, "Skipping onFixedRotationStarted on unknown" + " display, displayId=" + displayId); return; } for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) { mDisplayChangedListeners.get(i).onFixedRotationStarted( displayId, newRotation); } } }); } @Override public void onFixedRotationFinished(int displayId) { mHandler.post(() -> { synchronized (mDisplays) { if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) { Slog.w(TAG, "Skipping onFixedRotationFinished on unknown" + " display, displayId=" + displayId); return; } for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) { mDisplayChangedListeners.get(i).onFixedRotationFinished(displayId); } } }); } }; @Inject Loading Loading @@ -232,5 +265,15 @@ public class DisplayController { * Called when a display is removed. */ default void onDisplayRemoved(int displayId) {} /** * Called when fixed rotation on a display is started. */ default void onFixedRotationStarted(int displayId, int newRotation) {} /** * Called when fixed rotation on a display is finished. */ default void onFixedRotationFinished(int displayId) {} } } services/core/java/com/android/server/wm/DisplayContent.java +24 −7 Original line number Diff line number Diff line Loading @@ -493,10 +493,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * The launching activity which is using fixed rotation transformation. * * @see #handleTopActivityLaunchingInDifferentOrientation * @see #setFixedRotationLaunchingApp * @see #setFixedRotationLaunchingApp(ActivityRecord, int) * @see DisplayRotation#shouldRotateSeamlessly */ ActivityRecord mFixedRotationLaunchingApp; private ActivityRecord mFixedRotationLaunchingApp; final FixedRotationTransitionListener mFixedRotationTransitionListener = new FixedRotationTransitionListener(); Loading Loading @@ -1475,6 +1475,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return true; } @Nullable ActivityRecord getFixedRotationLaunchingApp() { return mFixedRotationLaunchingApp; } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r) { setFixedRotationLaunchingAppUnchecked(r, ROTATION_UNDEFINED); } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); } mFixedRotationLaunchingApp = r; } /** * Sets the provided record to {@link mFixedRotationLaunchingApp} if possible to apply fixed * rotation transform to it and indicate that the display may be rotated after it is launched. Loading @@ -1496,7 +1513,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (!r.hasFixedRotationTransform()) { startFixedRotationTransform(r, rotation); } mFixedRotationLaunchingApp = r; setFixedRotationLaunchingAppUnchecked(r, rotation); if (prevRotatedLaunchingApp != null) { prevRotatedLaunchingApp.finishFixedRotationTransform(); } Loading Loading @@ -1524,7 +1541,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** * Clears the {@link mFixedRotationLaunchingApp} without applying rotation to display. It is * Clears the {@link #mFixedRotationLaunchingApp} without applying rotation to display. It is * used when the display won't rotate (e.g. the orientation from sensor has updated again before * applying rotation to display) but the launching app has been transformed. So the record need * to be cleared and restored to stop using seamless rotation and rotated configuration. Loading @@ -1534,7 +1551,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } mFixedRotationLaunchingApp.finishFixedRotationTransform(); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } private void startFixedRotationTransform(WindowToken token, int rotation) { Loading Loading @@ -5260,7 +5277,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo rotatedLaunchingApp.finishFixedRotationTransform( () -> applyRotation(oldRotation, newRotation)); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } /** Checks whether the given activity is in size compatibility mode and notifies the change. */ Loading Loading @@ -5574,7 +5591,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) { // Because it won't affect display orientation, just finish the transform. animatingRecents.finishFixedRotationTransform(); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } else { // If there is already a launching activity that is not the recents, before its // transition is completed, the recents animation may be started. So if the recents Loading services/core/java/com/android/server/wm/DisplayRotation.java +1 −1 Original line number Diff line number Diff line Loading @@ -577,7 +577,7 @@ public class DisplayRotation { boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) { // Display doesn't need to be frozen because application has been started in correct // rotation already, so the rest of the windows can use seamless rotation. if (mDisplayContent.mFixedRotationLaunchingApp != null) { if (mDisplayContent.getFixedRotationLaunchingApp() != null) { return true; } Loading Loading
core/java/android/view/IDisplayWindowListener.aidl +9 −0 Original line number Diff line number Diff line Loading @@ -46,4 +46,13 @@ oneway interface IDisplayWindowListener { */ void onDisplayRemoved(int displayId); /** * Called when fixed rotation is started on a display. */ void onFixedRotationStarted(int displayId, int newRotation); /** * Called when the previous fixed rotation on a display is finished. */ void onFixedRotationFinished(int displayId); }
packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +84 −32 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.os.SomeArgs; import com.android.systemui.R; import com.android.systemui.pip.phone.PipUpdateThread; import com.android.systemui.stackdivider.Divider; import com.android.systemui.wm.DisplayController; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -82,8 +83,10 @@ import javax.inject.Singleton; * see also {@link com.android.systemui.pip.phone.PipMotionHelper}. */ @Singleton public class PipTaskOrganizer extends TaskOrganizer { public class PipTaskOrganizer extends TaskOrganizer implements DisplayController.OnDisplaysChangedListener { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final boolean DEBUG = false; private static final int MSG_RESIZE_IMMEDIATE = 1; private static final int MSG_RESIZE_ANIMATE = 2; Loading Loading @@ -206,10 +209,17 @@ public class PipTaskOrganizer extends TaskOrganizer { mSurfaceControlTransactionFactory; private PictureInPictureParams mPictureInPictureParams; /** * If set to {@code true}, the entering animation will be skipped and we will wait for * {@link #onFixedRotationFinished(int)} callback to actually enter PiP. */ private boolean mShouldDeferEnteringPip; @Inject public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @Nullable Divider divider) { @Nullable Divider divider, @NonNull DisplayController displayController) { mMainHandler = new Handler(Looper.getMainLooper()); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); mPipBoundsHandler = boundsHandler; Loading @@ -219,6 +229,7 @@ public class PipTaskOrganizer extends TaskOrganizer { mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; mSplitDivider = divider; displayController.addDisplayWindowListener(this); } public Handler getUpdateHandler() { Loading Loading @@ -281,7 +292,8 @@ public class PipTaskOrganizer extends TaskOrganizer { final int direction = syncWithSplitScreenBounds(destinationBounds) ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN; final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, mLastReportedBounds); tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height()); Loading Loading @@ -325,29 +337,47 @@ public class PipTaskOrganizer extends TaskOrganizer { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) { Objects.requireNonNull(info, "Requires RunningTaskInfo"); mPictureInPictureParams = info.pictureInPictureParams; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( info.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); mTaskInfo = info; mToken = mTaskInfo.token; mInPip = true; mLeash = leash; mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); mPictureInPictureParams = mTaskInfo.pictureInPictureParams; // TODO: Skip enter animation when entering pip from another orientation if (mShouldDeferEnteringPip) { if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing"); // if deferred, hide the surface till fixed rotation is completed final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(mLeash, 0f); tx.apply(); return; } final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { enterPipWithAlphaAnimation(destinationBounds, mEnterExitAnimationDuration); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } } 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 // while to process final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); tx.setAlpha(mLeash, 0f); tx.apply(); final WindowContainerTransaction wct = new WindowContainerTransaction(); Loading @@ -362,14 +392,10 @@ public class PipTaskOrganizer extends TaskOrganizer { .getAnimator(mLeash, destinationBounds, 0f, 1f) .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .setDuration(durationMs) .start()); } }); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } } /** Loading @@ -391,6 +417,7 @@ public class PipTaskOrganizer extends TaskOrganizer { Log.wtf(TAG, "Unrecognized token: " + token); return; } mShouldDeferEnteringPip = false; mPictureInPictureParams = null; mInPip = false; } Loading @@ -416,6 +443,23 @@ public class PipTaskOrganizer extends TaskOrganizer { // Do nothing } @Override public void onFixedRotationStarted(int displayId, int newRotation) { mShouldDeferEnteringPip = true; } @Override public void onFixedRotationFinished(int displayId) { if (mShouldDeferEnteringPip && mInPip) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams), null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); // schedule a regular animation to ensure all the callbacks are still being sent enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */); } mShouldDeferEnteringPip = false; } /** * TODO(b/152809058): consolidate the display info handling logic in SysUI * Loading Loading @@ -476,6 +520,10 @@ public class PipTaskOrganizer extends TaskOrganizer { */ public void scheduleAnimateResizePip(Rect toBounds, int duration, Consumer<Rect> updateBoundsCallback) { if (mShouldDeferEnteringPip) { Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } scheduleAnimateResizePip(mLastReportedBounds, toBounds, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); } Loading Loading @@ -567,6 +615,10 @@ public class PipTaskOrganizer extends TaskOrganizer { // can be initiated in other component, ignore if we are no longer in PIP return; } if (mShouldDeferEnteringPip) { Log.d(TAG, "skip scheduleOffsetPip, entering pip deferred"); return; } SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = originalBounds; Loading
packages/SystemUI/src/com/android/systemui/wm/DisplayController.java +43 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,39 @@ public class DisplayController { } }); } @Override public void onFixedRotationStarted(int displayId, int newRotation) { mHandler.post(() -> { synchronized (mDisplays) { if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) { Slog.w(TAG, "Skipping onFixedRotationStarted on unknown" + " display, displayId=" + displayId); return; } for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) { mDisplayChangedListeners.get(i).onFixedRotationStarted( displayId, newRotation); } } }); } @Override public void onFixedRotationFinished(int displayId) { mHandler.post(() -> { synchronized (mDisplays) { if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) { Slog.w(TAG, "Skipping onFixedRotationFinished on unknown" + " display, displayId=" + displayId); return; } for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) { mDisplayChangedListeners.get(i).onFixedRotationFinished(displayId); } } }); } }; @Inject Loading Loading @@ -232,5 +265,15 @@ public class DisplayController { * Called when a display is removed. */ default void onDisplayRemoved(int displayId) {} /** * Called when fixed rotation on a display is started. */ default void onFixedRotationStarted(int displayId, int newRotation) {} /** * Called when fixed rotation on a display is finished. */ default void onFixedRotationFinished(int displayId) {} } }
services/core/java/com/android/server/wm/DisplayContent.java +24 −7 Original line number Diff line number Diff line Loading @@ -493,10 +493,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * The launching activity which is using fixed rotation transformation. * * @see #handleTopActivityLaunchingInDifferentOrientation * @see #setFixedRotationLaunchingApp * @see #setFixedRotationLaunchingApp(ActivityRecord, int) * @see DisplayRotation#shouldRotateSeamlessly */ ActivityRecord mFixedRotationLaunchingApp; private ActivityRecord mFixedRotationLaunchingApp; final FixedRotationTransitionListener mFixedRotationTransitionListener = new FixedRotationTransitionListener(); Loading Loading @@ -1475,6 +1475,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return true; } @Nullable ActivityRecord getFixedRotationLaunchingApp() { return mFixedRotationLaunchingApp; } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r) { setFixedRotationLaunchingAppUnchecked(r, ROTATION_UNDEFINED); } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); } mFixedRotationLaunchingApp = r; } /** * Sets the provided record to {@link mFixedRotationLaunchingApp} if possible to apply fixed * rotation transform to it and indicate that the display may be rotated after it is launched. Loading @@ -1496,7 +1513,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (!r.hasFixedRotationTransform()) { startFixedRotationTransform(r, rotation); } mFixedRotationLaunchingApp = r; setFixedRotationLaunchingAppUnchecked(r, rotation); if (prevRotatedLaunchingApp != null) { prevRotatedLaunchingApp.finishFixedRotationTransform(); } Loading Loading @@ -1524,7 +1541,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** * Clears the {@link mFixedRotationLaunchingApp} without applying rotation to display. It is * Clears the {@link #mFixedRotationLaunchingApp} without applying rotation to display. It is * used when the display won't rotate (e.g. the orientation from sensor has updated again before * applying rotation to display) but the launching app has been transformed. So the record need * to be cleared and restored to stop using seamless rotation and rotated configuration. Loading @@ -1534,7 +1551,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } mFixedRotationLaunchingApp.finishFixedRotationTransform(); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } private void startFixedRotationTransform(WindowToken token, int rotation) { Loading Loading @@ -5260,7 +5277,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo rotatedLaunchingApp.finishFixedRotationTransform( () -> applyRotation(oldRotation, newRotation)); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } /** Checks whether the given activity is in size compatibility mode and notifies the change. */ Loading Loading @@ -5574,7 +5591,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) { // Because it won't affect display orientation, just finish the transform. animatingRecents.finishFixedRotationTransform(); mFixedRotationLaunchingApp = null; setFixedRotationLaunchingAppUnchecked(null); } else { // If there is already a launching activity that is not the recents, before its // transition is completed, the recents animation may be started. So if the recents Loading
services/core/java/com/android/server/wm/DisplayRotation.java +1 −1 Original line number Diff line number Diff line Loading @@ -577,7 +577,7 @@ public class DisplayRotation { boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) { // Display doesn't need to be frozen because application has been started in correct // rotation already, so the rest of the windows can use seamless rotation. if (mDisplayContent.mFixedRotationLaunchingApp != null) { if (mDisplayContent.getFixedRotationLaunchingApp() != null) { return true; } Loading