Merge "Change BrightnessMappingStrategy to use DDC values" into sc-dev

This commit is contained in:
Fiona Campbell
2021-02-25 13:25:10 +00:00
committed by Android (Google) Code Review
8 changed files with 483 additions and 359 deletions

View File

@@ -72,8 +72,6 @@ public class BrightnessController implements ToggleSlider.Listener {
private static final Uri BRIGHTNESS_FOR_VR_FLOAT_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT);
private final float mMinimumBacklight;
private final float mMaximumBacklight;
private final float mDefaultBacklight;
private final float mMinimumBacklightForVr;
private final float mMaximumBacklightForVr;
@@ -314,10 +312,6 @@ public class BrightnessController implements ToggleSlider.Listener {
mDisplayId = mContext.getDisplayId();
PowerManager pm = context.getSystemService(PowerManager.class);
mMinimumBacklight = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
mMaximumBacklight = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
mDefaultBacklight = mContext.getDisplay().getBrightnessDefault();
mMinimumBacklightForVr = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR);
@@ -375,8 +369,8 @@ public class BrightnessController implements ToggleSlider.Listener {
metric = mAutomatic
? MetricsEvent.ACTION_BRIGHTNESS_AUTO
: MetricsEvent.ACTION_BRIGHTNESS;
minBacklight = mMinimumBacklight;
maxBacklight = mMaximumBacklight;
minBacklight = PowerManager.BRIGHTNESS_MIN;
maxBacklight = PowerManager.BRIGHTNESS_MAX;
settingToChange = Settings.System.SCREEN_BRIGHTNESS_FLOAT;
}
final float valFloat = MathUtils.min(convertGammaToLinearFloat(value,
@@ -439,8 +433,8 @@ public class BrightnessController implements ToggleSlider.Listener {
min = mMinimumBacklightForVr;
max = mMaximumBacklightForVr;
} else {
min = mMinimumBacklight;
max = mMaximumBacklight;
min = PowerManager.BRIGHTNESS_MIN;
max = PowerManager.BRIGHTNESS_MAX;
}
// convertGammaToLinearFloat returns 0-1
if (BrightnessSynchronizer.floatEquals(brightnessValue,

View File

@@ -61,7 +61,10 @@ public abstract class BrightnessMappingStrategy {
private static final Plog PLOG = Plog.createSystemPlog(TAG);
@Nullable
public static BrightnessMappingStrategy create(Resources resources) {
public static BrightnessMappingStrategy create(Resources resources,
DisplayDeviceConfig displayDeviceConfig) {
// Display independent values
float[] luxLevels = getLuxLevels(resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels));
int[] brightnessLevelsBacklight = resources.getIntArray(
@@ -71,32 +74,22 @@ public abstract class BrightnessMappingStrategy {
float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
1, 1);
float[] nitsRange = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits));
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)
// Display dependent values - used for physical mapping strategy nits -> brightness
final float[] nitsRange = displayDeviceConfig.getNits();
final float[] brightnessRange = displayDeviceConfig.getBrightness();
if (isValidMapping(nitsRange, brightnessRange)
&& isValidMapping(luxLevels, brightnessLevelsNits)) {
int minimumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
int maximumBacklight = resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
if (backlightRange[0] > minimumBacklight
|| backlightRange[backlightRange.length - 1] < maximumBacklight) {
Slog.w(TAG, "Screen brightness mapping does not cover whole range of available " +
"backlight values, autobrightness functionality may be impaired.");
}
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
luxLevels, brightnessLevelsNits);
builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange,
autoBrightnessAdjustmentMaxGamma);
} else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
@@ -264,11 +257,11 @@ public abstract class BrightnessMappingStrategy {
public abstract boolean setAutoBrightnessAdjustment(float adjustment);
/**
* Converts the provided backlight value to nits if possible.
* Converts the provided brightness value to nits if possible.
*
* Returns -1.0f if there's no available mapping for the backlight to nits.
* Returns -1.0f if there's no available mapping for the brightness to nits.
*/
public abstract float convertToNits(int backlight);
public abstract float convertToNits(float brightness);
/**
* Adds a user interaction data point to the brightness mapping.
@@ -603,7 +596,7 @@ public abstract class BrightnessMappingStrategy {
}
@Override
public float convertToNits(int backlight) {
public float convertToNits(float brightness) {
return -1.0f;
}
@@ -701,37 +694,39 @@ public abstract class BrightnessMappingStrategy {
// in nits.
private Spline mBrightnessSpline;
// A spline mapping from nits to the corresponding backlight value, normalized to the range
// A spline mapping from nits to the corresponding brightness value, normalized to the range
// [0, 1.0].
private Spline mNitsToBacklightSpline;
private Spline mNitsToBrightnessSpline;
// A spline mapping from the system brightness value, normalized to the range [0, 1.0], to
// a brightness in nits.
private Spline mBrightnessToNitsSpline;
// The default brightness configuration.
private final BrightnessConfiguration mDefaultConfig;
// A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to
// a brightness in nits.
private Spline mBacklightToNitsSpline;
private float[] mNits;
private int[] mBacklight;
private final float[] mNits;
private final float[] mBrightness;
private boolean mBrightnessRangeAdjustmentApplied;
private float mMaxGamma;
private final float mMaxGamma;
private float mAutoBrightnessAdjustment;
private float mUserLux;
private float mUserBrightness;
public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
int[] backlight, float maxGamma) {
Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
"Nits and backlight arrays must not be empty!");
Preconditions.checkArgument(nits.length == backlight.length,
"Nits and backlight arrays must be the same length!");
float[] brightness, float maxGamma) {
Preconditions.checkArgument(nits.length != 0 && brightness.length != 0,
"Nits and brightness arrays must not be empty!");
Preconditions.checkArgument(nits.length == brightness.length,
"Nits and brightness arrays must be the same length!");
Objects.requireNonNull(config);
Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
Preconditions.checkArrayElementsInRange(backlight,
PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
Preconditions.checkArrayElementsInRange(brightness,
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, "brightness");
mMaxGamma = maxGamma;
mAutoBrightnessAdjustment = 0;
@@ -739,7 +734,7 @@ public abstract class BrightnessMappingStrategy {
mUserBrightness = -1;
mNits = nits;
mBacklight = backlight;
mBrightness = brightness;
computeNitsBrightnessSplines(mNits);
mDefaultConfig = config;
@@ -784,15 +779,15 @@ public abstract class BrightnessMappingStrategy {
public float getBrightness(float lux, String packageName,
@ApplicationInfo.Category int category) {
float nits = mBrightnessSpline.interpolate(lux);
float backlight = mNitsToBacklightSpline.interpolate(nits);
float brightness = mNitsToBrightnessSpline.interpolate(nits);
// Correct the brightness according to the current application and its category, but
// only if no user data point is set (as this will oevrride the user setting).
// only if no user data point is set (as this will override the user setting).
if (mUserLux == -1) {
backlight = correctBrightness(backlight, packageName, category);
brightness = correctBrightness(brightness, packageName, category);
} else if (mLoggingEnabled) {
Slog.d(TAG, "user point set, correction not applied");
}
return backlight;
return brightness;
}
@Override
@@ -817,8 +812,8 @@ public abstract class BrightnessMappingStrategy {
}
@Override
public float convertToNits(int backlight) {
return mBacklightToNitsSpline.interpolate(normalizeAbsoluteBrightness(backlight));
public float convertToNits(float brightness) {
return mBrightnessToNitsSpline.interpolate(brightness);
}
@Override
@@ -884,7 +879,8 @@ public abstract class BrightnessMappingStrategy {
pw.println("PhysicalMappingStrategy");
pw.println(" mConfig=" + mConfig);
pw.println(" mBrightnessSpline=" + mBrightnessSpline);
pw.println(" mNitsToBacklightSpline=" + mNitsToBacklightSpline);
pw.println(" mNitsToBrightnessSpline=" + mNitsToBrightnessSpline);
pw.println(" mBrightnessToNitsSpline=" + mBrightnessToNitsSpline);
pw.println(" mMaxGamma=" + mMaxGamma);
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mUserLux=" + mUserLux);
@@ -894,31 +890,25 @@ public abstract class BrightnessMappingStrategy {
}
private void computeNitsBrightnessSplines(float[] nits) {
final int len = nits.length;
float[] normalizedBacklight = new float[len];
for (int i = 0; i < len; i++) {
normalizedBacklight[i] = normalizeAbsoluteBrightness(mBacklight[i]);
}
mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight);
mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);
mNitsToBrightnessSpline = Spline.createSpline(nits, mBrightness);
mBrightnessToNitsSpline = Spline.createSpline(mBrightness, nits);
}
private void computeSpline() {
Pair<float[], float[]> defaultCurve = mConfig.getCurve();
float[] defaultLux = defaultCurve.first;
float[] defaultNits = defaultCurve.second;
float[] defaultBacklight = new float[defaultNits.length];
for (int i = 0; i < defaultBacklight.length; i++) {
defaultBacklight[i] = mNitsToBacklightSpline.interpolate(defaultNits[i]);
float[] defaultBrightness = new float[defaultNits.length];
for (int i = 0; i < defaultBrightness.length; i++) {
defaultBrightness[i] = mNitsToBrightnessSpline.interpolate(defaultNits[i]);
}
Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux,
Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBrightness, mUserLux,
mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
float[] lux = curve.first;
float[] backlight = curve.second;
float[] nits = new float[backlight.length];
float[] brightness = curve.second;
float[] nits = new float[brightness.length];
for (int i = 0; i < nits.length; i++) {
nits[i] = mBacklightToNitsSpline.interpolate(backlight[i]);
nits[i] = mBrightnessToNitsSpline.interpolate(brightness[i]);
}
mBrightnessSpline = Spline.createSpline(lux, nits);
}
@@ -926,7 +916,7 @@ public abstract class BrightnessMappingStrategy {
private float getUnadjustedBrightness(float lux) {
Pair<float[], float[]> curve = mConfig.getCurve();
Spline spline = Spline.createSpline(curve.first, curve.second);
return mNitsToBacklightSpline.interpolate(spline.interpolate(lux));
return mNitsToBrightnessSpline.interpolate(spline.interpolate(lux));
}
private float correctBrightness(float brightness, String packageName, int category) {

View File

@@ -18,9 +18,12 @@ package com.android.server.display;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.os.Environment;
import android.os.PowerManager;
import android.util.MathUtils;
import android.util.Slog;
import android.util.Spline;
import android.view.DisplayAddress;
import com.android.internal.R;
@@ -72,15 +75,31 @@ public class DisplayDeviceConfig {
private final Context mContext;
// Nits and backlight values that are loaded from either the display device config file, or
// config.xml. These are the raw values and just used for the dumpsys
private float[] mRawNits;
private float[] mRawBacklight;
// These arrays are calculated from the raw arrays, but clamped to contain values equal to and
// between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
// length
// Nits array that is used to store the entire range of nits values that the device supports
private float[] mNits;
// Backlight array holds the values that the HAL uses to display the corresponding nits values
private float[] mBacklight;
// Purely an array that covers the ranges of values 0.0 - 1.0, indicating the system brightness
// for the corresponding values above
private float[] mBrightness;
private float mBrightnessMinimum = Float.NaN;
private float mBrightnessMaximum = Float.NaN;
private float mBacklightMinimum = Float.NaN;
private float mBacklightMaximum = Float.NaN;
private float mBrightnessDefault = Float.NaN;
private float mBrightnessRampFastDecrease = Float.NaN;
private float mBrightnessRampFastIncrease = Float.NaN;
private float mBrightnessRampSlowDecrease = Float.NaN;
private float mBrightnessRampSlowIncrease = Float.NaN;
private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline;
private List<String> mQuirks;
private boolean mIsHighBrightnessModeEnabled = false;
private HighBrightnessModeData mHbmData;
@@ -167,7 +186,7 @@ public class DisplayDeviceConfig {
}
/**
* Return the brightness mapping nits array if one is defined in the configuration file.
* Return the brightness mapping nits array.
*
* @return The brightness mapping nits array.
*/
@@ -176,22 +195,40 @@ public class DisplayDeviceConfig {
}
/**
* Return the brightness mapping value array if one is defined in the configuration file.
* Return the brightness mapping backlight array.
*
* @return The brightness mapping value array.
* @return The backlight mapping value array.
*/
public float[] getBacklight() {
return mBacklight;
}
/**
* Calculates the backlight value, as recognised by the HAL, from the brightness value
* given that the rest of the system deals with.
*
* @param brightness value on the framework scale of 0-1
* @return backlight value on the HAL scale of 0-1
*/
public float getBacklightFromBrightness(float brightness) {
return mBrightnessToBacklightSpline.interpolate(brightness);
}
/**
* Return an array of equal length to backlight and nits, that covers the entire system
* brightness range of 0.0-1.0.
*
* @return brightness array
*/
public float[] getBrightness() {
return mBrightness;
}
public float getBrightnessMinimum() {
return mBrightnessMinimum;
}
public float getBrightnessMaximum() {
return mBrightnessMaximum;
}
/**
* Return the default brightness on a scale of 0.0f - 1.0f
*
* @return default brightness
*/
public float getBrightnessDefault() {
return mBrightnessDefault;
}
@@ -237,10 +274,15 @@ public class DisplayDeviceConfig {
@Override
public String toString() {
String str = "DisplayDeviceConfig{"
+ "mBrightness=" + Arrays.toString(mBrightness)
+ "mBacklight=" + Arrays.toString(mBacklight)
+ ", mNits=" + Arrays.toString(mNits)
+ ", mBrightnessMinimum=" + mBrightnessMinimum
+ ", mBrightnessMaximum=" + mBrightnessMaximum
+ ", mRawBacklight=" + Arrays.toString(mRawBacklight)
+ ", mRawNits=" + Arrays.toString(mRawNits)
+ ", mBrightness=" + Arrays.toString(mBrightness)
+ ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
+ ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
+ ", mBacklightMinimum=" + mBacklightMinimum
+ ", mBacklightMaximum=" + mBacklightMaximum
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
@@ -253,10 +295,6 @@ public class DisplayDeviceConfig {
return str;
}
private float getMaxBrightness() {
return mBrightness[mBrightness.length - 1];
}
private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
String suffixFormat, long idNumber) {
@@ -264,7 +302,6 @@ public class DisplayDeviceConfig {
final String filename = String.format(CONFIG_FILE_FORMAT, suffix);
final File filePath = Environment.buildPath(
baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
if (filePath.exists()) {
final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
config.initFromFile(filePath);
@@ -299,9 +336,9 @@ public class DisplayDeviceConfig {
try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
final DisplayConfiguration config = XmlParser.read(in);
if (config != null) {
loadBrightnessMap(config);
loadBrightnessDefaultFromDdcXml(config);
loadBrightnessConstraintsFromConfigXml();
loadBrightnessMap(config);
loadHighBrightnessModeData(config);
loadQuirks(config);
loadBrightnessRamps(config);
@@ -318,13 +355,20 @@ public class DisplayDeviceConfig {
// If no ddc exists, use config.xml
loadBrightnessDefaultFromConfigXml();
loadBrightnessConstraintsFromConfigXml();
loadBrightnessMapFromConfigXml();
loadBrightnessRampsFromConfigXml();
}
private void initFromPmValues() {
mBrightnessMinimum = PowerManager.BRIGHTNESS_MIN;
mBrightnessMaximum = PowerManager.BRIGHTNESS_MAX;
// Set all to basic values
mBacklightMinimum = PowerManager.BRIGHTNESS_MIN;
mBacklightMaximum = PowerManager.BRIGHTNESS_MAX;
mBrightnessDefault = BRIGHTNESS_DEFAULT;
mBrightnessRampFastDecrease = PowerManager.BRIGHTNESS_MAX;
mBrightnessRampFastIncrease = PowerManager.BRIGHTNESS_MAX;
mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
setSimpleMappingStrategyValues();
}
private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) {
@@ -364,24 +408,27 @@ public class DisplayDeviceConfig {
final float max = mContext.getResources().getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat);
if (min == INVALID_BRIGHTNESS_IN_CONFIG || max == INVALID_BRIGHTNESS_IN_CONFIG) {
mBrightnessMinimum = BrightnessSynchronizer.brightnessIntToFloat(
mBacklightMinimum = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessSettingMinimum));
mBrightnessMaximum = BrightnessSynchronizer.brightnessIntToFloat(
mBacklightMaximum = BrightnessSynchronizer.brightnessIntToFloat(
mContext.getResources().getInteger(com.android.internal.R.integer
.config_screenBrightnessSettingMaximum));
} else {
mBrightnessMinimum = min;
mBrightnessMaximum = max;
mBacklightMinimum = min;
mBacklightMaximum = max;
}
}
private void loadBrightnessMap(DisplayConfiguration config) {
final NitsMap map = config.getScreenBrightnessMap();
// Map may not exist in config file
// Map may not exist in display device config
if (map == null) {
loadBrightnessMapFromConfigXml();
return;
}
// Use the (preferred) display device config mapping
final List<Point> points = map.getPoint();
final int size = points.size();
@@ -408,8 +455,123 @@ public class DisplayDeviceConfig {
}
++i;
}
mNits = nits;
mBrightness = backlight;
mRawNits = nits;
mRawBacklight = backlight;
constrainNitsAndBacklightArrays();
}
private void loadBrightnessMapFromConfigXml() {
// Use the config.xml mapping
final Resources res = mContext.getResources();
final float[] sysNits = BrightnessMappingStrategy.getFloatArray(res.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits));
final int[] sysBrightness = res.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
final float[] sysBrightnessFloat = new float[sysBrightness.length];
for (int i = 0; i < sysBrightness.length; i++) {
sysBrightnessFloat[i] = BrightnessSynchronizer.brightnessIntToFloat(
sysBrightness[i]);
}
// These arrays are allowed to be empty, we set null values so that
// BrightnessMappingStrategy will create a SimpleMappingStrategy instead.
if (sysBrightnessFloat.length == 0 || sysNits.length == 0) {
setSimpleMappingStrategyValues();
return;
}
mRawNits = sysNits;
mRawBacklight = sysBrightnessFloat;
constrainNitsAndBacklightArrays();
}
private void setSimpleMappingStrategyValues() {
// No translation from backlight to brightness should occur if we are using a
// SimpleMappingStrategy (ie they should be the same) so the splines are
// set to be linear, between 0.0 and 1.0
mNits = null;
mBacklight = null;
float[] simpleMappingStrategyArray = new float[]{0.0f, 1.0f};
mBrightnessToBacklightSpline = Spline.createSpline(simpleMappingStrategyArray,
simpleMappingStrategyArray);
mBacklightToBrightnessSpline = Spline.createSpline(simpleMappingStrategyArray,
simpleMappingStrategyArray);
}
/**
* Change the nits and backlight arrays, so that they cover only the allowed backlight values
* Use the brightness minimum and maximum values to clamp these arrays.
*/
private void constrainNitsAndBacklightArrays() {
if (mRawBacklight[0] > mBacklightMinimum
|| mRawBacklight[mRawBacklight.length - 1] < mBacklightMaximum
|| mBacklightMinimum > mBacklightMaximum) {
throw new IllegalStateException("Min or max values are invalid"
+ "; raw min=" + mRawBacklight[0]
+ "; raw max=" + mRawBacklight[mRawBacklight.length - 1]
+ "; backlight min=" + mBacklightMinimum
+ "; backlight max=" + mBacklightMaximum);
}
float[] newNits = new float[mRawBacklight.length];
float[] newBacklight = new float[mRawBacklight.length];
// Find the starting index of the clamped arrays. This may be less than the min so
// we'll need to clamp this value still when actually doing the remapping.
int newStart = 0;
for (int i = 0; i < mRawBacklight.length - 1; i++) {
if (mRawBacklight[i + 1] > mBacklightMinimum) {
newStart = i;
break;
}
}
boolean isLastValue = false;
int newIndex = 0;
for (int i = newStart; i < mRawBacklight.length && !isLastValue; i++) {
newIndex = i - newStart;
final float newBacklightVal;
final float newNitsVal;
isLastValue = mRawBacklight[i] > mBacklightMaximum
|| i >= mRawBacklight.length - 1;
// Clamp beginning and end to valid backlight values.
if (newIndex == 0) {
newBacklightVal = MathUtils.max(mRawBacklight[i], mBacklightMinimum);
newNitsVal = rawBacklightToNits(i, newBacklightVal);
} else if (isLastValue) {
newBacklightVal = MathUtils.min(mRawBacklight[i], mBacklightMaximum);
newNitsVal = rawBacklightToNits(i - 1, newBacklightVal);
} else {
newBacklightVal = mRawBacklight[i];
newNitsVal = mRawNits[i];
}
newBacklight[newIndex] = newBacklightVal;
newNits[newIndex] = newNitsVal;
}
mBacklight = Arrays.copyOf(newBacklight, newIndex + 1);
mNits = Arrays.copyOf(newNits, newIndex + 1);
createBacklightConversionSplines();
}
private float rawBacklightToNits(int i, float backlight) {
return MathUtils.map(mRawBacklight[i], mRawBacklight[i + 1],
mRawNits[i], mRawNits[i + 1], backlight);
}
// This method creates a brightness spline that is of equal length with proportional increments
// to the backlight spline. The values of this array range from 0.0f to 1.0f instead of the
// potential constrained range that the backlight array covers
// These splines are used to convert from the system brightness value to the HAL backlight
// value
private void createBacklightConversionSplines() {
mBrightness = new float[mBacklight.length];
for (int i = 0; i < mBrightness.length; i++) {
mBrightness[i] = MathUtils.map(mBacklight[0],
mBacklight[mBacklight.length - 1],
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
}
mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
}
private void loadQuirks(DisplayConfiguration config) {
@@ -425,12 +587,14 @@ public class DisplayDeviceConfig {
mIsHighBrightnessModeEnabled = hbm.getEnabled();
mHbmData = new HighBrightnessModeData();
mHbmData.minimumLux = hbm.getMinimumLux_all().floatValue();
mHbmData.transitionPoint = hbm.getTransitionPoint_all().floatValue();
if (mHbmData.transitionPoint >= getMaxBrightness()) {
float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
if (transitionPointBacklightScale >= mBacklightMaximum) {
throw new IllegalArgumentException("HBM transition point invalid. "
+ mHbmData.transitionPoint + " is not less than "
+ getMaxBrightness());
+ mBacklightMaximum);
}
mHbmData.transitionPoint =
mBacklightToBrightnessSpline.interpolate(transitionPointBacklightScale);
final HbmTiming hbmTiming = hbm.getTiming_all();
mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;

View File

@@ -190,12 +190,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The dim screen brightness.
private final float mScreenBrightnessDimConfig;
// The minimum allowed brightness.
private final float mScreenBrightnessRangeMinimum;
// The maximum allowed brightness.
private final float mScreenBrightnessRangeMaximum;
private final float mScreenBrightnessDefault;
// The minimum allowed brightness while in VR.
@@ -443,8 +437,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final Resources resources = context.getResources();
final float screenBrightnessSettingMinimumFloat = clampAbsoluteBrightness(
pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM));
// DOZE AND DIM SETTINGS
mScreenBrightnessDozeConfig = clampAbsoluteBrightness(
@@ -453,10 +445,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DIM));
// NORMAL SCREEN SETTINGS
mScreenBrightnessRangeMinimum =
Math.min(screenBrightnessSettingMinimumFloat, mScreenBrightnessDimConfig);
mScreenBrightnessRangeMaximum = clampAbsoluteBrightness(
pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM));
mScreenBrightnessDefault = clampAbsoluteBrightness(
mLogicalDisplay.getDisplayInfoLocked().brightnessDefault);
@@ -545,12 +533,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
com.android.internal.R.string.config_displayLightSensorType);
Sensor lightSensor = findDisplayLightSensor(lightSensorType);
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
final DisplayDeviceConfig ddc =
logicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
mBrightnessMapper = BrightnessMappingStrategy.create(resources, ddc);
if (mBrightnessMapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
screenBrightnessThresholds, logicalDisplay, context);
@@ -838,9 +828,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
noteScreenBrightness(mPowerState.getScreenBrightness());
// Initialize all of the brightness tracking state
final float brightness = convertToNits(BrightnessSynchronizer.brightnessFloatToInt(
mPowerState.getScreenBrightness()));
if (brightness >= 0.0f) {
final float brightness = convertToNits(mPowerState.getScreenBrightness());
if (brightness >= PowerManager.BRIGHTNESS_MIN) {
mBrightnessTracker.start(brightness);
}
@@ -1151,10 +1140,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightnessState > mScreenBrightnessRangeMinimum) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
brightnessState = Math.max(Math.min(brightnessState
- SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
mScreenBrightnessDimConfig), PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
}
if (!mAppliedDimming) {
@@ -1168,12 +1157,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor
// as long as it is above the minimum threshold.
if (mPowerRequest.lowPowerMode) {
if (brightnessState > mScreenBrightnessRangeMinimum) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
final float lowPowerBrightnessFloat = (brightnessState * brightnessFactor);
brightnessState = Math.max(lowPowerBrightnessFloat,
mScreenBrightnessRangeMinimum);
brightnessState = Math.max(lowPowerBrightnessFloat, PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_LOW_POWER);
}
if (!mAppliedLowPower) {
@@ -1258,9 +1246,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// slider event so notify as if the system changed the brightness.
userInitiatedChange = false;
}
notifyBrightnessChanged(
BrightnessSynchronizer.brightnessFloatToInt(brightnessState),
userInitiatedChange, hadUserBrightnessPoint);
notifyBrightnessChanged(brightnessState, userInitiatedChange,
hadUserBrightnessPoint);
}
}
@@ -1487,17 +1474,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private float clampScreenBrightness(float value) {
if (Float.isNaN(value)) {
return mScreenBrightnessRangeMinimum;
return PowerManager.BRIGHTNESS_MIN;
}
return MathUtils.constrain(
value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
value, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
}
// Checks whether the brightness is within the valid brightness range, not including the off or
// invalid states.
private boolean isValidBrightnessValue(float brightnessState) {
return brightnessState >= mScreenBrightnessRangeMinimum
&& brightnessState <= mScreenBrightnessRangeMaximum;
return brightnessState >= PowerManager.BRIGHTNESS_MIN
&& brightnessState <= PowerManager.BRIGHTNESS_MAX;
}
private void animateScreenBrightness(float target, float rate) {
@@ -1874,7 +1861,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return true;
}
private void notifyBrightnessChanged(int brightness, boolean userInitiated,
private void notifyBrightnessChanged(float brightness, boolean userInitiated,
boolean hadUserDataPoint) {
final float brightnessInNits = convertToNits(brightness);
if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f
@@ -1891,9 +1878,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
private float convertToNits(int backlight) {
private float convertToNits(float brightness) {
if (mBrightnessMapper != null) {
return mBrightnessMapper.convertToNits(backlight);
return mBrightnessMapper.convertToNits(brightness);
} else {
return -1.0f;
}
@@ -1972,12 +1959,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println();
pw.println("Display Power Controller Configuration:");
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault);
pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mScreenBrightnessDefault=" + mScreenBrightnessDefault);
pw.println(" mScreenBrightnessForVrRangeMinimum=" + mScreenBrightnessForVrRangeMinimum);
pw.println(" mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
pw.println(" mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
@@ -2109,10 +2093,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
private static int clampAbsoluteBrightness(int value) {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
private static float clampAbsoluteBrightness(float value) {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX);

View File

@@ -30,7 +30,6 @@ import android.os.Trace;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Spline;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayCutout;
@@ -210,8 +209,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private SurfaceControl.DisplayMode[] mSfDisplayModes;
// The active display mode in SurfaceFlinger
private SurfaceControl.DisplayMode mActiveSfDisplayMode;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
private DisplayDeviceConfig mDisplayDeviceConfig;
private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
new DisplayEventReceiver.FrameRateOverride[0];
@@ -410,16 +408,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceConfig getDisplayDeviceConfig() {
if (mDisplayDeviceConfig == null) {
loadDisplayConfiguration();
loadDisplayDeviceConfig();
}
return mDisplayDeviceConfig;
}
private void loadDisplayConfiguration() {
Spline nitsToHal = null;
Spline sysToNits = null;
// Load the mapping from nits to HAL brightness range (display-device-config.xml)
private void loadDisplayDeviceConfig() {
// Load display device config
final Context context = getOverlayContext();
mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId,
mIsDefaultDisplay);
@@ -427,33 +422,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return;
}
// Load brightness HWC quirk
mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
DisplayDeviceConfig.QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC));
final float[] halNits = mDisplayDeviceConfig.getNits();
final float[] halBrightness = mDisplayDeviceConfig.getBrightness();
if (halNits == null || halBrightness == null) {
return;
}
nitsToHal = Spline.createSpline(halNits, halBrightness);
// Load the mapping from system brightness range to nits (config.xml)
final Resources res = context.getResources();
final float[] sysNits = BrightnessMappingStrategy.getFloatArray(res.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits));
final int[] sysBrightness = res.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight);
if (sysNits.length == 0 || sysBrightness.length != sysNits.length) {
return;
}
final float[] sysBrightnessFloat = new float[sysBrightness.length];
for (int i = 0; i < sysBrightness.length; i++) {
sysBrightnessFloat[i] = sysBrightness[i];
}
sysToNits = Spline.createSpline(sysBrightnessFloat, sysNits);
mNitsToHalBrightness = nitsToHal;
mSystemBrightnessToNits = sysToNits;
}
private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) {
@@ -665,13 +636,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// The display is trusted since it is created by system.
mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
if (mDisplayDeviceConfig != null) {
mInfo.brightnessMinimum = mDisplayDeviceConfig.getBrightnessMinimum();
mInfo.brightnessMaximum = mDisplayDeviceConfig.getBrightnessMaximum();
mInfo.brightnessDefault = mDisplayDeviceConfig.getBrightnessDefault();
} else {
mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
mInfo.brightnessDefault = 0.5f;
}
}
@@ -811,8 +780,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+ "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
try {
brightness = displayBrightnessToHalBrightness(brightness);
mBacklightAdapter.setBrightness(brightness);
float backlight = brightnessToBacklight(brightness);
mBacklightAdapter.setBacklight(backlight);
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(brightness));
@@ -821,35 +790,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
/**
* Converts brightness range from the framework's brightness space to the
* Hal brightness space if the HAL brightness space has been provided via
* a display device configuration file.
*/
private float displayBrightnessToHalBrightness(float brightness) {
// TODO: b/171380847 - This needs to be deprecated. The nits-to-brightness
// relationship should be specified in display-config OR config.xml, but not
// both, and no nits-space conversion should be necessary.
//
// Only do a conversion if there exists a unique system brightness and a
// unique HAL brightness-to-nits range defined.
if (mSystemBrightnessToNits == null || mNitsToHalBrightness == null) {
return brightness;
}
// Sys brightness in this conversion is always specified in the old 1-255
// range, so convert that here before the translation.
final float brightnessInt =
BrightnessSynchronizer.brightnessFloatToIntRange(brightness);
if (BrightnessSynchronizer.floatEquals(
brightnessInt, PowerManager.BRIGHTNESS_OFF)) {
return PowerManager.BRIGHTNESS_OFF_FLOAT;
}
final float nits = mSystemBrightnessToNits.interpolate(brightnessInt);
final float halBrightness = mNitsToHalBrightness.interpolate(nits);
return halBrightness;
private float brightnessToBacklight(float brightness) {
return getDisplayDeviceConfig().getBacklightFromBrightness(brightness);
}
};
}
@@ -1338,11 +1280,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
void setBrightness(float brightness) {
// Set backlight within min and max backlight values
void setBacklight(float backlight) {
if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, brightness);
mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
} else if (mBacklight != null) {
mBacklight.setBrightness(brightness);
mBacklight.setBrightness(backlight);
}
}

View File

@@ -27,11 +27,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -44,6 +47,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.display.LocalDisplayAdapter.BacklightAdapter;
import com.android.server.lights.LightsManager;
@@ -98,6 +102,9 @@ public class LocalDisplayAdapterTest {
@Mock
private LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
private static final int[] BACKLIGHT_RANGE = { 1, 255 };
private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f };
@Before
public void setUp() throws Exception {
@@ -114,6 +121,18 @@ public class LocalDisplayAdapterTest {
mListener, mInjector);
spyOn(mAdapter);
doReturn(mMockedContext).when(mAdapter).getOverlayContext();
TypedArray mockNitsRange = createFloatTypedArray(DISPLAY_RANGE_NITS);
when(mMockedResources.obtainTypedArray(R.array.config_screenBrightnessNits))
.thenReturn(mockNitsRange);
when(mMockedResources.getIntArray(R.array.config_screenBrightnessBacklight))
.thenReturn(BACKLIGHT_RANGE);
when(mMockedResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMinimumFloat))
.thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[0]);
when(mMockedResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat))
.thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[1]);
}
@After
@@ -629,13 +648,13 @@ public class LocalDisplayAdapterTest {
// Test as default display
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy);
ba.setBrightness(0.514f);
ba.setBacklight(0.514f);
verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f);
// Test as not default display
BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy);
ba2.setBrightness(0.323f);
ba2.setBacklight(0.323f);
verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f);
}
@@ -648,7 +667,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
mSurfaceControlProxy);
ba.setBrightness(0.123f);
ba.setBacklight(0.123f);
verify(mMockedBacklight).setBrightness(0.123f);
}
@@ -661,7 +680,7 @@ public class LocalDisplayAdapterTest {
BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/,
mSurfaceControlProxy);
ba.setBrightness(0.456f);
ba.setBacklight(0.456f);
// Adapter does not forward any brightness in this case.
verify(mMockedBacklight, never()).setBrightness(anyFloat());
@@ -864,4 +883,23 @@ public class LocalDisplayAdapterTest {
}
}
private TypedArray createFloatTypedArray(float[] vals) {
TypedArray mockArray = mock(TypedArray.class);
when(mockArray.length()).thenAnswer(invocation -> {
return vals.length;
});
when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> {
final float def = (float) invocation.getArguments()[1];
if (vals == null) {
return def;
}
int idx = (int) invocation.getArguments()[0];
if (idx >= 0 && idx < vals.length) {
return vals[idx];
} else {
return def;
}
});
return mockArray;
}
}

