diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java index 12813c82bfff5..47cde15174509 100644 --- a/services/core/java/com/android/server/display/BrightnessRangeController.java +++ b/services/core/java/com/android/server/display/BrightnessRangeController.java @@ -20,6 +20,7 @@ import android.hardware.display.BrightnessInfo; import android.os.IBinder; import java.io.PrintWriter; +import java.util.function.BooleanSupplier; class BrightnessRangeController { @@ -43,20 +44,10 @@ class BrightnessRangeController { } void onAmbientLuxChange(float ambientLux) { - if (NBM_FEATURE_FLAG) { - boolean nbmTransitionChanged = mNormalBrightnessModeController.onAmbientLuxChange( - ambientLux); - int previousHbm = mHbmController.getHighBrightnessMode(); - mHbmController.onAmbientLuxChange(ambientLux); - int nextHbm = mHbmController.getHighBrightnessMode(); - // if hbm changed - callback was triggered in mHbmController.onAmbientLuxChange - // if nbm transition not changed - no need to trigger callback - if (previousHbm == nextHbm && nbmTransitionChanged) { - mModeChangeCallback.run(); - } - } else { - mHbmController.onAmbientLuxChange(ambientLux); - } + applyChanges( + () -> mNormalBrightnessModeController.onAmbientLuxChange(ambientLux), + () -> mHbmController.onAmbientLuxChange(ambientLux) + ); } float getNormalBrightnessMax() { @@ -65,10 +56,16 @@ class BrightnessRangeController { void loadFromConfig(HighBrightnessModeMetadata hbmMetadata, IBinder token, DisplayDeviceInfo info, DisplayDeviceConfig displayDeviceConfig) { - mHbmController.setHighBrightnessModeMetadata(hbmMetadata); - mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, - displayDeviceConfig.getHighBrightnessModeData(), - displayDeviceConfig::getHdrBrightnessFromSdr); + applyChanges( + () -> mNormalBrightnessModeController.resetNbmData( + displayDeviceConfig.getLuxThrottlingData()), + () -> { + mHbmController.setHighBrightnessModeMetadata(hbmMetadata); + mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, + displayDeviceConfig.getHighBrightnessModeData(), + displayDeviceConfig::getHdrBrightnessFromSdr); + } + ); } void stop() { @@ -76,7 +73,10 @@ class BrightnessRangeController { } void setAutoBrightnessEnabled(int state) { - mHbmController.setAutoBrightnessEnabled(state); + applyChanges( + () -> mNormalBrightnessModeController.setAutoBrightnessState(state), + () -> mHbmController.setAutoBrightnessEnabled(state) + ); } void onBrightnessChanged(float brightness, float unthrottledBrightness, @@ -109,4 +109,18 @@ class BrightnessRangeController { float getTransitionPoint() { return mHbmController.getTransitionPoint(); } + + private void applyChanges(BooleanSupplier nbmChangesFunc, Runnable hbmChangesFunc) { + if (NBM_FEATURE_FLAG) { + boolean nbmTransitionChanged = nbmChangesFunc.getAsBoolean(); + hbmChangesFunc.run(); + // if nbm transition changed - trigger callback + // HighBrightnessModeController handles sending changes itself + if (nbmTransitionChanged) { + mModeChangeCallback.run(); + } + } else { + hbmChangesFunc.run(); + } + } } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 7a797dd2250ce..7ccfb448cf613 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -41,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.AutoBrightness; import com.android.server.display.config.BlockingZoneConfig; +import com.android.server.display.config.BrightnessLimitMap; import com.android.server.display.config.BrightnessThresholds; import com.android.server.display.config.BrightnessThrottlingMap; import com.android.server.display.config.BrightnessThrottlingPoint; @@ -51,8 +52,11 @@ import com.android.server.display.config.DisplayQuirks; import com.android.server.display.config.HbmTiming; import com.android.server.display.config.HighBrightnessMode; import com.android.server.display.config.IntegerArray; +import com.android.server.display.config.LuxThrottling; import com.android.server.display.config.NitsMap; +import com.android.server.display.config.NonNegativeFloatToFloatPoint; import com.android.server.display.config.Point; +import com.android.server.display.config.PredefinedBrightnessLimitNames; import com.android.server.display.config.RefreshRateConfigs; import com.android.server.display.config.RefreshRateRange; import com.android.server.display.config.RefreshRateThrottlingMap; @@ -219,6 +223,22 @@ import javax.xml.datatype.DatatypeConfigurationException; * false * * + * + * + * default + * + * + * 5000 + * 0.3 + * + * + * 5000 + * 0.3 + * + * + * + * + * * * canSetBrightnessViaHwc * @@ -693,6 +713,9 @@ public class DisplayDeviceConfig { private final Map> mRefreshRateThrottlingMap = new HashMap<>(); + private final Map> + mLuxThrottlingData = new HashMap<>(); + @Nullable private HostUsiVersion mHostUsiVersion; @@ -1344,6 +1367,11 @@ public class DisplayDeviceConfig { return hbmData; } + @NonNull + public Map> getLuxThrottlingData() { + return mLuxThrottlingData; + } + public List getRefreshRateLimitations() { return mRefreshRateLimitations; } @@ -1530,6 +1558,7 @@ public class DisplayDeviceConfig { + ", mBrightnessDefault=" + mBrightnessDefault + ", mQuirks=" + mQuirks + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled + + ", mLuxThrottlingData=" + mLuxThrottlingData + ", mHbmData=" + mHbmData + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline + ", mThermalBrightnessThrottlingDataMapByThrottlingId=" @@ -1676,6 +1705,7 @@ public class DisplayDeviceConfig { loadBrightnessMap(config); loadThermalThrottlingConfig(config); loadHighBrightnessModeData(config); + loadLuxThrottling(config); loadQuirks(config); loadBrightnessRamps(config); loadAmbientLightSensorFromDdc(config); @@ -2428,6 +2458,54 @@ public class DisplayDeviceConfig { } } + private void loadLuxThrottling(DisplayConfiguration config) { + LuxThrottling cfg = config.getLuxThrottling(); + if (cfg != null) { + HighBrightnessMode hbm = config.getHighBrightnessMode(); + float hbmTransitionPoint = hbm != null ? hbm.getTransitionPoint_all().floatValue() + : PowerManager.BRIGHTNESS_MAX; + List limitMaps = cfg.getBrightnessLimitMap(); + for (BrightnessLimitMap map : limitMaps) { + PredefinedBrightnessLimitNames type = map.getType(); + BrightnessLimitMapType mappedType = BrightnessLimitMapType.convert(type); + if (mappedType == null) { + Slog.wtf(TAG, "Invalid NBM config: unsupported map type=" + type); + continue; + } + if (mLuxThrottlingData.containsKey(mappedType)) { + Slog.wtf(TAG, "Invalid NBM config: duplicate map type=" + mappedType); + continue; + } + Map luxToTransitionPointMap = new HashMap<>(); + + List points = map.getMap().getPoint(); + for (NonNegativeFloatToFloatPoint point : points) { + float lux = point.getFirst().floatValue(); + float maxBrightness = point.getSecond().floatValue(); + if (maxBrightness > hbmTransitionPoint) { + Slog.wtf(TAG, + "Invalid NBM config: maxBrightness is greater than hbm" + + ".transitionPoint. type=" + + type + "; lux=" + lux + "; maxBrightness=" + + maxBrightness); + continue; + } + if (luxToTransitionPointMap.containsKey(lux)) { + Slog.wtf(TAG, + "Invalid NBM config: duplicate lux key. type=" + type + "; lux=" + + lux); + continue; + } + luxToTransitionPointMap.put(lux, + mBacklightToBrightnessSpline.interpolate(maxBrightness)); + } + if (!luxToTransitionPointMap.isEmpty()) { + mLuxThrottlingData.put(mappedType, luxToTransitionPointMap); + } + } + } + } + private void loadBrightnessRamps(DisplayConfiguration config) { // Priority 1: Value in the display device config (float) // Priority 2: Value in the config.xml (int) @@ -3155,4 +3233,19 @@ public class DisplayDeviceConfig { } } } + + public enum BrightnessLimitMapType { + DEFAULT, ADAPTIVE; + + @Nullable + private static BrightnessLimitMapType convert(PredefinedBrightnessLimitNames type) { + switch (type) { + case _default: + return DEFAULT; + case adaptive: + return ADAPTIVE; + } + return null; + } + } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 2b5523ae52b0c..f6e074f41743a 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -2141,7 +2141,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } void postBrightnessChangeRunnable() { - mHandler.post(mOnBrightnessChangeRunnable); + if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) { + mHandler.post(mOnBrightnessChangeRunnable); + } } private HighBrightnessModeController createHbmControllerLocked( diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index cc9f5394df9be..2e8c3420c3175 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -1788,7 +1788,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } void postBrightnessChangeRunnable() { - mHandler.post(mOnBrightnessChangeRunnable); + if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) { + mHandler.post(mOnBrightnessChangeRunnable); + } } private HighBrightnessModeController createHbmControllerLocked( diff --git a/services/core/java/com/android/server/display/NormalBrightnessModeController.java b/services/core/java/com/android/server/display/NormalBrightnessModeController.java index 91e4a9e407db1..dbabc24412242 100644 --- a/services/core/java/com/android/server/display/NormalBrightnessModeController.java +++ b/services/core/java/com/android/server/display/NormalBrightnessModeController.java @@ -16,36 +16,79 @@ package com.android.server.display; +import android.annotation.NonNull; import android.os.PowerManager; +import com.android.server.display.DisplayDeviceConfig.BrightnessLimitMapType; + import java.util.HashMap; import java.util.Map; +/** + * Limits brightness for normal-brightness mode, based on ambient lux + **/ class NormalBrightnessModeController { - private Map mTransitionPoints = new HashMap<>(); + @NonNull + private Map> mMaxBrightnessLimits = new HashMap<>(); + private float mAmbientLux = Float.MAX_VALUE; + private boolean mAutoBrightnessEnabled = false; // brightness limit in normal brightness mode, based on ambient lux. - private float mVirtualTransitionPoint = PowerManager.BRIGHTNESS_MAX; + private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX; boolean onAmbientLuxChange(float ambientLux) { - float currentAmbientBoundary = Float.MAX_VALUE; - float currentTransitionPoint = PowerManager.BRIGHTNESS_MAX; - for (Map.Entry transitionPoint: mTransitionPoints.entrySet()) { - float ambientBoundary = transitionPoint.getKey(); - // find ambient lux upper boundary closest to current ambient lux - if (ambientBoundary > ambientLux && ambientBoundary < currentAmbientBoundary) { - currentTransitionPoint = transitionPoint.getValue(); - currentAmbientBoundary = ambientBoundary; - } - } - if (mVirtualTransitionPoint != currentTransitionPoint) { - mVirtualTransitionPoint = currentTransitionPoint; - return true; + mAmbientLux = ambientLux; + return recalculateMaxBrightness(); + } + + boolean setAutoBrightnessState(int state) { + boolean isEnabled = state == AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED; + if (isEnabled != mAutoBrightnessEnabled) { + mAutoBrightnessEnabled = isEnabled; + return recalculateMaxBrightness(); } return false; } float getCurrentBrightnessMax() { - return mVirtualTransitionPoint; + return mMaxBrightness; + } + + boolean resetNbmData( + @NonNull Map> maxBrightnessLimits) { + mMaxBrightnessLimits = maxBrightnessLimits; + return recalculateMaxBrightness(); + } + + private boolean recalculateMaxBrightness() { + float foundAmbientBoundary = Float.MAX_VALUE; + float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; + + Map maxBrightnessPoints = null; + + if (mAutoBrightnessEnabled) { + maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.ADAPTIVE); + } + + if (maxBrightnessPoints == null) { + maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.DEFAULT); + } + + if (maxBrightnessPoints != null) { + for (Map.Entry brightnessPoint : maxBrightnessPoints.entrySet()) { + float ambientBoundary = brightnessPoint.getKey(); + // find ambient lux upper boundary closest to current ambient lux + if (ambientBoundary > mAmbientLux && ambientBoundary < foundAmbientBoundary) { + foundMaxBrightness = brightnessPoint.getValue(); + foundAmbientBoundary = ambientBoundary; + } + } + } + + if (mMaxBrightness != foundMaxBrightness) { + mMaxBrightness = foundMaxBrightness; + return true; + } + return false; } } diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index f96ca582c28f3..7104a80c668d1 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -46,6 +46,8 @@ + @@ -137,6 +139,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index ad6434e0c545e..507c9dccda59b 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -26,6 +26,14 @@ package com.android.server.display.config { method public final java.util.List getDisplayBrightnessPoint(); } + public class BrightnessLimitMap { + ctor public BrightnessLimitMap(); + method @NonNull public final com.android.server.display.config.NonNegativeFloatToFloatMap getMap(); + method @NonNull public final com.android.server.display.config.PredefinedBrightnessLimitNames getType(); + method public final void setMap(@NonNull com.android.server.display.config.NonNegativeFloatToFloatMap); + method public final void setType(@NonNull com.android.server.display.config.PredefinedBrightnessLimitNames); + } + public class BrightnessThresholds { ctor public BrightnessThresholds(); method public final com.android.server.display.config.ThresholdPoints getBrightnessThresholdPoints(); @@ -89,6 +97,7 @@ package com.android.server.display.config { method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle(); method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode(); method public final com.android.server.display.config.SensorDetails getLightSensor(); + method public com.android.server.display.config.LuxThrottling getLuxThrottling(); method @Nullable public final String getName(); method public final com.android.server.display.config.SensorDetails getProxSensor(); method public com.android.server.display.config.DisplayQuirks getQuirks(); @@ -115,6 +124,7 @@ package com.android.server.display.config { method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds); method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode); method public final void setLightSensor(com.android.server.display.config.SensorDetails); + method public void setLuxThrottling(com.android.server.display.config.LuxThrottling); method public final void setName(@Nullable String); method public final void setProxSensor(com.android.server.display.config.SensorDetails); method public void setQuirks(com.android.server.display.config.DisplayQuirks); @@ -173,6 +183,11 @@ package com.android.server.display.config { method public java.util.List getItem(); } + public class LuxThrottling { + ctor public LuxThrottling(); + method @NonNull public final java.util.List getBrightnessLimitMap(); + } + public class NitsMap { ctor public NitsMap(); method public String getInterpolation(); @@ -180,6 +195,19 @@ package com.android.server.display.config { method public void setInterpolation(String); } + public class NonNegativeFloatToFloatMap { + ctor public NonNegativeFloatToFloatMap(); + method @NonNull public final java.util.List getPoint(); + } + + public class NonNegativeFloatToFloatPoint { + ctor public NonNegativeFloatToFloatPoint(); + method @NonNull public final java.math.BigDecimal getFirst(); + method @NonNull public final java.math.BigDecimal getSecond(); + method public final void setFirst(@NonNull java.math.BigDecimal); + method public final void setSecond(@NonNull java.math.BigDecimal); + } + public class Point { ctor public Point(); method @NonNull public final java.math.BigDecimal getNits(); @@ -188,6 +216,12 @@ package com.android.server.display.config { method public final void setValue(@NonNull java.math.BigDecimal); } + public enum PredefinedBrightnessLimitNames { + method public String getRawName(); + enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames _default; + enum_constant public static final com.android.server.display.config.PredefinedBrightnessLimitNames adaptive; + } + public class RefreshRateConfigs { ctor public RefreshRateConfigs(); method public final java.math.BigInteger getDefaultPeakRefreshRate(); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index 5837b21b89fd4..708421d2a431b 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -52,6 +52,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; @SmallTest @RunWith(AndroidJUnit4.class) @@ -376,6 +377,116 @@ public final class DisplayDeviceConfigTest { assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA); } + @Test + public void testValidLuxThrottling() throws Exception { + setupDisplayDeviceConfigFromDisplayConfigFile(); + + Map> luxThrottlingData = + mDisplayDeviceConfig.getLuxThrottlingData(); + assertEquals(2, luxThrottlingData.size()); + + Map adaptiveOnBrightnessPoints = luxThrottlingData.get( + DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE); + assertEquals(2, adaptiveOnBrightnessPoints.size()); + assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA); + assertEquals(0.5f, adaptiveOnBrightnessPoints.get(5000f), SMALL_DELTA); + + Map adaptiveOffBrightnessPoints = luxThrottlingData.get( + DisplayDeviceConfig.BrightnessLimitMapType.DEFAULT); + assertEquals(2, adaptiveOffBrightnessPoints.size()); + assertEquals(0.35f, adaptiveOffBrightnessPoints.get(1500f), SMALL_DELTA); + assertEquals(0.55f, adaptiveOffBrightnessPoints.get(5500f), SMALL_DELTA); + } + + @Test + public void testInvalidLuxThrottling() throws Exception { + setupDisplayDeviceConfigFromDisplayConfigFile(getContent(getInvalidLuxThrottling())); + + Map> luxThrottlingData = + mDisplayDeviceConfig.getLuxThrottlingData(); + assertEquals(1, luxThrottlingData.size()); + + Map adaptiveOnBrightnessPoints = luxThrottlingData.get( + DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE); + assertEquals(1, adaptiveOnBrightnessPoints.size()); + assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA); + } + + private String getValidLuxThrottling() { + return "\n" + + " \n" + + " adaptive\n" + + " \n" + + " " + + " 1000\n" + + " 0.3\n" + + " " + + " " + + " 5000\n" + + " 0.5\n" + + " " + + " \n" + + " \n" + + " \n" + + " default\n" + + " \n" + + " " + + " 1500\n" + + " 0.35\n" + + " " + + " " + + " 5500\n" + + " 0.55\n" + + " " + + " \n" + + " \n" + + ""; + } + + private String getInvalidLuxThrottling() { + return "\n" + + " \n" + + " adaptive\n" + + " \n" + + " " + + " 1000\n" + + " 0.3\n" + + " " + + " " // second > hbm.transitionPoint, skipped + + " 1500\n" + + " 0.9\n" + + " " + + " " // same lux value, skipped + + " 1000\n" + + " 0.5\n" + + " " + + " \n" + + " \n" + + " \n" // Same type, skipped + + " adaptive\n" + + " \n" + + " " + + " 2000\n" + + " 0.35\n" + + " " + + " " + + " 6000\n" + + " 0.55\n" + + " " + + " \n" + + " \n" + + " \n" // Invalid points only, skipped + + " default\n" + + " \n" + + " " + + " 2500\n" + + " 0.99\n" + + " " + + " \n" + + " \n" + + ""; + } + private String getRefreshThermalThrottlingMaps() { return "\n" + " \n" @@ -405,6 +516,10 @@ public final class DisplayDeviceConfigTest { } private String getContent() { + return getContent(getValidLuxThrottling()); + } + + private String getContent(String brightnessCapConfig) { return "\n" + "\n" + "Example Display" @@ -462,6 +577,7 @@ public final class DisplayDeviceConfigTest { + "\n" + "\n" + "\n" + + brightnessCapConfig + "\n" + "sensor_12345\n" + "Sensor 12345\n" @@ -731,8 +847,12 @@ public final class DisplayDeviceConfigTest { } private void setupDisplayDeviceConfigFromDisplayConfigFile() throws IOException { + setupDisplayDeviceConfigFromDisplayConfigFile(getContent()); + } + + private void setupDisplayDeviceConfigFromDisplayConfigFile(String content) throws IOException { Path tempFile = Files.createTempFile("display_config", ".tmp"); - Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8)); + Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8)); mDisplayDeviceConfig = new DisplayDeviceConfig(mContext); mDisplayDeviceConfig.initFromFile(tempFile.toFile()); } diff --git a/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java new file mode 100644 index 0000000000000..c379d6b79ee78 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static org.junit.Assert.assertEquals; + +import android.os.PowerManager; + +import androidx.test.filters.SmallTest; + +import com.android.internal.annotations.Keep; +import com.android.server.display.DisplayDeviceConfig.BrightnessLimitMapType; + +import com.google.common.collect.ImmutableMap; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.HashMap; +import java.util.Map; + +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +@SmallTest +@RunWith(JUnitParamsRunner.class) +public class NormalBrightnessModeControllerTest { + private static final float FLOAT_TOLERANCE = 0.001f; + + private final NormalBrightnessModeController mController = new NormalBrightnessModeController(); + + @Keep + private static Object[][] brightnessData() { + return new Object[][]{ + // no brightness config + {0, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, new HashMap<>(), + PowerManager.BRIGHTNESS_MAX}, + {0, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, new HashMap<>(), + PowerManager.BRIGHTNESS_MAX}, + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, new HashMap<>(), + PowerManager.BRIGHTNESS_MAX}, + // Auto brightness - on, config only for default + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of( + BrightnessLimitMapType.DEFAULT, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f) + ), 0.2f}, + // Auto brightness - off, config only for default + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of( + BrightnessLimitMapType.DEFAULT, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f) + ), 0.2f}, + // Auto brightness - off, config only for adaptive + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of( + BrightnessLimitMapType.ADAPTIVE, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f) + ), PowerManager.BRIGHTNESS_MAX}, + // Auto brightness - on, config only for adaptive + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of( + BrightnessLimitMapType.ADAPTIVE, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f) + ), 0.2f}, + // Auto brightness - on, config for both + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of( + BrightnessLimitMapType.DEFAULT, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f), + BrightnessLimitMapType.ADAPTIVE, + ImmutableMap.of(99f, 0.3f, 101f, 0.4f) + ), 0.4f}, + // Auto brightness - off, config for both + {100, AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, ImmutableMap.of( + BrightnessLimitMapType.DEFAULT, + ImmutableMap.of(99f, 0.1f, 101f, 0.2f), + BrightnessLimitMapType.ADAPTIVE, + ImmutableMap.of(99f, 0.3f, 101f, 0.4f) + ), 0.2f}, + // Auto brightness - on, config for both, ambient high + {1000, AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, ImmutableMap.of( + BrightnessLimitMapType.DEFAULT, + ImmutableMap.of(1000f, 0.1f, 2000f, 0.2f), + BrightnessLimitMapType.ADAPTIVE, + ImmutableMap.of(99f, 0.3f, 101f, 0.4f) + ), PowerManager.BRIGHTNESS_MAX}, + }; + } + + @Test + @Parameters(method = "brightnessData") + public void testReturnsCorrectMaxBrightness(float ambientLux, int autoBrightnessState, + Map> maxBrightnessConfig, + float expectedBrightness) { + setupController(ambientLux, autoBrightnessState, maxBrightnessConfig); + + assertEquals(expectedBrightness, mController.getCurrentBrightnessMax(), FLOAT_TOLERANCE); + } + + private void setupController(float ambientLux, int autoBrightnessState, + Map> maxBrightnessConfig) { + mController.onAmbientLuxChange(ambientLux); + mController.setAutoBrightnessState(autoBrightnessState); + mController.resetNbmData(maxBrightnessConfig); + } +}