DO NOT MERGE DMD: Support minimum refresh rate

Bug: 139685237
Change-Id: Ib41dee351276d70733fffa18620455e4e6f9ddfc
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 5331aad..97fd02f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -525,8 +525,10 @@
     }
 
     private final class SettingsObserver extends ContentObserver {
-        private final Uri mRefreshRateSetting =
+        private final Uri mPeakRefreshRateSetting =
                 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+        private final Uri mMinRefreshRateSetting =
+                Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
         private final Uri mLowPowerModeSetting =
                 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
 
@@ -542,7 +544,9 @@
 
         public void observe() {
             final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(mRefreshRateSetting, false /*notifyDescendants*/, this,
+            cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
+                    UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
@@ -576,7 +580,8 @@
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             synchronized (mLock) {
-                if (mRefreshRateSetting.equals(uri)) {
+                if (mPeakRefreshRateSetting.equals(uri)
+                        || mMinRefreshRateSetting.equals(uri)) {
                     updateRefreshRateSettingLocked();
                 } else if (mLowPowerModeSetting.equals(uri)) {
                     updateLowPowerModeSettingLocked();
@@ -594,15 +599,22 @@
                 vote = null;
             }
             updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote);
-            mBrightnessObserver.onLowPowerModeEnabled(inLowPowerMode);
+            mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
         }
 
         private void updateRefreshRateSettingLocked() {
+            float minRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
+                    Settings.System.MIN_REFRESH_RATE, 0f);
             float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
                     Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
-            Vote vote = Vote.forRefreshRates(0f, peakRefreshRate);
+
+            if (peakRefreshRate < minRefreshRate) {
+                peakRefreshRate = minRefreshRate;
+            }
+
+            Vote vote = Vote.forRefreshRates(minRefreshRate, peakRefreshRate);
             updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote);
-            mBrightnessObserver.onPeakRefreshRateEnabled(peakRefreshRate > 60f);
+            mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate);
         }
 
         public void dumpLocked(PrintWriter pw) {
@@ -781,10 +793,10 @@
         private final ScreenStateReceiver mScreenStateReceiver;
 
         // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
-        // refresh rate enabled and low power mode off. After initialization, these states will
+        // refresh rate changeable and low power mode off. After initialization, these states will
         // be updated from the same handler thread.
         private boolean mScreenOn = false;
-        private boolean mPeakRefreshRateEnabled = false;
+        private boolean mRefreshRateChangeable = false;
         private boolean mLowPowerModeEnabled = false;
 
         BrightnessObserver(Context context, Handler handler) {
@@ -817,14 +829,19 @@
             mDeviceConfigDisplaySettings.startListening();
         }
 
-        public void onPeakRefreshRateEnabled(boolean b) {
-            if (mPeakRefreshRateEnabled != b) {
-                mPeakRefreshRateEnabled = b;
+        public void onRefreshRateSettingChangedLocked(float min, float max) {
+            boolean changeable = (max - min > 1f && max > 60f);
+            if (mRefreshRateChangeable != changeable) {
+                mRefreshRateChangeable = changeable;
                 updateSensorStatus();
+                if (!changeable) {
+                    // Revoke previous vote from BrightnessObserver
+                    updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
+                }
             }
         }
 
-        public void onLowPowerModeEnabled(boolean b) {
+        public void onLowPowerModeEnabledLocked(boolean b) {
             if (mLowPowerModeEnabled != b) {
                 mLowPowerModeEnabled = b;
                 updateSensorStatus();
@@ -862,7 +879,9 @@
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
             synchronized (mLock) {
-                onBrightnessChangedLocked();
+                if (mRefreshRateChangeable) {
+                    onBrightnessChangedLocked();
+                }
             }
         }
 
@@ -920,10 +939,11 @@
                 mScreenStateReceiver.unregister();
             }
 
-            updateSensorStatus();
-
-            synchronized (mLock) {
-                onBrightnessChangedLocked();
+            if (mRefreshRateChangeable) {
+                updateSensorStatus();
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
             }
         }
 
@@ -991,7 +1011,7 @@
             }
 
             if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
-                    && mPeakRefreshRateEnabled) {
+                    && mRefreshRateChangeable) {
                 mSensorManager.registerListener(mLightSensorListener,
                         mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
             } else {
@@ -1081,6 +1101,8 @@
 
         private final class ScreenStateReceiver extends BroadcastReceiver {
             final Context mContext;
+            boolean mRegistered;
+
             public ScreenStateReceiver(Context context) {
                 mContext = context;
             }
@@ -1091,15 +1113,21 @@
             }
 
             public void register() {
-                IntentFilter filter = new IntentFilter();
-                filter.addAction(Intent.ACTION_SCREEN_OFF);
-                filter.addAction(Intent.ACTION_SCREEN_ON);
-                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-                mContext.registerReceiver(this, filter, null, mHandler);
+                if (!mRegistered) {
+                    IntentFilter filter = new IntentFilter();
+                    filter.addAction(Intent.ACTION_SCREEN_OFF);
+                    filter.addAction(Intent.ACTION_SCREEN_ON);
+                    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+                    mContext.registerReceiver(this, filter, null, mHandler);
+                    mRegistered = true;
+                }
             }
 
             public void unregister() {
-                mContext.unregisterReceiver(this);
+                if (mRegistered) {
+                    mContext.unregisterReceiver(this);
+                    mRegistered = false;
+                }
             }
         }
     }