OSDN Git Service

Move rotation methods to DisplayContent
authorAndrii Kulian <akulian@google.com>
Tue, 14 Mar 2017 18:11:47 +0000 (11:11 -0700)
committerAndrii Kulian <akulian@google.com>
Wed, 15 Mar 2017 00:06:28 +0000 (17:06 -0700)
This moves some of the rotation logic applied to displays
from WindowManagerService to DisplayContent. No changes in
logic.

Bug: 34242678
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testRotationNotAffectingSecondaryScreen
Test: android.server.cts.ActivityManagerAppConfigurationTests
Change-Id: Ica8b5d700dea82edfc6b51b10be3362fc89854b0

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

index cb3a663..e5b00f3 100644 (file)
@@ -73,18 +73,24 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.CUSTOM_SCREEN_ROTATION;
 import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
+import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowManagerService.logSurface;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -94,6 +100,7 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE
 
 import android.annotation.NonNull;
 import android.app.ActivityManager.StackId;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
@@ -113,6 +120,7 @@ import android.util.MutableBoolean;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.InputDevice;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManagerPolicy;
@@ -181,12 +189,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
     private final Display mDisplay;
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+    /**
+     * For default display it contains real metrics, empty for others.
+     * @see WindowManagerService#createWatermarkInTransaction()
+     */
+    final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
+    /** @see #computeCompatSmallestWidth(boolean, int, int, int, int) */
+    private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
+    /**
+     * Compat metrics computed based on {@link #mDisplayMetrics}.
+     * @see #updateDisplayAndOrientation(int)
+     */
+    private final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
+
+    /** The desired scaling factor for compatible apps. */
+    float mCompatibleScreenScale;
 
     /**
      * Current rotation of the display.
      * Constants as per {@link android.view.Surface.Rotation}.
      *
-     * @see WindowManagerService#updateRotationUncheckedLocked(boolean, int)
+     * @see #updateRotationUnchecked(boolean)
      */
     private int mRotation = 0;
     /**
@@ -200,7 +223,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
      * Flag indicating that the application is receiving an orientation that has different metrics
      * than it expected. E.g. Portrait instead of Landscape.
      *
-     * @see WindowManagerService#updateRotationUncheckedLocked(boolean, int)
+     * @see #updateRotationUnchecked(boolean)
      */
     private boolean mAltOrientation = false;
     /**
@@ -218,7 +241,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
      */
     private int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
-    Rect mBaseDisplayRect = new Rect();
+    private Rect mBaseDisplayRect = new Rect();
     private Rect mContentRect = new Rect();
 
     // Accessed directly by all users.
@@ -828,6 +851,514 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         return mLastWindowForcedOrientation;
     }
 
