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
This commit is contained in:
Kenny Guy
2019-12-04 12:57:04 +00:00
parent e6a18182ce
commit b29fdf1d71
8 changed files with 353 additions and 45 deletions

View File

@@ -2353,9 +2353,13 @@ package android.hardware.display {
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 @@ package android.hardware.display {
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);
}

View File

@@ -1023,9 +1023,13 @@ package android.hardware.display {
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 @@ package android.hardware.display {
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);
}

View File

@@ -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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
}
dest.writeString(mDescription);
dest.writeBoolean(mShouldCollectColorSamples);
dest.writeLong(mShortTermModelTimeout);
dest.writeFloat(mShortTermModelLowerLuxMultiplier);
dest.writeFloat(mShortTermModelUpperLuxMultiplier);
}
@Override
@@ -182,6 +241,15 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
&& 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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
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 @@ public final class BrightnessConfiguration implements Parcelable {
} 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 @@ public final class BrightnessConfiguration implements Parcelable {
builder.addCorrectionByCategory(category, correction);
}
builder.setShouldCollectColorSamples(shouldCollectColorSamples);
builder.setShortTermModelTimeout(shortTermModelTimeout);
builder.setShortTermModelLowerLuxMultiplier(shortTermModelLowerLuxMultiplier);
builder.setShortTermModelUpperLuxMultiplier(shortTermModelUpperLuxMultiplier);
return builder.build();
}
@@ -392,6 +502,16 @@ public final class BrightnessConfiguration implements Parcelable {
}
}
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 @@ public final class BrightnessConfiguration implements Parcelable {
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.
@@ -541,6 +664,60 @@ public final class BrightnessConfiguration implements Parcelable {
return this;
}
/**
* 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}.
*/
@@ -550,7 +727,9 @@ public final class BrightnessConfiguration implements Parcelable {
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) {

View File

@@ -114,11 +114,27 @@ public class BrightnessConfigurationTest {
});
}
@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 @@ public class BrightnessConfigurationTest {
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 @@ public class BrightnessConfigurationTest {
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) {

View File

@@ -52,9 +52,6 @@ class AutomaticBrightnessController {
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 @@ class AutomaticBrightnessController {
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 @@ class AutomaticBrightnessController {
// 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 @@ class AutomaticBrightnessController {
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 @@ class AutomaticBrightnessController {
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 @@ class AutomaticBrightnessController {
mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
mAmbientBrightnessThresholds = ambientBrightnessThresholds;
mScreenBrightnessThresholds = screenBrightnessThresholds;
mShortTermModelTimeout = shortTermModelTimeout;
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
@@ -370,7 +357,7 @@ class AutomaticBrightnessController {
}
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 @@ class AutomaticBrightnessController {
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 @@ class AutomaticBrightnessController {
// 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;
}
}
}

View File

@@ -47,6 +47,7 @@ public abstract class BrightnessMappingStrategy {
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 @@ public abstract class BrightnessMappingStrategy {
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 @@ public abstract class BrightnessMappingStrategy {
}
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;
}
@@ -188,6 +195,12 @@ public abstract class BrightnessMappingStrategy {
*/
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 @@ public abstract class BrightnessMappingStrategy {
/** @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 @@ public abstract class BrightnessMappingStrategy {
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 @@ public abstract class BrightnessMappingStrategy {
PLOG.start("simple mapping strategy");
}
computeSpline();
mShortTermModelTimeout = timeout;
}
@Override
public long getShortTermModelTimeout() {
return mShortTermModelTimeout;
}
@Override
@@ -488,6 +554,11 @@ public abstract class BrightnessMappingStrategy {
return false;
}
@Override
public BrightnessConfiguration getBrightnessConfiguration() {
return null;
}
@Override
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {
@@ -659,6 +730,15 @@ public abstract class BrightnessMappingStrategy {
computeSpline();
}
@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) {
@@ -675,6 +755,11 @@ public abstract class BrightnessMappingStrategy {
return true;
}
@Override
public BrightnessConfiguration getBrightnessConfiguration() {
return mConfig;
}
@Override
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {

View File

@@ -483,8 +483,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
+ 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 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
screenBrightnessThresholds, shortTermModelTimeout,
context.getPackageManager());
screenBrightnessThresholds, context.getPackageManager());
} else {
mUseSoftwareAutoBrightnessConfig = false;
}

View File

@@ -53,7 +53,6 @@ public class AutomaticBrightnessControllerTest {
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 @@ public class AutomaticBrightnessControllerTest {
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 @@ public class AutomaticBrightnessControllerTest {
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);
}
}