diff options
13 files changed, 764 insertions, 121 deletions
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 75709fbb365a..d647757442e0 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -223,11 +223,11 @@ public class AutomaticBrightnessController { private final ShortTermModel mShortTermModel; private final ShortTermModel mPausedShortTermModel; - // Controls High Brightness Mode. - private HighBrightnessModeController mHbmController; + // Controls Brightness range (including High Brightness Mode). + private final BrightnessRangeController mBrightnessRangeController; // Throttles (caps) maximum allowed brightness - private BrightnessThrottler mBrightnessThrottler; + private final BrightnessThrottler mBrightnessThrottler; private boolean mIsBrightnessThrottled; // Context-sensitive brightness configurations require keeping track of the foreground app's @@ -257,7 +257,8 @@ public class AutomaticBrightnessController { HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler, + BrightnessRangeController brightnessModeController, + BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userBrightness) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, @@ -267,7 +268,7 @@ public class AutomaticBrightnessController { darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, screenBrightnessThresholds, ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, context, - hbmController, brightnessThrottler, idleModeBrightnessMapper, + brightnessModeController, brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort, ambientLightHorizonLong, userLux, userBrightness ); } @@ -283,7 +284,8 @@ public class AutomaticBrightnessController { HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler, + BrightnessRangeController brightnessModeController, + BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userBrightness) { mInjector = injector; @@ -326,7 +328,7 @@ public class AutomaticBrightnessController { mPendingForegroundAppPackageName = null; mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; - mHbmController = hbmController; + mBrightnessRangeController = brightnessModeController; mBrightnessThrottler = brightnessThrottler; mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper; mIdleModeBrightnessMapper = idleModeBrightnessMapper; @@ -607,10 +609,11 @@ public class AutomaticBrightnessController { pw.println(); pw.println(" mInteractiveMapper="); - mInteractiveModeBrightnessMapper.dump(pw, mHbmController.getNormalBrightnessMax()); + mInteractiveModeBrightnessMapper.dump(pw, + mBrightnessRangeController.getNormalBrightnessMax()); if (mIdleModeBrightnessMapper != null) { pw.println(" mIdleMapper="); - mIdleModeBrightnessMapper.dump(pw, mHbmController.getNormalBrightnessMax()); + mIdleModeBrightnessMapper.dump(pw, mBrightnessRangeController.getNormalBrightnessMax()); } pw.println(); @@ -736,7 +739,7 @@ public class AutomaticBrightnessController { mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux); } - mHbmController.onAmbientLuxChange(mAmbientLux); + mBrightnessRangeController.onAmbientLuxChange(mAmbientLux); // If the short term model was invalidated and the change is drastic enough, reset it. @@ -976,9 +979,9 @@ public class AutomaticBrightnessController { // Clamps values with float range [0.0-1.0] private float clampScreenBrightness(float value) { - final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(), + final float minBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMin(), mBrightnessThrottler.getBrightnessCap()); - final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(), + final float maxBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), mBrightnessThrottler.getBrightnessCap()); return MathUtils.constrain(value, minBrightness, maxBrightness); } diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java new file mode 100644 index 000000000000..47cde1517450 --- /dev/null +++ b/services/core/java/com/android/server/display/BrightnessRangeController.java @@ -0,0 +1,126 @@ +/* + * 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 android.hardware.display.BrightnessInfo; +import android.os.IBinder; + +import java.io.PrintWriter; +import java.util.function.BooleanSupplier; + +class BrightnessRangeController { + + private static final boolean NBM_FEATURE_FLAG = false; + + private final HighBrightnessModeController mHbmController; + private final NormalBrightnessModeController mNormalBrightnessModeController = + new NormalBrightnessModeController(); + + private final Runnable mModeChangeCallback; + + BrightnessRangeController(HighBrightnessModeController hbmController, + Runnable modeChangeCallback) { + mHbmController = hbmController; + mModeChangeCallback = modeChangeCallback; + } + + + void dump(PrintWriter pw) { + mHbmController.dump(pw); + } + + void onAmbientLuxChange(float ambientLux) { + applyChanges( + () -> mNormalBrightnessModeController.onAmbientLuxChange(ambientLux), + () -> mHbmController.onAmbientLuxChange(ambientLux) + ); + } + + float getNormalBrightnessMax() { + return mHbmController.getNormalBrightnessMax(); + } + + void loadFromConfig(HighBrightnessModeMetadata hbmMetadata, IBinder token, + DisplayDeviceInfo info, DisplayDeviceConfig displayDeviceConfig) { + applyChanges( + () -> mNormalBrightnessModeController.resetNbmData( + displayDeviceConfig.getLuxThrottlingData()), + () -> { + mHbmController.setHighBrightnessModeMetadata(hbmMetadata); + mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, + displayDeviceConfig.getHighBrightnessModeData(), + displayDeviceConfig::getHdrBrightnessFromSdr); + } + ); + } + + void stop() { + mHbmController.stop(); + } + + void setAutoBrightnessEnabled(int state) { + applyChanges( + () -> mNormalBrightnessModeController.setAutoBrightnessState(state), + () -> mHbmController.setAutoBrightnessEnabled(state) + ); + } + + void onBrightnessChanged(float brightness, float unthrottledBrightness, + @BrightnessInfo.BrightnessMaxReason int throttlingReason) { + mHbmController.onBrightnessChanged(brightness, unthrottledBrightness, throttlingReason); + } + + float getCurrentBrightnessMin() { + return mHbmController.getCurrentBrightnessMin(); + } + + + float getCurrentBrightnessMax() { + if (NBM_FEATURE_FLAG && mHbmController.getHighBrightnessMode() + == BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF) { + return Math.min(mHbmController.getCurrentBrightnessMax(), + mNormalBrightnessModeController.getCurrentBrightnessMax()); + } + return mHbmController.getCurrentBrightnessMax(); + } + + int getHighBrightnessMode() { + return mHbmController.getHighBrightnessMode(); + } + + float getHdrBrightnessValue() { + return mHbmController.getHdrBrightnessValue(); + } + + 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 9d31572c7d76..f6e074f41743 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -445,7 +445,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private final ColorDisplayServiceInternal mCdsi; private float[] mNitsRange; - private final HighBrightnessModeController mHbmController; + private final BrightnessRangeController mBrightnessRangeController; private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; private final BrightnessThrottler mBrightnessThrottler; @@ -654,8 +654,19 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call loadBrightnessRampRates(); mSkipScreenOnBrightnessRamp = resources.getBoolean( com.android.internal.R.bool.config_skipScreenOnBrightnessRamp); + Runnable modeChangeCallback = () -> { + sendUpdatePowerState(); + postBrightnessChangeRunnable(); + // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.update(); + } + }; - mHbmController = createHbmControllerLocked(); + HighBrightnessModeController hbmController = createHbmControllerLocked(modeChangeCallback); + + mBrightnessRangeController = new BrightnessRangeController(hbmController, + modeChangeCallback); mBrightnessThrottler = createBrightnessThrottlerLocked(); @@ -802,7 +813,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) { - mHbmController.onAmbientLuxChange(ambientLux); + mBrightnessRangeController.onAmbientLuxChange(ambientLux); if (nits < 0) { mBrightnessToFollow = leadDisplayBrightness; } else { @@ -1039,17 +1050,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRampIncreaseMaxTimeMillis, mBrightnessRampDecreaseMaxTimeMillis); } - mHbmController.setHighBrightnessModeMetadata(hbmMetadata); - mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, - mDisplayDeviceConfig.getHighBrightnessModeData(), - new HighBrightnessModeController.HdrBrightnessDeviceConfig() { - @Override - public float getHdrBrightnessFromSdr( - float sdrBrightness, float maxDesiredHdrSdrRatio) { - return mDisplayDeviceConfig.getHdrBrightnessFromSdr( - sdrBrightness, maxDesiredHdrSdrRatio); - } - }); + mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig); mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), mThermalBrightnessThrottlingDataId, mUniqueDisplayId); @@ -1264,7 +1265,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext, - mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper, + mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper, mDisplayDeviceConfig.getAmbientHorizonShort(), mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness); @@ -1364,7 +1365,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call /** Clean up all resources that are accessed via the {@link #mHandler} thread. */ private void cleanupHandlerThreadAfterStop() { setProximitySensorEnabled(false); - mHbmController.stop(); + mBrightnessRangeController.stop(); mBrightnessThrottler.stop(); mHandler.removeCallbacksAndMessages(null); @@ -1647,7 +1648,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mShouldResetShortTermModel); mShouldResetShortTermModel = false; } - mHbmController.setAutoBrightnessEnabled(mUseAutoBrightness + mBrightnessRangeController.setAutoBrightnessEnabled(mUseAutoBrightness ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); @@ -1820,7 +1821,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // here instead of having HbmController listen to the brightness setting because certain // brightness sources (such as an app override) are not saved to the setting, but should be // reflected in HBM calculations. - mHbmController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, + mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, mBrightnessThrottler.getBrightnessMaxReason()); // Animate the screen brightness when the screen is on or dozing. @@ -1874,13 +1875,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call float sdrAnimateValue = animateValue; // TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be // done in HighBrightnessModeController. - if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR + if (mBrightnessRangeController.getHighBrightnessMode() + == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0 && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER) == 0) { // We want to scale HDR brightness level with the SDR level, we also need to restore // SDR brightness immediately when entering dim or low power mode. - animateValue = mHbmController.getHdrBrightnessValue(); + animateValue = mBrightnessRangeController.getHdrBrightnessValue(); } final float currentBrightness = mPowerState.getScreenBrightness(); @@ -1942,8 +1944,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mTempBrightnessEvent.setBrightness(brightnessState); mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId); mTempBrightnessEvent.setReason(mBrightnessReason); - mTempBrightnessEvent.setHbmMax(mHbmController.getCurrentBrightnessMax()); - mTempBrightnessEvent.setHbmMode(mHbmController.getHighBrightnessMode()); + mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax()); + mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode()); mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags() | (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0) | (mPowerRequest.lowPowerMode ? BrightnessEvent.FLAG_LOW_POWER_MODE : 0)); @@ -2104,9 +2106,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) { synchronized (mCachedBrightnessInfo) { - final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(), + final float minBrightness = Math.min( + mBrightnessRangeController.getCurrentBrightnessMin(), mBrightnessThrottler.getBrightnessCap()); - final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(), + final float maxBrightness = Math.min( + mBrightnessRangeController.getCurrentBrightnessMax(), mBrightnessThrottler.getBrightnessCap()); boolean changed = false; @@ -2124,10 +2128,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call maxBrightness); changed |= mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode, - mHbmController.getHighBrightnessMode()); + mBrightnessRangeController.getHighBrightnessMode()); changed |= mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint, - mHbmController.getTransitionPoint()); + mBrightnessRangeController.getTransitionPoint()); changed |= mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason, mBrightnessThrottler.getBrightnessMaxReason()); @@ -2137,10 +2141,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } void postBrightnessChangeRunnable() { - mHandler.post(mOnBrightnessChangeRunnable); + if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) { + mHandler.post(mOnBrightnessChangeRunnable); + } } - private HighBrightnessModeController createHbmControllerLocked() { + private HighBrightnessModeController createHbmControllerLocked( + Runnable modeChangeCallback) { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); final IBinder displayToken = @@ -2159,15 +2166,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return mDisplayDeviceConfig.getHdrBrightnessFromSdr( sdrBrightness, maxDesiredHdrSdrRatio); } - }, - () -> { - sendUpdatePowerState(); - postBrightnessChangeRunnable(); - // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.update(); - } - }, mHighBrightnessModeMetadata, mContext); + }, modeChangeCallback, mHighBrightnessModeMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { @@ -2328,8 +2327,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (Float.isNaN(value)) { value = PowerManager.BRIGHTNESS_MIN; } - return MathUtils.constrain(value, - mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax()); + return MathUtils.constrain(value, mBrightnessRangeController.getCurrentBrightnessMin(), + mBrightnessRangeController.getCurrentBrightnessMax()); } // Checks whether the brightness is within the valid brightness range, not including off. @@ -3003,8 +3002,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mScreenOffBrightnessSensorController.dump(pw); } - if (mHbmController != null) { - mHbmController.dump(pw); + if (mBrightnessRangeController != null) { + mBrightnessRangeController.dump(pw); } if (mBrightnessThrottler != null) { @@ -3471,7 +3470,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler, + BrightnessRangeController brightnessRangeController, + BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userBrightness) { return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor, @@ -3480,9 +3480,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brighteningLightDebounceConfig, darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, screenBrightnessThresholds, ambientBrightnessThresholdsIdle, - screenBrightnessThresholdsIdle, context, hbmController, brightnessThrottler, - idleModeBrightnessMapper, ambientLightHorizonShort, ambientLightHorizonLong, - userLux, userBrightness); + screenBrightnessThresholdsIdle, context, brightnessRangeController, + brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort, + ambientLightHorizonLong, userLux, userBrightness); } BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources, diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 41e4671df1a7..2e8c3420c317 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -376,8 +376,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private final ColorDisplayServiceInternal mCdsi; private float[] mNitsRange; - private final HighBrightnessModeController mHbmController; - private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; + private final BrightnessRangeController mBrightnessRangeController; private final BrightnessThrottler mBrightnessThrottler; @@ -489,7 +488,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController( mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(), () -> updatePowerState(), mDisplayId, mSensorManager); - mHighBrightnessModeMetadata = hbmMetadata; mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId); mTag = "DisplayPowerController2[" + mDisplayId + "]"; @@ -532,9 +530,22 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mSkipScreenOnBrightnessRamp = resources.getBoolean( R.bool.config_skipScreenOnBrightnessRamp); - mHbmController = createHbmControllerLocked(); + Runnable modeChangeCallback = () -> { + sendUpdatePowerState(); + postBrightnessChangeRunnable(); + // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.update(); + } + }; + HighBrightnessModeController hbmController = createHbmControllerLocked(hbmMetadata, + modeChangeCallback); mBrightnessThrottler = createBrightnessThrottlerLocked(); + + mBrightnessRangeController = new BrightnessRangeController(hbmController, + modeChangeCallback); + mDisplayBrightnessController = new DisplayBrightnessController(context, null, mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault, @@ -848,17 +859,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mBrightnessRampIncreaseMaxTimeMillis, mBrightnessRampDecreaseMaxTimeMillis); } - mHbmController.setHighBrightnessModeMetadata(hbmMetadata); - mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId, - mDisplayDeviceConfig.getHighBrightnessModeData(), - new HighBrightnessModeController.HdrBrightnessDeviceConfig() { - @Override - public float getHdrBrightnessFromSdr( - float sdrBrightness, float maxDesiredHdrSdrRatio) { - return mDisplayDeviceConfig.getHdrBrightnessFromSdr( - sdrBrightness, maxDesiredHdrSdrRatio); - } - }); + + mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig); mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), mThermalBrightnessThrottlingDataId, mUniqueDisplayId); @@ -1076,7 +1078,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext, - mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper, + mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper, mDisplayDeviceConfig.getAmbientHorizonShort(), mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness); mDisplayBrightnessController.setAutomaticBrightnessController( @@ -1180,7 +1182,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal /** Clean up all resources that are accessed via the {@link #mHandler} thread. */ private void cleanupHandlerThreadAfterStop() { mDisplayPowerProximityStateController.cleanup(); - mHbmController.stop(); + mBrightnessRangeController.stop(); mBrightnessThrottler.stop(); mHandler.removeCallbacksAndMessages(null); @@ -1295,7 +1297,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal && (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged() || userSetBrightnessChanged); - mHbmController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy + mBrightnessRangeController.setAutoBrightnessEnabled(mAutomaticBrightnessStrategy .shouldUseAutoBrightness() ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); @@ -1452,7 +1454,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // here instead of having HbmController listen to the brightness setting because certain // brightness sources (such as an app override) are not saved to the setting, but should be // reflected in HBM calculations. - mHbmController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, + mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, mBrightnessThrottler.getBrightnessMaxReason()); // Animate the screen brightness when the screen is on or dozing. @@ -1509,13 +1511,14 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal float sdrAnimateValue = animateValue; // TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be // done in HighBrightnessModeController. - if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR + if (mBrightnessRangeController.getHighBrightnessMode() + == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0 && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER) == 0) { // We want to scale HDR brightness level with the SDR level, we also need to restore // SDR brightness immediately when entering dim or low power mode. - animateValue = mHbmController.getHdrBrightnessValue(); + animateValue = mBrightnessRangeController.getHdrBrightnessValue(); } final float currentBrightness = mPowerState.getScreenBrightness(); @@ -1579,8 +1582,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mTempBrightnessEvent.setBrightness(brightnessState); mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId); mTempBrightnessEvent.setReason(mBrightnessReason); - mTempBrightnessEvent.setHbmMax(mHbmController.getCurrentBrightnessMax()); - mTempBrightnessEvent.setHbmMode(mHbmController.getHighBrightnessMode()); + mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax()); + mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode()); mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags() | (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0) | (mPowerRequest.lowPowerMode ? BrightnessEvent.FLAG_LOW_POWER_MODE : 0)); @@ -1750,9 +1753,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) { synchronized (mCachedBrightnessInfo) { - final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(), + final float minBrightness = Math.min( + mBrightnessRangeController.getCurrentBrightnessMin(), mBrightnessThrottler.getBrightnessCap()); - final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(), + final float maxBrightness = Math.min( + mBrightnessRangeController.getCurrentBrightnessMax(), mBrightnessThrottler.getBrightnessCap()); boolean changed = false; @@ -1770,10 +1775,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal maxBrightness); changed |= mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode, - mHbmController.getHighBrightnessMode()); + mBrightnessRangeController.getHighBrightnessMode()); changed |= mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint, - mHbmController.getTransitionPoint()); + mBrightnessRangeController.getTransitionPoint()); changed |= mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason, mBrightnessThrottler.getBrightnessMaxReason()); @@ -1783,10 +1788,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } void postBrightnessChangeRunnable() { - mHandler.post(mOnBrightnessChangeRunnable); + if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) { + mHandler.post(mOnBrightnessChangeRunnable); + } } - private HighBrightnessModeController createHbmControllerLocked() { + private HighBrightnessModeController createHbmControllerLocked( + HighBrightnessModeMetadata hbmMetadata, Runnable modeChangeCallback) { final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); final IBinder displayToken = @@ -1798,22 +1806,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken, displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData, - new HighBrightnessModeController.HdrBrightnessDeviceConfig() { - @Override - public float getHdrBrightnessFromSdr( - float sdrBrightness, float maxDesiredHdrSdrRatio) { - return mDisplayDeviceConfig.getHdrBrightnessFromSdr( - sdrBrightness, maxDesiredHdrSdrRatio); - } - }, - () -> { - sendUpdatePowerState(); - postBrightnessChangeRunnable(); - // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.update(); - } - }, mHighBrightnessModeMetadata, mContext); + (sdrBrightness, maxDesiredHdrSdrRatio) -> + mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness, + maxDesiredHdrSdrRatio), modeChangeCallback, hbmMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { @@ -1960,8 +1955,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal if (Float.isNaN(value)) { value = PowerManager.BRIGHTNESS_MIN; } - return MathUtils.constrain(value, - mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax()); + return MathUtils.constrain(value, mBrightnessRangeController.getCurrentBrightnessMin(), + mBrightnessRangeController.getCurrentBrightnessMax()); } private void animateScreenBrightness(float target, float sdrTarget, float rate) { @@ -2195,7 +2190,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @Override public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux) { - mHbmController.onAmbientLuxChange(ambientLux); + mBrightnessRangeController.onAmbientLuxChange(ambientLux); if (nits < 0) { mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness); } else { @@ -2374,8 +2369,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal dumpRbcEvents(pw); - if (mHbmController != null) { - mHbmController.dump(pw); + if (mBrightnessRangeController != null) { + mBrightnessRangeController.dump(pw); } if (mBrightnessThrottler != null) { @@ -2840,7 +2835,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler, + BrightnessRangeController brightnessModeController, + BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userBrightness) { return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor, @@ -2849,9 +2845,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal brighteningLightDebounceConfig, darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, screenBrightnessThresholds, ambientBrightnessThresholdsIdle, - screenBrightnessThresholdsIdle, context, hbmController, brightnessThrottler, - idleModeBrightnessMapper, ambientLightHorizonShort, ambientLightHorizonLong, - userLux, userBrightness); + screenBrightnessThresholdsIdle, context, brightnessModeController, + brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort, + ambientLightHorizonLong, userLux, userBrightness); } BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources, diff --git a/services/core/java/com/android/server/display/NormalBrightnessModeController.java b/services/core/java/com/android/server/display/NormalBrightnessModeController.java new file mode 100644 index 000000000000..dbabc2441224 --- /dev/null +++ b/services/core/java/com/android/server/display/NormalBrightnessModeController.java @@ -0,0 +1,94 @@ +/* + * 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 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 { + @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 mMaxBrightness = PowerManager.BRIGHTNESS_MAX; + + boolean onAmbientLuxChange(float ambientLux) { + 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 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/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index 170076098b7d..4f98dca660df 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -815,7 +815,7 @@ public final class DisplayPowerController2Test { any(HysteresisLevels.class), any(HysteresisLevels.class), eq(mContext), - any(HighBrightnessModeController.class), + any(BrightnessRangeController.class), any(BrightnessThrottler.class), isNull(), anyInt(), @@ -1064,7 +1064,7 @@ public final class DisplayPowerController2Test { HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, + BrightnessRangeController brightnessRangeController, BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java index 5c0810fdca44..a93640b592cd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -819,7 +819,7 @@ public final class DisplayPowerControllerTest { any(HysteresisLevels.class), any(HysteresisLevels.class), eq(mContext), - any(HighBrightnessModeController.class), + any(BrightnessRangeController.class), any(BrightnessThrottler.class), isNull(), anyInt(), @@ -1038,7 +1038,7 @@ public final class DisplayPowerControllerTest { HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, - HighBrightnessModeController hbmController, + BrightnessRangeController brightnessRangeController, BrightnessThrottler brightnessThrottler, BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, 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 962e86776ea2..a6acd60f3bd7 100644 --- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -85,7 +85,7 @@ public class AutomaticBrightnessControllerTest { @Mock HysteresisLevels mAmbientBrightnessThresholdsIdle; @Mock HysteresisLevels mScreenBrightnessThresholdsIdle; @Mock Handler mNoOpHandler; - @Mock HighBrightnessModeController mHbmController; + @Mock BrightnessRangeController mBrightnessRangeController; @Mock BrightnessThrottler mBrightnessThrottler; @Before @@ -134,12 +134,15 @@ public class AutomaticBrightnessControllerTest { DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle, - mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy, - AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG, userLux, userBrightness + mContext, mBrightnessRangeController, mBrightnessThrottler, + mIdleBrightnessMappingStrategy, AMBIENT_LIGHT_HORIZON_SHORT, + AMBIENT_LIGHT_HORIZON_LONG, userLux, userBrightness ); - when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT); - when(mHbmController.getCurrentBrightnessMin()).thenReturn(BRIGHTNESS_MIN_FLOAT); + when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn( + BRIGHTNESS_MAX_FLOAT); + when(mBrightnessRangeController.getCurrentBrightnessMin()).thenReturn( + BRIGHTNESS_MIN_FLOAT); // Disable brightness throttling by default. Individual tests can enable it as needed. when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT); when(mBrightnessThrottler.isThrottled()).thenReturn(false); 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); + } +} |