Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3eb4dbc9 authored by Fiona Campbell's avatar Fiona Campbell Committed by Android (Google) Code Review
Browse files

Merge "Switch brightnessmapper within ABC"

parents ba5ad704 04c683b5
Loading
Loading
Loading
Loading
+98 −23
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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();
    }

    /**
@@ -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;
    }
@@ -311,7 +328,7 @@ class AutomaticBrightnessController {
    }

    public float getAutomaticScreenBrightnessAdjustment() {
        return mBrightnessMapper.getAutoBrightnessAdjustment();
        return mCurrentBrightnessMapper.getAutoBrightnessAdjustment();
    }

    public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
@@ -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();
    }

    /**
@@ -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);
        }
@@ -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) {
@@ -408,7 +430,7 @@ class AutomaticBrightnessController {
    }

    public void resetShortTermModel() {
        mBrightnessMapper.clearUserDataPoints();
        mCurrentBrightnessMapper.clearUserDataPoints();
        mShortTermModelValid = true;
        mShortTermModelAnchor = -1;
    }
@@ -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:");
@@ -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);
@@ -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);
@@ -544,7 +583,7 @@ class AutomaticBrightnessController {
    }

    private boolean setAutoBrightnessAdjustment(float adjustment) {
        return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
        return mCurrentBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
    }

    private void setAmbientLux(float lux) {
@@ -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;
@@ -743,7 +783,7 @@ class AutomaticBrightnessController {
            return;
        }

        float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
        float value = mCurrentBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
                mForegroundAppCategory);
        float newScreenAutoBrightness = clampScreenBrightness(value);

@@ -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*/);
+20 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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.
@@ -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);
@@ -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!");
@@ -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;
@@ -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);
+44 −28
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
        }

@@ -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;
@@ -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);
@@ -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;
        }
@@ -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) {
@@ -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
@@ -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() {
@@ -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());
+44 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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);
    }
}