Add new system API for stable display size

Fixes: 34388294
Test: manual
Change-Id: Ie380230bbd82370f507161b4cdb6f0d100b09f11
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 8269042..d0a1d9e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -31,6 +31,8 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Point;
 import android.hardware.SensorManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.DisplayManagerInternal;
@@ -211,6 +213,12 @@
     // The virtual display adapter, or null if not registered.
     private VirtualDisplayAdapter mVirtualDisplayAdapter;
 
+    // The stable device screen height and width. These are not tied to a specific display, even
+    // the default display, because they need to be stable over the course of the device's entire
+    // life, even if the default display changes (e.g. a new monitor is plugged into a PC-like
+    // device).
+    private Point mStableDisplaySize = new Point();
+
     // Viewports of the default display and the display that should receive touch
     // input from an external source.  Used by the input system.
     private final DisplayViewport mDefaultViewport = new DisplayViewport();
@@ -284,7 +292,10 @@
         // adapter is up so that we have it's configuration. We could load it lazily, but since
         // we're going to have to read it in eventually we may as well do it here rather than after
         // we've waited for the display to register itself with us.
-        mPersistentDataStore.loadIfNeeded();
+		synchronized(mSyncRoot) {
+			mPersistentDataStore.loadIfNeeded();
+			loadStableDisplayValuesLocked();
+        }
         mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
 
         publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
@@ -346,6 +357,34 @@
         return mHandler;
     }
 
+    private void loadStableDisplayValuesLocked() {
+        final Point size = mPersistentDataStore.getStableDisplaySize();
+        if (size.x > 0 && size.y > 0) {
+            // Just set these values directly so we don't write the display persistent data again
+            // unnecessarily
+            mStableDisplaySize.set(size.x, size.y);
+        } else {
+            final Resources res = mContext.getResources();
+            final int width = res.getInteger(
+                    com.android.internal.R.integer.config_stableDeviceDisplayWidth);
+            final int height = res.getInteger(
+                    com.android.internal.R.integer.config_stableDeviceDisplayHeight);
+            if (width > 0 && height > 0) {
+                setStableDisplaySizeLocked(width, height);
+            }
+        }
+    }
+
+    private Point getStableDisplaySizeInternal() {
+        Point r = new Point();
+        synchronized (mSyncRoot) {
+            if (mStableDisplaySize.x > 0 && mStableDisplaySize.y > 0) {
+                r.set(mStableDisplaySize.x, mStableDisplaySize.y);
+            }
+        }
+        return r;
+    }
+
     private void registerDisplayTransactionListenerInternal(
             DisplayTransactionListener listener) {
         // List is self-synchronized copy-on-write.
@@ -770,18 +809,6 @@
         if (work != null) {
             work.run();
         }
-        if (display != null && display.getPrimaryDisplayDeviceLocked() == device) {
-            int colorMode = mPersistentDataStore.getColorMode(device);
-            if (colorMode == Display.COLOR_MODE_INVALID) {
-                if ((device.getDisplayDeviceInfoLocked().flags
-                     & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
-                    colorMode = mDefaultDisplayDefaultColorMode;
-                } else {
-                    colorMode = Display.COLOR_MODE_DEFAULT;
-                }
-            }
-            display.setRequestedColorModeLocked(colorMode);
-        }
         scheduleTraversalLocked(false);
     }
 
@@ -886,6 +913,11 @@
             return null;
         }
 
+        configureColorModeLocked(display, device);
+        if (isDefault) {
+            recordStableDisplayStatsIfNeededLocked(display);
+        }
+
         mLogicalDisplays.put(displayId, display);
 
         // Wake up waitForDefaultDisplay.
@@ -907,6 +939,40 @@
         return displayId;
     }
 
+    private void configureColorModeLocked(LogicalDisplay display, DisplayDevice device) {
+        if (display.getPrimaryDisplayDeviceLocked() == device) {
+            int colorMode = mPersistentDataStore.getColorMode(device);
+            if (colorMode == Display.COLOR_MODE_INVALID) {
+                if ((device.getDisplayDeviceInfoLocked().flags
+                     & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+                    colorMode = mDefaultDisplayDefaultColorMode;
+                } else {
+                    colorMode = Display.COLOR_MODE_DEFAULT;
+                }
+            }
+            display.setRequestedColorModeLocked(colorMode);
+        }
+    }
+
+    // If we've never recorded stable device stats for this device before and they aren't
+    // explicitly configured, go ahead and record the stable device stats now based on the status
+    // of the default display at first boot.
+    private void recordStableDisplayStatsIfNeededLocked(LogicalDisplay d) {
+        if (mStableDisplaySize.x <= 0 && mStableDisplaySize.y <= 0) {
+            DisplayInfo info = d.getDisplayInfoLocked();
+            setStableDisplaySizeLocked(info.getNaturalWidth(), info.getNaturalHeight());
+        }
+    }
+
+    private void setStableDisplaySizeLocked(int width, int height) {
+        mStableDisplaySize = new Point(width, height);
+        try {
+            mPersistentDataStore.setStableDisplaySize(mStableDisplaySize);
+        } finally {
+            mPersistentDataStore.saveIfNeeded();
+        }
+    }
+
     // Updates all existing logical displays given the current set of display devices.
     // Removes invalid logical displays.
     // Sends notifications if needed.
@@ -1166,6 +1232,8 @@
             pw.println("  mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
             pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
             pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
+            pw.println("  mStableDisplaySize=" + mStableDisplaySize);
+
 
             IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
             ipw.increaseIndent();
@@ -1378,6 +1446,19 @@
             }
         }
 
+        /**
+         * Returns the stable device display size, in pixels.
+         */
+        @Override // Binder call
+        public Point getStableDisplaySize() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getStableDisplaySizeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         @Override // Binder call
         public void registerCallback(IDisplayManagerCallback callback) {
             if (callback == null) {