+    /**
+     * Update rotation of the display.
+     *
+     * Returns true if the rotation has been changed.  In this case YOU MUST CALL
+     * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+     */
+    boolean updateRotationUnchecked(boolean inTransaction) {
+        if (mService.mDeferredRotationPauseCount > 0) {
+            // Rotation updates have been paused temporarily.  Defer the update until
+            // updates have been resumed.
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
+            return false;
+        }
+
+        ScreenRotationAnimation screenRotationAnimation =
+                mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+            // Rotation updates cannot be performed while the previous rotation change
+            // animation is still in progress.  Skip this update.  We will try updating
+            // again after the animation is finished and the display is unfrozen.
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
+            return false;
+        }
+        if (mService.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 (!mService.mDisplayEnabled) {
+            // No point choosing a rotation if the display is not enabled.
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
+            return false;
+        }
+
+        final int oldRotation = mRotation;
+        final int lastOrientation = mLastOrientation;
+        final boolean oldAltOrientation = mAltOrientation;
+        int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
+        final boolean rotateSeamlessly;
+
+        if (mService.mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
+            final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
+            if (seamlessRotated != null) {
+                // 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.
+                return false;
+            }
+
+            final WindowState cantSeamlesslyRotate = getWindow((w) ->
+                    w.isChildWindow() && w.isVisibleNow()
+                            && !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
+            if (cantSeamlesslyRotate != null) {
+                // 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.
+                rotateSeamlessly = false;
+            } else {
+                rotateSeamlessly = true;
+            }
+        } else {
+            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.
+        //       eg. Portrait instead of Landscape.
+
+        final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw(
+                lastOrientation, rotation);
+
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
+                + ", got rotation " + rotation + " which has "
+                + (altOrientation ? "incompatible" : "compatible") + " metrics");
+
+        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
+            // No change.
+            return false;
+        }
+
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
+                + (altOrientation ? " (alt)" : "") + " from " + oldRotation
+                + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
+
+        if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
+            mService.mWaitingForConfig = true;
+        }
+
+        mRotation = rotation;
+        mAltOrientation = altOrientation;
+        if (isDefaultDisplay) {
+            mService.mPolicy.setRotationLw(rotation);
+        }
+
+        mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
+        mService.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
+        mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
+                WINDOW_FREEZE_TIMEOUT_DURATION);
+
+        setLayoutNeeded();
+        final int[] anim = new int[2];
+        if (isDimming()) {
+            anim[0] = anim[1] = 0;
+        } else {
+            mService.mPolicy.selectRotationAnimationLw(anim);
+        }
+
+        if (!rotateSeamlessly) {
+            mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
+            // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
+            screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
+                    mDisplayId);
+        } else {
+            // The screen rotation animation uses a screenshot to freeze the screen
+            // while windows resize underneath.
+            // 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.
+            mService.mSeamlessRotationCount = 0;
+        }
+
+        // We need to update our screen size information to match the new rotation. If the rotation
+        // has actually changed then this method will return true and, according to the comment at
+        // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
+        // By updating the Display info here it will be available to
+        // #computeScreenConfiguration() later.
+        updateDisplayAndOrientation(getConfiguration().uiMode);
+
+        if (!inTransaction) {
+            if (SHOW_TRANSACTIONS) {
+                Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
+            }
+            mService.openSurfaceTransaction();
+        }
+        try {
+            // NOTE: We disable the rotation in the emulator because
+            //       it doesn't support hardware OpenGL emulation yet.
+            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
+                    && screenRotationAnimation.hasScreenshot()) {
+                if (screenRotationAnimation.setRotationInTransaction(
+                        rotation, mService.mFxSession,
+                        MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
+                        mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
+                    mService.scheduleAnimationLocked();
+                }
+            }
+
+            if (rotateSeamlessly) {
+                forAllWindows(w -> {
+                    w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
+                }, true /* traverseTopToBottom */);
+            }
+
+            mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+        } finally {
+            if (!inTransaction) {
+                mService.closeSurfaceTransaction();
+                if (SHOW_LIGHT_TRANSACTIONS) {
+                    Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
+                }
+            }
+        }
+
+        forAllWindows(w -> {
+            // Discard surface after orientation change, these can't be reused.
+            if (w.mAppToken != null) {
+                w.mAppToken.destroySavedSurfaces();
+            }
+            if (w.mHasSurface && !rotateSeamlessly) {
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
+                w.mOrientationChanging = true;
+                mService.mRoot.mOrientationChangeComplete = false;
+                w.mLastFreezeDuration = 0;
+            }
+            w.mReportOrientationChanged = true;
+        }, true /* traverseTopToBottom */);
+
+        if (rotateSeamlessly) {
+            mService.mH.removeMessages(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT);
+            mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
+                    SEAMLESS_ROTATION_TIMEOUT_DURATION);
+        }
+
+        for (int i = mService.mRotationWatchers.size() - 1; i >= 0; i--) {
+            final WindowManagerService.RotationWatcher rotationWatcher
+                    = mService.mRotationWatchers.get(i);
+            if (rotationWatcher.mDisplayId == mDisplayId) {
+                try {
+                    rotationWatcher.mWatcher.onRotationChanged(rotation);
+                } catch (RemoteException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        // TODO (multi-display): Magnification is supported only for the default display.
+        // Announce rotation only if we will not animate as we already have the
+        // windows in final state. Otherwise, we make this call at the rotation end.
+        if (screenRotationAnimation == null && mService.mAccessibilityController != null
+                && isDefaultDisplay) {
+            mService.mAccessibilityController.onRotationChangedLocked(this);
+        }
+
+        return true;
+    }
+
+    /**
+     * Update {@link #mDisplayInfo} and other internal variables when display is rotated or config
+     * changed.
+     * Do not call if {@link WindowManagerService#mDisplayReady} == false.
+     */
+    private DisplayInfo updateDisplayAndOrientation(int uiMode) {
+        // Use the effective "visual" dimensions based on current rotation
+        final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
+        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
+        int dw = realdw;
+        int dh = realdh;
+
+        if (mAltOrientation) {
+            if (realdw > realdh) {
+                // Turn landscape into portrait.
+                int maxw = (int)(realdh/1.3f);
+                if (maxw < realdw) {
+                    dw = maxw;
+                }
+            } else {
+                // Turn portrait into landscape.
+                int maxh = (int)(realdw/1.3f);
+                if (maxh < realdh) {
+                    dh = maxh;
+                }
+            }
+        }
+
+        // Update application display metrics.
+        final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
+                mDisplayId);
+        final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
+                mDisplayId);
+        mDisplayInfo.rotation = mRotation;
+        mDisplayInfo.logicalWidth = dw;
+        mDisplayInfo.logicalHeight = dh;
+        mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
+        mDisplayInfo.appWidth = appWidth;
+        mDisplayInfo.appHeight = appHeight;
+        if (isDefaultDisplay) {
+            mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        }
+        mDisplayInfo.getAppMetrics(mDisplayMetrics);
+        if (mDisplayScalingDisabled) {
+            mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
+        } else {
+            mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
+        }
+
+        mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
+                mDisplayInfo);
+
+        mBaseDisplayRect.set(0, 0, dw, dh);
+
+        if (isDefaultDisplay) {
+            mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
+                    mCompatDisplayMetrics);
+        }
+        return mDisplayInfo;
+    }
+
+    /**
+     * Compute display configuration based on display properties and policy settings.
+     * Do not call if mDisplayReady == false.
+     */
+    void computeScreenConfiguration(Configuration config) {
+        final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode);
+
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
+        config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
+                Configuration.ORIENTATION_LANDSCAPE;
+        config.screenWidthDp =
+                (int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
+                        config.uiMode, mDisplayId) / mDisplayMetrics.density);
+        config.screenHeightDp =
+                (int)(mService.mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
+                        config.uiMode, mDisplayId) / mDisplayMetrics.density);
+        final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
+                || displayInfo.rotation == Surface.ROTATION_270);
+
+        computeSizeRangesAndScreenLayout(displayInfo, mDisplayId, rotated, config.uiMode, dw, dh,
+                mDisplayMetrics.density, config);
+
+        config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
+                | ((displayInfo.flags & Display.FLAG_ROUND) != 0
+                ? Configuration.SCREENLAYOUT_ROUND_YES
+                : Configuration.SCREENLAYOUT_ROUND_NO);
+
+        config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
+        config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
+        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
+                dh, mDisplayId);
+        config.densityDpi = displayInfo.logicalDensityDpi;
+
+        config.colorMode =
+                (displayInfo.isHdr()
+                        ? Configuration.COLOR_MODE_HDR_YES
+                        : Configuration.COLOR_MODE_HDR_NO)
+                        | (displayInfo.isWideColorGamut()
+                        ? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
+                        : Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
+
+        // Update the configuration based on available input devices, lid switch,
+        // and platform configuration.
+        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+        config.keyboard = Configuration.KEYBOARD_NOKEYS;
+        config.navigation = Configuration.NAVIGATION_NONAV;
+
+        int keyboardPresence = 0;
+        int navigationPresence = 0;
+        final InputDevice[] devices = mService.mInputManager.getInputDevices();
+        final int len = devices != null ? devices.length : 0;
+        for (int i = 0; i < len; i++) {
+            InputDevice device = devices[i];
+            if (!device.isVirtual()) {
+                final int sources = device.getSources();
+                final int presenceFlag = device.isExternal() ?
+                        WindowManagerPolicy.PRESENCE_EXTERNAL :
+                        WindowManagerPolicy.PRESENCE_INTERNAL;
+
+                // TODO(multi-display): Configure on per-display basis.
+                if (mService.mIsTouchDevice) {
+                    if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
+                            InputDevice.SOURCE_TOUCHSCREEN) {
+                        config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
+                    }
+                } else {
+                    config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+                }
+
+                if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
+                    config.navigation = Configuration.NAVIGATION_TRACKBALL;
+                    navigationPresence |= presenceFlag;
+                } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
+                        && config.navigation == Configuration.NAVIGATION_NONAV) {
+                    config.navigation = Configuration.NAVIGATION_DPAD;
+                    navigationPresence |= presenceFlag;
+                }
+
+                if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
+                    config.keyboard = Configuration.KEYBOARD_QWERTY;
+                    keyboardPresence |= presenceFlag;
+                }
+            }
+        }
+
+        if (config.navigation == Configuration.NAVIGATION_NONAV && mService.mHasPermanentDpad) {
+            config.navigation = Configuration.NAVIGATION_DPAD;
+            navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
+        }
+
+        // Determine whether a hard keyboard is available and enabled.
+        // TODO(multi-display): Should the hardware keyboard be tied to a display or to a device?
+        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
+        if (hardKeyboardAvailable != mService.mHardKeyboardAvailable) {
+            mService.mHardKeyboardAvailable = hardKeyboardAvailable;
+            mService.mH.removeMessages(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+            mService.mH.sendEmptyMessage(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+        }
+
+        // Let the policy update hidden states.
+        config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+        config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
+        config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
+        mService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
+    }
+
+    private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
+            int displayId) {
+        mTmpDisplayMetrics.setTo(mDisplayMetrics);
+        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
+        final int unrotDw, unrotDh;
+        if (rotated) {
+            unrotDw = dh;
+            unrotDh = dw;
+        } else {
+            unrotDw = dw;
+            unrotDh = dh;
+        }
+        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
+                displayId);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
+                displayId);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
+                displayId);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
+                displayId);
+        return sw;
+    }
+
+    private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
+            DisplayMetrics dm, int dw, int dh, int displayId) {
+        dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
+                displayId);
+        dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
+                uiMode, displayId);
+        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
+        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
+        if (curSize == 0 || size < curSize) {
+            curSize = size;
+        }
+        return curSize;
+    }
+
+    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
+            boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
+
+        // We need to determine the smallest width that will occur under normal
+        // operation.  To this, start with the base screen size and compute the
+        // width under the different possible rotations.  We need to un-rotate
+        // the current screen dimensions before doing this.
+        int unrotDw, unrotDh;
+        if (rotated) {
+            unrotDw = dh;
+            unrotDh = dw;
+        } else {
+            unrotDw = dw;
+            unrotDh = dh;
+        }
+        displayInfo.smallestNominalAppWidth = 1<<30;
+        displayInfo.smallestNominalAppHeight = 1<<30;
+        displayInfo.largestNominalAppWidth = 0;
+        displayInfo.largestNominalAppHeight = 0;
+        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
+                unrotDh);
+        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
+                unrotDw);
+        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
+                unrotDh);
+        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
+                unrotDw);
+        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
+                displayId);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
+                displayId);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
+                displayId);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
+                displayId);
+        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
+        outConfig.screenLayout = sl;
+    }
+
+    private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
+            int uiMode, int displayId) {
+        // Get the app screen size at this rotation.
+        int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
+        int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
+
+        // Compute the screen layout size class for this rotation.
+        int longSize = w;
+        int shortSize = h;
+        if (longSize < shortSize) {
+            int tmp = longSize;
+            longSize = shortSize;
+            shortSize = tmp;
+        }
+        longSize = (int)(longSize/density);
+        shortSize = (int)(shortSize/density);
+        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
+    }
+
+    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
+            int uiMode, int dw, int dh) {
+        final int width = mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
+                displayId);
+        if (width < displayInfo.smallestNominalAppWidth) {
+            displayInfo.smallestNominalAppWidth = width;
+        }
+        if (width > displayInfo.largestNominalAppWidth) {
+            displayInfo.largestNominalAppWidth = width;
+        }
+        final int height = mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode,
+                displayId);
+        if (height < displayInfo.smallestNominalAppHeight) {
+            displayInfo.smallestNominalAppHeight = height;
+        }
+        if (height > displayInfo.largestNominalAppHeight) {
+            displayInfo.largestNominalAppHeight = height;
+        }
+    }
+
     DockedStackDividerController getDockedDividerController() {
         return mDividerControllerLocked;
     }
