summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayManager.java23
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java128
4 files changed, 121 insertions, 35 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 21c49add6cba..bf794731c6b4 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -829,23 +829,36 @@ public final class DisplayManager {
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.R.array#config_brightnessThresholdsOfPeakRefreshRate
* @hide
*/
- String KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS =
+ String KEY_PEAK_REFRESH_RATE_DISPLAY_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.R.array#config_brightnessThresholdsOfPeakRefreshRate
+ * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
* @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
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index df879816facb..1577a227ff67 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4167,6 +4167,10 @@
-->
</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
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
<string name="config_displayLightSensorType" translatable="false" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 92c5d2cf88df..0d9c4b39fea0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3791,6 +3791,7 @@
<!-- For high refresh rate displays -->
<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_ambientThresholdsOfPeakRefreshRate" />
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 58aadd1cbef4..1fc0db3ff7cb 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -69,6 +69,7 @@ public class DisplayModeDirector {
private static final int MSG_ALLOWED_MODES_CHANGED = 1;
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_REFRESH_RATE_IN_ZONE_CHANGED = 4;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -440,23 +441,48 @@ public class DisplayModeDirector {
mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged(
defaultPeakRefreshRate);
break;
+
+ case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
+ refreshRateInZone);
+ break;
}
}
}
private static final class Vote {
- // We split the app request into two priorities in case we can satisfy one desire without
- // the other.
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 0;
- public static final int PRIORITY_APP_REQUEST_SIZE = 1;
- public static final int PRIORITY_USER_SETTING_REFRESH_RATE = 2;
- public static final int PRIORITY_LOW_BRIGHTNESS = 3;
- public static final int PRIORITY_LOW_POWER_MODE = 4;
+ // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+ // If the higher voters result is a range, it will fix the rate to a single choice.
+ // It's used to avoid rate switch in certain conditions.
+ public static final int PRIORITY_LOW_BRIGHTNESS = 0;
+
+ // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
+ // 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
// 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;
/**
@@ -500,12 +526,16 @@ public class DisplayModeDirector {
public static String priorityToString(int 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:
return "PRIORITY_APP_REQUEST_REFRESH_RATE";
case PRIORITY_APP_REQUEST_SIZE:
return "PRIORITY_APP_REQUEST_SIZE";
- case PRIORITY_USER_SETTING_REFRESH_RATE:
- return "PRIORITY_USER_SETTING_REFRESH_RATE";
+ case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
+ return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
case PRIORITY_LOW_POWER_MODE:
return "PRIORITY_LOW_POWER_MODE";
default:
@@ -608,12 +638,11 @@ public class DisplayModeDirector {
float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(),
Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
- if (peakRefreshRate < minRefreshRate) {
- peakRefreshRate = minRefreshRate;
- }
+ updateVoteLocked(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
+ 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);
}
@@ -655,6 +684,7 @@ public class DisplayModeDirector {
refreshRateVote = null;
sizeVote = null;
}
+
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote);
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
return;
@@ -799,6 +829,8 @@ public class DisplayModeDirector {
private boolean mRefreshRateChangeable = false;
private boolean mLowPowerModeEnabled = false;
+ private int mRefreshRateInZone;
+
BrightnessObserver(Context context, Handler handler) {
super(handler);
mContext = context;
@@ -815,6 +847,7 @@ public class DisplayModeDirector {
public void observe(SensorManager sensorManager) {
mSensorManager = sensorManager;
+
// DeviceConfig is accessible after system ready.
int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
@@ -824,6 +857,8 @@ public class DisplayModeDirector {
mDisplayBrightnessThresholds = brightnessThresholds;
mAmbientBrightnessThresholds = ambientThresholds;
}
+
+ mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
restartObserver();
mDeviceConfigDisplaySettings.startListening();
}
@@ -863,8 +898,16 @@ public class DisplayModeDirector {
restartObserver();
}
+ public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInZone) {
+ mRefreshRateInZone = refreshRate;
+ restartObserver();
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
+ pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
for (int d: mDisplayBrightnessThresholds) {
pw.println(" mDisplayBrightnessThreshold: " + d);
@@ -950,6 +993,10 @@ public class DisplayModeDirector {
* to value changes.
*/
private boolean checkShouldObserve(int[] a) {
+ if (mRefreshRateInZone <= 0) {
+ return false;
+ }
+
for (int d: a) {
if (d >= 0) {
return true;
@@ -959,37 +1006,42 @@ public class DisplayModeDirector {
return false;
}
- private void onBrightnessChangedLocked() {
- int brightness = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS, -1);
-
- Vote vote = null;
+ private boolean isInsideZone(int brightness, float lux) {
for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
int disp = mDisplayBrightnessThresholds[i];
int ambi = mAmbientBrightnessThresholds[i];
if (disp >= 0 && ambi >= 0) {
if (brightness <= disp && mAmbientLux <= ambi) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
} else if (disp >= 0) {
if (brightness <= disp) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
} else if (ambi >= 0) {
if (mAmbientLux <= ambi) {
- vote = Vote.forRefreshRates(0f, 60f);
+ return true;
}
}
+ }
- if (vote != null) {
- break;
- }
+ return false;
+ }
+
+ 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) {
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);
}
@@ -1104,7 +1156,6 @@ public class DisplayModeDirector {
}
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
-
public DeviceConfigDisplaySettings() {
}
@@ -1118,7 +1169,8 @@ public class DisplayModeDirector {
*/
public int[] getBrightnessThresholds() {
return getIntArrayProperty(
- DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS);
+ DisplayManager.DeviceConfig.
+ KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
}
/*
@@ -1126,7 +1178,8 @@ public class DisplayModeDirector {
*/
public int[] getAmbientThresholds() {
return getIntArrayProperty(
- DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS);
+ DisplayManager.DeviceConfig.
+ KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
}
/*
@@ -1143,17 +1196,32 @@ public class DisplayModeDirector {
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
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
int[] brightnessThresholds = getBrightnessThresholds();
int[] ambientThresholds = getAmbientThresholds();
Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
+ int refreshRateInZone = getRefreshRateInZone();
mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
.sendToTarget();
mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
defaultPeakRefreshRate).sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
+ 0).sendToTarget();
}
private int[] getIntArrayProperty(String prop) {