Merge changes I99f18930,I5f6830d8 into nyc-mr1-dev
* changes:
Prevent any rotation while seamless rotation is pending.
Prevent triggering orientation changes until previous completes.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ce0ad25..7a73759 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 @@
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);
@@ -6807,6 +6813,13 @@
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
return false;
}
+ if (mDisplayFrozen) {
+ // Even if the screen rotation animation has finished (e.g. isAnimating
+ // returns false), there is still some time where we haven't yet unfrozen
+ // the display. We also need to abort rotation here.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
+ return false;
+ }
if (!mDisplayEnabled) {
// No point choosing a rotation if the display is not enabled.
@@ -6814,6 +6827,38 @@
return false;
}
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ final WindowList windows = displayContent.getWindowList();
+
+ 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) {
+ return false;
+ }
+ // In what can only be called an unfortunate workaround we require
+ // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
+ // flag. Due to limitations in the client API, there is no way for
+ // the client to set this flag in a race free fashion. If we seamlessly rotate
+ // a window which does not have this flag, but then gains it, we will get
+ // an incorrect visual result (rotated viewfinder). This means if we want to
+ // support seamlessly rotating windows which could gain this flag, we can't
+ // rotate windows without it. This limits seamless rotation in N to camera framework
+ // users, windows without children, and native code. This is unfortunate but
+ // having the camera work is our primary goal.
+ if (w.isChildWindow() & w.isVisibleNow() &&
+ !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
+ rotateSeamlessly = false;
+ }
+ }
+ }
+
// TODO: Implement forced rotation changes.
// Set mAltOrientation to indicate that the application is receiving
// an orientation that has different metrics than it expected.
@@ -6832,7 +6877,7 @@
if (mRotation == rotation && mAltOrientation == altOrientation) {
// No change.
- return false;
+ return false;
}
if (DEBUG_ORIENTATION) {
@@ -6842,8 +6887,6 @@
+ ", lastOrientation=" + mLastOrientation);
}
- int oldRotation = mRotation;
-
mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);
@@ -6852,7 +6895,6 @@
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()) {
@@ -6860,33 +6902,6 @@
} 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.
- if (rotateSeamlessly) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState w = windows.get(i);
- if (w.mSeamlesslyRotated) {
- rotateSeamlessly = false;
- break;
- }
- // In what can only be called an unfortunate workaround we require
- // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
- // flag. Due to limitations in the client API, there is no way for
- // the client to set this flag in a race free fashion. If we seamlessly rotate
- // a window which does not have this flag, but then gains it, we will get
- // an incorrect visual result (rotated viewfinder). This means if we want to
- // support seamlessly rotating windows which could gain this flag, we can't
- // rotate windows without it. This limits seamless rotation in N to camera framework
- // users, windows without children, and native code. This is unfortunate but
- // having the camera work is our primary goal.
- if (w.isChildWindow() & w.isVisibleNow() &&
- !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
- rotateSeamlessly = false;
- }
- }
- }
if (!rotateSeamlessly) {
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
@@ -6899,6 +6914,10 @@
// 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
@@ -8914,8 +8933,8 @@
if (w.mSeamlesslyRotated) {
layoutNeeded = true;
w.setDisplayLayoutNeeded();
+ markForSeamlessRotation(w, false);
}
- w.mSeamlesslyRotated = false;
}
if (layoutNeeded) {
mWindowPlacerLocked.performSurfacePlacement();
@@ -11501,6 +11520,26 @@
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 0285f70..650dac9 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 @@
// 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 @@
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];