diff options
5 files changed, 205 insertions, 19 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a36785f37d3f..86400aa290cf 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1483,6 +1483,30 @@ <integer-array name="config_autoBrightnessLevels"> </integer-array> + <!-- Array of light sensor lux values to define our levels for auto backlight brightness + support whilst in idle mode. + The N entries of this array define N + 1 control points as follows: + (1-based arrays) + + Point 1: (0, value[1]): lux <= 0 + Point 2: (level[1], value[2]): 0 < lux <= level[1] + Point 3: (level[2], value[3]): level[2] < lux <= level[3] + ... + Point N+1: (level[N], value[N+1]): level[N] < lux + + The control points must be strictly increasing. Each control point + corresponds to an entry in the brightness backlight values arrays. + For example, if lux == level[1] (first element of the levels array) + then the brightness will be determined by value[2] (second element + of the brightness values array). + + Spline interpolation is used to determine the auto-brightness + backlight values for lux levels between these control points. + + Must be overridden in platform specific overlays --> + <integer-array name="config_autoBrightnessLevelsIdle"> + </integer-array> + <!-- Timeout (in milliseconds) after which we remove the effects any user interactions might've had on the brightness mapping. This timeout doesn't start until we transition to a non-interactive display policy so that we don't reset while users are using their devices, @@ -1506,6 +1530,10 @@ <integer-array name="config_autoBrightnessLcdBacklightValues_doze"> </integer-array> + <!-- Enables idle screen brightness mode on this device. + If this is true, config_autoBrightnessDisplayValuesNitsIdle must be defined. --> + <bool name="config_enableIdleScreenBrightnessMode">false</bool> + <!-- Array of desired screen brightness in nits corresponding to the lux values in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and config_screenBrightnessMaximumNits, the display brightness is defined as the measured @@ -1522,6 +1550,13 @@ <array name="config_autoBrightnessDisplayValuesNits"> </array> + <!-- Array of desired screen brightness in nits for idle screen brightness mode. + This array should meet the same requirements as config_autoBrightnessDisplayValuesNits. + This array also corresponds to the lux values given in config_autoBrightnessLevelsIdle. + In order to activate this mode, config_enableIdleScreenBrightnessMode must be true. --> + <array name="config_autoBrightnessDisplayValuesNitsIdle"> + </array> + <!-- Array of output values for button backlight corresponding to the luX values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index faa99027d9ad..96a5098b8f8b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1902,6 +1902,7 @@ <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues_doze" /> <java-symbol type="array" name="config_autoBrightnessLevels" /> + <java-symbol type="array" name="config_autoBrightnessLevelsIdle" /> <java-symbol type="array" name="config_ambientThresholdLevels" /> <java-symbol type="array" name="config_ambientBrighteningThresholds" /> <java-symbol type="array" name="config_ambientDarkeningThresholds" /> @@ -3788,7 +3789,9 @@ <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" /> <java-symbol type="drawable" name="ic_logout" /> + <java-symbol type="bool" name="config_enableIdleScreenBrightnessMode" /> <java-symbol type="array" name="config_autoBrightnessDisplayValuesNits" /> + <java-symbol type="array" name="config_autoBrightnessDisplayValuesNitsIdle" /> <java-symbol type="array" name="config_screenBrightnessBacklight" /> <java-symbol type="array" name="config_screenBrightnessNits" /> diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 74a21a733fb9..beb4d5b28d5c 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -60,17 +60,62 @@ public abstract class BrightnessMappingStrategy { private static final Plog PLOG = Plog.createSystemPlog(TAG); + /** + * Creates a BrightnessMappingStrategy for active (normal) mode. + * @param resources + * @param displayDeviceConfig + * @return the BrightnessMappingStrategy + */ @Nullable public static BrightnessMappingStrategy create(Resources resources, DisplayDeviceConfig displayDeviceConfig) { + return create(resources, displayDeviceConfig, /* isForIdleMode= */ false); + } + + /** + * Creates a BrightnessMappingStrategy for idle screen brightness mode. + * @param resources + * @param displayDeviceConfig + * @return the BrightnessMappingStrategy + */ + @Nullable + public static BrightnessMappingStrategy createForIdleMode(Resources resources, + DisplayDeviceConfig displayDeviceConfig) { + return create(resources, displayDeviceConfig, /* isForIdleMode= */ true); + } + + /** + * Creates a BrightnessMapping strategy for either active or idle screen brightness mode. + * We do not create a simple mapping strategy for idle mode. + * + * @param resources + * @param displayDeviceConfig + * @param isForIdleMode determines whether the configurations loaded are for idle screen + * brightness mode or active screen brightness mode. + * @return the BrightnessMappingStrategy + */ + @Nullable + private static BrightnessMappingStrategy create(Resources resources, + DisplayDeviceConfig displayDeviceConfig, boolean isForIdleMode) { + + // Display independent, mode dependent values + float[] brightnessLevelsNits; + float[] luxLevels; + if (isForIdleMode) { + brightnessLevelsNits = getFloatArray(resources.obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle)); + luxLevels = getLuxLevels(resources.getIntArray( + com.android.internal.R.array.config_autoBrightnessLevelsIdle)); + } else { + brightnessLevelsNits = getFloatArray(resources.obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)); + luxLevels = getLuxLevels(resources.getIntArray( + com.android.internal.R.array.config_autoBrightnessLevels)); + } - // Display independent values - float[] luxLevels = getLuxLevels(resources.getIntArray( - com.android.internal.R.array.config_autoBrightnessLevels)); + // Display independent, mode independent values int[] brightnessLevelsBacklight = resources.getIntArray( com.android.internal.R.array.config_autoBrightnessLcdBacklightValues); - float[] brightnessLevelsNits = getFloatArray(resources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)); float autoBrightnessAdjustmentMaxGamma = resources.getFraction( com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma, 1, 1); @@ -91,7 +136,7 @@ public abstract class BrightnessMappingStrategy { builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange, autoBrightnessAdjustmentMaxGamma); - } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) { + } else if (isValidMapping(luxLevels, brightnessLevelsBacklight) && !isForIdleMode) { return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight, autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout); } else { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 5f79f727ca97..7f78cac651dc 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -54,6 +54,7 @@ import android.util.Slog; import android.util.TimeUtils; import android.view.Display; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.display.BrightnessSynchronizer; @@ -386,8 +387,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private Sensor mLightSensor; // The mapper between ambient lux, display backlight values, and display brightness. + // This mapper holds the current one that is being used. We will switch between the idle + // mapper and active mapper here. @Nullable - private BrightnessMappingStrategy mBrightnessMapper; + private BrightnessMappingStrategy mCurrentBrightnessMapper; + + // Mapper used for active (normal) screen brightness mode + @Nullable + private BrightnessMappingStrategy mInteractiveModeBrightnessMapper; + // Mapper used for idle screen brightness mode + @Nullable + private BrightnessMappingStrategy mIdleModeBrightnessMapper; // The current brightness configuration. @Nullable @@ -408,7 +418,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The temporary screen brightness. Typically set when a user is interacting with the // brightness slider but hasn't settled on a choice yet. Set to - // PowerManager.BRIGHNTESS_INVALID_FLOAT when there's no temporary brightness set. + // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set. private float mTemporaryScreenBrightness; // The current screen brightness while in VR mode. @@ -600,7 +610,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void handleRbcChanged(boolean strengthChanged, boolean justActivated) { - if (mBrightnessMapper == null) { + if (mCurrentBrightnessMapper == null) { Log.w(TAG, "No brightness mapping available to recalculate splines"); return; } @@ -609,7 +619,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call for (int i = 0; i < mNitsRange.length; i++) { adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]); } - mBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits); + mCurrentBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), + adjustedNits); mPendingRbcOnOrChanged = strengthChanged || justActivated; @@ -867,9 +878,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return; } - mBrightnessMapper = BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig); + final boolean isIdleScreenBrightnessEnabled = resources.getBoolean( + R.bool.config_enableIdleScreenBrightnessMode); + mInteractiveModeBrightnessMapper = BrightnessMappingStrategy.create(resources, + mDisplayDeviceConfig); + if (isIdleScreenBrightnessEnabled) { + mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources, + mDisplayDeviceConfig); + } + mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper; - if (mBrightnessMapper != null) { + if (mCurrentBrightnessMapper != null) { final float dozeScaleFactor = resources.getFraction( com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor, 1, 1); @@ -920,7 +939,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.stop(); } mAutomaticBrightnessController = new AutomaticBrightnessController(this, - handler.getLooper(), mSensorManager, mLightSensor, mBrightnessMapper, + handler.getLooper(), mSensorManager, mLightSensor, mCurrentBrightnessMapper, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, @@ -2143,8 +2162,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private float convertToNits(float brightness) { - if (mBrightnessMapper != null) { - return mBrightnessMapper.convertToNits(brightness); + if (mCurrentBrightnessMapper != null) { + return mCurrentBrightnessMapper.convertToNits(brightness); } else { return -1.0f; } @@ -2296,6 +2315,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mReportedToPolicy=" + reportedToPolicyToString(mReportedScreenStateToPolicy)); + if (mIdleModeBrightnessMapper != null) { + pw.println(" mIdleModeBrightnessMapper= "); + mIdleModeBrightnessMapper.dump(pw); + } + if (mScreenBrightnessRampAnimator != null) { pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" + mScreenBrightnessRampAnimator.isAnimating()); diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java index 285806b5dcd7..c6757261ce42 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java @@ -59,6 +59,20 @@ public class BrightnessMappingStrategyTest { 5000 }; + private static final int[] LUX_LEVELS_IDLE = { + 0, + 10, + 40, + 80, + 200, + 655, + 1200, + 2500, + 4400, + 8000, + 10000 + }; + private static final float[] DISPLAY_LEVELS_NITS = { 13.25f, 54.0f, @@ -73,6 +87,20 @@ public class BrightnessMappingStrategyTest { 478.5f, }; + private static final float[] DISPLAY_LEVELS_NITS_IDLE = { + 23.25f, + 64.0f, + 88.85f, + 115.02f, + 142.7f, + 180.12f, + 222.1f, + 275.2f, + 345.8f, + 425.2f, + 468.5f, + }; + private static final int[] DISPLAY_LEVELS_BACKLIGHT = { 9, 30, @@ -88,7 +116,6 @@ public class BrightnessMappingStrategyTest { }; private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f }; - private static final float[] DISPLAY_LEVELS_RANGE_NITS = { 13.25f, 478.5f }; private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f }; private static final float[] DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT = { 0.03149606299f, 1.0f }; @@ -118,6 +145,8 @@ public class BrightnessMappingStrategyTest { new float[] { 0.0f, 100.0f, 1000.0f, 2500.0f, 4000.0f, 4900.0f, 5000.0f }, new float[] { 0.0475f, 0.0475f, 0.2225f, 0.5140f, 0.8056f, 0.9805f, 1.0f }); + private static final float TOLERANCE = 0.0001f; + @Test public void testSimpleStrategyMappingAtControlPoints() { Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT); @@ -357,6 +386,27 @@ public class BrightnessMappingStrategyTest { assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc)); } + @Test + public void testIdleModeConfigLoadsCorrectly() { + Resources res = createResourcesIdle(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE); + DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE); + + // Create an idle mode bms + // This will fail if it tries to fetch the wrong configuration. + BrightnessMappingStrategy bms = BrightnessMappingStrategy.createForIdleMode(res, ddc); + assertNotNull("BrightnessMappingStrategy should not be null", bms); + + // Ensure that the config is the one we set + // Ensure that the lux -> brightness -> nits path works. () + for (int i = 0; i < DISPLAY_LEVELS_NITS_IDLE.length; i++) { + assertEquals(LUX_LEVELS_IDLE[i], bms.getDefaultConfig().getCurve().first[i], TOLERANCE); + assertEquals(DISPLAY_LEVELS_NITS_IDLE[i], bms.getDefaultConfig().getCurve().second[i], + TOLERANCE); + assertEquals(bms.convertToNits(bms.getBrightness(LUX_LEVELS_IDLE[i])), + DISPLAY_LEVELS_NITS_IDLE[i], TOLERANCE); + } + } + private static void assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy strategy) { // Save out all of the initial brightness data for comparison after reset. float[] initialBrightnessLevels = new float[LUX_LEVELS.length]; @@ -421,14 +471,39 @@ public class BrightnessMappingStrategyTest { brightnessLevelsNits); } + private Resources createResourcesIdle(int[] luxLevels, float[] brightnessLevelsNits) { + return createResources(EMPTY_INT_ARRAY, EMPTY_INT_ARRAY, EMPTY_FLOAT_ARRAY, + luxLevels, brightnessLevelsNits); + } + private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight, float[] brightnessLevelsNits) { + return createResources(luxLevels, brightnessLevelsBacklight, brightnessLevelsNits, + EMPTY_INT_ARRAY, EMPTY_FLOAT_ARRAY); + + } + + private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight, + float[] brightnessLevelsNits, int[] luxLevelsIdle, float[] brightnessLevelsNitsIdle) { + Resources mockResources = mock(Resources.class); + // For historical reasons, the lux levels resource implicitly defines the first point as 0, // so we need to chop it off of the array the mock resource object returns. - int[] luxLevelsResource = Arrays.copyOfRange(luxLevels, 1, luxLevels.length); - when(mockResources.getIntArray(com.android.internal.R.array.config_autoBrightnessLevels)) - .thenReturn(luxLevelsResource); + // Don't mock if these values are not set. If we try to use them, we will fail. + if (luxLevels.length > 0) { + int[] luxLevelsResource = Arrays.copyOfRange(luxLevels, 1, luxLevels.length); + when(mockResources.getIntArray( + com.android.internal.R.array.config_autoBrightnessLevels)) + .thenReturn(luxLevelsResource); + } + if (luxLevelsIdle.length > 0) { + int[] luxLevelsIdleResource = Arrays.copyOfRange(luxLevelsIdle, 1, + luxLevelsIdle.length); + when(mockResources.getIntArray( + com.android.internal.R.array.config_autoBrightnessLevelsIdle)) + .thenReturn(luxLevelsIdleResource); + } when(mockResources.getIntArray( com.android.internal.R.array.config_autoBrightnessLcdBacklightValues)) @@ -438,6 +513,10 @@ public class BrightnessMappingStrategyTest { when(mockResources.obtainTypedArray( com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) .thenReturn(mockBrightnessLevelNits); + TypedArray mockBrightnessLevelNitsIdle = createFloatTypedArray(brightnessLevelsNitsIdle); + when(mockResources.obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle)) + .thenReturn(mockBrightnessLevelNitsIdle); when(mockResources.getInteger( com.android.internal.R.integer.config_screenBrightnessSettingMinimum)) |