Loading services/core/java/com/android/server/display/AutomaticBrightnessController.java +98 −23 Original line number Diff line number Diff line Loading @@ -87,7 +87,10 @@ class AutomaticBrightnessController { private final Sensor mLightSensor; // The mapper to translate ambient lux to screen brightness in the range [0, 1.0]. private final BrightnessMappingStrategy mBrightnessMapper; @Nullable private BrightnessMappingStrategy mCurrentBrightnessMapper; private final BrightnessMappingStrategy mInteractiveModeBrightnessMapper; private final BrightnessMappingStrategy mIdleModeBrightnessMapper; // The minimum and maximum screen brightnesses. private final float mScreenBrightnessRangeMinimum; Loading Loading @@ -215,36 +218,41 @@ class AutomaticBrightnessController { private final Injector mInjector; AutomaticBrightnessController(Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy interactiveModeBrightnessMapper, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, Context context, HighBrightnessModeController hbmController) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper, HighBrightnessModeController hbmController, BrightnessMappingStrategy idleModeBrightnessMapper) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, interactiveModeBrightnessMapper, lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig, darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, screenBrightnessThresholds, context, hbmController hbmController, idleModeBrightnessMapper ); } @VisibleForTesting AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy interactiveModeBrightnessMapper, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, Context context, HighBrightnessModeController hbmController) { HighBrightnessModeController hbmController, BrightnessMappingStrategy idleModeBrightnessMapper) { mInjector = injector; mContext = context; mCallbacks = callbacks; mSensorManager = sensorManager; mBrightnessMapper = mapper; mCurrentBrightnessMapper = interactiveModeBrightnessMapper; mScreenBrightnessRangeMinimum = brightnessMin; mScreenBrightnessRangeMaximum = brightnessMax; mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime; Loading Loading @@ -277,6 +285,10 @@ class AutomaticBrightnessController { mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; mHbmController = hbmController; mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper; mIdleModeBrightnessMapper = idleModeBrightnessMapper; // Initialize to active (normal) screen brightness mode switchToInteractiveScreenBrightnessMode(); } /** Loading @@ -291,7 +303,12 @@ class AutomaticBrightnessController { if (mLoggingEnabled == loggingEnabled) { return false; } mBrightnessMapper.setLoggingEnabled(loggingEnabled); if (mInteractiveModeBrightnessMapper != null) { mInteractiveModeBrightnessMapper.setLoggingEnabled(loggingEnabled); } if (mIdleModeBrightnessMapper != null) { mIdleModeBrightnessMapper.setLoggingEnabled(loggingEnabled); } mLoggingEnabled = loggingEnabled; return true; } Loading @@ -311,7 +328,7 @@ class AutomaticBrightnessController { } public float getAutomaticScreenBrightnessAdjustment() { return mBrightnessMapper.getAutoBrightnessAdjustment(); return mCurrentBrightnessMapper.getAutoBrightnessAdjustment(); } public void configure(boolean enable, @Nullable BrightnessConfiguration configuration, Loading Loading @@ -350,15 +367,20 @@ class AutomaticBrightnessController { } public boolean hasUserDataPoints() { return mBrightnessMapper.hasUserDataPoints(); return mCurrentBrightnessMapper.hasUserDataPoints(); } // Used internally to establish whether we have deviated from the default config. public boolean isDefaultConfig() { return mBrightnessMapper.isDefaultConfig(); if (isInIdleMode()) { return false; } return mInteractiveModeBrightnessMapper.isDefaultConfig(); } // Called from APIs to get the configuration. public BrightnessConfiguration getDefaultConfig() { return mBrightnessMapper.getDefaultConfig(); return mInteractiveModeBrightnessMapper.getDefaultConfig(); } /** Loading @@ -379,7 +401,7 @@ class AutomaticBrightnessController { } if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL, mBrightnessMapper.getShortTermModelTimeout()); mCurrentBrightnessMapper.getShortTermModelTimeout()); } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL); } Loading @@ -398,7 +420,7 @@ class AutomaticBrightnessController { // and we can't use this data to add a new control point to the short-term model. return false; } mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); mCurrentBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); mShortTermModelValid = true; mShortTermModelAnchor = mAmbientLux; if (mLoggingEnabled) { Loading @@ -408,7 +430,7 @@ class AutomaticBrightnessController { } public void resetShortTermModel() { mBrightnessMapper.clearUserDataPoints(); mCurrentBrightnessMapper.clearUserDataPoints(); mShortTermModelValid = true; mShortTermModelAnchor = -1; } Loading @@ -421,13 +443,19 @@ class AutomaticBrightnessController { } public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) { if (mBrightnessMapper.setBrightnessConfiguration(configuration)) { if (mInteractiveModeBrightnessMapper.setBrightnessConfiguration(configuration)) { if (!isInIdleMode()) { resetShortTermModel(); } return true; } return false; } public boolean isInIdleMode() { return mCurrentBrightnessMapper.isForIdleMode(); } public void dump(PrintWriter pw) { pw.println(); pw.println("Automatic Brightness Controller Configuration:"); Loading Loading @@ -461,7 +489,12 @@ class AutomaticBrightnessController { pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer); pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy)); pw.println(" mShortTermModelTimeout=" + mBrightnessMapper.getShortTermModelTimeout()); pw.println(" mShortTermModelTimeout(active)=" + mInteractiveModeBrightnessMapper.getShortTermModelTimeout()); if (mIdleModeBrightnessMapper != null) { pw.println(" mShortTermModelTimeout(idle)=" + mIdleModeBrightnessMapper.getShortTermModelTimeout()); } pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor); pw.println(" mShortTermModelValid=" + mShortTermModelValid); pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending); Loading @@ -472,9 +505,15 @@ class AutomaticBrightnessController { pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName); pw.println(" mForegroundAppCategory=" + mForegroundAppCategory); pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory); pw.println(" Idle mode active=" + mCurrentBrightnessMapper.isForIdleMode()); pw.println(); mBrightnessMapper.dump(pw); pw.println(" mActiveMapper="); mInteractiveModeBrightnessMapper.dump(pw); if (mIdleModeBrightnessMapper != null) { pw.println(" mIdleMapper="); mIdleModeBrightnessMapper.dump(pw); } pw.println(); mAmbientBrightnessThresholds.dump(pw); Loading Loading @@ -544,7 +583,7 @@ class AutomaticBrightnessController { } private boolean setAutoBrightnessAdjustment(float adjustment) { return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment); return mCurrentBrightnessMapper.setAutoBrightnessAdjustment(adjustment); } private void setAmbientLux(float lux) { Loading @@ -562,7 +601,8 @@ class AutomaticBrightnessController { // If the short term model was invalidated and the change is drastic enough, reset it. if (!mShortTermModelValid && mShortTermModelAnchor != -1) { if (mBrightnessMapper.shouldResetShortTermModel(mAmbientLux, mShortTermModelAnchor)) { if (mCurrentBrightnessMapper.shouldResetShortTermModel( mAmbientLux, mShortTermModelAnchor)) { resetShortTermModel(); } else { mShortTermModelValid = true; Loading Loading @@ -743,7 +783,7 @@ class AutomaticBrightnessController { return; } float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, float value = mCurrentBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, mForegroundAppCategory); float newScreenAutoBrightness = clampScreenBrightness(value); Loading Loading @@ -909,6 +949,41 @@ class AutomaticBrightnessController { updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */); } void switchToIdleMode() { if (mIdleModeBrightnessMapper == null) { return; } if (mCurrentBrightnessMapper.isForIdleMode()) { return; } Slog.i(TAG, "Switching to Idle Screen Brightness Mode"); mCurrentBrightnessMapper = mIdleModeBrightnessMapper; resetShortTermModel(); update(); } void switchToInteractiveScreenBrightnessMode() { if (!mCurrentBrightnessMapper.isForIdleMode()) { return; } Slog.i(TAG, "Switching to Interactive Screen Brightness Mode"); mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper; resetShortTermModel(); update(); } public float convertToNits(float brightness) { if (mCurrentBrightnessMapper != null) { return mCurrentBrightnessMapper.convertToNits(brightness); } else { return -1.0f; } } public void recalculateSplines(boolean applyAdjustment, float[] adjustment) { mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment); } private final class AutomaticBrightnessHandler extends Handler { public AutomaticBrightnessHandler(Looper looper) { super(looper, null, true /*async*/); Loading services/core/java/com/android/server/display/BrightnessMappingStrategy.java +20 −2 Original line number Diff line number Diff line Loading @@ -135,7 +135,7 @@ public abstract class BrightnessMappingStrategy { builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange, autoBrightnessAdjustmentMaxGamma); autoBrightnessAdjustmentMaxGamma, isForIdleMode); } else if (isValidMapping(luxLevels, brightnessLevelsBacklight) && !isForIdleMode) { return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight, autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout); Loading Loading @@ -354,6 +354,12 @@ public abstract class BrightnessMappingStrategy { public abstract void dump(PrintWriter pw); /** * We can designate a mapping strategy to be used for idle screen brightness mode. * @return whether this mapping strategy is to be used for idle screen brightness mode. */ public abstract boolean isForIdleMode(); /** * Check if the short term model should be reset given the anchor lux the last * brightness change was made at and the current ambient lux. Loading Loading @@ -711,6 +717,11 @@ public abstract class BrightnessMappingStrategy { pw.println(" mUserBrightness=" + mUserBrightness); } @Override public boolean isForIdleMode() { return false; } private void computeSpline() { Pair<float[], float[]> curve = getAdjustedCurve(mLux, mBrightness, mUserLux, mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma); Loading Loading @@ -758,9 +769,10 @@ public abstract class BrightnessMappingStrategy { private float mAutoBrightnessAdjustment; private float mUserLux; private float mUserBrightness; private final boolean mIsForIdleMode; public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits, float[] brightness, float maxGamma) { float[] brightness, float maxGamma, boolean isForIdleMode) { Preconditions.checkArgument(nits.length != 0 && brightness.length != 0, "Nits and brightness arrays must not be empty!"); Loading @@ -772,6 +784,7 @@ public abstract class BrightnessMappingStrategy { Preconditions.checkArrayElementsInRange(brightness, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, "brightness"); mIsForIdleMode = isForIdleMode; mMaxGamma = maxGamma; mAutoBrightnessAdjustment = 0; mUserLux = -1; Loading Loading @@ -933,6 +946,11 @@ public abstract class BrightnessMappingStrategy { pw.println(" mBrightnessRangeAdjustmentApplied=" + mBrightnessRangeAdjustmentApplied); } @Override public boolean isForIdleMode() { return mIsForIdleMode; } private void computeNitsBrightnessSplines(float[] nits) { mNitsToBrightnessSpline = Spline.createSpline(nits, mBrightness); mBrightnessToNitsSpline = Spline.createSpline(mBrightness, nits); Loading services/core/java/com/android/server/display/DisplayPowerController.java +44 −28 Original line number Diff line number Diff line Loading @@ -386,12 +386,8 @@ 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 mCurrentBrightnessMapper; // The mappers between ambient lux, display backlight values, and display brightness. // We will switch between the idle mapper and active mapper in AutomaticBrightnessController. // Mapper used for active (normal) screen brightness mode @Nullable private BrightnessMappingStrategy mInteractiveModeBrightnessMapper; Loading @@ -399,6 +395,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Nullable private BrightnessMappingStrategy mIdleModeBrightnessMapper; // If these are both true, and mIdleModeBrightnessMapper != null, // then we are in idle screen brightness mode. private boolean mIsDreaming; private boolean mIsDocked; // The current brightness configuration. @Nullable private BrightnessConfiguration mBrightnessConfiguration; Loading Loading @@ -610,8 +611,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void handleRbcChanged(boolean strengthChanged, boolean justActivated) { if (mCurrentBrightnessMapper == null) { Log.w(TAG, "No brightness mapping available to recalculate splines"); if (mAutomaticBrightnessController == null) { return; } if ((!mAutomaticBrightnessController.isInIdleMode() && mInteractiveModeBrightnessMapper == null) || (mAutomaticBrightnessController.isInIdleMode() && mIdleModeBrightnessMapper == null)) { Log.w(TAG, "No brightness mapping available to recalculate splines for this mode"); return; } Loading @@ -619,7 +626,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call for (int i = 0; i < mNitsRange.length; i++) { adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]); } mCurrentBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits); mPendingRbcOnOrChanged = strengthChanged || justActivated; Loading Loading @@ -886,9 +893,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources, mDisplayDeviceConfig); } mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper; if (mCurrentBrightnessMapper != null) { if (mInteractiveModeBrightnessMapper != null) { final float dozeScaleFactor = resources.getFraction( com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor, 1, 1); Loading Loading @@ -939,12 +945,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.stop(); } mAutomaticBrightnessController = new AutomaticBrightnessController(this, handler.getLooper(), mSensorManager, mLightSensor, mCurrentBrightnessMapper, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, mContext, mHbmController); handler.getLooper(), mSensorManager, mLightSensor, mInteractiveModeBrightnessMapper, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, mContext, mHbmController, mIdleModeBrightnessMapper); } else { mUseSoftwareAutoBrightnessConfig = false; } Loading Loading @@ -974,6 +981,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } public void setAutomaticScreenBrightnessMode(boolean isIdle) { if (mAutomaticBrightnessController != null) { if (isIdle) { mAutomaticBrightnessController.switchToIdleMode(); } else { mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode(); } } } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Loading Loading @@ -1422,7 +1439,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } if (!brightnessIsTemporary) { // Report brightness to brightnesstracker: // If brightness is not temporary (ie the slider has been released) // AND if we are not in idle screen brightness mode. if (!brightnessIsTemporary && (mAutomaticBrightnessController != null && !mAutomaticBrightnessController.isInIdleMode())) { if (userInitiatedChange && (mAutomaticBrightnessController == null || !mAutomaticBrightnessController.hasValidAmbientLux())) { // If we don't have a valid lux reading we can't report a valid Loading Loading @@ -2162,11 +2184,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private float convertToNits(float brightness) { if (mCurrentBrightnessMapper != null) { return mCurrentBrightnessMapper.convertToNits(brightness); } else { return -1.0f; if (mAutomaticBrightnessController == null) { return -1f; } return mAutomaticBrightnessController.convertToNits(brightness); } private void updatePendingProximityRequestsLocked() { Loading Loading @@ -2315,11 +2336,6 @@ 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()); Loading services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +44 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyFloat; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.content.Context; Loading Loading @@ -63,6 +65,7 @@ public class AutomaticBrightnessControllerTest { @Mock SensorManager mSensorManager; @Mock BrightnessMappingStrategy mBrightnessMappingStrategy; @Mock BrightnessMappingStrategy mIdleBrightnessMappingStrategy; @Mock HysteresisLevels mAmbientBrightnessThresholds; @Mock HysteresisLevels mScreenBrightnessThresholds; @Mock Handler mNoOpHandler; Loading Loading @@ -100,7 +103,7 @@ public class AutomaticBrightnessControllerTest { INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext, mHbmController mContext, mHbmController, mIdleBrightnessMappingStrategy ); when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT); Loading Loading @@ -231,4 +234,44 @@ public class AutomaticBrightnessControllerTest { // There should be a user data point added to the mapper. verify(mBrightnessMappingStrategy).addUserDataPoint(1000f, 0.5f); } @Test public void testSwitchToIdleMappingStrategy() throws Exception { Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); mController = setupController(lightSensor); ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor), eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); SensorEventListener listener = listenerCaptor.getValue(); // Sensor reads 1000 lux, listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000)); // User sets brightness to 100 mController.configure(true /* enable */, null /* configuration */, 0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); // There should be a user data point added to the mapper. verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f); verify(mBrightnessMappingStrategy, times(2)).setBrightnessConfiguration(any()); verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt()); // Now let's do the same for idle mode mController.switchToIdleMode(); // Called once for init, and once when switching verify(mBrightnessMappingStrategy, times(2)).isForIdleMode(); // Ensure, after switching, original BMS is not used anymore verifyNoMoreInteractions(mBrightnessMappingStrategy); // User sets idle brightness to 0.5 mController.configure(true /* enable */, null /* configuration */, 0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); // Ensure we use the correct mapping strategy verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f); } } Loading
services/core/java/com/android/server/display/AutomaticBrightnessController.java +98 −23 Original line number Diff line number Diff line Loading @@ -87,7 +87,10 @@ class AutomaticBrightnessController { private final Sensor mLightSensor; // The mapper to translate ambient lux to screen brightness in the range [0, 1.0]. private final BrightnessMappingStrategy mBrightnessMapper; @Nullable private BrightnessMappingStrategy mCurrentBrightnessMapper; private final BrightnessMappingStrategy mInteractiveModeBrightnessMapper; private final BrightnessMappingStrategy mIdleModeBrightnessMapper; // The minimum and maximum screen brightnesses. private final float mScreenBrightnessRangeMinimum; Loading Loading @@ -215,36 +218,41 @@ class AutomaticBrightnessController { private final Injector mInjector; AutomaticBrightnessController(Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy interactiveModeBrightnessMapper, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, Context context, HighBrightnessModeController hbmController) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper, HighBrightnessModeController hbmController, BrightnessMappingStrategy idleModeBrightnessMapper) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, interactiveModeBrightnessMapper, lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig, darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, screenBrightnessThresholds, context, hbmController hbmController, idleModeBrightnessMapper ); } @VisibleForTesting AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper, SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy interactiveModeBrightnessMapper, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, Context context, HighBrightnessModeController hbmController) { HighBrightnessModeController hbmController, BrightnessMappingStrategy idleModeBrightnessMapper) { mInjector = injector; mContext = context; mCallbacks = callbacks; mSensorManager = sensorManager; mBrightnessMapper = mapper; mCurrentBrightnessMapper = interactiveModeBrightnessMapper; mScreenBrightnessRangeMinimum = brightnessMin; mScreenBrightnessRangeMaximum = brightnessMax; mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime; Loading Loading @@ -277,6 +285,10 @@ class AutomaticBrightnessController { mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; mHbmController = hbmController; mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper; mIdleModeBrightnessMapper = idleModeBrightnessMapper; // Initialize to active (normal) screen brightness mode switchToInteractiveScreenBrightnessMode(); } /** Loading @@ -291,7 +303,12 @@ class AutomaticBrightnessController { if (mLoggingEnabled == loggingEnabled) { return false; } mBrightnessMapper.setLoggingEnabled(loggingEnabled); if (mInteractiveModeBrightnessMapper != null) { mInteractiveModeBrightnessMapper.setLoggingEnabled(loggingEnabled); } if (mIdleModeBrightnessMapper != null) { mIdleModeBrightnessMapper.setLoggingEnabled(loggingEnabled); } mLoggingEnabled = loggingEnabled; return true; } Loading @@ -311,7 +328,7 @@ class AutomaticBrightnessController { } public float getAutomaticScreenBrightnessAdjustment() { return mBrightnessMapper.getAutoBrightnessAdjustment(); return mCurrentBrightnessMapper.getAutoBrightnessAdjustment(); } public void configure(boolean enable, @Nullable BrightnessConfiguration configuration, Loading Loading @@ -350,15 +367,20 @@ class AutomaticBrightnessController { } public boolean hasUserDataPoints() { return mBrightnessMapper.hasUserDataPoints(); return mCurrentBrightnessMapper.hasUserDataPoints(); } // Used internally to establish whether we have deviated from the default config. public boolean isDefaultConfig() { return mBrightnessMapper.isDefaultConfig(); if (isInIdleMode()) { return false; } return mInteractiveModeBrightnessMapper.isDefaultConfig(); } // Called from APIs to get the configuration. public BrightnessConfiguration getDefaultConfig() { return mBrightnessMapper.getDefaultConfig(); return mInteractiveModeBrightnessMapper.getDefaultConfig(); } /** Loading @@ -379,7 +401,7 @@ class AutomaticBrightnessController { } if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL, mBrightnessMapper.getShortTermModelTimeout()); mCurrentBrightnessMapper.getShortTermModelTimeout()); } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL); } Loading @@ -398,7 +420,7 @@ class AutomaticBrightnessController { // and we can't use this data to add a new control point to the short-term model. return false; } mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); mCurrentBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); mShortTermModelValid = true; mShortTermModelAnchor = mAmbientLux; if (mLoggingEnabled) { Loading @@ -408,7 +430,7 @@ class AutomaticBrightnessController { } public void resetShortTermModel() { mBrightnessMapper.clearUserDataPoints(); mCurrentBrightnessMapper.clearUserDataPoints(); mShortTermModelValid = true; mShortTermModelAnchor = -1; } Loading @@ -421,13 +443,19 @@ class AutomaticBrightnessController { } public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) { if (mBrightnessMapper.setBrightnessConfiguration(configuration)) { if (mInteractiveModeBrightnessMapper.setBrightnessConfiguration(configuration)) { if (!isInIdleMode()) { resetShortTermModel(); } return true; } return false; } public boolean isInIdleMode() { return mCurrentBrightnessMapper.isForIdleMode(); } public void dump(PrintWriter pw) { pw.println(); pw.println("Automatic Brightness Controller Configuration:"); Loading Loading @@ -461,7 +489,12 @@ class AutomaticBrightnessController { pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer); pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy)); pw.println(" mShortTermModelTimeout=" + mBrightnessMapper.getShortTermModelTimeout()); pw.println(" mShortTermModelTimeout(active)=" + mInteractiveModeBrightnessMapper.getShortTermModelTimeout()); if (mIdleModeBrightnessMapper != null) { pw.println(" mShortTermModelTimeout(idle)=" + mIdleModeBrightnessMapper.getShortTermModelTimeout()); } pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor); pw.println(" mShortTermModelValid=" + mShortTermModelValid); pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending); Loading @@ -472,9 +505,15 @@ class AutomaticBrightnessController { pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName); pw.println(" mForegroundAppCategory=" + mForegroundAppCategory); pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory); pw.println(" Idle mode active=" + mCurrentBrightnessMapper.isForIdleMode()); pw.println(); mBrightnessMapper.dump(pw); pw.println(" mActiveMapper="); mInteractiveModeBrightnessMapper.dump(pw); if (mIdleModeBrightnessMapper != null) { pw.println(" mIdleMapper="); mIdleModeBrightnessMapper.dump(pw); } pw.println(); mAmbientBrightnessThresholds.dump(pw); Loading Loading @@ -544,7 +583,7 @@ class AutomaticBrightnessController { } private boolean setAutoBrightnessAdjustment(float adjustment) { return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment); return mCurrentBrightnessMapper.setAutoBrightnessAdjustment(adjustment); } private void setAmbientLux(float lux) { Loading @@ -562,7 +601,8 @@ class AutomaticBrightnessController { // If the short term model was invalidated and the change is drastic enough, reset it. if (!mShortTermModelValid && mShortTermModelAnchor != -1) { if (mBrightnessMapper.shouldResetShortTermModel(mAmbientLux, mShortTermModelAnchor)) { if (mCurrentBrightnessMapper.shouldResetShortTermModel( mAmbientLux, mShortTermModelAnchor)) { resetShortTermModel(); } else { mShortTermModelValid = true; Loading Loading @@ -743,7 +783,7 @@ class AutomaticBrightnessController { return; } float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, float value = mCurrentBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, mForegroundAppCategory); float newScreenAutoBrightness = clampScreenBrightness(value); Loading Loading @@ -909,6 +949,41 @@ class AutomaticBrightnessController { updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */); } void switchToIdleMode() { if (mIdleModeBrightnessMapper == null) { return; } if (mCurrentBrightnessMapper.isForIdleMode()) { return; } Slog.i(TAG, "Switching to Idle Screen Brightness Mode"); mCurrentBrightnessMapper = mIdleModeBrightnessMapper; resetShortTermModel(); update(); } void switchToInteractiveScreenBrightnessMode() { if (!mCurrentBrightnessMapper.isForIdleMode()) { return; } Slog.i(TAG, "Switching to Interactive Screen Brightness Mode"); mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper; resetShortTermModel(); update(); } public float convertToNits(float brightness) { if (mCurrentBrightnessMapper != null) { return mCurrentBrightnessMapper.convertToNits(brightness); } else { return -1.0f; } } public void recalculateSplines(boolean applyAdjustment, float[] adjustment) { mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment); } private final class AutomaticBrightnessHandler extends Handler { public AutomaticBrightnessHandler(Looper looper) { super(looper, null, true /*async*/); Loading
services/core/java/com/android/server/display/BrightnessMappingStrategy.java +20 −2 Original line number Diff line number Diff line Loading @@ -135,7 +135,7 @@ public abstract class BrightnessMappingStrategy { builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange, autoBrightnessAdjustmentMaxGamma); autoBrightnessAdjustmentMaxGamma, isForIdleMode); } else if (isValidMapping(luxLevels, brightnessLevelsBacklight) && !isForIdleMode) { return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight, autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout); Loading Loading @@ -354,6 +354,12 @@ public abstract class BrightnessMappingStrategy { public abstract void dump(PrintWriter pw); /** * We can designate a mapping strategy to be used for idle screen brightness mode. * @return whether this mapping strategy is to be used for idle screen brightness mode. */ public abstract boolean isForIdleMode(); /** * Check if the short term model should be reset given the anchor lux the last * brightness change was made at and the current ambient lux. Loading Loading @@ -711,6 +717,11 @@ public abstract class BrightnessMappingStrategy { pw.println(" mUserBrightness=" + mUserBrightness); } @Override public boolean isForIdleMode() { return false; } private void computeSpline() { Pair<float[], float[]> curve = getAdjustedCurve(mLux, mBrightness, mUserLux, mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma); Loading Loading @@ -758,9 +769,10 @@ public abstract class BrightnessMappingStrategy { private float mAutoBrightnessAdjustment; private float mUserLux; private float mUserBrightness; private final boolean mIsForIdleMode; public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits, float[] brightness, float maxGamma) { float[] brightness, float maxGamma, boolean isForIdleMode) { Preconditions.checkArgument(nits.length != 0 && brightness.length != 0, "Nits and brightness arrays must not be empty!"); Loading @@ -772,6 +784,7 @@ public abstract class BrightnessMappingStrategy { Preconditions.checkArrayElementsInRange(brightness, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, "brightness"); mIsForIdleMode = isForIdleMode; mMaxGamma = maxGamma; mAutoBrightnessAdjustment = 0; mUserLux = -1; Loading Loading @@ -933,6 +946,11 @@ public abstract class BrightnessMappingStrategy { pw.println(" mBrightnessRangeAdjustmentApplied=" + mBrightnessRangeAdjustmentApplied); } @Override public boolean isForIdleMode() { return mIsForIdleMode; } private void computeNitsBrightnessSplines(float[] nits) { mNitsToBrightnessSpline = Spline.createSpline(nits, mBrightness); mBrightnessToNitsSpline = Spline.createSpline(mBrightness, nits); Loading
services/core/java/com/android/server/display/DisplayPowerController.java +44 −28 Original line number Diff line number Diff line Loading @@ -386,12 +386,8 @@ 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 mCurrentBrightnessMapper; // The mappers between ambient lux, display backlight values, and display brightness. // We will switch between the idle mapper and active mapper in AutomaticBrightnessController. // Mapper used for active (normal) screen brightness mode @Nullable private BrightnessMappingStrategy mInteractiveModeBrightnessMapper; Loading @@ -399,6 +395,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Nullable private BrightnessMappingStrategy mIdleModeBrightnessMapper; // If these are both true, and mIdleModeBrightnessMapper != null, // then we are in idle screen brightness mode. private boolean mIsDreaming; private boolean mIsDocked; // The current brightness configuration. @Nullable private BrightnessConfiguration mBrightnessConfiguration; Loading Loading @@ -610,8 +611,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void handleRbcChanged(boolean strengthChanged, boolean justActivated) { if (mCurrentBrightnessMapper == null) { Log.w(TAG, "No brightness mapping available to recalculate splines"); if (mAutomaticBrightnessController == null) { return; } if ((!mAutomaticBrightnessController.isInIdleMode() && mInteractiveModeBrightnessMapper == null) || (mAutomaticBrightnessController.isInIdleMode() && mIdleModeBrightnessMapper == null)) { Log.w(TAG, "No brightness mapping available to recalculate splines for this mode"); return; } Loading @@ -619,7 +626,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call for (int i = 0; i < mNitsRange.length; i++) { adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]); } mCurrentBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits); mPendingRbcOnOrChanged = strengthChanged || justActivated; Loading Loading @@ -886,9 +893,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources, mDisplayDeviceConfig); } mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper; if (mCurrentBrightnessMapper != null) { if (mInteractiveModeBrightnessMapper != null) { final float dozeScaleFactor = resources.getFraction( com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor, 1, 1); Loading Loading @@ -939,12 +945,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.stop(); } mAutomaticBrightnessController = new AutomaticBrightnessController(this, handler.getLooper(), mSensorManager, mLightSensor, mCurrentBrightnessMapper, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, mContext, mHbmController); handler.getLooper(), mSensorManager, mLightSensor, mInteractiveModeBrightnessMapper, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, screenBrightnessThresholds, mContext, mHbmController, mIdleModeBrightnessMapper); } else { mUseSoftwareAutoBrightnessConfig = false; } Loading Loading @@ -974,6 +981,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } public void setAutomaticScreenBrightnessMode(boolean isIdle) { if (mAutomaticBrightnessController != null) { if (isIdle) { mAutomaticBrightnessController.switchToIdleMode(); } else { mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode(); } } } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { Loading Loading @@ -1422,7 +1439,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } if (!brightnessIsTemporary) { // Report brightness to brightnesstracker: // If brightness is not temporary (ie the slider has been released) // AND if we are not in idle screen brightness mode. if (!brightnessIsTemporary && (mAutomaticBrightnessController != null && !mAutomaticBrightnessController.isInIdleMode())) { if (userInitiatedChange && (mAutomaticBrightnessController == null || !mAutomaticBrightnessController.hasValidAmbientLux())) { // If we don't have a valid lux reading we can't report a valid Loading Loading @@ -2162,11 +2184,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private float convertToNits(float brightness) { if (mCurrentBrightnessMapper != null) { return mCurrentBrightnessMapper.convertToNits(brightness); } else { return -1.0f; if (mAutomaticBrightnessController == null) { return -1f; } return mAutomaticBrightnessController.convertToNits(brightness); } private void updatePendingProximityRequestsLocked() { Loading Loading @@ -2315,11 +2336,6 @@ 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()); Loading
services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +44 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyFloat; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.content.Context; Loading Loading @@ -63,6 +65,7 @@ public class AutomaticBrightnessControllerTest { @Mock SensorManager mSensorManager; @Mock BrightnessMappingStrategy mBrightnessMappingStrategy; @Mock BrightnessMappingStrategy mIdleBrightnessMappingStrategy; @Mock HysteresisLevels mAmbientBrightnessThresholds; @Mock HysteresisLevels mScreenBrightnessThresholds; @Mock Handler mNoOpHandler; Loading Loading @@ -100,7 +103,7 @@ public class AutomaticBrightnessControllerTest { INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext, mHbmController mContext, mHbmController, mIdleBrightnessMappingStrategy ); when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT); Loading Loading @@ -231,4 +234,44 @@ public class AutomaticBrightnessControllerTest { // There should be a user data point added to the mapper. verify(mBrightnessMappingStrategy).addUserDataPoint(1000f, 0.5f); } @Test public void testSwitchToIdleMappingStrategy() throws Exception { Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); mController = setupController(lightSensor); ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor), eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); SensorEventListener listener = listenerCaptor.getValue(); // Sensor reads 1000 lux, listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000)); // User sets brightness to 100 mController.configure(true /* enable */, null /* configuration */, 0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); // There should be a user data point added to the mapper. verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f); verify(mBrightnessMappingStrategy, times(2)).setBrightnessConfiguration(any()); verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt()); // Now let's do the same for idle mode mController.switchToIdleMode(); // Called once for init, and once when switching verify(mBrightnessMappingStrategy, times(2)).isForIdleMode(); // Ensure, after switching, original BMS is not used anymore verifyNoMoreInteractions(mBrightnessMappingStrategy); // User sets idle brightness to 0.5 mController.configure(true /* enable */, null /* configuration */, 0.5f /* brightness */, true /* userChangedBrightness */, 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT); // Ensure we use the correct mapping strategy verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f); } }