diff options
| author | 2018-03-27 14:43:14 +0000 | |
|---|---|---|
| committer | 2018-03-27 14:43:14 +0000 | |
| commit | abe80b8dfda459def0a747962826fed871725fc6 (patch) | |
| tree | 2f7d7a79d31282aa49527bb74989849ae670de6e | |
| parent | b429012907e8b48bf88c5ec5e91312c3379ca325 (diff) | |
| parent | f1e673649e11b98f537489b7889f1d6efa6e7ff9 (diff) | |
Merge "Added safeguards for pushed brighntess curve." into pi-dev
4 files changed, 152 insertions, 4 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 55c17b9b2af4..b5e223cbec43 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 75f80137da03..5eeb4186557e 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 4313d1724214..711d40b7fb8a 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 @@ public abstract class BrightnessMappingStrategy { 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 @@ public abstract class BrightnessMappingStrategy { } 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 @@ public abstract class BrightnessMappingStrategy { 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 @@ public abstract class BrightnessMappingStrategy { normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]); } + mMinimumBrightnessCurve = Spline.createSpline( + minimumBrightnessCurveLux, minimumBrightnessCurveNits); + mNitsToBacklightSpline = createSpline(nits, normalizedBacklight); mBacklightToNitsSpline = createSpline(normalizedBacklight, nits); @@ -484,7 +497,7 @@ public abstract class BrightnessMappingStrategy { 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 @@ public abstract class BrightnessMappingStrategy { 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 fb25cf3f01e0..d922df38b189 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 @@ public class BrightnessMappingStrategyTest { 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 @@ public class BrightnessMappingStrategyTest { 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 @@ public class BrightnessMappingStrategyTest { 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)); + } } |