Make the short term brightness model configurable.
Bug: 146141793
Test: atest BrightnessConfigurationTest
Test: atest AutomaticBrightnessControllerTest
Test: manual - use reflection to configure the new parameters from turbo app and check dumpsys
Change-Id: I78af8009f15400f2f91e55363066d97f008a7922
diff --git a/api/system-current.txt b/api/system-current.txt
index d18c0dc..ad95691 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2353,9 +2353,13 @@
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
method public android.util.Pair<float[],float[]> getCurve();
+ method public float getShortTermModelLowerLuxMultiplier();
+ method public long getShortTermModelTimeout();
+ method public float getShortTermModelUpperLuxMultiplier();
method public boolean shouldCollectColorSamples();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
+ field public static final long SHORT_TERM_TIMEOUT_UNSET = -1L; // 0xffffffffffffffffL
}
public static class BrightnessConfiguration.Builder {
@@ -2366,6 +2370,9 @@
method public int getMaxCorrectionsByCategory();
method public int getMaxCorrectionsByPackageName();
method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float);
method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 3bdd479..4a047c6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1023,9 +1023,13 @@
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
method public android.util.Pair<float[],float[]> getCurve();
+ method public float getShortTermModelLowerLuxMultiplier();
+ method public long getShortTermModelTimeout();
+ method public float getShortTermModelUpperLuxMultiplier();
method public boolean shouldCollectColorSamples();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
+ field public static final long SHORT_TERM_TIMEOUT_UNSET = -1L; // 0xffffffffffffffffL
}
public static class BrightnessConfiguration.Builder {
@@ -1036,6 +1040,9 @@
method public int getMaxCorrectionsByCategory();
method public int getMaxCorrectionsByPackageName();
method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long);
+ method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float);
method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean);
}
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 139be8e..0a38538 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -56,6 +57,16 @@
private static final String ATTR_PACKAGE_NAME = "package-name";
private static final String ATTR_CATEGORY = "category";
private static final String ATTR_COLLECT_COLOR = "collect-color";
+ private static final String ATTR_MODEL_TIMEOUT = "model-timeout";
+ private static final String ATTR_MODEL_LOWER_BOUND = "model-lower-bound";
+ private static final String ATTR_MODEL_UPPER_BOUND = "model-upper-bound";
+ /**
+ * Returned from {@link #getShortTermModelTimeout()} if no timeout has been set.
+ * In this case the device will use the default timeout available in the
+ * {@link BrightnessConfiguration} returned from
+ * {@link DisplayManager#getDefaultBrightnessConfiguration()}.
+ */
+ public static final long SHORT_TERM_TIMEOUT_UNSET = -1;
private final float[] mLux;
private final float[] mNits;
@@ -63,17 +74,26 @@
private final Map<Integer, BrightnessCorrection> mCorrectionsByCategory;
private final String mDescription;
private final boolean mShouldCollectColorSamples;
+ private final long mShortTermModelTimeout;
+ private final float mShortTermModelLowerLuxMultiplier;
+ private final float mShortTermModelUpperLuxMultiplier;
private BrightnessConfiguration(float[] lux, float[] nits,
Map<String, BrightnessCorrection> correctionsByPackageName,
Map<Integer, BrightnessCorrection> correctionsByCategory, String description,
- boolean shouldCollectColorSamples) {
+ boolean shouldCollectColorSamples,
+ long shortTermModelTimeout,
+ float shortTermModelLowerLuxMultiplier,
+ float shortTermModelUpperLuxMultiplier) {
mLux = lux;
mNits = nits;
mCorrectionsByPackageName = correctionsByPackageName;
mCorrectionsByCategory = correctionsByCategory;
mDescription = description;
mShouldCollectColorSamples = shouldCollectColorSamples;
+ mShortTermModelTimeout = shortTermModelTimeout;
+ mShortTermModelLowerLuxMultiplier = shortTermModelLowerLuxMultiplier;
+ mShortTermModelUpperLuxMultiplier = shortTermModelUpperLuxMultiplier;
}
/**
@@ -132,6 +152,42 @@
return mShouldCollectColorSamples;
}
+ /**
+ * Returns the timeout for the short term model in milliseconds.
+ *
+ * If the screen is inactive for this timeout then the short term model
+ * will check the lux range defined by {@link #getShortTermModelLowerLuxMultiplier()} and
+ * {@link #getShortTermModelUpperLuxMultiplier()} to decide whether to keep any adjustment
+ * the user has made to adaptive brightness.
+ */
+ public long getShortTermModelTimeout() {
+ return mShortTermModelTimeout;
+ }
+
+ /**
+ * Returns the multiplier used to calculate the upper bound for which
+ * a users adaptive brightness is considered valid.
+ *
+ * For example if a user changes the brightness when the ambient light level
+ * is 100 lux, the adjustment will be kept if the current ambient light level
+ * is {@code <= 100 + (100 * getShortTermModelUpperLuxMultiplier())}.
+ */
+ public float getShortTermModelUpperLuxMultiplier() {
+ return mShortTermModelUpperLuxMultiplier;
+ }
+
+ /**
+ * Returns the multiplier used to calculate the lower bound for which
+ * a users adaptive brightness is considered valid.
+ *
+ * For example if a user changes the brightness when the ambient light level
+ * is 100 lux, the adjustment will be kept if the current ambient light level
+ * is {@code >= 100 - (100 * getShortTermModelLowerLuxMultiplier())}.
+ */
+ public float getShortTermModelLowerLuxMultiplier() {
+ return mShortTermModelLowerLuxMultiplier;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeFloatArray(mLux);
@@ -152,6 +208,9 @@
}
dest.writeString(mDescription);
dest.writeBoolean(mShouldCollectColorSamples);
+ dest.writeLong(mShortTermModelTimeout);
+ dest.writeFloat(mShortTermModelLowerLuxMultiplier);
+ dest.writeFloat(mShortTermModelUpperLuxMultiplier);
}
@Override
@@ -182,6 +241,15 @@
sb.append(mDescription);
}
sb.append(", shouldCollectColorSamples = " + mShouldCollectColorSamples);
+ if (mShortTermModelTimeout >= 0) {
+ sb.append(", shortTermModelTimeout = " + mShortTermModelTimeout);
+ }
+ if (!Float.isNaN(mShortTermModelLowerLuxMultiplier)) {
+ sb.append(", shortTermModelLowerLuxMultiplier = " + mShortTermModelLowerLuxMultiplier);
+ }
+ if (!Float.isNaN(mShortTermModelLowerLuxMultiplier)) {
+ sb.append(", shortTermModelUpperLuxMultiplier = " + mShortTermModelUpperLuxMultiplier);
+ }
sb.append("'}");
return sb.toString();
}
@@ -197,6 +265,9 @@
result = result * 31 + mDescription.hashCode();
}
result = result * 31 + Boolean.hashCode(mShouldCollectColorSamples);
+ result = result * 31 + Long.hashCode(mShortTermModelTimeout);
+ result = result * 31 + Float.hashCode(mShortTermModelLowerLuxMultiplier);
+ result = result * 31 + Float.hashCode(mShortTermModelUpperLuxMultiplier);
return result;
}
@@ -213,7 +284,19 @@
&& mCorrectionsByPackageName.equals(other.mCorrectionsByPackageName)
&& mCorrectionsByCategory.equals(other.mCorrectionsByCategory)
&& Objects.equals(mDescription, other.mDescription)
- && mShouldCollectColorSamples == other.mShouldCollectColorSamples;
+ && mShouldCollectColorSamples == other.mShouldCollectColorSamples
+ && mShortTermModelTimeout == other.mShortTermModelTimeout
+ && checkFloatEquals(mShortTermModelLowerLuxMultiplier,
+ other.mShortTermModelLowerLuxMultiplier)
+ && checkFloatEquals(mShortTermModelUpperLuxMultiplier,
+ other.mShortTermModelUpperLuxMultiplier);
+ }
+
+ private boolean checkFloatEquals(float one, float two) {
+ if (Float.isNaN(one) && Float.isNaN(two)) {
+ return true;
+ }
+ return one == two;
}
public static final @android.annotation.NonNull Creator<BrightnessConfiguration> CREATOR =
@@ -243,6 +326,9 @@
builder.setDescription(description);
final boolean shouldCollectColorSamples = in.readBoolean();
builder.setShouldCollectColorSamples(shouldCollectColorSamples);
+ builder.setShortTermModelTimeout(in.readLong());
+ builder.setShortTermModelLowerLuxMultiplier(in.readFloat());
+ builder.setShortTermModelUpperLuxMultiplier(in.readFloat());
return builder.build();
}
@@ -296,6 +382,18 @@
if (mShouldCollectColorSamples) {
serializer.attribute(null, ATTR_COLLECT_COLOR, Boolean.toString(true));
}
+ if (mShortTermModelTimeout >= 0) {
+ serializer.attribute(null, ATTR_MODEL_TIMEOUT,
+ Long.toString(mShortTermModelTimeout));
+ }
+ if (!Float.isNaN(mShortTermModelLowerLuxMultiplier)) {
+ serializer.attribute(null, ATTR_MODEL_LOWER_BOUND,
+ Float.toString(mShortTermModelLowerLuxMultiplier));
+ }
+ if (!Float.isNaN(mShortTermModelUpperLuxMultiplier)) {
+ serializer.attribute(null, ATTR_MODEL_UPPER_BOUND,
+ Float.toString(mShortTermModelUpperLuxMultiplier));
+ }
serializer.endTag(null, TAG_BRIGHTNESS_PARAMS);
}
@@ -320,6 +418,9 @@
Map<String, BrightnessCorrection> correctionsByPackageName = new HashMap<>();
Map<Integer, BrightnessCorrection> correctionsByCategory = new HashMap<>();
boolean shouldCollectColorSamples = false;
+ long shortTermModelTimeout = SHORT_TERM_TIMEOUT_UNSET;
+ float shortTermModelLowerLuxMultiplier = Float.NaN;
+ float shortTermModelUpperLuxMultiplier = Float.NaN;
final int configDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, configDepth)) {
if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) {
@@ -357,6 +458,12 @@
} else if (TAG_BRIGHTNESS_PARAMS.equals(parser.getName())) {
shouldCollectColorSamples =
Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_COLLECT_COLOR));
+ Long timeout = loadLongFromXml(parser, ATTR_MODEL_TIMEOUT);
+ if (timeout != null) {
+ shortTermModelTimeout = timeout;
+ }
+ shortTermModelLowerLuxMultiplier = loadFloatFromXml(parser, ATTR_MODEL_LOWER_BOUND);
+ shortTermModelUpperLuxMultiplier = loadFloatFromXml(parser, ATTR_MODEL_UPPER_BOUND);
}
}
final int n = luxList.size();
@@ -380,6 +487,9 @@
builder.addCorrectionByCategory(category, correction);
}
builder.setShouldCollectColorSamples(shouldCollectColorSamples);
+ builder.setShortTermModelTimeout(shortTermModelTimeout);
+ builder.setShortTermModelLowerLuxMultiplier(shortTermModelLowerLuxMultiplier);
+ builder.setShortTermModelUpperLuxMultiplier(shortTermModelUpperLuxMultiplier);
return builder.build();
}
@@ -392,6 +502,16 @@
}
}
+ private static Long loadLongFromXml(XmlPullParser parser, String attribute) {
+ final String string = parser.getAttributeValue(null, attribute);
+ try {
+ return Long.parseLong(string);
+ } catch (NullPointerException | NumberFormatException e) {
+ // Ignoring
+ }
+ return null;
+ }
+
/**
* A builder class for {@link BrightnessConfiguration}s.
*/
@@ -405,6 +525,9 @@
private Map<Integer, BrightnessCorrection> mCorrectionsByCategory;
private String mDescription;
private boolean mShouldCollectColorSamples;
+ private long mShortTermModelTimeout = SHORT_TERM_TIMEOUT_UNSET;
+ private float mShortTermModelLowerLuxMultiplier = Float.NaN;
+ private float mShortTermModelUpperLuxMultiplier = Float.NaN;
/**
* Constructs the builder with the control points for the brightness curve.
@@ -542,6 +665,60 @@
}
/**
+ * Sets the timeout for the short term model in milliseconds.
+ *
+ * If the screen is inactive for this timeout then the short term model
+ * will check the lux range defined by {@link #setShortTermModelLowerLuxMultiplier(float))}
+ * and {@link #setShortTermModelUpperLuxMultiplier(float)} to decide whether to keep any
+ * adjustment the user has made to adaptive brightness.
+ */
+ @NonNull
+ public Builder setShortTermModelTimeout(long shortTermModelTimeout) {
+ mShortTermModelTimeout = shortTermModelTimeout;
+ return this;
+ }
+
+ /**
+ * Sets the multiplier used to calculate the upper bound for which
+ * a users adaptive brightness is considered valid.
+ *
+ * For example if a user changes the brightness when the ambient light level
+ * is 100 lux, the adjustment will be kept if the current ambient light level
+ * is {@code <= 100 + (100 * shortTermModelUpperLuxMultiplier)}.
+ *
+ * @throws IllegalArgumentException if shortTermModelUpperLuxMultiplier is negative.
+ */
+ @NonNull
+ public Builder setShortTermModelUpperLuxMultiplier(
+ @FloatRange(from = 0.0f) float shortTermModelUpperLuxMultiplier) {
+ if (shortTermModelUpperLuxMultiplier < 0.0f) {
+ throw new IllegalArgumentException("Negative lux multiplier");
+ }
+ mShortTermModelUpperLuxMultiplier = shortTermModelUpperLuxMultiplier;
+ return this;
+ }
+
+ /**
+ * Returns the multiplier used to calculate the lower bound for which
+ * a users adaptive brightness is considered valid.
+ *
+ * For example if a user changes the brightness when the ambient light level
+ * is 100 lux, the adjustment will be kept if the current ambient light level
+ * is {@code >= 100 - (100 * shortTermModelLowerLuxMultiplier)}.
+ *
+ * @throws IllegalArgumentException if shortTermModelUpperLuxMultiplier is negative.
+ */
+ @NonNull
+ public Builder setShortTermModelLowerLuxMultiplier(
+ @FloatRange(from = 0.0f) float shortTermModelLowerLuxMultiplier) {
+ if (shortTermModelLowerLuxMultiplier < 0.0f) {
+ throw new IllegalArgumentException("Negative lux multiplier");
+ }
+ mShortTermModelLowerLuxMultiplier = shortTermModelLowerLuxMultiplier;
+ return this;
+ }
+
+ /**
* Builds the {@link BrightnessConfiguration}.
*/
@NonNull
@@ -550,7 +727,9 @@
throw new IllegalStateException("A curve must be set!");
}
return new BrightnessConfiguration(mCurveLux, mCurveNits, mCorrectionsByPackageName,
- mCorrectionsByCategory, mDescription, mShouldCollectColorSamples);
+ mCorrectionsByCategory, mDescription, mShouldCollectColorSamples,
+ mShortTermModelTimeout, mShortTermModelLowerLuxMultiplier,
+ mShortTermModelUpperLuxMultiplier);
}
private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) {
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index 85aa118..895b22c 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -115,10 +115,26 @@
}
@Test
+ public void testLuxMultipliersMustBePositive() {
+ BrightnessConfiguration.Builder config = new BrightnessConfiguration.Builder(
+ LUX_LEVELS, NITS_LEVELS);
+ assertThrows(IllegalArgumentException.class, () -> {
+ config.setShortTermModelUpperLuxMultiplier(-1f);
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ config.setShortTermModelLowerLuxMultiplier(-1f);
+ });
+ }
+
+ @Test
public void testParceledConfigIsEquivalent() {
BrightnessConfiguration.Builder builder =
new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
builder.setShouldCollectColorSamples(true);
+ builder.setShortTermModelTimeout(1234L);
+ builder.setShortTermModelLowerLuxMultiplier(0.9f);
+ builder.setShortTermModelUpperLuxMultiplier(0.2f);
builder.addCorrectionByCategory(3,
BrightnessCorrection.createScaleAndTranslateLog(1.0f, 2.0f));
builder.addCorrectionByPackageName("a.package.name",
@@ -137,6 +153,9 @@
BrightnessConfiguration.Builder builder =
new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
builder.setShouldCollectColorSamples(true);
+ builder.setShortTermModelTimeout(123L);
+ builder.setShortTermModelLowerLuxMultiplier(0.4f);
+ builder.setShortTermModelUpperLuxMultiplier(0.8f);
builder.addCorrectionByCategory(3,
BrightnessCorrection.createScaleAndTranslateLog(1.0f, 2.0f));
builder.addCorrectionByPackageName("a.package.name",
@@ -208,13 +227,28 @@
BrightnessCorrection.createScaleAndTranslateLog(1.0f, 2.0f));
builder.addCorrectionByPackageName("a.package.name",
BrightnessCorrection.createScaleAndTranslateLog(1.0f, 2.0f));
+ BrightnessConfiguration correctionsDiffer = builder.build();
+ assertNotEquals(baseConfig, correctionsDiffer);
+
+ builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
+ builder.setShouldCollectColorSamples(true);
BrightnessConfiguration colorCollectionDiffers = builder.build();
assertNotEquals(baseConfig, colorCollectionDiffers);
builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
- builder.setShouldCollectColorSamples(true);
- BrightnessConfiguration correctionsDiffer = builder.build();
- assertNotEquals(baseConfig, correctionsDiffer);
+ builder.setShortTermModelTimeout(300L);
+ BrightnessConfiguration timeoutDiffers = builder.build();
+ assertNotEquals(baseConfig, timeoutDiffers);
+
+ builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
+ builder.setShortTermModelLowerLuxMultiplier(0.7f);
+ BrightnessConfiguration lowerLuxDiffers = builder.build();
+ assertNotEquals(baseConfig, lowerLuxDiffers);
+
+ builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
+ builder.setShortTermModelUpperLuxMultiplier(0.6f);
+ BrightnessConfiguration upperLuxDiffers = builder.build();
+ assertNotEquals(baseConfig, upperLuxDiffers);
}
private static void assertArrayEquals(float[] expected, float[] actual, String name) {
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 177e2d8..c99774a 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -52,9 +52,6 @@
private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
- // If true, enables the use of the screen auto-brightness adjustment setting.
- private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
-
// How long the current sensor reading is assumed to be valid beyond the current time.
// This provides a bit of prediction, as well as ensures that the weight for the last sample is
// non-zero, which in turn ensures that the total weight is non-zero.
@@ -131,13 +128,6 @@
private boolean mLoggingEnabled;
- // Timeout after which we remove the effects any user interactions might've had on the
- // brightness mapping. This timeout doesn't start until we transition to a non-interactive
- // display policy so that we don't reset while users are using their devices, but also so that
- // we don't erroneously keep the short-term model if the device is dozing but the display is
- // fully on.
- private long mShortTermModelTimeout;
-
// Amount of time to delay auto-brightness after screen on while waiting for
// the light sensor to warm-up in milliseconds.
// May be 0 if no warm-up is required.
@@ -202,7 +192,6 @@
// we use a relative threshold to determine when to revert to the OEM curve.
private boolean mShortTermModelValid;
private float mShortTermModelAnchor;
- private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
// Context-sensitive brightness configurations require keeping track of the foreground app's
// package name and category, which is done by registering a TaskStackListener to call back to
@@ -224,14 +213,13 @@
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
+ HysteresisLevels screenBrightnessThresholds,
PackageManager packageManager) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
- ambientBrightnessThresholds, screenBrightnessThresholds, shortTermModelTimeout,
- packageManager);
+ ambientBrightnessThresholds, screenBrightnessThresholds, packageManager);
}
@VisibleForTesting
@@ -241,7 +229,7 @@
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
+ HysteresisLevels screenBrightnessThresholds,
PackageManager packageManager) {
mInjector = injector;
mCallbacks = callbacks;
@@ -261,7 +249,6 @@
mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
mAmbientBrightnessThresholds = ambientBrightnessThresholds;
mScreenBrightnessThresholds = screenBrightnessThresholds;
- mShortTermModelTimeout = shortTermModelTimeout;
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
@@ -370,7 +357,7 @@
}
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
- mShortTermModelTimeout);
+ mBrightnessMapper.getShortTermModelTimeout());
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
}
@@ -452,7 +439,7 @@
pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
- pw.println(" mShortTermModelTimeout=" + mShortTermModelTimeout);
+ pw.println(" mShortTermModelTimeout=" + mBrightnessMapper.getShortTermModelTimeout());
pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
pw.println(" mShortTermModelValid=" + mShortTermModelValid);
pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
@@ -552,20 +539,10 @@
// If the short term model was invalidated and the change is drastic enough, reset it.
if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
- final float minAmbientLux =
- mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
- final float maxAmbientLux =
- mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
- if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
- if (mLoggingEnabled) {
- Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
- minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
- }
- mShortTermModelValid = true;
- } else {
- Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
- "(" + minAmbientLux + ", " + maxAmbientLux + ")");
+ if (mBrightnessMapper.shouldResetShortTermModel(mAmbientLux, mShortTermModelAnchor)) {
resetShortTermModel();
+ } else {
+ mShortTermModelValid = true;
}
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 171cc5a..ff0b015 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -47,6 +47,7 @@
private static final float LUX_GRAD_SMOOTHING = 0.25f;
private static final float MAX_GRAD = 1.0f;
+ private static final float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
protected boolean mLoggingEnabled;
@@ -69,6 +70,9 @@
int[] backlightRange = resources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
+ long shortTermModelTimeout = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
+
if (isValidMapping(nitsRange, backlightRange)
&& isValidMapping(luxLevels, brightnessLevelsNits)) {
int minimumBacklight = resources.getInteger(
@@ -82,11 +86,14 @@
}
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
luxLevels, brightnessLevelsNits);
+ builder.setShortTermModelTimeout(shortTermModelTimeout);
+ builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
+ builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
autoBrightnessAdjustmentMaxGamma);
} else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
- autoBrightnessAdjustmentMaxGamma);
+ autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
} else {
return null;
}
@@ -189,6 +196,12 @@
public abstract boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config);
/**
+ * Gets the current {@link BrightnessConfiguration}.
+ */
+ @Nullable
+ public abstract BrightnessConfiguration getBrightnessConfiguration();
+
+ /**
* Returns the desired brightness of the display based on the current ambient lux, including
* any context-related corrections.
*
@@ -274,8 +287,53 @@
/** @return The default brightness configuration. */
public abstract BrightnessConfiguration getDefaultConfig();
+
+ /**
+ * Returns the timeout for the short term model
+ *
+ * Timeout after which we remove the effects any user interactions might've had on the
+ * brightness mapping. This timeout doesn't start until we transition to a non-interactive
+ * display policy so that we don't reset while users are using their devices, but also so that
+ * we don't erroneously keep the short-term model if the device is dozing but the
+ * display is fully on.
+ */
+ public abstract long getShortTermModelTimeout();
+
public abstract void dump(PrintWriter pw);
+ /**
+ * Check if the short term model should be reset given the anchor lux the last
+ * brightness change was made at and the current ambient lux.
+ */
+ public boolean shouldResetShortTermModel(float ambientLux, float shortTermModelAnchor) {
+ BrightnessConfiguration config = getBrightnessConfiguration();
+ float minThresholdRatio = SHORT_TERM_MODEL_THRESHOLD_RATIO;
+ float maxThresholdRatio = SHORT_TERM_MODEL_THRESHOLD_RATIO;
+ if (config != null) {
+ if (!Float.isNaN(config.getShortTermModelLowerLuxMultiplier())) {
+ minThresholdRatio = config.getShortTermModelLowerLuxMultiplier();
+ }
+ if (!Float.isNaN(config.getShortTermModelUpperLuxMultiplier())) {
+ maxThresholdRatio = config.getShortTermModelUpperLuxMultiplier();
+ }
+ }
+ final float minAmbientLux =
+ shortTermModelAnchor - shortTermModelAnchor * minThresholdRatio;
+ final float maxAmbientLux =
+ shortTermModelAnchor + shortTermModelAnchor * maxThresholdRatio;
+ if (minAmbientLux < ambientLux && ambientLux <= maxAmbientLux) {
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is "
+ + minAmbientLux + " < " + ambientLux + " < " + maxAmbientLux);
+ }
+ return false;
+ } else {
+ Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + ambientLux
+ + "(" + minAmbientLux + ", " + maxAmbientLux + ")");
+ return true;
+ }
+ }
+
protected float normalizeAbsoluteBrightness(int brightness) {
brightness = MathUtils.constrain(brightness,
PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
@@ -455,8 +513,10 @@
private float mAutoBrightnessAdjustment;
private float mUserLux;
private float mUserBrightness;
+ private long mShortTermModelTimeout;
- public SimpleMappingStrategy(float[] lux, int[] brightness, float maxGamma) {
+ private SimpleMappingStrategy(float[] lux, int[] brightness, float maxGamma,
+ long timeout) {
Preconditions.checkArgument(lux.length != 0 && brightness.length != 0,
"Lux and brightness arrays must not be empty!");
Preconditions.checkArgument(lux.length == brightness.length,
@@ -481,6 +541,12 @@
PLOG.start("simple mapping strategy");
}
computeSpline();
+ mShortTermModelTimeout = timeout;
+ }
+
+ @Override
+ public long getShortTermModelTimeout() {
+ return mShortTermModelTimeout;
}
@Override
@@ -489,6 +555,11 @@
}
@Override
+ public BrightnessConfiguration getBrightnessConfiguration() {
+ return null;
+ }
+
+ @Override
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {
return mSpline.interpolate(lux);
@@ -660,6 +731,15 @@
}
@Override
+ public long getShortTermModelTimeout() {
+ if (mConfig.getShortTermModelTimeout() >= 0) {
+ return mConfig.getShortTermModelTimeout();
+ } else {
+ return mDefaultConfig.getShortTermModelTimeout();
+ }
+ }
+
+ @Override
public boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config) {
if (config == null) {
config = mDefaultConfig;
@@ -676,6 +756,11 @@
}
@Override
+ public BrightnessConfiguration getBrightnessConfiguration() {
+ return mConfig;
+ }
+
+ @Override
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {
float nits = mBrightnessSpline.interpolate(lux);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index e42545e..f1655f0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -483,8 +483,6 @@
+ initialLightSensorRate + ") to be less than or equal to "
+ "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
}
- int shortTermModelTimeout = resources.getInteger(
- com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
String lightSensorType = resources.getString(
com.android.internal.R.string.config_displayLightSensorType);
@@ -498,8 +496,7 @@
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
- screenBrightnessThresholds, shortTermModelTimeout,
- context.getPackageManager());
+ screenBrightnessThresholds, context.getPackageManager());
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
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 f6c4d3a..ca00116 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -53,7 +53,6 @@
private static final int INITIAL_LIGHT_SENSOR_RATE = 20;
private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG = 0;
private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0;
- private static final int SHORT_TERM_MODEL_TIMEOUT = 0;
private static final float DOZE_SCALE_FACTOR = 0.0f;
private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
@@ -86,7 +85,7 @@
BRIGHTNESS_MAX, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, INITIAL_LIGHT_SENSOR_RATE,
BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG,
RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds,
- mScreenBrightnessThresholds, SHORT_TERM_MODEL_TIMEOUT, mPackageManager);
+ mScreenBrightnessThresholds, mPackageManager);
controller.setLoggingEnabled(true);
// Configure the brightness controller and grab an instance of the sensor listener,
@@ -189,4 +188,27 @@
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2));
assertEquals(255, controller.getAutomaticScreenBrightness());
}
+
+ @Test
+ public void testUserAddUserDataPoint() throws Exception {
+ Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+ AutomaticBrightnessController controller = setupController(lightSensor);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000));
+
+ // User sets brightness to 100
+ controller.configure(true /* enable */, null /* configuration */,
+ 100 /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */,
+ false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+
+ // There should be a user data point added to the mapper.
+ verify(mBrightnessMappingStrategy).addUserDataPoint(1000f, 100);
+ }
}