Add DisplayModeDirector to determine set of allowed modes.

SurfaceFlinger now knows how to automatically schedule between various
display modes, so we need to tell it what modes are available to switch
between based on overall system state as well as display specific
properties. To capture all of this system state we've introduced
DisplayModeDirector which monitors all of the various inputs for
deciding display mode and notifies the rest of the display
infrastructure when they change.

Bug: 123727652
Test: manual
Change-Id: I83184664bf63c99ebd31889764720bb55c2e15a8
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 1aaaf41..2f53951 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -167,13 +167,13 @@
     private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
     private static final int MSG_REQUEST_TRAVERSAL = 4;
     private static final int MSG_UPDATE_VIEWPORT = 5;
-    private static final int MSG_REGISTER_BRIGHTNESS_TRACKER = 6;
-    private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 7;
+    private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
 
     private final Context mContext;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
+    private final DisplayModeDirector mDisplayModeDirector;
     private WindowManagerInternal mWindowManagerInternal;
     private InputManagerInternal mInputManagerInternal;
     private IMediaProjectionManager mProjectionService;
@@ -310,6 +310,7 @@
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
+        mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         Resources resources = mContext.getResources();
         mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
@@ -322,7 +323,7 @@
         mMinimumBrightnessCurve = new Curve(lux, nits);
         mMinimumBrightnessSpline = Spline.createSpline(lux, nits);
 
-        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = mContext.getSystemService(PowerManager.class);
         mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
         mCurrentUserId = UserHandle.USER_SYSTEM;
         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
@@ -347,9 +348,9 @@
         // 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.
-		synchronized(mSyncRoot) {
-			mPersistentDataStore.loadIfNeeded();
-			loadStableDisplayValuesLocked();
+        synchronized (mSyncRoot) {
+            mPersistentDataStore.loadIfNeeded();
+            loadStableDisplayValuesLocked();
         }
         mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
 
@@ -417,8 +418,10 @@
             mOnlyCore = onlyCore;
         }
 
+        mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
+        mDisplayModeDirector.start();
+
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
-        mHandler.sendEmptyMessage(MSG_REGISTER_BRIGHTNESS_TRACKER);
     }
 
     @VisibleForTesting
@@ -1194,13 +1197,8 @@
                 requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate(
                         requestedRefreshRate);
             }
-            if (display.getRequestedModeIdLocked() != requestedModeId) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Display " + displayId + " switching to mode " + requestedModeId);
-                }
-                display.setRequestedModeIdLocked(requestedModeId);
-                scheduleTraversalLocked(inTraversal);
-            }
+            mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
+                    displayId, requestedModeId);
         }
     }
 
@@ -1319,6 +1317,28 @@
         return SurfaceControl.getDisplayedContentSample(token, maxFrames, timestamp);
     }
 
+    private void onAllowedDisplayModesChangedInternal() {
+        boolean changed = false;
+        synchronized (mSyncRoot) {
+            final int count = mLogicalDisplays.size();
+            for (int i = 0; i < count; i++) {
+                LogicalDisplay display = mLogicalDisplays.valueAt(i);
+                int displayId = mLogicalDisplays.keyAt(i);
+                int[] allowedModes = mDisplayModeDirector.getAllowedModes(displayId);
+                // Note that order is important here since not all display devices are capable of
+                // automatically switching, so we do actually want to check for equality and not
+                // just equivalent contents (regardless of order).
+                if (!Arrays.equals(allowedModes, display.getAllowedDisplayModesLocked())) {
+                    display.setAllowedDisplayModesLocked(allowedModes);
+                    changed = true;
+                }
+            }
+            if (changed) {
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mViewports.clear();
     }
@@ -1518,6 +1538,9 @@
                 display.dumpLocked(ipw);
             }
 
+            pw.println();
+            mDisplayModeDirector.dump(pw);
+
             final int callbackCount = mCallbacks.size();
             pw.println();
             pw.println("Callbacks: size=" + callbackCount);
@@ -2425,4 +2448,10 @@
         }
 
     }
+
+    class AllowedDisplayModeObserver implements DisplayModeDirector.Listener {
+        public void onAllowedDisplayModesChanged() {
+            onAllowedDisplayModesChangedInternal();
+        }
+    }
 }