Fix "incall in landscape sometimes" bug #2523942

The problem turns out to have been a deep weirdness in the way that keyguard
and incall interact.  Incall gets relaunched when the keyboard is opened/closed,
which transiently exposes keyguard with its nosensor orientation demands, and
that plus the long keyguard-hide animation was leaving incall in a bad state
from which the window manager didn't try to recover.

We now disregard animating-towards-hidden windows [i.e. keyguard] when running
through the app tokens to determine what orientation should be, and do not do
configuration calculations at all while the display is frozen.  There can still
be a transient state in which incall is drawn in landscape, but things proceed
from there to relaunch it back into the proper portrait orientation, and it
ends up in the right state in the end.

Change-Id: I0d74ee19064b6d7f65600976f1b5b16b7ec36f31
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a1a8bf2..cd6a131 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -367,6 +367,8 @@
     boolean mSafeMode;
     boolean mDisplayEnabled = false;
     boolean mSystemBooted = false;
+    int mInitialDisplayWidth = 0;
+    int mInitialDisplayHeight = 0;
     int mRotation = 0;
     int mRequestedRotation = 0;
     int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -1842,6 +1844,8 @@
             if (mDisplay == null) {
                 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
                 mDisplay = wm.getDefaultDisplay();
+                mInitialDisplayWidth = mDisplay.getWidth();
+                mInitialDisplayHeight = mDisplay.getHeight();
                 mQueue.setDisplay(mDisplay);
                 reportNewConfig = true;
             }
@@ -3025,7 +3029,7 @@
                 // app window. No point in continuing further.
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
-            if (!wtoken.isVisibleLw()) {
+            if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
                 continue;
             }
             int req = wtoken.mAttrs.screenOrientation;
@@ -3154,6 +3158,15 @@
      * android.os.IBinder)
      */
     boolean updateOrientationFromAppTokensLocked() {
+        if (mDisplayFrozen) {
+            // If the display is frozen, some activities may be in the middle
+            // of restarting, and thus have removed their old window.  If the
+            // window has the flag to hide the lock screen, then the lock screen
+            // can re-appear and inflict its own orientation on us.  Keep the
+            // orientation stable until this all settles down.
+            return false;
+        }
+
         boolean changed = false;
         long ident = Binder.clearCallingIdentity();
         try {
@@ -4843,8 +4856,13 @@
             return false;
         }
         mQueue.getInputConfiguration(config);
-        final int dw = mDisplay.getWidth();
-        final int dh = mDisplay.getHeight();
+
+        // Use the effective "visual" dimensions based on current rotation
+        final boolean rotated = (mRotation == Surface.ROTATION_90
+                || mRotation == Surface.ROTATION_270);
+        final int dw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
+        final int dh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
+
         int orientation = Configuration.ORIENTATION_SQUARE;
         if (dw < dh) {
             orientation = Configuration.ORIENTATION_PORTRAIT;
@@ -10998,6 +11016,14 @@
             mKeyWaiter.notifyAll();
         }
 
+        // While the display is frozen we don't re-compute the orientation
+        // to avoid inconsistent states.  However, something interesting
+        // could have actually changed during that time so re-evaluate it
+        // now to catch that.
+        if (updateOrientationFromAppTokensLocked()) {
+            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+        }
+
         // A little kludge: a lot could have happened while the
         // display was frozen, so now that we are coming back we
         // do a gc so that any remote references the system