diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index bd266968613de..7a73759f03886 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -654,6 +654,12 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; + // A count of the windows which are 'seamlessly rotated', e.g. a surface + // at an old orientation is being transformed. We freeze orientation updates + // while any windows are seamlessly rotated, so we need to track when this + // hits zero so we can apply deferred orientation updates. + int mSeamlessRotationCount = 0; + private final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); @@ -6821,62 +6827,20 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - // TODO: Implement forced rotation changes. - // Set mAltOrientation to indicate that the application is receiving - // an orientation that has different metrics than it expected. - // eg. Portrait instead of Landscape. - - int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation); - boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( - mLastOrientation, rotation); - - if (DEBUG_ORIENTATION) { - Slog.v(TAG_WM, "Selected orientation " - + mLastOrientation + ", got rotation " + rotation - + " which has " + (altOrientation ? "incompatible" : "compatible") - + " metrics"); - } - - if (mRotation == rotation && mAltOrientation == altOrientation) { - // No change. - return false; - } - - if (DEBUG_ORIENTATION) { - Slog.v(TAG_WM, - "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") - + " from " + mRotation + (mAltOrientation ? " (alt)" : "") - + ", lastOrientation=" + mLastOrientation); - } - - int oldRotation = mRotation; - - mRotation = rotation; - mAltOrientation = altOrientation; - mPolicy.setRotationLw(mRotation); - - mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; - mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); - mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION); - mWaitingForConfig = true; final DisplayContent displayContent = getDefaultDisplayContentLocked(); - displayContent.layoutNeeded = true; - final int[] anim = new int[2]; - if (displayContent.isDimming()) { - anim[0] = anim[1] = 0; - } else { - mPolicy.selectRotationAnimationLw(anim); - } - boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation); final WindowList windows = displayContent.getWindowList(); - // We can't rotate seamlessly while an existing seamless rotation is still - // waiting on windows to finish drawing. + + final int oldRotation = mRotation; + boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation); + if (rotateSeamlessly) { for (int i = windows.size() - 1; i >= 0; i--) { WindowState w = windows.get(i); + // We can't rotate (seamlessly or not) while waiting for the last seamless rotation + // to complete (that is, waiting for windows to redraw). It's tempting to check + // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal. if (w.mSeamlesslyRotated) { - rotateSeamlessly = false; - break; + return false; } // In what can only be called an unfortunate workaround we require // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE @@ -6895,6 +6859,50 @@ public class WindowManagerService extends IWindowManager.Stub } } + // TODO: Implement forced rotation changes. + // Set mAltOrientation to indicate that the application is receiving + // an orientation that has different metrics than it expected. + // eg. Portrait instead of Landscape. + + int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation); + boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( + mLastOrientation, rotation); + + if (DEBUG_ORIENTATION) { + Slog.v(TAG_WM, "Selected orientation " + + mLastOrientation + ", got rotation " + rotation + + " which has " + (altOrientation ? "incompatible" : "compatible") + + " metrics"); + } + + if (mRotation == rotation && mAltOrientation == altOrientation) { + // No change. + return false; + } + + if (DEBUG_ORIENTATION) { + Slog.v(TAG_WM, + "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") + + " from " + mRotation + (mAltOrientation ? " (alt)" : "") + + ", lastOrientation=" + mLastOrientation); + } + + mRotation = rotation; + mAltOrientation = altOrientation; + mPolicy.setRotationLw(mRotation); + + mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; + mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); + mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION); + mWaitingForConfig = true; + displayContent.layoutNeeded = true; + final int[] anim = new int[2]; + if (displayContent.isDimming()) { + anim[0] = anim[1] = 0; + } else { + mPolicy.selectRotationAnimationLw(anim); + } + if (!rotateSeamlessly) { startFreezingDisplayLocked(inTransaction, anim[0], anim[1]); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. @@ -6906,6 +6914,10 @@ public class WindowManagerService extends IWindowManager.Stub // When we are rotating seamlessly, we allow the elements to transition // to their rotated state independently and without a freeze required. screenRotationAnimation = null; + + // We have to reset this in case a window was removed before it + // finished seamless rotation. + mSeamlessRotationCount = 0; } // We need to update our screen size information to match the new rotation. If the rotation @@ -8921,8 +8933,8 @@ public class WindowManagerService extends IWindowManager.Stub if (w.mSeamlesslyRotated) { layoutNeeded = true; w.setDisplayLayoutNeeded(); + markForSeamlessRotation(w, false); } - w.mSeamlesslyRotated = false; } if (layoutNeeded) { mWindowPlacerLocked.performSurfacePlacement(); @@ -11508,6 +11520,26 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver); } + void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) { + if (seamlesslyRotated == w.mSeamlesslyRotated) { + return; + } + w.mSeamlesslyRotated = seamlesslyRotated; + if (seamlesslyRotated) { + mSeamlessRotationCount++; + } else { + mSeamlessRotationCount--; + } + if (mSeamlessRotationCount == 0) { + if (DEBUG_ORIENTATION) { + Slog.i(TAG, "Performing post-rotate rotation after seamless rotation"); + } + if (updateRotationUncheckedLocked(false)) { + mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); + } + } + } + private final class LocalService extends WindowManagerInternal { @Override public void requestTraversalFromDisplayManager() { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 0285f7075e957..650dac91eb7f9 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1431,7 +1431,7 @@ class WindowStateAnimator { // If we are undergoing seamless rotation, the surface has already // been set up to persist at it's old location. We need to freeze // updates until a resize occurs. - w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized; + mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized); calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect); @@ -2156,7 +2156,7 @@ class WindowStateAnimator { cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight); mSurfaceController.setCropInTransaction(cropRect, false); } else { - w.mSeamlesslyRotated = true; + mService.markForSeamlessRotation(w, true); transform.getValues(mService.mTmpFloats); float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];