index 0222b3d..68d0f24 100644 (file)
@@ -55,13 +55,11 @@ import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -740,7 +738,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             // TODO(multi-display): Update rotation for different displays separately.
             final int displayId = defaultDisplay.getDisplayId();
-            if (mService.updateRotationUncheckedLocked(false, displayId)) {
+            if (defaultDisplay.updateRotationUnchecked(false /* inTransaction */)) {
                 mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
             } else {
                 mUpdateRotation = false;
index 64614fe..b063e01 100644 (file)
@@ -111,7 +111,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -592,11 +591,6 @@ public class WindowManagerService extends IWindowManager.Stub
 
     boolean mIsTouchDevice;
 
-    final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-    final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
-    final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
-    final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
-
     final H mH = new H();
 
     final Choreographer mChoreographer = Choreographer.getInstance();
@@ -841,9 +835,6 @@ public class WindowManagerService extends IWindowManager.Stub
 
     final Configuration mTempConfiguration = new Configuration();
 
-    // The desired scaling factor for compatible apps.
-    float mCompatibleScreenScale;
-
     // If true, only the core apps and services are being launched because the device
     // is in a special boot mode, such as being encrypted or waiting for a decryption password.
     // For example, when this flag is true, there will be no wallpaper service.
@@ -2461,10 +2452,10 @@ public class WindowManagerService extends IWindowManager.Stub
             // to keep override configs clear of non-empty values (e.g. fontSize).
             mTempConfiguration.unset();
             mTempConfiguration.updateFrom(currentConfig);
-            computeScreenConfigurationLocked(mTempConfiguration, displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            displayContent.computeScreenConfiguration(mTempConfiguration);
             if (currentConfig.diff(mTempConfiguration) != 0) {
                 mWaitingForConfig = true;
-                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 displayContent.setLayoutNeeded();
                 int anim[] = new int[2];
                 if (displayContent.isDimming()) {
@@ -2505,7 +2496,7 @@ public class WindowManagerService extends IWindowManager.Stub
                 if (dc.isDefaultDisplay) {
                     mPolicy.setCurrentOrientationLw(req);
                 }
-                if (updateRotationUncheckedLocked(inTransaction, displayId)) {
+                if (dc.updateRotationUnchecked(inTransaction)) {
                     // changed
                     return true;
                 }
@@ -3843,10 +3834,12 @@ public class WindowManagerService extends IWindowManager.Stub
             mDeferredRotationPauseCount -= 1;
             if (mDeferredRotationPauseCount == 0) {
                 // TODO(multi-display): Update rotation for different displays separately.
-                final int displayId = DEFAULT_DISPLAY;
-                final boolean changed = updateRotationUncheckedLocked(false, displayId);
+                final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                final boolean changed = displayContent.updateRotationUnchecked(
+                        false /* inTransaction */);
                 if (changed) {
-                    mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+                    mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
+                            .sendToTarget();
                 }
             }
         }
@@ -3862,9 +3855,10 @@ public class WindowManagerService extends IWindowManager.Stub
         try {
             final boolean rotationChanged;
             // TODO(multi-display): Update rotation for different displays separately.
-            int displayId = DEFAULT_DISPLAY;
+            final DisplayContent displayContent = getDefaultDisplayContentLocked();
             synchronized (mWindowMap) {
-                rotationChanged = updateRotationUncheckedLocked(false, displayId);
+                rotationChanged = displayContent.updateRotationUnchecked(
+                        false /* inTransaction */);
                 if (!rotationChanged || forceRelayout) {
                     getDefaultDisplayContentLocked().setLayoutNeeded();
                     mWindowPlacerLocked.performSurfacePlacement();
@@ -3872,234 +3866,13 @@ public class WindowManagerService extends IWindowManager.Stub
             }
 
             if (rotationChanged || alwaysSendConfiguration) {
-                sendNewConfiguration(displayId);
+                sendNewConfiguration(displayContent.getDisplayId());
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
-
-    // TODO(multidisplay): Rotate any display? Move to DisplayContent
-    /**
-     * Updates the current rotation of the specified display.
-     *
-     * Returns true if the rotation has been changed.  In this case YOU MUST CALL
-     * {@link #sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
-     */
-    boolean updateRotationUncheckedLocked(boolean inTransaction, int displayId) {
-        if (mDeferredRotationPauseCount > 0) {
-            // Rotation updates have been paused temporarily.  Defer the update until
-            // updates have been resumed.
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
-            return false;
-        }
-
-        ScreenRotationAnimation screenRotationAnimation =
-                mAnimator.getScreenRotationAnimationLocked(displayId);
-        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-            // Rotation updates cannot be performed while the previous rotation change
-            // animation is still in progress.  Skip this update.  We will try updating
-            // again after the animation is finished and the display is unfrozen.
-            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.
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
-            return false;
-        }
-
-        final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
-        final int oldRotation = dc.getRotation();
-        final int lastOrientation = dc.getLastOrientation();
-        final boolean oldAltOrientation = dc.getAltOrientation();
-        int rotation = mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
-        final boolean rotateSeamlessly;
-
-        if (mPolicy.shouldRotateSeamlessly(oldRotation, rotation)) {
-            final WindowState seamlessRotated = dc.getWindow((w) -> w.mSeamlesslyRotated);
-            if (seamlessRotated != null) {
-                // 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.
-                return false;
-            }
-
-            final WindowState cantSeamlesslyRotate = dc.getWindow((w) ->
-                    w.isChildWindow() && w.isVisibleNow()
-                            && !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse());
-            if (cantSeamlesslyRotate != null) {
-                // 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.
-                rotateSeamlessly = false;
-            } else {
-                rotateSeamlessly = true;
-            }
-        } else {
-            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.
-        //       eg. Portrait instead of Landscape.
-
-        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(lastOrientation, rotation);
-
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
-                + ", got rotation " + rotation + " which has "
-                + (altOrientation ? "incompatible" : "compatible") + " metrics");
-
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
-            // No change.
-            return false;
-        }
-
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
-                + (altOrientation ? " (alt)" : "") + " from " + oldRotation
-                + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
-
-        if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
-            mWaitingForConfig = true;
-        }
-
-        dc.setRotation(rotation);
-        dc.setAltOrientation(altOrientation);
-        if (dc.isDefaultDisplay) {
-            mPolicy.setRotationLw(rotation);
-        }
-
-        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
-        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
-        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
-
-        dc.setLayoutNeeded();
-        final int[] anim = new int[2];
-        if (dc.isDimming()) {
-            anim[0] = anim[1] = 0;
-        } else {
-            mPolicy.selectRotationAnimationLw(anim);
-        }
-
-        if (!rotateSeamlessly) {
-            startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
-            // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
-            screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(displayId);
-        } else {
-            // The screen rotation animation uses a screenshot to freeze the screen
-            // while windows resize underneath.
-            // 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
-        // has actually changed then this method will return true and, according to the comment at
-        // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
-        // By updating the Display info here it will be available to
-        // computeScreenConfigurationLocked later.
-        updateDisplayAndOrientationLocked(dc.getConfiguration().uiMode, displayId);
-
-        final DisplayInfo displayInfo = dc.getDisplayInfo();
-        if (!inTransaction) {
-            if (SHOW_TRANSACTIONS) {
-                Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
-            }
-            openSurfaceTransaction();
-        }
-        try {
-            // NOTE: We disable the rotation in the emulator because
-            //       it doesn't support hardware OpenGL emulation yet.
-            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
-                    && screenRotationAnimation.hasScreenshot()) {
-                if (screenRotationAnimation.setRotationInTransaction(
-                        rotation, mFxSession,
-                        MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(),
-                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
-                    scheduleAnimationLocked();
-                }
-            }
-
-            if (rotateSeamlessly) {
-                dc.forAllWindows(w -> {
-                        w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
-                }, true /* traverseTopToBottom */);
-            }
-
-            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
-        } finally {
-            if (!inTransaction) {
-                closeSurfaceTransaction();
-                if (SHOW_LIGHT_TRANSACTIONS) {
-                    Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
-                }
-            }
-        }
-
-        dc.forAllWindows(w -> {
-            // Discard surface after orientation change, these can't be reused.
-            if (w.mAppToken != null) {
-                w.mAppToken.destroySavedSurfaces();
-            }
-            if (w.mHasSurface && !rotateSeamlessly) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
-                w.mOrientationChanging = true;
-                mRoot.mOrientationChangeComplete = false;
-                w.mLastFreezeDuration = 0;
-            }
-            w.mReportOrientationChanged = true;
-        }, true /* traverseTopToBottom */);
-
-        if (rotateSeamlessly) {
-            mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
-            mH.sendEmptyMessageDelayed(H.SEAMLESS_ROTATION_TIMEOUT, SEAMLESS_ROTATION_TIMEOUT_DURATION);
-        }
-
-        for (int i = mRotationWatchers.size() - 1; i >= 0; i--) {
-            final RotationWatcher rotationWatcher = mRotationWatchers.get(i);
-            if (rotationWatcher.mDisplayId == displayId) {
-                try {
-                    rotationWatcher.mWatcher.onRotationChanged(rotation);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        // TODO (multidisplay): Magnification is supported only for the default display.
-        // Announce rotation only if we will not animate as we already have the
-        // windows in final state. Otherwise, we make this call at the rotation end.
-        if (screenRotationAnimation == null && mAccessibilityController != null
-                && dc.getDisplayId() == DEFAULT_DISPLAY) {
-            mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked());
-        }
-
-        return true;
-    }
-
     @Override
     public int getDefaultDisplayRotation() {
         synchronized (mWindowMap) {
@@ -4572,7 +4345,7 @@ public class WindowManagerService extends IWindowManager.Stub
                 // Something changed (E.g. device rotation), but no configuration update is needed.
                 // E.g. changing device rotation by 180 degrees. Go ahead and perform surface
                 // placement to unfreeze the display since we froze it when the rotation was updated
-                // in updateRotationUncheckedLocked.
+                // in DisplayContent#updateRotationUnchecked.
                 synchronized (mWindowMap) {
                     if (mWaitingForConfig) {
                         mWaitingForConfig = false;
@@ -4597,297 +4370,9 @@ public class WindowManagerService extends IWindowManager.Stub
             return null;
         }
         final Configuration config = new Configuration();
-        computeScreenConfigurationLocked(config, displayId);
-        return config;
-    }
-
-    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
-            int uiMode, int dw, int dh) {
-        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode, displayId);
-        if (width < displayInfo.smallestNominalAppWidth) {
-            displayInfo.smallestNominalAppWidth = width;
-        }
-        if (width > displayInfo.largestNominalAppWidth) {
-            displayInfo.largestNominalAppWidth = width;
-        }
-        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode, displayId);
-        if (height < displayInfo.smallestNominalAppHeight) {
-            displayInfo.smallestNominalAppHeight = height;
-        }
-        if (height > displayInfo.largestNominalAppHeight) {
-            displayInfo.largestNominalAppHeight = height;
-        }
-    }
-
-    private int reduceConfigLayout(int curLayout, int rotation, float density,
-            int dw, int dh, int uiMode, int displayId) {
-        // Get the app screen size at this rotation.
-        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
-        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
-
-        // Compute the screen layout size class for this rotation.
-        int longSize = w;
-        int shortSize = h;
-        if (longSize < shortSize) {
-            int tmp = longSize;
-            longSize = shortSize;
-            shortSize = tmp;
-        }
-        longSize = (int)(longSize/density);
-        shortSize = (int)(shortSize/density);
-        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
-    }
-
-    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
-            boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
-
-        // We need to determine the smallest width that will occur under normal
-        // operation.  To this, start with the base screen size and compute the
-        // width under the different possible rotations.  We need to un-rotate
-        // the current screen dimensions before doing this.
-        int unrotDw, unrotDh;
-        if (rotated) {
-            unrotDw = dh;
-            unrotDh = dw;
-        } else {
-            unrotDw = dw;
-            unrotDh = dh;
-        }
-        displayInfo.smallestNominalAppWidth = 1<<30;
-        displayInfo.smallestNominalAppHeight = 1<<30;
-        displayInfo.largestNominalAppWidth = 0;
-        displayInfo.largestNominalAppHeight = 0;
-        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
-                unrotDh);
-        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
-                unrotDw);
-        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
-                unrotDh);
-        adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
-                unrotDw);
-        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
-                displayId);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
-                displayId);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
-                displayId);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
-                displayId);
-        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
-        outConfig.screenLayout = sl;
-    }
-
-    private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
-            DisplayMetrics dm, int dw, int dh, int displayId) {
-        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
-                displayId);
-        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
-                displayId);
-        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
-        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
-        if (curSize == 0 || size < curSize) {
-            curSize = size;
-        }
-        return curSize;
-    }
-
-    private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw,
-            int dh, int displayId) {
-        mTmpDisplayMetrics.setTo(dm);
-        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
-        final int unrotDw, unrotDh;
-        if (rotated) {
-            unrotDw = dh;
-            unrotDh = dw;
-        } else {
-            unrotDw = dw;
-            unrotDh = dh;
-        }
-        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
-                displayId);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
-                displayId);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
-                displayId);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
-                displayId);
-        return sw;
-    }
-
-    /** Do not call if mDisplayReady == false */
-    private DisplayInfo updateDisplayAndOrientationLocked(int uiMode, int displayId) {
         final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-
-        // TODO(multi-display): Implement rotation for secondary displays.
-        final boolean isDefaultDisplay = displayContent.isDefaultDisplay;
-        final int displayRotation = displayContent.getRotation();
-        final boolean altDisplayOrientation = displayContent.getAltOrientation();
-
-        // Use the effective "visual" dimensions based on current rotation
-        final boolean rotated = (displayRotation == Surface.ROTATION_90
-                || displayRotation == Surface.ROTATION_270);
-        final int realdw = rotated ?
-                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
-        final int realdh = rotated ?
-                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
-        int dw = realdw;
-        int dh = realdh;
-
-        if (altDisplayOrientation) {
-            if (realdw > realdh) {
-                // Turn landscape into portrait.
-                int maxw = (int)(realdh/1.3f);
-                if (maxw < realdw) {
-                    dw = maxw;
-                }
-            } else {
-                // Turn portrait into landscape.
-                int maxh = (int)(realdw/1.3f);
-                if (maxh < realdh) {
-                    dh = maxh;
-                }
-            }
-        }
-
-        // Update application display metrics.
-        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, displayRotation, uiMode,
-                displayId);
-        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, displayRotation, uiMode,
-                displayId);
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        displayInfo.rotation = displayRotation;
-        displayInfo.logicalWidth = dw;
-        displayInfo.logicalHeight = dh;
-        displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
-        displayInfo.appWidth = appWidth;
-        displayInfo.appHeight = appHeight;
-        if (isDefaultDisplay) {
-            displayInfo.getLogicalMetrics(mRealDisplayMetrics,
-                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
-        }
-        displayInfo.getAppMetrics(mDisplayMetrics);
-        if (displayContent.mDisplayScalingDisabled) {
-            displayInfo.flags |= Display.FLAG_SCALING_DISABLED;
-        } else {
-            displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
-        }
-
-        mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
-                displayContent.getDisplayId(), displayInfo);
-
-        displayContent.mBaseDisplayRect.set(0, 0, dw, dh);
-        if (false) {
-            Slog.i(TAG_WM, "Set app display size: " + appWidth + " x " + appHeight);
-        }
-
-        if (isDefaultDisplay) {
-            mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
-                    mCompatDisplayMetrics);
-        }
-        return displayInfo;
-    }
-
-    /** Do not call if mDisplayReady == false */
-    private void computeScreenConfigurationLocked(Configuration config, int displayId) {
-        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(config.uiMode, displayId);
-
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
-        config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
-                Configuration.ORIENTATION_LANDSCAPE;
-        config.screenWidthDp =
-                (int)(mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation, config.uiMode,
-                        displayId) / mDisplayMetrics.density);
-        config.screenHeightDp =
-                (int)(mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation, config.uiMode,
-                        displayId) / mDisplayMetrics.density);
-        final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
-                || displayInfo.rotation == Surface.ROTATION_270);
-
-        computeSizeRangesAndScreenLayout(displayInfo, displayId, rotated, config.uiMode, dw, dh,
-                mDisplayMetrics.density, config);
-
-        config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
-                | ((displayInfo.flags & Display.FLAG_ROUND) != 0
-                        ? Configuration.SCREENLAYOUT_ROUND_YES
-                        : Configuration.SCREENLAYOUT_ROUND_NO);
-
-        config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
-        config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
-        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode,
-                mDisplayMetrics, dw, dh, displayId);
-        config.densityDpi = displayInfo.logicalDensityDpi;
-
-        config.colorMode =
-                (displayInfo.isHdr()
-                        ? Configuration.COLOR_MODE_HDR_YES
-                        : Configuration.COLOR_MODE_HDR_NO)
-                | (displayInfo.isWideColorGamut()
-                        ? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
-                        : Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
-
-        // Update the configuration based on available input devices, lid switch,
-        // and platform configuration.
-        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-        config.keyboard = Configuration.KEYBOARD_NOKEYS;
-        config.navigation = Configuration.NAVIGATION_NONAV;
-
-        int keyboardPresence = 0;
-        int navigationPresence = 0;
-        final InputDevice[] devices = mInputManager.getInputDevices();
-        final int len = devices != null ? devices.length : 0;
-        for (int i = 0; i < len; i++) {
-            InputDevice device = devices[i];
-            if (!device.isVirtual()) {
-                final int sources = device.getSources();
-                final int presenceFlag = device.isExternal() ?
-                        WindowManagerPolicy.PRESENCE_EXTERNAL :
-                                WindowManagerPolicy.PRESENCE_INTERNAL;
-
-                if (mIsTouchDevice) {
-                    if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
-                            InputDevice.SOURCE_TOUCHSCREEN) {
-                        config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
-                    }
-                } else {
-                    config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-                }
-
-                if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
-                    config.navigation = Configuration.NAVIGATION_TRACKBALL;
-                    navigationPresence |= presenceFlag;
-                } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
-                        && config.navigation == Configuration.NAVIGATION_NONAV) {
-                    config.navigation = Configuration.NAVIGATION_DPAD;
-                    navigationPresence |= presenceFlag;
-                }
-
-                if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
-                    config.keyboard = Configuration.KEYBOARD_QWERTY;
-                    keyboardPresence |= presenceFlag;
-                }
-            }
-        }
-
-        if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {
-            config.navigation = Configuration.NAVIGATION_DPAD;
-            navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
-        }
-
-        // Determine whether a hard keyboard is available and enabled.
-        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
-        if (hardKeyboardAvailable != mHardKeyboardAvailable) {
-            mHardKeyboardAvailable = hardKeyboardAvailable;
-            mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
-            mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
-        }
-
-        // Let the policy update hidden states.
-        config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
-        config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
-        config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
-        mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
+        displayContent.computeScreenConfiguration(config);
+        return config;
     }
 
     void notifyHardKeyboardStatusChange() {
@@ -6099,7 +5584,7 @@ public class WindowManagerService extends IWindowManager.Stub
                 displayId);
         final Configuration currentDisplayConfig = displayContent.getConfiguration();
         mTempConfiguration.setTo(currentDisplayConfig);
