OSDN Git Service

Only allow AM to update display orientation based on app containers
authorWale Ogunwale <ogunwale@google.com>
Tue, 2 May 2017 21:49:04 +0000 (14:49 -0700)
committerWale Ogunwale <ogunwale@google.com>
Wed, 3 May 2017 14:22:24 +0000 (07:22 -0700)
Activity manager choregraphs several app states when starting an
activity including when the display orientation should be updated based
on the app that is now in the foreground. It is possible for a call to
originate within WM after AM adds the starting app token, but before AM
makes the app visible and resumed. E.g. A relayout call due to a
starting window. When this happens WM can prematurely update the display
orientation with incomplete information causing the starting app to be
in an incorrect orientation initially.
To fix this problem we now only factor in app containers (stacks, task,
..) when updating the display orientation if the call to update is
coming from AM. Otherwise we only use the non-app/system containers to
determine the orientation or return the last orientation.

Change-Id: I431ce9260ee31257732311a548c62cbcdb27eae7
Fixes: 37550022
Test: Launch 2 apps that don't fix orientation and use the recent button
to switch between them while holding the device in landscape.

services/core/java/com/android/server/wm/DisplayContent.java
services/core/java/com/android/server/wm/WindowManagerService.java

index 67704e7..be242b6 100644 (file)
@@ -1503,8 +1503,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
-    @Override
-    int getOrientation() {
+    /**
+     * Returns the orientation that this display should be in factoring in its children containers.
+     *
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     * @return The orientation the display should be in.
+     */
+    int getOrientation(boolean includeAppContainers) {
         final WindowManagerPolicy policy = mService.mPolicy;
 
         if (mService.mDisplayFrozen) {
@@ -1533,8 +1541,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
             }
         }
 
-        // Top system windows are not requesting an orientation. Start searching from apps.
-        return mTaskStackContainers.getOrientation();
+        // Top system windows are not requesting an orientation. Get orientation from app containers
+        // if allowed. Otherwise, return the last orientation.
+        return includeAppContainers ? mTaskStackContainers.getOrientation() : mLastOrientation;
+    }
+
+    @Override
+    int getOrientation() {
+        return getOrientation(true /* includeAppContainers */);
     }
 
     void updateDisplayInfo() {
index a7f6600..a48397b 100644 (file)
@@ -2373,7 +2373,7 @@ public class WindowManagerService extends IWindowManager.Stub
         try {
             synchronized(mWindowMap) {
                 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
-                        displayId);
+                        displayId, true /* includeAppContainers */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2383,13 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded, int displayId) {
+            IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
         if (!mDisplayReady) {
             return null;
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId)) {
+        if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2427,6 +2427,11 @@ public class WindowManagerService extends IWindowManager.Stub
         return config;
     }
 
+    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+        return updateOrientationFromAppTokensLocked(inTransaction, displayId,
+                false /* includeAppContainers */);
+    }
+
     /**
      * Determine the new desired orientation of the display, returning a non-null new Configuration
      * if it has changed from the current orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
@@ -2437,13 +2442,25 @@ public class WindowManagerService extends IWindowManager.Stub
      * The orientation is computed from non-application windows first. If none of the
      * non-application windows specify orientation, the orientation is computed from application
      * tokens.
+     *
+     * @param inTransaction True if we are currently in a surface transaction.
+     * @param displayId Id of the display to update orientation for.
+     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
+     *                             factored in when determining the orientation. If false only
+     *                             non-app/system containers will be used to determine the returned
+     *                             orientation.
+     *                             NOTE: Only call originating from activity manager are expected to
+     *                             set this to true as it needs to synchronize several app states
+     *                             like visibility with the update of display orientation.
+     * @return True if the display orientation was updated.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
      */
-    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
-        long ident = Binder.clearCallingIdentity();
+    private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
+            boolean includeAppContainers) {
+        final long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
-            final int req = dc.getOrientation();
+            final int req = dc.getOrientation(includeAppContainers);
             if (req != dc.getLastOrientation()) {
                 dc.setLastOrientation(req);
                 //send a message to Policy indicating orientation change to take