From 9764e3ab72cacc536a1f64c5d5e84908276aa6ea Mon Sep 17 00:00:00 2001 From: Fiona Campbell Date: Tue, 19 Jan 2021 16:47:54 +0000 Subject: [PATCH] Change BrightnessMappingStrategy to use DDC values Use brightness min and max values from display device config. Use brightness nits and backlight ranges from display device config Convert the nits to backlight splines to only use the valid range considering the min and max values given in the ddc. Backlight refers to the values handled by the HAL. Brightness refers to the values used and stored in the system. Bug: 151620088 Bug: 174757872 Bug: 171380847 Test: LocalDisplayAdapterTest, AutomaticBrightessControllerTest, BrightnessMappingStrategyTest Change-Id: I6907f11cdf4e62ec9e6ed4304d11fe7686f5c8b6 --- .../brightness/BrightnessController.java | 14 +- .../display/BrightnessMappingStrategy.java | 114 ++++--- .../server/display/DisplayDeviceConfig.java | 232 +++++++++++--- .../display/DisplayPowerController.java | 60 ++-- .../server/display/LocalDisplayAdapter.java | 87 +----- .../display/LocalDisplayAdapterTest.java | 46 ++- .../AutomaticBrightnessControllerTest.java | 1 - .../BrightnessMappingStrategyTest.java | 288 +++++++++--------- 8 files changed, 483 insertions(+), 359 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java index 0bfc8e5d554b9..fea521f15b849 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java @@ -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, diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index a62f67a743adf..30cbf27456387 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -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 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 curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux, + Pair 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 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) { diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 49328f1019c3f..0071b2f558c4b 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -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 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 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; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 62cf86b311807..2005a742c3d3f 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -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); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index a4e2c7001b275..37125c420bd7f 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -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) { @@ -649,13 +620,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; } } @@ -790,8 +759,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)); @@ -800,35 +769,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); } }; } @@ -1317,11 +1259,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); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index d6d1c466c92f8..70bb814290d72 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -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 @@ -561,13 +580,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); } @@ -580,7 +599,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); } @@ -593,7 +612,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()); @@ -796,4 +815,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; + } } diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index 23a4c2f417c5b..54825ee2745a6 100644 --- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -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; diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java index f0b4f1bec77b9..285806b5dcd70 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java @@ -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 */); } }