-        computeScreenConfigurationLocked(mTempConfiguration, displayId);
+        displayContent.computeScreenConfiguration(mTempConfiguration);
         configChanged |= currentDisplayConfig.diff(mTempConfiguration) != 0;
 
         if (configChanged) {
@@ -6562,7 +6047,8 @@ public class WindowManagerService extends IWindowManager.Stub
 
         if (updateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
-            configChanged |= updateRotationUncheckedLocked(false, displayId);
+            configChanged |= displayContent.updateRotationUnchecked(
+                    false /* inTransaction */);
         }
 
         if (configChanged) {
@@ -6605,8 +6091,9 @@ public class WindowManagerService extends IWindowManager.Stub
                 String[] toks = line.split("%");
                 if (toks != null && toks.length > 0) {
                     // TODO(multi-display): Show watermarks on secondary displays.
-                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
-                            mRealDisplayMetrics, mFxSession, toks);
+                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                    mWatermark = new Watermark(displayContent.getDisplay(),
+                            displayContent.mRealDisplayMetrics, mFxSession, toks);
                 }
             }
         } catch (FileNotFoundException e) {
@@ -7642,9 +7129,10 @@ public class WindowManagerService extends IWindowManager.Stub
             if (DEBUG_ORIENTATION) {
                 Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
             }
-            final int displayId = w.getDisplayId();
-            if (updateRotationUncheckedLocked(false, displayId)) {
-                mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+            final DisplayContent displayContent = w.getDisplayContent();
+            if (displayContent.updateRotationUnchecked(false /* inTransaction */)) {
+                mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
+                        .sendToTarget();
             }
         }
     }
index ccbc5ba..4e593d8 100644 (file)
@@ -1273,8 +1273,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
 
     void prelayout() {
         if (mEnforceSizeCompat) {
-            mGlobalScale = mService.mCompatibleScreenScale;
-            mInvGlobalScale = 1/mGlobalScale;
+            mGlobalScale = getDisplayContent().mCompatibleScreenScale;
+            mInvGlobalScale = 1 / mGlobalScale;
         } else {
             mGlobalScale = mInvGlobalScale = 1;
         }