diff options
9 files changed, 520 insertions, 38 deletions
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java index 12813c82bfff..47cde1517450 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 7a797dd2250c..7ccfb448cf61 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; * <allowInLowPowerMode>false</allowInLowPowerMode> * </highBrightnessMode> * + * <luxThrottling> + * <brightnessLimitMap> + * <type>default</type> + * <map> + * <point> + * <first>5000</first> + * <second>0.3</second> + * </point> + * <point> + * <first>5000</first> + * <second>0.3</second> + * </point> + * </map> + * </brightnessPeakMap> + * </luxThrottling> + * * <quirks> * <quirk>canSetBrightnessViaHwc</quirk> * </quirks> @@ -693,6 +713,9 @@ public class DisplayDeviceConfig { private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>> mRefreshRateThrottlingMap = new HashMap<>(); + private final Map<BrightnessLimitMapType, Map<Float, Float>> + mLuxThrottlingData = new HashMap<>(); + @Nullable private HostUsiVersion mHostUsiVersion; @@ -1344,6 +1367,11 @@ public class DisplayDeviceConfig { return hbmData; } + @NonNull + public Map<BrightnessLimitMapType, Map<Float, Float>> getLuxThrottlingData() { + return mLuxThrottlingData; + } + public List<RefreshRateLimitation> 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<BrightnessLimitMap> 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<Float, Float> luxToTransitionPointMap = new HashMap<>(); + + List<NonNegativeFloatToFloatPoint> 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 7d8bde9feabf..80114ccd6568 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 040ceccbc7c9..c8b0a724ffed 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 91e4a9e407db..dbabc2441224 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<Float, Float> mTransitionPoints = new HashMap<>(); + @NonNull + private Map<BrightnessLimitMapType, Map<Float, Float>> 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<Float, Float> 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<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessLimits) { + mMaxBrightnessLimits = maxBrightnessLimits; + return recalculateMaxBrightness(); + } + + private boolean recalculateMaxBrightness() { + float foundAmbientBoundary = Float.MAX_VALUE; + float foundMaxBrightness = PowerManager.BRIGHTNESS_MAX; + + Map<Float, Float> maxBrightnessPoints = null; + + if (mAutoBrightnessEnabled) { + maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.ADAPTIVE); + } + + if (maxBrightnessPoints == null) { + maxBrightnessPoints = mMaxBrightnessLimits.get(BrightnessLimitMapType.DEFAULT); + } + + if (maxBrightnessPoints != null) { + for (Map.Entry<Float, Float> 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 f96ca582c28f..7104a80c668d 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 @@ <xs:annotation name="nonnull"/> <xs:annotation name="final"/> </xs:element> + <xs:element type="luxThrottling" name="luxThrottling" minOccurs="0" + maxOccurs="1"/> <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" maxOccurs="1"/> <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1"/> @@ -137,6 +139,39 @@ </xs:sequence> </xs:complexType> + <xs:complexType name="luxThrottling"> + <xs:sequence> + <xs:element name="brightnessLimitMap" type="brightnessLimitMap" + maxOccurs="unbounded"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="brightnessLimitMap"> + <xs:sequence> + <xs:element name="type" type="PredefinedBrightnessLimitNames"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <!-- lux level from light sensor to screen brightness recommended max value map. + Screen brightness recommended max value is to highBrightnessMode.transitionPoint and must be below that --> + <xs:element name="map" type="nonNegativeFloatToFloatMap"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <!-- Predefined type names as defined by DisplayDeviceConfig.BrightnessLimitMapType --> + <xs:simpleType name="PredefinedBrightnessLimitNames"> + <xs:restriction base="xs:string"> + <xs:enumeration value="default"/> + <xs:enumeration value="adaptive"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="highBrightnessMode"> <xs:all> <xs:element name="transitionPoint" type="nonNegativeDecimal" minOccurs="1" @@ -575,4 +610,27 @@ <xs:annotation name="final"/> </xs:element> </xs:complexType> + + <!-- generic types --> + <xs:complexType name="nonNegativeFloatToFloatPoint"> + <xs:sequence> + <xs:element name="first" type="nonNegativeDecimal"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="second" type="nonNegativeDecimal"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="nonNegativeFloatToFloatMap"> + <xs:sequence> + <xs:element name="point" type="nonNegativeFloatToFloatPoint" maxOccurs="unbounded"> + <xs:annotation name="nonnull"/> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> </xs:schema> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index ad6434e0c545..507c9dccda59 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<com.android.server.display.config.DisplayBrightnessPoint> 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<java.math.BigInteger> getItem(); } + public class LuxThrottling { + ctor public LuxThrottling(); + method @NonNull public final java.util.List<com.android.server.display.config.BrightnessLimitMap> 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<com.android.server.display.config.NonNegativeFloatToFloatPoint> 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 5837b21b89fd..708421d2a431 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<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData = + mDisplayDeviceConfig.getLuxThrottlingData(); + assertEquals(2, luxThrottlingData.size()); + + Map<Float, Float> 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<Float, Float> 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<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData = + mDisplayDeviceConfig.getLuxThrottlingData(); + assertEquals(1, luxThrottlingData.size()); + + Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get( + DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE); + assertEquals(1, adaptiveOnBrightnessPoints.size()); + assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA); + } + + private String getValidLuxThrottling() { + return "<luxThrottling>\n" + + " <brightnessLimitMap>\n" + + " <type>adaptive</type>\n" + + " <map>\n" + + " <point>" + + " <first>1000</first>\n" + + " <second>0.3</second>\n" + + " </point>" + + " <point>" + + " <first>5000</first>\n" + + " <second>0.5</second>\n" + + " </point>" + + " </map>\n" + + " </brightnessLimitMap>\n" + + " <brightnessLimitMap>\n" + + " <type>default</type>\n" + + " <map>\n" + + " <point>" + + " <first>1500</first>\n" + + " <second>0.35</second>\n" + + " </point>" + + " <point>" + + " <first>5500</first>\n" + + " <second>0.55</second>\n" + + " </point>" + + " </map>\n" + + " </brightnessLimitMap>\n" + + "</luxThrottling>"; + } + + private String getInvalidLuxThrottling() { + return "<luxThrottling>\n" + + " <brightnessLimitMap>\n" + + " <type>adaptive</type>\n" + + " <map>\n" + + " <point>" + + " <first>1000</first>\n" + + " <second>0.3</second>\n" + + " </point>" + + " <point>" // second > hbm.transitionPoint, skipped + + " <first>1500</first>\n" + + " <second>0.9</second>\n" + + " </point>" + + " <point>" // same lux value, skipped + + " <first>1000</first>\n" + + " <second>0.5</second>\n" + + " </point>" + + " </map>\n" + + " </brightnessLimitMap>\n" + + " <brightnessLimitMap>\n" // Same type, skipped + + " <type>adaptive</type>\n" + + " <map>\n" + + " <point>" + + " <first>2000</first>\n" + + " <second>0.35</second>\n" + + " </point>" + + " <point>" + + " <first>6000</first>\n" + + " <second>0.55</second>\n" + + " </point>" + + " </map>\n" + + " </brightnessLimitMap>\n" + + " <brightnessLimitMap>\n" // Invalid points only, skipped + + " <type>default</type>\n" + + " <map>\n" + + " <point>" + + " <first>2500</first>\n" + + " <second>0.99</second>\n" + + " </point>" + + " </map>\n" + + " </brightnessLimitMap>\n" + + "</luxThrottling>"; + } + private String getRefreshThermalThrottlingMaps() { return "<refreshRateThrottlingMap>\n" + " <refreshRateThrottlingPoint>\n" @@ -405,6 +516,10 @@ public final class DisplayDeviceConfigTest { } private String getContent() { + return getContent(getValidLuxThrottling()); + } + + private String getContent(String brightnessCapConfig) { return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<displayConfiguration>\n" + "<name>Example Display</name>" @@ -462,6 +577,7 @@ public final class DisplayDeviceConfigTest { + "</point>\n" + "</sdrHdrRatioMap>\n" + "</highBrightnessMode>\n" + + brightnessCapConfig + "<screenOffBrightnessSensor>\n" + "<type>sensor_12345</type>\n" + "<name>Sensor 12345</name>\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 000000000000..c379d6b79ee7 --- /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<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessConfig, + float expectedBrightness) { + setupController(ambientLux, autoBrightnessState, maxBrightnessConfig); + + assertEquals(expectedBrightness, mController.getCurrentBrightnessMax(), FLOAT_TOLERANCE); + } + + private void setupController(float ambientLux, int autoBrightnessState, + Map<BrightnessLimitMapType, Map<Float, Float>> maxBrightnessConfig) { + mController.onAmbientLuxChange(ambientLux); + mController.setAutoBrightnessState(autoBrightnessState); + mController.resetNbmData(maxBrightnessConfig); + } +} |