Loading core/java/android/hardware/display/DisplayManager.java +18 −5 Original line number Original line Diff line number Diff line Loading @@ -829,23 +829,36 @@ public final class DisplayManager { public interface DeviceConfig { public interface DeviceConfig { /** /** * Key for accessing the 60 hz only regions. * Key for refresh rate in the zone defined by thresholds. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultZoneBehavior */ String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone"; /** * Key for accessing the display brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). * * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @hide * @hide */ */ String KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS = String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_brightness_thresholds"; "peak_refresh_rate_brightness_thresholds"; /** /** * Key for accessing the 60 hz only regions. * Key for accessing the ambient brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in lux. * * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate * @hide * @hide */ */ String KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; /** /** * Key for default peak refresh rate * Key for default peak refresh rate Loading core/res/res/values/config.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -4167,6 +4167,10 @@ --> --> </integer-array> </integer-array> <!-- Default refresh rate in the zone defined by brightness and ambient thresholds. If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> <integer name="config_defaultRefreshRateInZone">0</integer> <!-- The type of the light sensor to be used by the display framework for things like <!-- The type of the light sensor to be used by the display framework for things like auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> <string name="config_displayLightSensorType" translatable="false" /> <string name="config_displayLightSensorType" translatable="false" /> Loading core/res/res/values/symbols.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -3791,6 +3791,7 @@ <!-- For high refresh rate displays --> <!-- For high refresh rate displays --> <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> <java-symbol type="integer" name="config_defaultRefreshRateInZone" /> <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> Loading services/core/java/com/android/server/display/DisplayModeDirector.java +98 −30 Original line number Original line Diff line number Diff line Loading @@ -69,6 +69,7 @@ public class DisplayModeDirector { private static final int MSG_ALLOWED_MODES_CHANGED = 1; private static final int MSG_ALLOWED_MODES_CHANGED = 1; private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4; // Special ID used to indicate that given vote is to be applied globally, rather than to a // Special ID used to indicate that given vote is to be applied globally, rather than to a // specific display. // specific display. Loading Loading @@ -440,23 +441,48 @@ public class DisplayModeDirector { mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( defaultPeakRefreshRate); defaultPeakRefreshRate); break; break; case MSG_REFRESH_RATE_IN_ZONE_CHANGED: int refreshRateInZone = msg.arg1; mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged( refreshRateInZone); break; } } } } } } private static final class Vote { private static final class Vote { // We split the app request into two priorities in case we can satisfy one desire without // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null. // the other. // If the higher voters result is a range, it will fix the rate to a single choice. public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 0; // It's used to avoid rate switch in certain conditions. public static final int PRIORITY_APP_REQUEST_SIZE = 1; public static final int PRIORITY_LOW_BRIGHTNESS = 0; public static final int PRIORITY_USER_SETTING_REFRESH_RATE = 2; public static final int PRIORITY_LOW_BRIGHTNESS = 3; // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate. public static final int PRIORITY_LOW_POWER_MODE = 4; // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY] public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1; // We split the app request into different priorities in case we can satisfy one desire // without the other. // Application can specify preferred refresh rate with below attrs. // @see android.view.WindowManager.LayoutParams#preferredRefreshRate // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId // System also forces some apps like blacklisted app to run at a lower refresh rate. // @see android.R.array#config_highRefreshRateBlacklist public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2; public static final int PRIORITY_APP_REQUEST_SIZE = 3; // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest // of low priority voters. It votes [0, max(PEAK, MIN)] public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4; // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on. public static final int PRIORITY_LOW_POWER_MODE = 5; // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as // appropriate, as well as priorityToString. // appropriate, as well as priorityToString. public static final int MIN_PRIORITY = PRIORITY_APP_REQUEST_REFRESH_RATE; public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS; public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; /** /** Loading Loading @@ -500,12 +526,16 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { public static String priorityToString(int priority) { switch (priority) { switch (priority) { case PRIORITY_LOW_BRIGHTNESS: return "PRIORITY_LOW_BRIGHTNESS"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_REFRESH_RATE: case PRIORITY_APP_REQUEST_REFRESH_RATE: return "PRIORITY_APP_REQUEST_REFRESH_RATE"; return "PRIORITY_APP_REQUEST_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_USER_SETTING_REFRESH_RATE: case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_REFRESH_RATE"; return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; case PRIORITY_LOW_POWER_MODE: case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; return "PRIORITY_LOW_POWER_MODE"; default: default: Loading Loading @@ -608,12 +638,11 @@ public class DisplayModeDirector { float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate); Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate); if (peakRefreshRate < minRefreshRate) { updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, peakRefreshRate = minRefreshRate; Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate))); } updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY)); Vote vote = Vote.forRefreshRates(minRefreshRate, peakRefreshRate); updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote); mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate); mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate); } } Loading Loading @@ -655,6 +684,7 @@ public class DisplayModeDirector { refreshRateVote = null; refreshRateVote = null; sizeVote = null; sizeVote = null; } } updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); return; return; Loading Loading @@ -799,6 +829,8 @@ public class DisplayModeDirector { private boolean mRefreshRateChangeable = false; private boolean mRefreshRateChangeable = false; private boolean mLowPowerModeEnabled = false; private boolean mLowPowerModeEnabled = false; private int mRefreshRateInZone; BrightnessObserver(Context context, Handler handler) { BrightnessObserver(Context context, Handler handler) { super(handler); super(handler); mContext = context; mContext = context; Loading @@ -815,6 +847,7 @@ public class DisplayModeDirector { public void observe(SensorManager sensorManager) { public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; mSensorManager = sensorManager; // DeviceConfig is accessible after system ready. // DeviceConfig is accessible after system ready. int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); Loading @@ -824,6 +857,8 @@ public class DisplayModeDirector { mDisplayBrightnessThresholds = brightnessThresholds; mDisplayBrightnessThresholds = brightnessThresholds; mAmbientBrightnessThresholds = ambientThresholds; mAmbientBrightnessThresholds = ambientThresholds; } } mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone(); restartObserver(); restartObserver(); mDeviceConfigDisplaySettings.startListening(); mDeviceConfigDisplaySettings.startListening(); } } Loading Loading @@ -863,8 +898,16 @@ public class DisplayModeDirector { restartObserver(); restartObserver(); } } public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) { if (refreshRate != mRefreshRateInZone) { mRefreshRateInZone = refreshRate; restartObserver(); } } public void dumpLocked(PrintWriter pw) { public void dumpLocked(PrintWriter pw) { pw.println(" BrightnessObserver"); pw.println(" BrightnessObserver"); pw.println(" mRefreshRateInZone: " + mRefreshRateInZone); for (int d: mDisplayBrightnessThresholds) { for (int d: mDisplayBrightnessThresholds) { pw.println(" mDisplayBrightnessThreshold: " + d); pw.println(" mDisplayBrightnessThreshold: " + d); Loading Loading @@ -950,6 +993,10 @@ public class DisplayModeDirector { * to value changes. * to value changes. */ */ private boolean checkShouldObserve(int[] a) { private boolean checkShouldObserve(int[] a) { if (mRefreshRateInZone <= 0) { return false; } for (int d: a) { for (int d: a) { if (d >= 0) { if (d >= 0) { return true; return true; Loading @@ -959,37 +1006,42 @@ public class DisplayModeDirector { return false; return false; } } private void onBrightnessChangedLocked() { private boolean isInsideZone(int brightness, float lux) { int brightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, -1); Vote vote = null; for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { int disp = mDisplayBrightnessThresholds[i]; int disp = mDisplayBrightnessThresholds[i]; int ambi = mAmbientBrightnessThresholds[i]; int ambi = mAmbientBrightnessThresholds[i]; if (disp >= 0 && ambi >= 0) { if (disp >= 0 && ambi >= 0) { if (brightness <= disp && mAmbientLux <= ambi) { if (brightness <= disp && mAmbientLux <= ambi) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } else if (disp >= 0) { } else if (disp >= 0) { if (brightness <= disp) { if (brightness <= disp) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } else if (ambi >= 0) { } else if (ambi >= 0) { if (mAmbientLux <= ambi) { if (mAmbientLux <= ambi) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } } } if (vote != null) { return false; break; } } private void onBrightnessChangedLocked() { int brightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, -1); Vote vote = null; boolean insideZone = isInsideZone(brightness, mAmbientLux); if (insideZone) { vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone); } } if (DEBUG) { if (DEBUG) { Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + (vote != null ? " 60hz only" : " no refresh rate limit")); ", Vote " + vote); } } updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); } } Loading Loading @@ -1104,7 +1156,6 @@ public class DisplayModeDirector { } } private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { public DeviceConfigDisplaySettings() { } } Loading @@ -1118,7 +1169,8 @@ public class DisplayModeDirector { */ */ public int[] getBrightnessThresholds() { public int[] getBrightnessThresholds() { return getIntArrayProperty( return getIntArrayProperty( DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS); DisplayManager.DeviceConfig. KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS); } } /* /* Loading @@ -1126,7 +1178,8 @@ public class DisplayModeDirector { */ */ public int[] getAmbientThresholds() { public int[] getAmbientThresholds() { return getIntArrayProperty( return getIntArrayProperty( DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS); DisplayManager.DeviceConfig. KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS); } } /* /* Loading @@ -1143,17 +1196,32 @@ public class DisplayModeDirector { return defaultPeakRefreshRate; return defaultPeakRefreshRate; } } public int getRefreshRateInZone() { int defaultRefreshRateInZone = mContext.getResources().getInteger( R.integer.config_defaultRefreshRateInZone); int refreshRate = DeviceConfig.getInt( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE, defaultRefreshRateInZone); return refreshRate; } @Override @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { int[] brightnessThresholds = getBrightnessThresholds(); int[] brightnessThresholds = getBrightnessThresholds(); int[] ambientThresholds = getAmbientThresholds(); int[] ambientThresholds = getAmbientThresholds(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); int refreshRateInZone = getRefreshRateInZone(); mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) .sendToTarget(); .sendToTarget(); mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, defaultPeakRefreshRate).sendToTarget(); defaultPeakRefreshRate).sendToTarget(); mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone, 0).sendToTarget(); } } private int[] getIntArrayProperty(String prop) { private int[] getIntArrayProperty(String prop) { Loading Loading
core/java/android/hardware/display/DisplayManager.java +18 −5 Original line number Original line Diff line number Diff line Loading @@ -829,23 +829,36 @@ public final class DisplayManager { public interface DeviceConfig { public interface DeviceConfig { /** /** * Key for accessing the 60 hz only regions. * Key for refresh rate in the zone defined by thresholds. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultZoneBehavior */ String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone"; /** * Key for accessing the display brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). * * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @hide * @hide */ */ String KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS = String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_brightness_thresholds"; "peak_refresh_rate_brightness_thresholds"; /** /** * Key for accessing the 60 hz only regions. * Key for accessing the ambient brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in lux. * * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate * @hide * @hide */ */ String KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; /** /** * Key for default peak refresh rate * Key for default peak refresh rate Loading
core/res/res/values/config.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -4167,6 +4167,10 @@ --> --> </integer-array> </integer-array> <!-- Default refresh rate in the zone defined by brightness and ambient thresholds. If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> <integer name="config_defaultRefreshRateInZone">0</integer> <!-- The type of the light sensor to be used by the display framework for things like <!-- The type of the light sensor to be used by the display framework for things like auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> <string name="config_displayLightSensorType" translatable="false" /> <string name="config_displayLightSensorType" translatable="false" /> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -3791,6 +3791,7 @@ <!-- For high refresh rate displays --> <!-- For high refresh rate displays --> <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> <java-symbol type="integer" name="config_defaultPeakRefreshRate" /> <java-symbol type="integer" name="config_defaultRefreshRateInZone" /> <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> Loading
services/core/java/com/android/server/display/DisplayModeDirector.java +98 −30 Original line number Original line Diff line number Diff line Loading @@ -69,6 +69,7 @@ public class DisplayModeDirector { private static final int MSG_ALLOWED_MODES_CHANGED = 1; private static final int MSG_ALLOWED_MODES_CHANGED = 1; private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4; // Special ID used to indicate that given vote is to be applied globally, rather than to a // Special ID used to indicate that given vote is to be applied globally, rather than to a // specific display. // specific display. Loading Loading @@ -440,23 +441,48 @@ public class DisplayModeDirector { mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( defaultPeakRefreshRate); defaultPeakRefreshRate); break; break; case MSG_REFRESH_RATE_IN_ZONE_CHANGED: int refreshRateInZone = msg.arg1; mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged( refreshRateInZone); break; } } } } } } private static final class Vote { private static final class Vote { // We split the app request into two priorities in case we can satisfy one desire without // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null. // the other. // If the higher voters result is a range, it will fix the rate to a single choice. public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 0; // It's used to avoid rate switch in certain conditions. public static final int PRIORITY_APP_REQUEST_SIZE = 1; public static final int PRIORITY_LOW_BRIGHTNESS = 0; public static final int PRIORITY_USER_SETTING_REFRESH_RATE = 2; public static final int PRIORITY_LOW_BRIGHTNESS = 3; // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate. public static final int PRIORITY_LOW_POWER_MODE = 4; // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY] public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 1; // We split the app request into different priorities in case we can satisfy one desire // without the other. // Application can specify preferred refresh rate with below attrs. // @see android.view.WindowManager.LayoutParams#preferredRefreshRate // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId // System also forces some apps like blacklisted app to run at a lower refresh rate. // @see android.R.array#config_highRefreshRateBlacklist public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 2; public static final int PRIORITY_APP_REQUEST_SIZE = 3; // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest // of low priority voters. It votes [0, max(PEAK, MIN)] public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 4; // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on. public static final int PRIORITY_LOW_POWER_MODE = 5; // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as // appropriate, as well as priorityToString. // appropriate, as well as priorityToString. public static final int MIN_PRIORITY = PRIORITY_APP_REQUEST_REFRESH_RATE; public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS; public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE; /** /** Loading Loading @@ -500,12 +526,16 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { public static String priorityToString(int priority) { switch (priority) { switch (priority) { case PRIORITY_LOW_BRIGHTNESS: return "PRIORITY_LOW_BRIGHTNESS"; case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; case PRIORITY_APP_REQUEST_REFRESH_RATE: case PRIORITY_APP_REQUEST_REFRESH_RATE: return "PRIORITY_APP_REQUEST_REFRESH_RATE"; return "PRIORITY_APP_REQUEST_REFRESH_RATE"; case PRIORITY_APP_REQUEST_SIZE: case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_USER_SETTING_REFRESH_RATE: case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: return "PRIORITY_USER_SETTING_REFRESH_RATE"; return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; case PRIORITY_LOW_POWER_MODE: case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; return "PRIORITY_LOW_POWER_MODE"; default: default: Loading Loading @@ -608,12 +638,11 @@ public class DisplayModeDirector { float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate); Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate); if (peakRefreshRate < minRefreshRate) { updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, peakRefreshRate = minRefreshRate; Vote.forRefreshRates(0f, Math.max(minRefreshRate, peakRefreshRate))); } updateVoteLocked(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(minRefreshRate, Float.POSITIVE_INFINITY)); Vote vote = Vote.forRefreshRates(minRefreshRate, peakRefreshRate); updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote); mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate); mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, peakRefreshRate); } } Loading Loading @@ -655,6 +684,7 @@ public class DisplayModeDirector { refreshRateVote = null; refreshRateVote = null; sizeVote = null; sizeVote = null; } } updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); return; return; Loading Loading @@ -799,6 +829,8 @@ public class DisplayModeDirector { private boolean mRefreshRateChangeable = false; private boolean mRefreshRateChangeable = false; private boolean mLowPowerModeEnabled = false; private boolean mLowPowerModeEnabled = false; private int mRefreshRateInZone; BrightnessObserver(Context context, Handler handler) { BrightnessObserver(Context context, Handler handler) { super(handler); super(handler); mContext = context; mContext = context; Loading @@ -815,6 +847,7 @@ public class DisplayModeDirector { public void observe(SensorManager sensorManager) { public void observe(SensorManager sensorManager) { mSensorManager = sensorManager; mSensorManager = sensorManager; // DeviceConfig is accessible after system ready. // DeviceConfig is accessible after system ready. int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds(); int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds(); Loading @@ -824,6 +857,8 @@ public class DisplayModeDirector { mDisplayBrightnessThresholds = brightnessThresholds; mDisplayBrightnessThresholds = brightnessThresholds; mAmbientBrightnessThresholds = ambientThresholds; mAmbientBrightnessThresholds = ambientThresholds; } } mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone(); restartObserver(); restartObserver(); mDeviceConfigDisplaySettings.startListening(); mDeviceConfigDisplaySettings.startListening(); } } Loading Loading @@ -863,8 +898,16 @@ public class DisplayModeDirector { restartObserver(); restartObserver(); } } public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) { if (refreshRate != mRefreshRateInZone) { mRefreshRateInZone = refreshRate; restartObserver(); } } public void dumpLocked(PrintWriter pw) { public void dumpLocked(PrintWriter pw) { pw.println(" BrightnessObserver"); pw.println(" BrightnessObserver"); pw.println(" mRefreshRateInZone: " + mRefreshRateInZone); for (int d: mDisplayBrightnessThresholds) { for (int d: mDisplayBrightnessThresholds) { pw.println(" mDisplayBrightnessThreshold: " + d); pw.println(" mDisplayBrightnessThreshold: " + d); Loading Loading @@ -950,6 +993,10 @@ public class DisplayModeDirector { * to value changes. * to value changes. */ */ private boolean checkShouldObserve(int[] a) { private boolean checkShouldObserve(int[] a) { if (mRefreshRateInZone <= 0) { return false; } for (int d: a) { for (int d: a) { if (d >= 0) { if (d >= 0) { return true; return true; Loading @@ -959,37 +1006,42 @@ public class DisplayModeDirector { return false; return false; } } private void onBrightnessChangedLocked() { private boolean isInsideZone(int brightness, float lux) { int brightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, -1); Vote vote = null; for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) { int disp = mDisplayBrightnessThresholds[i]; int disp = mDisplayBrightnessThresholds[i]; int ambi = mAmbientBrightnessThresholds[i]; int ambi = mAmbientBrightnessThresholds[i]; if (disp >= 0 && ambi >= 0) { if (disp >= 0 && ambi >= 0) { if (brightness <= disp && mAmbientLux <= ambi) { if (brightness <= disp && mAmbientLux <= ambi) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } else if (disp >= 0) { } else if (disp >= 0) { if (brightness <= disp) { if (brightness <= disp) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } else if (ambi >= 0) { } else if (ambi >= 0) { if (mAmbientLux <= ambi) { if (mAmbientLux <= ambi) { vote = Vote.forRefreshRates(0f, 60f); return true; } } } } } if (vote != null) { return false; break; } } private void onBrightnessChangedLocked() { int brightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, -1); Vote vote = null; boolean insideZone = isInsideZone(brightness, mAmbientLux); if (insideZone) { vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone); } } if (DEBUG) { if (DEBUG) { Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux + (vote != null ? " 60hz only" : " no refresh rate limit")); ", Vote " + vote); } } updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote); } } Loading Loading @@ -1104,7 +1156,6 @@ public class DisplayModeDirector { } } private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { public DeviceConfigDisplaySettings() { } } Loading @@ -1118,7 +1169,8 @@ public class DisplayModeDirector { */ */ public int[] getBrightnessThresholds() { public int[] getBrightnessThresholds() { return getIntArrayProperty( return getIntArrayProperty( DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS); DisplayManager.DeviceConfig. KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS); } } /* /* Loading @@ -1126,7 +1178,8 @@ public class DisplayModeDirector { */ */ public int[] getAmbientThresholds() { public int[] getAmbientThresholds() { return getIntArrayProperty( return getIntArrayProperty( DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS); DisplayManager.DeviceConfig. KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS); } } /* /* Loading @@ -1143,17 +1196,32 @@ public class DisplayModeDirector { return defaultPeakRefreshRate; return defaultPeakRefreshRate; } } public int getRefreshRateInZone() { int defaultRefreshRateInZone = mContext.getResources().getInteger( R.integer.config_defaultRefreshRateInZone); int refreshRate = DeviceConfig.getInt( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE, defaultRefreshRateInZone); return refreshRate; } @Override @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { int[] brightnessThresholds = getBrightnessThresholds(); int[] brightnessThresholds = getBrightnessThresholds(); int[] ambientThresholds = getAmbientThresholds(); int[] ambientThresholds = getAmbientThresholds(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); int refreshRateInZone = getRefreshRateInZone(); mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) new Pair<int[], int[]>(brightnessThresholds, ambientThresholds)) .sendToTarget(); .sendToTarget(); mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, defaultPeakRefreshRate).sendToTarget(); defaultPeakRefreshRate).sendToTarget(); mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone, 0).sendToTarget(); } } private int[] getIntArrayProperty(String prop) { private int[] getIntArrayProperty(String prop) { Loading