diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 3df2422071b82..f3969b19e11f5 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -32,6 +32,7 @@ import android.view.DisplayAddress; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; +import com.android.server.display.config.BrightnessThresholds; import com.android.server.display.config.Density; import com.android.server.display.config.DisplayConfiguration; import com.android.server.display.config.DisplayQuirks; @@ -42,6 +43,7 @@ import com.android.server.display.config.Point; import com.android.server.display.config.RefreshRateRange; import com.android.server.display.config.SensorDetails; import com.android.server.display.config.ThermalStatus; +import com.android.server.display.config.Thresholds; import com.android.server.display.config.XmlParser; import org.xmlpull.v1.XmlPullParserException; @@ -130,6 +132,10 @@ public class DisplayDeviceConfig { private float mBrightnessRampSlowIncrease = Float.NaN; private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS; private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS; + private float mScreenBrighteningMinThreshold = 0.0f; // Retain behaviour as though there is + private float mScreenDarkeningMinThreshold = 0.0f; // no minimum threshold for change in + private float mAmbientLuxBrighteningMinThreshold = 0.0f; // screen brightness or ambient + private float mAmbientLuxDarkeningMinThreshold = 0.0f; // brightness. private Spline mBrightnessToBacklightSpline; private Spline mBacklightToBrightnessSpline; private Spline mBacklightToNitsSpline; @@ -364,6 +370,22 @@ public class DisplayDeviceConfig { return mAmbientHorizonShort; } + public float getScreenBrighteningMinThreshold() { + return mScreenBrighteningMinThreshold; + } + + public float getScreenDarkeningMinThreshold() { + return mScreenDarkeningMinThreshold; + } + + public float getAmbientLuxBrighteningMinThreshold() { + return mAmbientLuxBrighteningMinThreshold; + } + + public float getAmbientLuxDarkeningMinThreshold() { + return mAmbientLuxDarkeningMinThreshold; + } + SensorData getAmbientLightSensor() { return mAmbientLightSensor; } @@ -425,6 +447,10 @@ public class DisplayDeviceConfig { + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease + ", mAmbientHorizonLong=" + mAmbientHorizonLong + ", mAmbientHorizonShort=" + mAmbientHorizonShort + + ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold + + ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold + + ", mAmbientLuxDarkeningMinThreshold=" + mAmbientLuxDarkeningMinThreshold + + ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) @@ -482,6 +508,7 @@ public class DisplayDeviceConfig { loadAmbientLightSensorFromDdc(config); loadProxSensorFromDdc(config); loadAmbientHorizonFromDdc(config); + loadBrightnessChangeThresholds(config); } else { Slog.w(TAG, "DisplayDeviceConfig file is null"); } @@ -865,6 +892,45 @@ public class DisplayDeviceConfig { } } + private void loadBrightnessChangeThresholds(DisplayConfiguration config) { + Thresholds displayBrightnessThresholds = config.getDisplayBrightnessChangeThresholds(); + Thresholds ambientBrightnessThresholds = config.getAmbientBrightnessChangeThresholds(); + + if (displayBrightnessThresholds != null) { + BrightnessThresholds brighteningScreen = + displayBrightnessThresholds.getBrighteningThresholds(); + BrightnessThresholds darkeningScreen = + displayBrightnessThresholds.getDarkeningThresholds(); + + final BigDecimal screenBrighteningThreshold = brighteningScreen.getMinimum(); + final BigDecimal screenDarkeningThreshold = darkeningScreen.getMinimum(); + + if (screenBrighteningThreshold != null) { + mScreenBrighteningMinThreshold = screenBrighteningThreshold.floatValue(); + } + if (screenDarkeningThreshold != null) { + mScreenDarkeningMinThreshold = screenDarkeningThreshold.floatValue(); + } + } + + if (ambientBrightnessThresholds != null) { + BrightnessThresholds brighteningAmbientLux = + ambientBrightnessThresholds.getBrighteningThresholds(); + BrightnessThresholds darkeningAmbientLux = + ambientBrightnessThresholds.getDarkeningThresholds(); + + final BigDecimal ambientBrighteningThreshold = brighteningAmbientLux.getMinimum(); + final BigDecimal ambientDarkeningThreshold = darkeningAmbientLux.getMinimum(); + + if (ambientBrighteningThreshold != null) { + mAmbientLuxBrighteningMinThreshold = ambientBrighteningThreshold.floatValue(); + } + if (ambientDarkeningThreshold != null) { + mAmbientLuxDarkeningMinThreshold = ambientDarkeningThreshold.floatValue(); + } + } + } + private @PowerManager.ThermalStatus int convertThermalStatus(ThermalStatus value) { if (value == null) { return PowerManager.THERMAL_STATUS_NONE; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index c6d3829231694..31c496eda1314 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -909,9 +909,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call com.android.internal.R.array.config_ambientDarkeningThresholds); int[] ambientThresholdLevels = resources.getIntArray( com.android.internal.R.array.config_ambientThresholdLevels); + float ambientDarkeningMinThreshold = + mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(); + float ambientBrighteningMinThreshold = + mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(); HysteresisLevels ambientBrightnessThresholds = new HysteresisLevels( ambientBrighteningThresholds, ambientDarkeningThresholds, - ambientThresholdLevels); + ambientThresholdLevels, ambientDarkeningMinThreshold, + ambientBrighteningMinThreshold); int[] screenBrighteningThresholds = resources.getIntArray( com.android.internal.R.array.config_screenBrighteningThresholds); @@ -919,8 +924,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call com.android.internal.R.array.config_screenDarkeningThresholds); int[] screenThresholdLevels = resources.getIntArray( com.android.internal.R.array.config_screenThresholdLevels); + float screenDarkeningMinThreshold = + mDisplayDeviceConfig.getScreenDarkeningMinThreshold(); + float screenBrighteningMinThreshold = + mDisplayDeviceConfig.getScreenBrighteningMinThreshold(); HysteresisLevels screenBrightnessThresholds = new HysteresisLevels( - screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels); + screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels, + screenDarkeningMinThreshold, screenBrighteningMinThreshold); long brighteningLightDebounce = resources.getInteger( com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce); diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java index 2b565698ff8ce..7a932ce6d7cf4 100644 --- a/services/core/java/com/android/server/display/HysteresisLevels.java +++ b/services/core/java/com/android/server/display/HysteresisLevels.java @@ -30,17 +30,13 @@ import java.util.Arrays; public class HysteresisLevels { private static final String TAG = "HysteresisLevels"; - // Default hysteresis constraints for brightening or darkening. - // The recent value must have changed by at least this fraction relative to the - // current value before a change will be considered. - private static final float DEFAULT_BRIGHTENING_HYSTERESIS = 0.10f; - private static final float DEFAULT_DARKENING_HYSTERESIS = 0.20f; - private static final boolean DEBUG = false; private final float[] mBrighteningThresholds; private final float[] mDarkeningThresholds; private final float[] mThresholdLevels; + private final float mMinDarkening; + private final float mMinBrightening; /** * Creates a {@code HysteresisLevels} object with the given equal-length @@ -48,9 +44,12 @@ public class HysteresisLevels { * @param brighteningThresholds an array of brightening hysteresis constraint constants. * @param darkeningThresholds an array of darkening hysteresis constraint constants. * @param thresholdLevels a monotonically increasing array of threshold levels. + * @param minBrighteningThreshold the minimum value for which the brightening value needs to + * return. + * @param minDarkeningThreshold the minimum value for which the darkening value needs to return. */ HysteresisLevels(int[] brighteningThresholds, int[] darkeningThresholds, - int[] thresholdLevels) { + int[] thresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold) { if (brighteningThresholds.length != darkeningThresholds.length || darkeningThresholds.length != thresholdLevels.length + 1) { throw new IllegalArgumentException("Mismatch between hysteresis array lengths."); @@ -58,6 +57,8 @@ public class HysteresisLevels { mBrighteningThresholds = setArrayFormat(brighteningThresholds, 1000.0f); mDarkeningThresholds = setArrayFormat(darkeningThresholds, 1000.0f); mThresholdLevels = setArrayFormat(thresholdLevels, 1.0f); + mMinDarkening = minDarkeningThreshold; + mMinBrightening = minBrighteningThreshold; } /** @@ -65,11 +66,13 @@ public class HysteresisLevels { */ public float getBrighteningThreshold(float value) { final float brightConstant = getReferenceLevel(value, mBrighteningThresholds); - final float brightThreshold = value * (1.0f + brightConstant); + float brightThreshold = value * (1.0f + brightConstant); if (DEBUG) { Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold=" + brightThreshold + ", value=" + value); } + + brightThreshold = Math.max(brightThreshold, value + mMinBrightening); return brightThreshold; } @@ -78,12 +81,13 @@ public class HysteresisLevels { */ public float getDarkeningThreshold(float value) { final float darkConstant = getReferenceLevel(value, mDarkeningThresholds); - final float darkThreshold = value * (1.0f - darkConstant); + float darkThreshold = value * (1.0f - darkConstant); if (DEBUG) { Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold=" + darkThreshold + ", value=" + value); } - return darkThreshold; + darkThreshold = Math.min(darkThreshold, value - mMinDarkening); + return Math.max(darkThreshold, 0.0f); } /** diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index baf2ede07fa30..574dbfd1046dd 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -38,7 +38,8 @@ - + @@ -67,6 +68,19 @@ + + + + + + + + + + + @@ -81,7 +95,8 @@ - + @@ -110,7 +125,8 @@ - + @@ -216,5 +232,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 6f97431b48739..04f0916dbc549 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -1,6 +1,12 @@ // Signature format: 2.0 package com.android.server.display.config { + public class BrightnessThresholds { + ctor public BrightnessThresholds(); + method @NonNull public final java.math.BigDecimal getMinimum(); + method public final void setMinimum(@NonNull java.math.BigDecimal); + } + public class Density { ctor public Density(); method @NonNull public final java.math.BigInteger getDensity(); @@ -18,9 +24,11 @@ package com.android.server.display.config { public class DisplayConfiguration { ctor public DisplayConfiguration(); + method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds(); method public final java.math.BigInteger getAmbientLightHorizonLong(); method public final java.math.BigInteger getAmbientLightHorizonShort(); method @Nullable public final com.android.server.display.config.DensityMap getDensityMap(); + method @NonNull public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholds(); method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode(); method public final com.android.server.display.config.SensorDetails getLightSensor(); method public final com.android.server.display.config.SensorDetails getProxSensor(); @@ -31,9 +39,11 @@ package com.android.server.display.config { method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease(); method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease(); method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease(); + method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds); method public final void setAmbientLightHorizonLong(java.math.BigInteger); method public final void setAmbientLightHorizonShort(java.math.BigInteger); method public final void setDensityMap(@Nullable com.android.server.display.config.DensityMap); + method public final void setDisplayBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds); method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode); method public final void setLightSensor(com.android.server.display.config.SensorDetails); method public final void setProxSensor(com.android.server.display.config.SensorDetails); @@ -121,6 +131,14 @@ package com.android.server.display.config { enum_constant public static final com.android.server.display.config.ThermalStatus shutdown; } + public class Thresholds { + ctor public Thresholds(); + method @NonNull public final com.android.server.display.config.BrightnessThresholds getBrighteningThresholds(); + method @NonNull public final com.android.server.display.config.BrightnessThresholds getDarkeningThresholds(); + method public final void setBrighteningThresholds(@NonNull com.android.server.display.config.BrightnessThresholds); + method public final void setDarkeningThresholds(@NonNull com.android.server.display.config.BrightnessThresholds); + } + public class XmlParser { ctor public XmlParser(); method public static com.android.server.display.config.DisplayConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index 54945e44fee58..4caa85cee7db6 100644 --- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -391,4 +391,33 @@ public class AutomaticBrightnessControllerTest { listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0)); assertEquals(0.0f, mController.getAmbientLux(), EPSILON); } + + @Test + public void testHysteresisLevels() { + int[] ambientBrighteningThresholds = {100, 200}; + int[] ambientDarkeningThresholds = {400, 500}; + int[] ambientThresholdLevels = {500}; + float ambientDarkeningMinChangeThreshold = 3.0f; + float ambientBrighteningMinChangeThreshold = 1.5f; + HysteresisLevels hysteresisLevels = new HysteresisLevels(ambientBrighteningThresholds, + ambientDarkeningThresholds, ambientThresholdLevels, + ambientDarkeningMinChangeThreshold, ambientBrighteningMinChangeThreshold); + + // test low, activate minimum change thresholds. + assertEquals(1.5f, hysteresisLevels.getBrighteningThreshold(0.0f), EPSILON); + assertEquals(0f, hysteresisLevels.getDarkeningThreshold(0.0f), EPSILON); + assertEquals(1f, hysteresisLevels.getDarkeningThreshold(4.0f), EPSILON); + + // test max + assertEquals(12000f, hysteresisLevels.getBrighteningThreshold(10000.0f), EPSILON); + assertEquals(5000f, hysteresisLevels.getDarkeningThreshold(10000.0f), EPSILON); + + // test just below threshold + assertEquals(548.9f, hysteresisLevels.getBrighteningThreshold(499f), EPSILON); + assertEquals(299.4f, hysteresisLevels.getDarkeningThreshold(499f), EPSILON); + + // test at (considered above) threshold + assertEquals(600f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON); + assertEquals(250f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON); + } }