1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.display; 18 19 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED; 20 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; 21 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; 22 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; 23 24 import static org.junit.Assert.assertArrayEquals; 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.any; 29 import static org.mockito.Mockito.anyFloat; 30 import static org.mockito.Mockito.anyInt; 31 import static org.mockito.Mockito.clearInvocations; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.verifyNoMoreInteractions; 36 import static org.mockito.Mockito.when; 37 38 import android.content.Context; 39 import android.content.pm.ApplicationInfo; 40 import android.hardware.Sensor; 41 import android.hardware.SensorEventListener; 42 import android.hardware.SensorManager; 43 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; 44 import android.os.Handler; 45 import android.os.PowerManager; 46 import android.os.SystemClock; 47 import android.os.test.TestLooper; 48 import android.util.SparseArray; 49 import android.view.Display; 50 51 import androidx.test.InstrumentationRegistry; 52 import androidx.test.filters.SmallTest; 53 import androidx.test.runner.AndroidJUnit4; 54 55 import com.android.server.display.brightness.clamper.BrightnessClamperController; 56 import com.android.server.display.config.HysteresisLevels; 57 import com.android.server.display.feature.DisplayManagerFlags; 58 import com.android.server.testutils.OffsettableClock; 59 60 import org.junit.After; 61 import org.junit.Before; 62 import org.junit.Test; 63 import org.junit.runner.RunWith; 64 import org.mockito.ArgumentCaptor; 65 import org.mockito.Mock; 66 import org.mockito.Mockito; 67 import org.mockito.MockitoAnnotations; 68 69 @SmallTest 70 @RunWith(AndroidJUnit4.class) 71 public class AutomaticBrightnessControllerTest { 72 private static final int ANDROID_SLEEP_TIME = 1000; 73 private static final int NANO_SECONDS_MULTIPLIER = 1000000; 74 private static final float BRIGHTNESS_MIN_FLOAT = 0.0f; 75 private static final float BRIGHTNESS_MAX_FLOAT = 1.0f; 76 private static final int LIGHT_SENSOR_RATE = 20; 77 private static final int INITIAL_LIGHT_SENSOR_RATE = 20; 78 private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG = 2000; 79 private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 4000; 80 private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG_IDLE = 1000; 81 private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG_IDLE = 2000; 82 private static final float DOZE_SCALE_FACTOR = 0.54f; 83 private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false; 84 private static final int LIGHT_SENSOR_WARMUP_TIME = 0; 85 private static final int AMBIENT_LIGHT_HORIZON_SHORT = 1000; 86 private static final int AMBIENT_LIGHT_HORIZON_LONG = 2000; 87 private static final float EPSILON = 0.001f; 88 private OffsettableClock mClock = new OffsettableClock(); 89 private TestLooper mTestLooper; 90 private Context mContext; 91 private AutomaticBrightnessController mController; 92 private Sensor mLightSensor; 93 94 @Mock SensorManager mSensorManager; 95 @Mock BrightnessMappingStrategy mBrightnessMappingStrategy; 96 @Mock BrightnessMappingStrategy mIdleBrightnessMappingStrategy; 97 @Mock BrightnessMappingStrategy mDozeBrightnessMappingStrategy; 98 @Mock HysteresisLevels mAmbientBrightnessThresholds; 99 @Mock HysteresisLevels mScreenBrightnessThresholds; 100 @Mock HysteresisLevels mAmbientBrightnessThresholdsIdle; 101 @Mock HysteresisLevels mScreenBrightnessThresholdsIdle; 102 @Mock Handler mNoOpHandler; 103 @Mock BrightnessRangeController mBrightnessRangeController; 104 @Mock 105 DisplayManagerFlags mDisplayManagerFlags; 106 @Mock 107 BrightnessClamperController mBrightnessClamperController; 108 109 @Before setUp()110 public void setUp() throws Exception { 111 // Share classloader to allow package private access. 112 System.setProperty("dexmaker.share_classloader", "true"); 113 MockitoAnnotations.initMocks(this); 114 115 mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); 116 mContext = InstrumentationRegistry.getContext(); 117 setupController(BrightnessMappingStrategy.INVALID_LUX, 118 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ false, 119 /* useHorizon= */ true); 120 } 121 122 @After tearDown()123 public void tearDown() { 124 if (mController != null) { 125 // Stop the update Brightness loop. 126 mController.stop(); 127 mController = null; 128 } 129 } 130 setupController(float userLux, float userNits, boolean applyDebounce, boolean useHorizon)131 private void setupController(float userLux, float userNits, boolean applyDebounce, 132 boolean useHorizon) { 133 mClock = new OffsettableClock.Stopped(); 134 mTestLooper = new TestLooper(mClock::now); 135 136 when(mBrightnessMappingStrategy.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_DEFAULT); 137 when(mIdleBrightnessMappingStrategy.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE); 138 when(mDozeBrightnessMappingStrategy.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_DOZE); 139 140 SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap = new SparseArray<>(); 141 brightnessMappingStrategyMap.append(AUTO_BRIGHTNESS_MODE_DEFAULT, 142 mBrightnessMappingStrategy); 143 brightnessMappingStrategyMap.append(AUTO_BRIGHTNESS_MODE_IDLE, 144 mIdleBrightnessMappingStrategy); 145 brightnessMappingStrategyMap.append(AUTO_BRIGHTNESS_MODE_DOZE, 146 mDozeBrightnessMappingStrategy); 147 mController = new AutomaticBrightnessController( 148 new AutomaticBrightnessController.Injector() { 149 @Override 150 public Handler getBackgroundThreadHandler() { 151 return mNoOpHandler; 152 } 153 154 @Override 155 AutomaticBrightnessController.Clock createClock() { 156 return new AutomaticBrightnessController.Clock() { 157 @Override 158 public long uptimeMillis() { 159 return mClock.now(); 160 } 161 162 @Override 163 public long getSensorEventScaleTime() { 164 return mClock.now() + ANDROID_SLEEP_TIME; 165 } 166 }; 167 } 168 169 }, // pass in test looper instead, pass in offsettable clock 170 () -> { }, mTestLooper.getLooper(), mSensorManager, mLightSensor, 171 brightnessMappingStrategyMap, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT, 172 BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, 173 INITIAL_LIGHT_SENSOR_RATE, applyDebounce ? BRIGHTENING_LIGHT_DEBOUNCE_CONFIG : 0, 174 applyDebounce ? DARKENING_LIGHT_DEBOUNCE_CONFIG : 0, 175 applyDebounce ? BRIGHTENING_LIGHT_DEBOUNCE_CONFIG_IDLE : 0, 176 applyDebounce ? DARKENING_LIGHT_DEBOUNCE_CONFIG_IDLE : 0, 177 RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, 178 mAmbientBrightnessThresholds, mScreenBrightnessThresholds, 179 mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle, 180 mContext, mBrightnessRangeController, mBrightnessClamperController, 181 useHorizon ? AMBIENT_LIGHT_HORIZON_SHORT : 1, 182 useHorizon ? AMBIENT_LIGHT_HORIZON_LONG : 10000, userLux, userNits, 183 mDisplayManagerFlags 184 ); 185 186 when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn( 187 BRIGHTNESS_MAX_FLOAT); 188 when(mBrightnessRangeController.getCurrentBrightnessMin()).thenReturn( 189 BRIGHTNESS_MIN_FLOAT); 190 // Disable brightness throttling by default. Individual tests can enable it as needed. 191 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 192 when(mBrightnessClamperController.isThrottled()).thenReturn(false); 193 194 // Configure the brightness controller and grab an instance of the sensor listener, 195 // through which we can deliver fake (for test) sensor values. 196 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 197 0 /* brightness= */, false /* userChangedBrightness= */, 0 /* adjustment= */, 198 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 199 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 200 } 201 202 @Test testNoHysteresisAtMinBrightness()203 public void testNoHysteresisAtMinBrightness() throws Exception { 204 ArgumentCaptor<SensorEventListener> listenerCaptor = 205 ArgumentCaptor.forClass(SensorEventListener.class); 206 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 207 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 208 SensorEventListener listener = listenerCaptor.getValue(); 209 210 // Set up system to return 0.02f as a brightness value 211 float lux1 = 100.0f; 212 // Brightness as float (from 0.0f to 1.0f) 213 float normalizedBrightness1 = 0.02f; 214 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1)) 215 .thenReturn(lux1); 216 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1)) 217 .thenReturn(lux1); 218 when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt())) 219 .thenReturn(normalizedBrightness1); 220 221 // This is the important bit: When the new brightness is set, make sure the new 222 // brightening threshold is beyond the maximum brightness value...so that we can test that 223 // our threshold clamping works. 224 when(mScreenBrightnessThresholds.getBrighteningThreshold(normalizedBrightness1)) 225 .thenReturn(1.0f); 226 227 // Send new sensor value and verify 228 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1)); 229 assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON); 230 231 // Set up system to return 0.0f (minimum possible brightness) as a brightness value 232 float lux2 = 10.0f; 233 float normalizedBrightness2 = 0.0f; 234 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2)) 235 .thenReturn(lux2); 236 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2)) 237 .thenReturn(lux2); 238 when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) 239 .thenReturn(normalizedBrightness2); 240 241 // Send new sensor value and verify 242 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2)); 243 assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON); 244 } 245 246 @Test testNoHysteresisAtMaxBrightness()247 public void testNoHysteresisAtMaxBrightness() throws Exception { 248 ArgumentCaptor<SensorEventListener> listenerCaptor = 249 ArgumentCaptor.forClass(SensorEventListener.class); 250 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 251 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 252 SensorEventListener listener = listenerCaptor.getValue(); 253 254 // Set up system to return 0.98f as a brightness value 255 float lux1 = 100.0f; 256 float normalizedBrightness1 = 0.98f; 257 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1)) 258 .thenReturn(lux1); 259 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1)) 260 .thenReturn(lux1); 261 when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt())) 262 .thenReturn(normalizedBrightness1); 263 264 // This is the important bit: When the new brightness is set, make sure the new 265 // brightening threshold is beyond the maximum brightness value...so that we can test that 266 // our threshold clamping works. 267 when(mScreenBrightnessThresholds.getBrighteningThreshold(normalizedBrightness1)) 268 .thenReturn(1.1f); 269 270 // Send new sensor value and verify 271 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1)); 272 assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON); 273 274 275 // Set up system to return 1.0f as a brightness value (brightness_max) 276 float lux2 = 110.0f; 277 float normalizedBrightness2 = 1.0f; 278 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2)) 279 .thenReturn(lux2); 280 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2)) 281 .thenReturn(lux2); 282 when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt())) 283 .thenReturn(normalizedBrightness2); 284 285 // Send new sensor value and verify 286 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2)); 287 assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON); 288 } 289 290 @Test testUserAddUserDataPoint()291 public void testUserAddUserDataPoint() throws Exception { 292 ArgumentCaptor<SensorEventListener> listenerCaptor = 293 ArgumentCaptor.forClass(SensorEventListener.class); 294 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 295 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 296 SensorEventListener listener = listenerCaptor.getValue(); 297 298 // Sensor reads 1000 lux, 299 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 300 301 // User sets brightness to 100 302 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 303 0.5f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */, 304 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 305 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 306 307 // There should be a user data point added to the mapper. 308 verify(mBrightnessMappingStrategy).addUserDataPoint(/* lux= */ 1000f, 309 /* brightness= */ 0.5f); 310 } 311 312 @Test testRecalculateSplines()313 public void testRecalculateSplines() throws Exception { 314 // Enabling the light sensor, and setting the ambient lux to 1000 315 int currentLux = 1000; 316 ArgumentCaptor<SensorEventListener> listenerCaptor = 317 ArgumentCaptor.forClass(SensorEventListener.class); 318 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 319 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 320 SensorEventListener listener = listenerCaptor.getValue(); 321 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, currentLux)); 322 323 // User sets brightness to 0.5f 324 when(mBrightnessMappingStrategy.getBrightness(currentLux, 325 null, ApplicationInfo.CATEGORY_UNDEFINED)).thenReturn(0.5f); 326 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 327 0.5f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */, 328 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 329 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 330 331 //Recalculating the spline with RBC enabled, verifying that the short term model is reset, 332 //and the interaction is learnt in short term model 333 float[] adjustments = new float[]{0.2f, 0.6f}; 334 mController.recalculateSplines(true, adjustments); 335 verify(mBrightnessMappingStrategy).clearUserDataPoints(); 336 verify(mBrightnessMappingStrategy).recalculateSplines(true, adjustments); 337 verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux, 338 /* brightness= */ 0.5f); 339 340 clearInvocations(mBrightnessMappingStrategy); 341 342 // Verify short term model is not learnt when RBC is disabled 343 mController.recalculateSplines(false, adjustments); 344 verify(mBrightnessMappingStrategy).clearUserDataPoints(); 345 verify(mBrightnessMappingStrategy).recalculateSplines(false, adjustments); 346 verifyNoMoreInteractions(mBrightnessMappingStrategy); 347 } 348 349 @Test testShortTermModelTimesOut()350 public void testShortTermModelTimesOut() throws Exception { 351 ArgumentCaptor<SensorEventListener> listenerCaptor = 352 ArgumentCaptor.forClass(SensorEventListener.class); 353 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 354 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 355 SensorEventListener listener = listenerCaptor.getValue(); 356 357 // Sensor reads 123 lux, 358 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123)); 359 // User sets brightness to 100 360 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 361 /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0, 362 /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 363 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 364 365 when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L); 366 367 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 368 when(mBrightnessMappingStrategy.shouldResetShortTermModel( 369 123f, 0.5f)).thenReturn(true); 370 371 // Sensor reads 1000 lux, 372 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 373 mTestLooper.moveTimeForward( 374 mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000); 375 mTestLooper.dispatchAll(); 376 377 mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true); 378 mTestLooper.moveTimeForward(4000); 379 mTestLooper.dispatchAll(); 380 381 // Verify only happens on the first configure. (i.e. not again when switching back) 382 // Intentionally using any() to ensure it's not called whatsoever. 383 verify(mBrightnessMappingStrategy, times(1)) 384 .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f); 385 verify(mBrightnessMappingStrategy, times(1)) 386 .addUserDataPoint(anyFloat(), anyFloat()); 387 } 388 389 @Test testShortTermModelDoesntTimeOut()390 public void testShortTermModelDoesntTimeOut() throws Exception { 391 ArgumentCaptor<SensorEventListener> listenerCaptor = 392 ArgumentCaptor.forClass(SensorEventListener.class); 393 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 394 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 395 SensorEventListener listener = listenerCaptor.getValue(); 396 397 // Sensor reads 123 lux, 398 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123)); 399 // User sets brightness to 100 400 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 401 0.51f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */, 402 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 403 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 404 405 when(mBrightnessMappingStrategy.shouldResetShortTermModel( 406 anyFloat(), anyFloat())).thenReturn(true); 407 when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L); 408 when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.51f); 409 when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123.0f); 410 411 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 412 413 // Time does not move forward, since clock is doesn't increment naturally. 414 mTestLooper.dispatchAll(); 415 416 // Sensor reads 100000 lux, 417 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 678910)); 418 mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true); 419 420 // Verify short term model is not reset. 421 verify(mBrightnessMappingStrategy, never()).clearUserDataPoints(); 422 423 // Verify that we add the data point once when the user sets it, and again when we return 424 // interactive mode. 425 verify(mBrightnessMappingStrategy, times(2)) 426 .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.51f); 427 } 428 429 @Test testShortTermModelIsRestoredWhenSwitchingWithinTimeout()430 public void testShortTermModelIsRestoredWhenSwitchingWithinTimeout() throws Exception { 431 ArgumentCaptor<SensorEventListener> listenerCaptor = 432 ArgumentCaptor.forClass(SensorEventListener.class); 433 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 434 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 435 SensorEventListener listener = listenerCaptor.getValue(); 436 437 // Sensor reads 123 lux, 438 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123)); 439 // User sets brightness to 100 440 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 441 /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0, 442 /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 443 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 444 445 when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L); 446 when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f); 447 when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f); 448 449 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 450 when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn( 451 PowerManager.BRIGHTNESS_INVALID_FLOAT); 452 when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn( 453 BrightnessMappingStrategy.INVALID_LUX); 454 when(mBrightnessMappingStrategy.shouldResetShortTermModel( 455 123f, 0.5f)).thenReturn(true); 456 457 // Sensor reads 1000 lux, 458 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 459 mTestLooper.moveTimeForward( 460 mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000); 461 mTestLooper.dispatchAll(); 462 463 mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true); 464 mTestLooper.moveTimeForward(4000); 465 mTestLooper.dispatchAll(); 466 467 // Verify only happens on the first configure. (i.e. not again when switching back) 468 // Intentionally using any() to ensure it's not called whatsoever. 469 verify(mBrightnessMappingStrategy, times(1)) 470 .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f); 471 verify(mBrightnessMappingStrategy, times(1)) 472 .addUserDataPoint(anyFloat(), anyFloat()); 473 } 474 475 @Test testShortTermModelNotRestoredAfterTimeout()476 public void testShortTermModelNotRestoredAfterTimeout() throws Exception { 477 ArgumentCaptor<SensorEventListener> listenerCaptor = 478 ArgumentCaptor.forClass(SensorEventListener.class); 479 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 480 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 481 SensorEventListener listener = listenerCaptor.getValue(); 482 483 // Sensor reads 123 lux, 484 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123)); 485 // User sets brightness to 100 486 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 487 /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0, 488 /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 489 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 490 491 when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L); 492 493 when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f); 494 when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f); 495 496 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 497 when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn( 498 PowerManager.BRIGHTNESS_INVALID_FLOAT); 499 when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn( 500 BrightnessMappingStrategy.INVALID_LUX); 501 502 when(mBrightnessMappingStrategy.shouldResetShortTermModel( 503 123f, 0.5f)).thenReturn(true); 504 505 // Sensor reads 1000 lux, 506 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 507 // Do not fast-forward time. 508 mTestLooper.dispatchAll(); 509 510 mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true); 511 // Do not fast-forward time 512 mTestLooper.dispatchAll(); 513 514 // Verify this happens on the first configure and again when switching back 515 // Intentionally using any() to ensure it's not called any other times whatsoever. 516 verify(mBrightnessMappingStrategy, times(2)) 517 .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f); 518 verify(mBrightnessMappingStrategy, times(2)) 519 .addUserDataPoint(anyFloat(), anyFloat()); 520 } 521 522 @Test testSwitchBetweenModesNoUserInteractions()523 public void testSwitchBetweenModesNoUserInteractions() throws Exception { 524 ArgumentCaptor<SensorEventListener> listenerCaptor = 525 ArgumentCaptor.forClass(SensorEventListener.class); 526 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 527 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 528 SensorEventListener listener = listenerCaptor.getValue(); 529 530 // Sensor reads 123 lux, 531 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123)); 532 when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L); 533 when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn( 534 PowerManager.BRIGHTNESS_INVALID_FLOAT); 535 when(mBrightnessMappingStrategy.getUserLux()).thenReturn( 536 BrightnessMappingStrategy.INVALID_LUX); 537 538 // No user brightness interaction. 539 540 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 541 when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn( 542 PowerManager.BRIGHTNESS_INVALID_FLOAT); 543 when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn( 544 BrightnessMappingStrategy.INVALID_LUX); 545 546 // Sensor reads 1000 lux, 547 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 548 // Do not fast-forward time. 549 mTestLooper.dispatchAll(); 550 551 mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true); 552 // Do not fast-forward time 553 mTestLooper.dispatchAll(); 554 555 // Ensure that there are no data points added, since the user has never adjusted the 556 // brightness 557 verify(mBrightnessMappingStrategy, times(0)) 558 .addUserDataPoint(anyFloat(), anyFloat()); 559 } 560 561 @Test testSwitchToIdleMappingStrategy()562 public void testSwitchToIdleMappingStrategy() throws Exception { 563 ArgumentCaptor<SensorEventListener> listenerCaptor = 564 ArgumentCaptor.forClass(SensorEventListener.class); 565 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 566 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 567 SensorEventListener listener = listenerCaptor.getValue(); 568 569 // Sensor reads 1000 lux, 570 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000)); 571 572 // User sets brightness to 100 573 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 574 0.5f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */, 575 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 576 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 577 578 // There should be a user data point added to the mapper. 579 verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f, 580 /* brightness= */ 0.5f); 581 verify(mBrightnessMappingStrategy, times(2)).setBrightnessConfiguration(any()); 582 verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt()); 583 584 // Now let's do the same for idle mode 585 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 586 // Called once when switching, 587 // setAmbientLux() is called twice and once in updateAutoBrightness(), 588 // nextAmbientLightBrighteningTransition() and nextAmbientLightDarkeningTransition() are 589 // called twice each. 590 verify(mBrightnessMappingStrategy, times(8)).getMode(); 591 // Called when switching. 592 verify(mBrightnessMappingStrategy, times(1)).getShortTermModelTimeout(); 593 verify(mBrightnessMappingStrategy, times(1)).getUserBrightness(); 594 verify(mBrightnessMappingStrategy, times(1)).getUserLux(); 595 596 // Ensure, after switching, original BMS is not used anymore 597 verifyNoMoreInteractions(mBrightnessMappingStrategy); 598 599 // User sets idle brightness to 0.5 600 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 601 0.5f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */, 602 false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON, 603 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 604 605 // Ensure we use the correct mapping strategy 606 verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f, 607 /* brightness= */ 0.5f); 608 } 609 610 @Test testAmbientLightHorizon()611 public void testAmbientLightHorizon() throws Exception { 612 ArgumentCaptor<SensorEventListener> listenerCaptor = 613 ArgumentCaptor.forClass(SensorEventListener.class); 614 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 615 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 616 SensorEventListener listener = listenerCaptor.getValue(); 617 618 long increment = 500; 619 // set autobrightness to low 620 // t = 0 621 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 622 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 623 624 // t = 500 625 mClock.fastForward(increment); 626 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 627 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 628 629 // t = 1000 630 mClock.fastForward(increment); 631 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 632 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 633 assertEquals(0.0f, mController.getAmbientLux(), EPSILON); 634 635 // t = 1500 636 mClock.fastForward(increment); 637 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 638 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 639 assertEquals(0.0f, mController.getAmbientLux(), EPSILON); 640 641 // t = 2000 642 // ensure that our reading is at 0. 643 mClock.fastForward(increment); 644 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 645 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 646 assertEquals(0.0f, mController.getAmbientLux(), EPSILON); 647 648 // t = 2500 649 // first 10000 lux sensor event reading 650 mClock.fastForward(increment); 651 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, 652 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 653 assertTrue(mController.getAmbientLux() > 0.0f); 654 assertTrue(mController.getAmbientLux() < 10000.0f); 655 656 // t = 3000 657 // lux reading should still not yet be 10000. 658 mClock.fastForward(increment); 659 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, 660 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 661 assertTrue(mController.getAmbientLux() > 0.0f); 662 assertTrue(mController.getAmbientLux() < 10000.0f); 663 664 // t = 3500 665 mClock.fastForward(increment); 666 // lux has been high (10000) for 1000ms. 667 // lux reading should be 10000 668 // short horizon (ambient lux) is high, long horizon is still not high 669 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, 670 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 671 assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); 672 673 // t = 4000 674 // stay high 675 mClock.fastForward(increment); 676 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, 677 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 678 assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); 679 680 // t = 4500 681 Mockito.clearInvocations(mBrightnessMappingStrategy); 682 mClock.fastForward(increment); 683 // short horizon is high, long horizon is high too 684 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, 685 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 686 verify(mBrightnessMappingStrategy, times(1)).getBrightness(10000, null, -1); 687 assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); 688 689 // t = 5000 690 mClock.fastForward(increment); 691 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 692 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 693 assertTrue(mController.getAmbientLux() > 0.0f); 694 assertTrue(mController.getAmbientLux() < 10000.0f); 695 696 // t = 5500 697 mClock.fastForward(increment); 698 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 699 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 700 assertTrue(mController.getAmbientLux() > 0.0f); 701 assertTrue(mController.getAmbientLux() < 10000.0f); 702 703 // t = 6000 704 mClock.fastForward(increment); 705 // ambient lux goes to 0 706 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, 707 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 708 assertEquals(0.0f, mController.getAmbientLux(), EPSILON); 709 710 // only the values within the horizon should be kept 711 assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(), 712 EPSILON); 713 assertArrayEquals(new long[]{4000 + ANDROID_SLEEP_TIME, 4500 + ANDROID_SLEEP_TIME, 714 5000 + ANDROID_SLEEP_TIME, 5500 + ANDROID_SLEEP_TIME, 715 6000 + ANDROID_SLEEP_TIME}, 716 mController.getLastSensorTimestamps()); 717 } 718 719 @Test 720 public void testHysteresisLevels() { 721 float[] ambientBrighteningThresholds = {50, 100}; 722 float[] ambientDarkeningThresholds = {10, 20}; 723 float[] ambientThresholdLevels = {0, 500}; 724 float ambientDarkeningMinChangeThreshold = 3.0f; 725 float ambientBrighteningMinChangeThreshold = 1.5f; 726 HysteresisLevels hysteresisLevels = new HysteresisLevels(ambientBrighteningThresholds, 727 ambientDarkeningThresholds, ambientThresholdLevels, ambientThresholdLevels, 728 ambientDarkeningMinChangeThreshold, ambientBrighteningMinChangeThreshold); 729 730 // test low, activate minimum change thresholds. 731 assertEquals(1.5f, hysteresisLevels.getBrighteningThreshold(0.0f), EPSILON); 732 assertEquals(0f, hysteresisLevels.getDarkeningThreshold(0.0f), EPSILON); 733 assertEquals(1f, hysteresisLevels.getDarkeningThreshold(4.0f), EPSILON); 734 735 // test max 736 // epsilon is x2 here, since the next floating point value about 20,000 is 0.0019531 greater 737 assertEquals(20000f, hysteresisLevels.getBrighteningThreshold(10000.0f), EPSILON * 2); 738 assertEquals(8000f, hysteresisLevels.getDarkeningThreshold(10000.0f), EPSILON); 739 740 // test just below threshold 741 assertEquals(748.5f, hysteresisLevels.getBrighteningThreshold(499f), EPSILON); 742 assertEquals(449.1f, hysteresisLevels.getDarkeningThreshold(499f), EPSILON); 743 744 // test at (considered above) threshold 745 assertEquals(1000f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON); 746 assertEquals(400f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON); 747 } 748 749 @Test 750 public void testBrightnessGetsThrottled() throws Exception { 751 ArgumentCaptor<SensorEventListener> listenerCaptor = 752 ArgumentCaptor.forClass(SensorEventListener.class); 753 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 754 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 755 SensorEventListener listener = listenerCaptor.getValue(); 756 757 // Set up system to return max brightness at 100 lux 758 final float normalizedBrightness = BRIGHTNESS_MAX_FLOAT; 759 final float lux = 100.0f; 760 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)) 761 .thenReturn(lux); 762 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)) 763 .thenReturn(lux); 764 when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt())) 765 .thenReturn(normalizedBrightness); 766 767 // Sensor reads 100 lux. We should get max brightness. 768 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 769 assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f); 770 assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getRawAutomaticScreenBrightness(), 0.0f); 771 772 // Apply throttling and notify ABC (simulates DisplayPowerController#updatePowerState()) 773 final float throttledBrightness = 0.123f; 774 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(throttledBrightness); 775 when(mBrightnessClamperController.isThrottled()).thenReturn(true); 776 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 777 BRIGHTNESS_MAX_FLOAT /* brightness= */, false /* userChangedBrightness= */, 778 0 /* adjustment= */, false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, 779 Display.STATE_ON, /* useNormalBrightnessForDoze= */ false, 780 /* shouldResetShortTermModel= */ true); 781 assertEquals(throttledBrightness, mController.getAutomaticScreenBrightness(), 0.0f); 782 // The raw brightness value should not have throttling applied 783 assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getRawAutomaticScreenBrightness(), 0.0f); 784 785 // Remove throttling and notify ABC again 786 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 787 when(mBrightnessClamperController.isThrottled()).thenReturn(false); 788 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 789 BRIGHTNESS_MAX_FLOAT /* brightness= */, false /* userChangedBrightness= */, 790 0 /* adjustment= */, false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, 791 Display.STATE_ON, /* useNormalBrightnessForDoze= */ false, 792 /* shouldResetShortTermModel= */ true); 793 assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f); 794 assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getRawAutomaticScreenBrightness(), 0.0f); 795 } 796 797 @Test 798 public void testGetSensorReadings() throws Exception { 799 ArgumentCaptor<SensorEventListener> listenerCaptor = 800 ArgumentCaptor.forClass(SensorEventListener.class); 801 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 802 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 803 SensorEventListener listener = listenerCaptor.getValue(); 804 805 // Choose values such that the ring buffer's capacity is extended and the buffer is pruned 806 int increment = 11; 807 int lux = 5000; 808 for (int i = 0; i < 1000; i++) { 809 lux += increment; 810 mClock.fastForward(increment); 811 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, 812 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 813 } 814 815 int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1); 816 float[] sensorValues = mController.getLastSensorValues(); 817 long[] sensorTimestamps = mController.getLastSensorTimestamps(); 818 819 // Only the values within the horizon should be kept 820 assertEquals(valuesCount, sensorValues.length); 821 assertEquals(valuesCount, sensorTimestamps.length); 822 823 long sensorTimestamp = mClock.now(); 824 for (int i = valuesCount - 1; i >= 1; i--) { 825 assertEquals(lux, sensorValues[i], EPSILON); 826 assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]); 827 lux -= increment; 828 sensorTimestamp -= increment; 829 } 830 assertEquals(lux, sensorValues[0], EPSILON); 831 assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME, 832 sensorTimestamps[0]); 833 } 834 835 @Test 836 public void testAmbientLuxBuffers_prunedBeyondLongHorizonExceptLatestValue() throws Exception { 837 ArgumentCaptor<SensorEventListener> listenerCaptor = 838 ArgumentCaptor.forClass(SensorEventListener.class); 839 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 840 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 841 SensorEventListener listener = listenerCaptor.getValue(); 842 843 // Choose values such that the ring buffer's capacity is extended and the buffer is pruned 844 int increment = 11; 845 int lux = 5000; 846 for (int i = 0; i < 1000; i++) { 847 lux += increment; 848 mClock.fastForward(increment); 849 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, 850 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 851 } 852 mClock.fastForward(AMBIENT_LIGHT_HORIZON_LONG + 10); 853 int newLux = 2000; 854 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, newLux, 855 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 856 857 float[] sensorValues = mController.getLastSensorValues(); 858 long[] sensorTimestamps = mController.getLastSensorTimestamps(); 859 // Only the values within the horizon should be kept 860 assertEquals(2, sensorValues.length); 861 assertEquals(2, sensorTimestamps.length); 862 863 assertEquals(lux, sensorValues[0], EPSILON); 864 assertEquals(newLux, sensorValues[1], EPSILON); 865 assertEquals(mClock.now() + ANDROID_SLEEP_TIME - AMBIENT_LIGHT_HORIZON_LONG, 866 sensorTimestamps[0]); 867 assertEquals(mClock.now() + ANDROID_SLEEP_TIME, 868 sensorTimestamps[1]); 869 } 870 871 @Test 872 public void testGetSensorReadingsFullBuffer() throws Exception { 873 ArgumentCaptor<SensorEventListener> listenerCaptor = 874 ArgumentCaptor.forClass(SensorEventListener.class); 875 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 876 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 877 SensorEventListener listener = listenerCaptor.getValue(); 878 int initialCapacity = 150; 879 880 // Choose values such that the ring buffer is pruned 881 int increment1 = 200; 882 int lux = 5000; 883 for (int i = 0; i < 20; i++) { 884 lux += increment1; 885 mClock.fastForward(increment1); 886 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, 887 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 888 } 889 890 int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1); 891 892 // Choose values such that the buffer becomes full 893 int increment2 = 1; 894 for (int i = 0; i < initialCapacity - valuesCount; i++) { 895 lux += increment2; 896 mClock.fastForward(increment2); 897 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, 898 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 899 } 900 901 float[] sensorValues = mController.getLastSensorValues(); 902 long[] sensorTimestamps = mController.getLastSensorTimestamps(); 903 904 // The buffer should be full 905 assertEquals(initialCapacity, sensorValues.length); 906 assertEquals(initialCapacity, sensorTimestamps.length); 907 908 long sensorTimestamp = mClock.now(); 909 for (int i = initialCapacity - 1; i >= 1; i--) { 910 assertEquals(lux, sensorValues[i], EPSILON); 911 assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]); 912 913 if (i >= valuesCount) { 914 lux -= increment2; 915 sensorTimestamp -= increment2; 916 } else { 917 lux -= increment1; 918 sensorTimestamp -= increment1; 919 } 920 } 921 assertEquals(lux, sensorValues[0], EPSILON); 922 assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME, 923 sensorTimestamps[0]); 924 } 925 926 @Test 927 public void testResetShortTermModelWhenConfigChanges() { 928 when(mBrightnessMappingStrategy.setBrightnessConfiguration(any())).thenReturn(true); 929 930 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 931 BRIGHTNESS_MAX_FLOAT /* brightness= */, false /* userChangedBrightness= */, 932 0 /* adjustment= */, false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, 933 Display.STATE_ON, /* useNormalBrightnessForDoze= */ false, 934 /* shouldResetShortTermModel= */ false); 935 verify(mBrightnessMappingStrategy, never()).clearUserDataPoints(); 936 937 mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */, 938 BRIGHTNESS_MAX_FLOAT /* brightness= */, false /* userChangedBrightness= */, 939 0 /* adjustment= */, false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT, 940 Display.STATE_ON, /* useNormalBrightnessForDoze= */ false, 941 /* shouldResetShortTermModel= */ true); 942 verify(mBrightnessMappingStrategy).clearUserDataPoints(); 943 } 944 945 @Test 946 public void testUseProvidedShortTermModel() { 947 verify(mBrightnessMappingStrategy, never()).addUserDataPoint(anyFloat(), anyFloat()); 948 949 float userLux = 1000; 950 float userNits = 500; 951 float userBrightness = 0.3f; 952 when(mBrightnessMappingStrategy.getBrightnessFromNits(userNits)).thenReturn(userBrightness); 953 setupController(userLux, userNits, /* applyDebounce= */ true, 954 /* useHorizon= */ false); 955 verify(mBrightnessMappingStrategy).addUserDataPoint(userLux, userBrightness); 956 } 957 958 @Test 959 public void testBrighteningLightDebounce() throws Exception { 960 clearInvocations(mSensorManager); 961 setupController(BrightnessMappingStrategy.INVALID_LUX, 962 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true, 963 /* useHorizon= */ false); 964 965 ArgumentCaptor<SensorEventListener> listenerCaptor = 966 ArgumentCaptor.forClass(SensorEventListener.class); 967 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 968 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 969 SensorEventListener listener = listenerCaptor.getValue(); 970 971 // t = 0 972 // Initial lux 973 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 974 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 975 assertEquals(500, mController.getAmbientLux(), EPSILON); 976 977 // t = 1000 978 // Lux isn't steady yet 979 mClock.fastForward(1000); 980 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 981 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 982 assertEquals(500, mController.getAmbientLux(), EPSILON); 983 984 // t = 1500 985 // Lux isn't steady yet 986 mClock.fastForward(500); 987 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 988 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 989 assertEquals(500, mController.getAmbientLux(), EPSILON); 990 991 // t = 2500 992 // Lux is steady now 993 mClock.fastForward(1000); 994 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 995 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 996 assertEquals(1200, mController.getAmbientLux(), EPSILON); 997 } 998 999 @Test 1000 public void testDarkeningLightDebounce() throws Exception { 1001 clearInvocations(mSensorManager); 1002 when(mAmbientBrightnessThresholds.getBrighteningThreshold(anyFloat())) 1003 .thenReturn(10000f); 1004 when(mAmbientBrightnessThresholds.getDarkeningThreshold(anyFloat())) 1005 .thenReturn(10000f); 1006 setupController(BrightnessMappingStrategy.INVALID_LUX, 1007 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true, 1008 /* useHorizon= */ false); 1009 1010 ArgumentCaptor<SensorEventListener> listenerCaptor = 1011 ArgumentCaptor.forClass(SensorEventListener.class); 1012 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1013 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1014 SensorEventListener listener = listenerCaptor.getValue(); 1015 1016 // t = 0 1017 // Initial lux 1018 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 1019 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1020 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1021 1022 // t = 2000 1023 // Lux isn't steady yet 1024 mClock.fastForward(2000); 1025 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1026 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1027 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1028 1029 // t = 2500 1030 // Lux isn't steady yet 1031 mClock.fastForward(500); 1032 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1033 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1034 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1035 1036 // t = 4500 1037 // Lux is steady now 1038 mClock.fastForward(2000); 1039 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1040 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1041 assertEquals(500, mController.getAmbientLux(), EPSILON); 1042 } 1043 1044 @Test 1045 public void testBrighteningLightDebounceIdle() throws Exception { 1046 clearInvocations(mSensorManager); 1047 setupController(BrightnessMappingStrategy.INVALID_LUX, 1048 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true, 1049 /* useHorizon= */ false); 1050 1051 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 1052 1053 ArgumentCaptor<SensorEventListener> listenerCaptor = 1054 ArgumentCaptor.forClass(SensorEventListener.class); 1055 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1056 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1057 SensorEventListener listener = listenerCaptor.getValue(); 1058 1059 // t = 0 1060 // Initial lux 1061 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1062 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1063 assertEquals(500, mController.getAmbientLux(), EPSILON); 1064 1065 // t = 500 1066 // Lux isn't steady yet 1067 mClock.fastForward(500); 1068 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 1069 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1070 assertEquals(500, mController.getAmbientLux(), EPSILON); 1071 1072 // t = 1500 1073 // Lux is steady now 1074 mClock.fastForward(1000); 1075 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 1076 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1077 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1078 } 1079 1080 @Test 1081 public void testDarkeningLightDebounceIdle() throws Exception { 1082 clearInvocations(mSensorManager); 1083 when(mAmbientBrightnessThresholdsIdle.getBrighteningThreshold(anyFloat())) 1084 .thenReturn(10000f); 1085 when(mAmbientBrightnessThresholdsIdle.getDarkeningThreshold(anyFloat())) 1086 .thenReturn(10000f); 1087 setupController(BrightnessMappingStrategy.INVALID_LUX, 1088 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true, 1089 /* useHorizon= */ false); 1090 1091 mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true); 1092 1093 ArgumentCaptor<SensorEventListener> listenerCaptor = 1094 ArgumentCaptor.forClass(SensorEventListener.class); 1095 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1096 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1097 SensorEventListener listener = listenerCaptor.getValue(); 1098 1099 // t = 0 1100 // Initial lux 1101 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, 1102 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1103 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1104 1105 // t = 1000 1106 // Lux isn't steady yet 1107 mClock.fastForward(1000); 1108 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1109 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1110 assertEquals(1200, mController.getAmbientLux(), EPSILON); 1111 1112 // t = 2500 1113 // Lux is steady now 1114 mClock.fastForward(1500); 1115 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, 1116 (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); 1117 assertEquals(500, mController.getAmbientLux(), EPSILON); 1118 } 1119 1120 @Test 1121 public void testAutoBrightnessInDoze() throws Exception { 1122 ArgumentCaptor<SensorEventListener> listenerCaptor = 1123 ArgumentCaptor.forClass(SensorEventListener.class); 1124 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1125 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1126 SensorEventListener listener = listenerCaptor.getValue(); 1127 1128 // Set up system to return 0.3f as a brightness value 1129 float lux = 100.0f; 1130 // Brightness as float (from 0.0f to 1.0f) 1131 float normalizedBrightness = 0.3f; 1132 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1133 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1134 when(mBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1135 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1136 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1137 1138 // Set policy to DOZE 1139 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 1140 /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0, 1141 /* userChanged= */ false, DisplayPowerRequest.POLICY_DOZE, Display.STATE_DOZE, 1142 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 1143 1144 // Send a new sensor value 1145 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1146 1147 // The brightness should be scaled by the doze factor 1148 assertEquals(normalizedBrightness * DOZE_SCALE_FACTOR, 1149 mController.getAutomaticScreenBrightness( 1150 /* brightnessEvent= */ null), EPSILON); 1151 } 1152 1153 @Test 1154 public void testAutoBrightnessInDoze_useNormalBrightnessForDozeFalse_scaleScreenOn() 1155 throws Exception { 1156 when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn( 1157 true); 1158 1159 ArgumentCaptor<SensorEventListener> listenerCaptor = 1160 ArgumentCaptor.forClass(SensorEventListener.class); 1161 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1162 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1163 SensorEventListener listener = listenerCaptor.getValue(); 1164 1165 // Set up system to return 0.3f as a brightness value 1166 float lux = 100.0f; 1167 // Brightness as float (from 0.0f to 1.0f) 1168 float normalizedBrightness = 0.3f; 1169 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1170 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1171 when(mBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1172 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1173 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1174 1175 // Set policy to DOZE 1176 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 1177 /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0, 1178 /* userChanged= */ false, DisplayPowerRequest.POLICY_DOZE, Display.STATE_ON, 1179 /* useNormalBrightnessForDoze= */ false, /* shouldResetShortTermModel= */ true); 1180 1181 // Send a new sensor value 1182 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1183 1184 // The brightness should be scaled by the doze factor 1185 assertEquals(normalizedBrightness * DOZE_SCALE_FACTOR, 1186 mController.getAutomaticScreenBrightness( 1187 /* brightnessEvent= */ null), EPSILON); 1188 } 1189 1190 @Test 1191 public void testAutoBrightnessInDoze_useNormalBrightnessForDozeTrue_notScaleScreenOn() 1192 throws Exception { 1193 when(mDisplayManagerFlags.isNormalBrightnessForDozeParameterEnabled(mContext)).thenReturn( 1194 true); 1195 1196 ArgumentCaptor<SensorEventListener> listenerCaptor = 1197 ArgumentCaptor.forClass(SensorEventListener.class); 1198 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1199 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1200 SensorEventListener listener = listenerCaptor.getValue(); 1201 1202 // Set up system to return 0.3f as a brightness value 1203 float lux = 100.0f; 1204 // Brightness as float (from 0.0f to 1.0f) 1205 float normalizedBrightness = 0.3f; 1206 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1207 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1208 when(mBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1209 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1210 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1211 1212 // Set policy to DOZE 1213 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 1214 /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0, 1215 /* userChanged= */ false, DisplayPowerRequest.POLICY_DOZE, Display.STATE_ON, 1216 /* useNormalBrightnessForDoze= */ true, /* shouldResetShortTermModel= */ true); 1217 1218 // Send a new sensor value 1219 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1220 1221 // The brightness should not be scaled by the doze factor 1222 assertEquals(normalizedBrightness, 1223 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON); 1224 } 1225 1226 @Test 1227 public void testAutoBrightnessInDoze_ShouldNotScaleIfUsingDozeCurve() throws Exception { 1228 ArgumentCaptor<SensorEventListener> listenerCaptor = 1229 ArgumentCaptor.forClass(SensorEventListener.class); 1230 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1231 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1232 SensorEventListener listener = listenerCaptor.getValue(); 1233 1234 // Set up system to return 0.3f as a brightness value 1235 float lux = 100.0f; 1236 // Brightness as float (from 0.0f to 1.0f) 1237 float normalizedBrightness = 0.3f; 1238 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1239 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1240 when(mDozeBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1241 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1242 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1243 1244 // Switch mode to DOZE 1245 mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false); 1246 1247 // Set policy to DOZE 1248 mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null, 1249 /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0, 1250 /* userChanged= */ false, DisplayPowerRequest.POLICY_DOZE, Display.STATE_DOZE, 1251 /* useNormalBrightnessForDoze= */ true, /* shouldResetShortTermModel= */ true); 1252 1253 // Send a new sensor value 1254 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1255 1256 // The brightness should not be scaled by the doze factor 1257 assertEquals(normalizedBrightness, 1258 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON); 1259 } 1260 1261 @Test 1262 public void testSwitchMode_UpdateBrightnessImmediately() throws Exception { 1263 ArgumentCaptor<SensorEventListener> listenerCaptor = 1264 ArgumentCaptor.forClass(SensorEventListener.class); 1265 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1266 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1267 SensorEventListener listener = listenerCaptor.getValue(); 1268 1269 // Set up system to return 0.3f as a brightness value 1270 float lux = 100.0f; 1271 // Brightness as float (from 0.0f to 1.0f) 1272 float normalizedBrightness = 0.3f; 1273 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1274 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1275 when(mDozeBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1276 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1277 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1278 1279 // Send a new sensor value 1280 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1281 1282 // Switch mode to DOZE 1283 mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false); 1284 1285 assertEquals(normalizedBrightness, 1286 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON); 1287 } 1288 1289 @Test 1290 public void testSwitchMode_UpdateBrightnessInBackground() throws Exception { 1291 ArgumentCaptor<SensorEventListener> listenerCaptor = 1292 ArgumentCaptor.forClass(SensorEventListener.class); 1293 verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), 1294 eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); 1295 SensorEventListener listener = listenerCaptor.getValue(); 1296 1297 // Set up system to return 0.3f as a brightness value 1298 float lux = 100.0f; 1299 // Brightness as float (from 0.0f to 1.0f) 1300 float normalizedBrightness = 0.3f; 1301 when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); 1302 when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); 1303 when(mDozeBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null), 1304 /* category= */ anyInt())).thenReturn(normalizedBrightness); 1305 when(mBrightnessClamperController.getMaxBrightness()).thenReturn(BRIGHTNESS_MAX_FLOAT); 1306 1307 // Send a new sensor value 1308 listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); 1309 1310 // Switch mode to DOZE 1311 mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ true); 1312 mClock.fastForward(SystemClock.uptimeMillis()); 1313 mTestLooper.dispatchAll(); 1314 1315 assertEquals(normalizedBrightness, 1316 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON); 1317 } 1318 } 1319