Move orientation request into hierarchy.

This CL also removes a hidden method in IWindowManager that's only used
inside of WM right now.

Also wire up Task level logic.

Bug: 113252523
Test: Manual test that app requested orientation still rotates the
display and WmTests.
Change-Id: I7c5046e9beaea79de4ec471eabc792e3593583a2
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1943efc..a5ceee2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -397,10 +397,11 @@
     private final Matrix mTmpMatrix = new Matrix();
     private final Region mTmpRegion = new Region();
 
-
     /** Used for handing back size of display */
     private final Rect mTmpBounds = new Rect();
 
+    private final Configuration mTmpConfiguration = new Configuration();
+
     /** Remove this display when animation on it has completed. */
     private boolean mDeferredRemoval;
 
@@ -1156,6 +1157,36 @@
         mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
     }
 
+    @Override
+    boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+            ConfigurationContainer requestingContainer) {
+        final Configuration config = updateOrientationFromAppTokens(
+                getRequestedOverrideConfiguration(), freezeDisplayToken, false);
+        // If display rotation class tells us that it doesn't consider app requested orientation,
+        // this display won't rotate just because of an app changes its requested orientation. Thus
+        // it indicates that this display chooses not to handle this request.
+        final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+        if (config == null) {
+            return handled;
+        }
+
+        if (handled && requestingContainer instanceof ActivityRecord) {
+            final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
+            final boolean kept = mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+                    config, activityRecord, false /* deferResume */, getDisplayId());
+            activityRecord.frozenBeforeDestroy = true;
+            if (!kept) {
+                mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+            }
+        } else {
+            // We have a new configuration to push so we need to update ATMS for now.
+            // TODO: Clean up display configuration push between ATMS and WMS after unification.
+            mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+                    config, null /* starting */, false /* deferResume */, getDisplayId());
+        }
+        return handled;
+    }
+
     /**
      * Determine the new desired orientation of this display.
      *
@@ -1169,7 +1200,56 @@
         return updateOrientationFromAppTokens(false /* forceUpdate */);
     }
 
-    boolean updateOrientationFromAppTokens(boolean forceUpdate) {
+    /**
+     * Update orientation of the target display, returning a non-null new Configuration if it has
+     * changed from the current orientation. If a non-null configuration is returned, someone must
+     * call {@link WindowManagerService#setNewDisplayOverrideConfiguration(Configuration,
+     * DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
+     * be done by calling {@link WindowManagerService#sendNewConfiguration(int)}.
+     */
+    Configuration updateOrientationFromAppTokens(Configuration currentConfig,
+            IBinder freezeDisplayToken, boolean forceUpdate) {
+        if (!mDisplayReady) {
+            return null;
+        }
+
+        Configuration config = null;
+        if (updateOrientationFromAppTokens(forceUpdate)) {
+            // If we changed the orientation but mOrientationChangeComplete is already true,
+            // we used seamless rotation, and we don't need to freeze the screen.
+            if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
+                final AppWindowToken atoken = getAppWindowToken(freezeDisplayToken);
+                if (atoken != null) {
+                    atoken.startFreezingScreen();
+                }
+            }
+            config = new Configuration();
+            computeScreenConfiguration(config);
+        } else if (currentConfig != null) {
+            // No obvious action we need to take, but if our current state mismatches the
+            // activity manager's, update it, disregarding font scale, which should remain set
+            // to the value of the previous configuration.
+            // Here we're calling Configuration#unset() instead of setToDefaults() because we
+            // need to keep override configs clear of non-empty values (e.g. fontSize).
+            mTmpConfiguration.unset();
+            mTmpConfiguration.updateFrom(currentConfig);
+            computeScreenConfiguration(mTmpConfiguration);
+            if (currentConfig.diff(mTmpConfiguration) != 0) {
+                mWaitingForConfig = true;
+                setLayoutNeeded();
+                int[] anim = new int[2];
+                getDisplayPolicy().selectRotationAnimationLw(anim);
+
+                mWmService.startFreezingDisplayLocked(anim[0], anim[1], this);
+                config = new Configuration(mTmpConfiguration);
+            }
+        }
+
+        return config;
+    }
+
+
+    private boolean updateOrientationFromAppTokens(boolean forceUpdate) {
         final int req = getOrientation();
         if (req != mLastOrientation || forceUpdate) {
             mLastOrientation = req;