View File

@@ -64,7 +64,6 @@ public class AutomaticBrightnessControllerTest {
@Mock HysteresisLevels mAmbientBrightnessThresholds;
@Mock HysteresisLevels mScreenBrightnessThresholds;
@Mock Handler mNoOpHandler;
@Mock DisplayDeviceConfig mDisplayDeviceConfig;
@Mock DisplayDevice mDisplayDevice;
private static final int LIGHT_SENSOR_WARMUP_TIME = 0;

View File

@@ -88,7 +88,9 @@ public class BrightnessMappingStrategyTest {
};
private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
private static final int[] BACKLIGHT_RANGE = { 1, 255 };
private static final float[] DISPLAY_LEVELS_RANGE_NITS = { 13.25f, 478.5f };
private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f };
private static final float[] DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT = { 0.03149606299f, 1.0f };
private static final float[] EMPTY_FLOAT_ARRAY = new float[0];
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -114,25 +116,28 @@ public class BrightnessMappingStrategyTest {
};
private static final Spline GAMMA_CORRECTION_SPLINE = Spline.createSpline(
new float[] { 0.0f, 100.0f, 1000.0f, 2500.0f, 4000.0f, 4900.0f, 5000.0f },
new float[] { 0.035f, 0.035f, 0.221f, 0.523f, 0.797f, 0.980f, 1.0f });
new float[] { 0.0475f, 0.0475f, 0.2225f, 0.5140f, 0.8056f, 0.9805f, 1.0f });
@Test
public void testSimpleStrategyMappingAtControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel =
(float) DISPLAY_LEVELS_BACKLIGHT[i] / PowerManager.BRIGHTNESS_ON;
final float expectedLevel = MathUtils.map(PowerManager.BRIGHTNESS_OFF + 1,
PowerManager.BRIGHTNESS_ON, PowerManager.BRIGHTNESS_MIN,
PowerManager.BRIGHTNESS_MAX, DISPLAY_LEVELS_BACKLIGHT[i]);
assertEquals(expectedLevel,
simple.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
simple.getBrightness(LUX_LEVELS[i]), 0.0001f /*tolerance*/);
}
}
@Test
public void testSimpleStrategyMappingBetweenControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -146,66 +151,71 @@ public class BrightnessMappingStrategyTest {
@Test
public void testSimpleStrategyIgnoresNewConfiguration() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
final int N = LUX_LEVELS.length;
final float[] lux = { 0f, 1f };
final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
.build();
strategy.setBrightnessConfiguration(config);
assertNotEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
assertNotEquals(1.0f, strategy.getBrightness(1f), 0.0001f /*tolerance*/);
}
@Test
public void testSimpleStrategyIgnoresNullConfiguration() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
strategy.setBrightnessConfiguration(null);
final int N = DISPLAY_LEVELS_BACKLIGHT.length;
final float expectedBrightness =
(float) DISPLAY_LEVELS_BACKLIGHT[N - 1] / PowerManager.BRIGHTNESS_ON;
assertEquals(expectedBrightness,
strategy.getBrightness(LUX_LEVELS[N - 1]), 0.01 /*tolerance*/);
strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
}
@Test
public void testPhysicalStrategyMappingAtControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel = DISPLAY_LEVELS_NITS[i] / DISPLAY_RANGE_NITS[1];
final float expectedLevel = MathUtils.map(DISPLAY_RANGE_NITS[0], DISPLAY_RANGE_NITS[1],
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT[0],
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT[1],
DISPLAY_LEVELS_NITS[i]);
assertEquals(expectedLevel,
physical.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
physical.getBrightness(LUX_LEVELS[i]),
0.0001f /*tolerance*/);
}
}
@Test
public void testPhysicalStrategyMappingBetweenControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
Spline backlightToBrightness =
Spline.createSpline(toFloatArray(BACKLIGHT_RANGE), DISPLAY_RANGE_NITS);
Spline brightnessToNits =
Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
final float backlight = physical.getBrightness(lux) * PowerManager.BRIGHTNESS_ON;
final float nits = backlightToBrightness.interpolate(backlight);
assertTrue("Desired brightness should be between adjacent control points.",
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2.0f;
final float brightness = physical.getBrightness(lux);
final float nits = brightnessToNits.interpolate(brightness);
assertTrue("Desired brightness should be between adjacent control points: " + nits,
nits > DISPLAY_LEVELS_NITS[i - 1] && nits < DISPLAY_LEVELS_NITS[i]);
}
}
@Test
public void testPhysicalStrategyUsesNewConfigurations() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
final float[] lux = { 0f, 1f };
final float[] nits = {
@@ -216,46 +226,53 @@ public class BrightnessMappingStrategyTest {
BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
.build();
strategy.setBrightnessConfiguration(config);
assertEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
assertEquals(1.0f, strategy.getBrightness(1f), 0.0001f /*tolerance*/);
// Check that null returns us to the default configuration.
strategy.setBrightnessConfiguration(null);
final int N = DISPLAY_LEVELS_NITS.length;
final float expectedBrightness = DISPLAY_LEVELS_NITS[N - 1] / DISPLAY_RANGE_NITS[1];
assertEquals(expectedBrightness,
strategy.getBrightness(LUX_LEVELS[N - 1]), 0.01f /*tolerance*/);
strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
}
@Test
public void testPhysicalStrategyRecalculateSplines() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
BACKLIGHT_RANGE);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
float[] adjustedNits50p = new float[DISPLAY_RANGE_NITS.length];
for (int i = 0; i < DISPLAY_RANGE_NITS.length; i++) {
adjustedNits50p[i] = DISPLAY_RANGE_NITS[i] * 0.5f;
}
// Default is unadjusted
assertEquals(2.685f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
assertEquals(478.5f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[0], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]),
0.0001f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[1], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]),
0.0001f /* tolerance */);
// When adjustment is turned on, adjustment array is used
strategy.recalculateSplines(true, adjustedNits50p);
assertEquals(1.3425f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
assertEquals(239.25f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[0] / 2,
strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]), 0.0001f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[1] / 2,
strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]), 0.0001f /* tolerance */);
// When adjustment is turned off, adjustment array is ignored
strategy.recalculateSplines(false, adjustedNits50p);
assertEquals(2.685f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
assertEquals(478.5f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[0], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]),
0.0001f /* tolerance */);
assertEquals(DISPLAY_RANGE_NITS[1], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]),
0.0001f /* tolerance */);
}
@Test
public void testDefaultStrategyIsPhysical() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
}
@@ -266,15 +283,15 @@ public class BrightnessMappingStrategyTest {
int tmp = lux[idx];
lux[idx] = lux[idx+1];
lux[idx+1] = tmp;
Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
// And make sure we get the same result even if it's monotone but not increasing.
lux[idx] = lux[idx+1];
res = createResources(lux, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
strategy = BrightnessMappingStrategy.create(res);
res = createResources(lux, DISPLAY_LEVELS_NITS);
strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
}
@@ -285,13 +302,13 @@ public class BrightnessMappingStrategyTest {
// Make sure it's strictly increasing so that the only failure is the differing array
// lengths
lux[lux.length - 1] = lux[lux.length - 2] + 1;
Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
res = createResources(lux, DISPLAY_LEVELS_BACKLIGHT);
strategy = BrightnessMappingStrategy.create(res);
strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
// Extra backlight level
@@ -299,43 +316,45 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
res = createResources(LUX_LEVELS, backlight);
strategy = BrightnessMappingStrategy.create(res);
strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
// Extra nits level
final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
nits[nits.length - 1] = nits[nits.length - 2] + 1;
res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
strategy = BrightnessMappingStrategy.create(res);
res = createResources(LUX_LEVELS, nits);
strategy = BrightnessMappingStrategy.create(res, ddc);
assertNull(strategy);
}
@Test
public void testPhysicalStrategyRequiresNitsMapping() {
Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/, BACKLIGHT_RANGE);
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY /*nitsRange*/);
BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
assertNull(physical);
res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, EMPTY_INT_ARRAY /*backlightRange*/);
physical = BrightnessMappingStrategy.create(res);
DISPLAY_LEVELS_NITS);
physical = BrightnessMappingStrategy.create(res, ddc);
assertNull(physical);
res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/,
EMPTY_INT_ARRAY /*backlightRange*/);
physical = BrightnessMappingStrategy.create(res);
DISPLAY_LEVELS_NITS);
physical = BrightnessMappingStrategy.create(res, ddc);
assertNull(physical);
}
@Test
public void testStrategiesAdaptToUserDataPoint() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res));
Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res));
assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
}
private static void assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy strategy) {
@@ -351,7 +370,7 @@ public class BrightnessMappingStrategyTest {
// Then make sure that all control points after the middle lux level are also set to max...
for (int i = idx; i < LUX_LEVELS.length; i++) {
assertEquals(strategy.getBrightness(LUX_LEVELS[idx]), 1.0, 0.01 /*tolerance*/);
assertEquals(strategy.getBrightness(LUX_LEVELS[idx]), 1.0, 0.0001f /*tolerance*/);
}
// ...and that all control points before the middle lux level are strictly less than the
@@ -369,12 +388,12 @@ public class BrightnessMappingStrategyTest {
strategy.clearUserDataPoints();
for (int i = 0; i < LUX_LEVELS.length; i++) {
assertEquals(initialBrightnessLevels[i], strategy.getBrightness(LUX_LEVELS[i]),
0.01 /*tolerance*/);
0.0001f /*tolerance*/);
}
// Now set the middle of the lux range to something just above the minimum.
float minBrightness = strategy.getBrightness(LUX_LEVELS[0]);
strategy.addUserDataPoint(LUX_LEVELS[idx], minBrightness + 0.01f);
strategy.addUserDataPoint(LUX_LEVELS[idx], minBrightness + 0.0001f);
// Then make sure the curve is still monotonic.
prevBrightness = 0f;
@@ -389,31 +408,21 @@ public class BrightnessMappingStrategyTest {
// be true assuming that there are more than two lux levels in the curve since we picked a
// brightness just barely above the minimum for the middle of the curve.
minBrightness = (float) MathUtils.pow(minBrightness, MAXIMUM_GAMMA); // Gamma correction.
assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.01 /*tolerance*/);
}
private static float[] toFloatArray(int[] vals) {
float[] newVals = new float[vals.length];
for (int i = 0; i < vals.length; i++) {
newVals[i] = (float) vals[i];
}
return newVals;
assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.0001f /*tolerance*/);
}
private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight) {
return createResources(luxLevels, brightnessLevelsBacklight,
EMPTY_FLOAT_ARRAY /*brightnessLevelsNits*/, EMPTY_FLOAT_ARRAY /*nitsRange*/,
EMPTY_INT_ARRAY /*backlightRange*/);
EMPTY_FLOAT_ARRAY /*brightnessLevelsNits*/);
}
private Resources createResources(int[] luxLevels, float[] brightnessLevelsNits,
float[] nitsRange, int[] backlightRange) {
private Resources createResources(int[] luxLevels, float[] brightnessLevelsNits) {
return createResources(luxLevels, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
brightnessLevelsNits, nitsRange, backlightRange);
brightnessLevelsNits);
}
private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight,
float[] brightnessLevelsNits, float[] nitsRange, int[] backlightRange) {
float[] brightnessLevelsNits) {
Resources mockResources = mock(Resources.class);
// For historical reasons, the lux levels resource implicitly defines the first point as 0,
// so we need to chop it off of the array the mock resource object returns.
@@ -430,15 +439,6 @@ public class BrightnessMappingStrategyTest {
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
.thenReturn(mockBrightnessLevelNits);
TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
when(mockResources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits))
.thenReturn(mockNitsRange);
when(mockResources.getIntArray(
com.android.internal.R.array.config_screenBrightnessBacklight))
.thenReturn(backlightRange);
when(mockResources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum))
.thenReturn(1);
@@ -451,6 +451,21 @@ public class BrightnessMappingStrategyTest {
return mockResources;
}
private DisplayDeviceConfig createDdc() {
return createDdc(DISPLAY_RANGE_NITS);
}
private DisplayDeviceConfig createDdc(float[] nitsArray) {
return createDdc(nitsArray, DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT);
}
private DisplayDeviceConfig createDdc(float[] nitsArray, float[] backlightArray) {
DisplayDeviceConfig mockDdc = mock(DisplayDeviceConfig.class);
when(mockDdc.getNits()).thenReturn(nitsArray);
when(mockDdc.getBrightness()).thenReturn(backlightArray);
return mockDdc;
}
private TypedArray createFloatTypedArray(float[] vals) {
TypedArray mockArray = mock(TypedArray.class);
when(mockArray.length()).thenAnswer(invocation -> {
@@ -488,21 +503,22 @@ public class BrightnessMappingStrategyTest {
final float y1 = GAMMA_CORRECTION_SPLINE.interpolate(x1);
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
// Let's start with a validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.01f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(y3, strategy.getBrightness(x3), 0.01f /* tolerance */);
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(y3, strategy.getBrightness(x3), 0.0001f /* tolerance */);
// OK, let's roll:
float gamma = 0.5f;
strategy.addUserDataPoint(x2, (float) MathUtils.pow(y2, gamma));
assertEquals(MathUtils.pow(y1, gamma), strategy.getBrightness(x1), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y3, gamma), strategy.getBrightness(x3), 0.01f /* tolerance */);
// The adjustment should be +0.63 (manual calculation).
assertEquals(+0.63f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y1, gamma), strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y3, gamma), strategy.getBrightness(x3), 0.0001f /* tolerance */);
// The adjustment should be +0.6308 (manual calculation).
assertEquals(+0.6308f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
}
@Test
@@ -516,39 +532,39 @@ public class BrightnessMappingStrategyTest {
final float y1 = GAMMA_CORRECTION_SPLINE.interpolate(x1);
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
// Validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.01f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(y3, strategy.getBrightness(x3), 0.01f /* tolerance */);
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(y3, strategy.getBrightness(x3), 0.0001f /* tolerance */);
// Let's roll:
float gamma = 0.25f;
final float minGamma = 1.0f / MAXIMUM_GAMMA;
strategy.addUserDataPoint(x2, (float) MathUtils.pow(y2, gamma));
assertEquals(MathUtils.pow(y1, minGamma), strategy.getBrightness(x1),
0.01f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2),
0.01f /* tolerance */);
assertEquals(MathUtils.pow(y3, minGamma), strategy.getBrightness(x3),
0.01f /* tolerance */);
assertEquals(MathUtils.pow(y1, minGamma),
strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma),
strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y3, minGamma),
strategy.getBrightness(x3), 0.0001f /* tolerance */);
// The adjustment should be +1.0 (maximum adjustment).
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
}
@Test
public void testGammaCorrectionExtremeChangeAtCenter() {
// Extreme changes (e.g. setting brightness to 0.0 or 1.0) can't be gamma corrected, so we
// just make sure the adjustment reflects the change.
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
strategy.addUserDataPoint(2500, 1.0f);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
strategy.addUserDataPoint(2500, 0.0f);
assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
}
@Test
@@ -562,28 +578,28 @@ public class BrightnessMappingStrategyTest {
final float y0 = GAMMA_CORRECTION_SPLINE.interpolate(x0);
final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
final float y4 = GAMMA_CORRECTION_SPLINE.interpolate(x4);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
// Validity, as per tradition:
assertEquals(y0, strategy.getBrightness(x0), 0.01f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(y4, strategy.getBrightness(x4), 0.01f /* tolerance */);
assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(y4, strategy.getBrightness(x4), 0.0001f /* tolerance */);
// Rollin':
float adjustment = 0.3f;
float gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
strategy.addUserDataPoint(x0, y0 + adjustment);
assertEquals(y0 + adjustment, strategy.getBrightness(x0), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y4, gamma), strategy.getBrightness(x4), 0.01f /* tolerance */);
assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(y0 + adjustment, strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y4, gamma), strategy.getBrightness(x4), 0.0001f /* tolerance */);
assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
// Similarly, if we set a user data point at (x4, 1.0), the adjustment should be 1 - y4.
adjustment = 1.0f - y4;
gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
strategy.addUserDataPoint(x4, 1.0f);
assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
assertEquals(1.0f, strategy.getBrightness(x4), 0.01f /* tolerance */);
assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
assertEquals(1.0f, strategy.getBrightness(x4), 0.0001f /* tolerance */);
assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
}
}