Merge "Added safeguards for pushed brighntess curve." into pi-dev
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 55c17b9..b5e223c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1340,6 +1340,30 @@
<integer-array name="config_autoBrightnessKeyboardBacklightValues">
</integer-array>
+ <!-- Array of light sensor lux values to define the minimum brightness curve, which guarantees
+ that any curve that dips below it is rejected by the system.
+ This prevents auto-brightness from setting the screen so dark as to prevent the user from
+ disabling auto-brightness or reseting the brightness curve via ADB.
+
+ The control points must be strictly increasing. Each control point corresponds to an entry
+ in the minimum brightness nits array. -->
+ <integer-array name="config_autoBrightnessMinimumBrightnessCurveLux">
+ <item>2000</item>
+ <item>4000</item>
+ </integer-array>
+
+ <!-- Array of desired screen brightness in nits corresponding to the lux values
+ in the config_autoBrightnessMinimumBrightnessCurveLux array.
+
+ This array should have size one greater than the size of the
+ config_autoBrightnessMinimumBrightnessCurveLux array. The values must be non-negative and
+ non-decreasing. -->
+ <array name="config_autoBrightnessMinimumBrightnessCurveNits">
+ <item>1.0</item>
+ <item>50.0</item>
+ <item>90.0</item>
+ </array>
+
<!-- Array of hysteresis constraint values for brightening, represented as tenths of a
percent. The length of this array is assumed to be one greater than
config_dynamicHysteresisLuxLevels. The brightening threshold is calculated as
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 75f8013..5eeb418 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1794,6 +1794,8 @@
<java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
<java-symbol type="array" name="config_autoBrightnessLevels" />
+ <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveLux" />
+ <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveNits" />
<java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
<java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
<java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 4313d17..711d40b 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -60,8 +60,14 @@
int[] backlightRange = resources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
+ float[] minimumBrightnessCurveLux = getLuxLevels(resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux));
+ float[] minimumBrightnessCurveNits = getFloatArray(resources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits));
+
if (isValidMapping(nitsRange, backlightRange)
- && isValidMapping(luxLevels, brightnessLevelsNits)) {
+ && isValidMapping(luxLevels, brightnessLevelsNits)
+ && isValidMapping(minimumBrightnessCurveLux, minimumBrightnessCurveNits)) {
int minimumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
int maximumBacklight = resources.getInteger(
@@ -73,7 +79,8 @@
}
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
builder.setCurve(luxLevels, brightnessLevelsNits);
- return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
+ return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
+ minimumBrightnessCurveLux, minimumBrightnessCurveNits);
} else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight);
} else {
@@ -448,8 +455,11 @@
private float mUserLux;
private float mUserBrightness;
+ private final Spline mMinimumBrightnessCurve;
+
public PhysicalMappingStrategy(BrightnessConfiguration config,
- float[] nits, int[] backlight) {
+ float[] nits, int[] backlight, float[] minimumBrightnessCurveLux,
+ float[] minimumBrightnessCurveNits) {
Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
"Nits and backlight arrays must not be empty!");
Preconditions.checkArgument(nits.length == backlight.length,
@@ -469,6 +479,9 @@
normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
}
+ mMinimumBrightnessCurve = Spline.createSpline(
+ minimumBrightnessCurveLux, minimumBrightnessCurveNits);
+
mNitsToBacklightSpline = createSpline(nits, normalizedBacklight);
mBacklightToNitsSpline = createSpline(normalizedBacklight, nits);
@@ -484,7 +497,7 @@
if (config.equals(mConfig)) {
return false;
}
-
+ validateBrightnessConfiguration(config);
Pair<float[], float[]> curve = config.getCurve();
mBrightnessSpline = createSpline(curve.first /*lux*/, curve.second /*nits*/);
mConfig = config;
@@ -549,5 +562,24 @@
pw.println(" mUserLux=" + mUserLux);
pw.println(" mUserBrightness=" + mUserBrightness);
}
+
+ private void validateBrightnessConfiguration(BrightnessConfiguration config) {
+ Pair<float[], float[]> curve = config.getCurve();
+ Spline brightnessSpline = Spline.createSpline(curve.first, curve.second);
+ if (isBrightnessSplineTooDark(brightnessSpline)) {
+ throw new IllegalArgumentException("brightness curve is too dark");
+ }
+ }
+
+ private boolean isBrightnessSplineTooDark(Spline brightnessSpline) {
+ float[] lux = mDefaultConfig.getCurve().first;
+ for (int i = 0; i < lux.length; i++) {
+ if (brightnessSpline.interpolate(lux[i]) <
+ mMinimumBrightnessCurve.interpolate(lux[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index fb25cf3..d922df3 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -85,6 +85,9 @@
255
};
+ private static final int[] MINIMUM_BRIGHTNESS_CURVE_LUX = { 2000, 4000 };
+ private static final float[] MINIMUM_BRIGHTNESS_CURVE_NITS = { 1.0f, 50.0f, 90.0f };
+
private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
private static final int[] BACKLIGHT_RANGE = { 1, 255 };
@@ -381,6 +384,19 @@
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
.thenReturn(mockBrightnessLevelNits);
+ int[] mockMinimumBrightnessCurveLux = new int[MINIMUM_BRIGHTNESS_CURVE_LUX.length];
+ for (int i = 0; i < mockMinimumBrightnessCurveLux.length; i++) {
+ mockMinimumBrightnessCurveLux[i] = (int) MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+ }
+ when(mockResources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux))
+ .thenReturn(mockMinimumBrightnessCurveLux);
+ TypedArray mockMinimumBrightnessCurveNits = createFloatTypedArray(
+ MINIMUM_BRIGHTNESS_CURVE_NITS);
+ when(mockResources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits))
+ .thenReturn(mockMinimumBrightnessCurveNits);
+
TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
when(mockResources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits))
@@ -419,4 +435,78 @@
return mockArray;
}
+ private float[] getNearMinimumNits(float epsilon) {
+ float[] lux = new float[MINIMUM_BRIGHTNESS_CURVE_LUX.length + 1];
+ for (int i = 0; i < MINIMUM_BRIGHTNESS_CURVE_LUX.length; i++) {
+ lux[i+1] = MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+ }
+ Spline minimumBrightnessCurve = Spline.createSpline(lux, MINIMUM_BRIGHTNESS_CURVE_NITS);
+ float[] nits = new float[LUX_LEVELS.length];
+ for (int i = 0; i < nits.length; i++) {
+ nits[i] = minimumBrightnessCurve.interpolate(LUX_LEVELS[i]) + epsilon;
+ }
+ return nits;
+ }
+
+ @Test
+ public void testCreateWithTooDarkBrightnessConfigurationThrowsException() {
+ float[] nits = getNearMinimumNits(-0.1f);
+ Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ Exception thrown = null;
+ try {
+ BrightnessMappingStrategy.create(res);
+ } catch (IllegalArgumentException e) {
+ thrown = e;
+ }
+ assertNotNull("Failed to throw IllegalArgumentException", thrown);
+ }
+
+ @Test
+ public void testCreationWithBrightEnoughBrightnessConfigurationDoesNotThrowException() {
+ float[] nits = getNearMinimumNits(0);
+ Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+ assertNotNull("Failed to create BrightnessMappingStrategy",
+ BrightnessMappingStrategy.create(res));
+ }
+
+ @Test
+ public void testSettingTooDarkBrightnessConfigurationThrowsException() {
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+ BACKLIGHT_RANGE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+ assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+ float[] lux = new float[LUX_LEVELS.length];
+ for (int i = 0; i < lux.length; i++) {
+ lux[i] = LUX_LEVELS[i];
+ }
+ float[] nits = getNearMinimumNits(-0.1f);
+ BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+ .setCurve(lux, nits)
+ .build();
+ Exception thrown = null;
+ try {
+ strategy.setBrightnessConfiguration(config);
+ } catch (IllegalArgumentException e) {
+ thrown = e;
+ }
+ assertNotNull("Failed to throw IllegalArgumentException", thrown);
+ }
+
+ @Test
+ public void testSettingBrightEnouhgBrightnessConfigurationDoesNotThrowException() {
+ Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+ BACKLIGHT_RANGE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+ assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+ float[] lux = new float[LUX_LEVELS.length];
+ for (int i = 0; i < lux.length; i++) {
+ lux[i] = LUX_LEVELS[i];
+ }
+ float[] nits = getNearMinimumNits(0);
+ BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+ .setCurve(lux, nits)
+ .build();
+ assertTrue("failed to set brightness configuration",
+ strategy.setBrightnessConfiguration(config));
+ }
}