1 /* 2 * Copyright 2017 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 org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.assertSame; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 28 import android.app.ActivityTaskManager.RootTaskInfo; 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.ParceledListSlice; 36 import android.database.ContentObserver; 37 import android.hardware.Sensor; 38 import android.hardware.SensorEvent; 39 import android.hardware.SensorEventListener; 40 import android.hardware.display.AmbientBrightnessDayStats; 41 import android.hardware.display.BrightnessChangeEvent; 42 import android.hardware.display.BrightnessConfiguration; 43 import android.hardware.display.ColorDisplayManager; 44 import android.hardware.display.DisplayManager; 45 import android.hardware.display.DisplayedContentSample; 46 import android.hardware.display.DisplayedContentSamplingAttributes; 47 import android.hardware.input.InputSensorInfo; 48 import android.os.BatteryManager; 49 import android.os.Handler; 50 import android.os.HandlerThread; 51 import android.os.MessageQueue; 52 import android.os.Parcel; 53 import android.os.RemoteException; 54 import android.os.SystemClock; 55 import android.os.UserManager; 56 import android.provider.Settings; 57 import android.util.AtomicFile; 58 import android.view.Display; 59 60 import androidx.test.InstrumentationRegistry; 61 import androidx.test.filters.SmallTest; 62 import androidx.test.runner.AndroidJUnit4; 63 64 import com.android.internal.R; 65 66 import org.junit.Before; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.mockito.Mock; 70 import org.mockito.MockitoAnnotations; 71 72 import java.io.ByteArrayInputStream; 73 import java.io.ByteArrayOutputStream; 74 import java.io.IOException; 75 import java.io.InputStream; 76 import java.lang.reflect.Constructor; 77 import java.nio.charset.StandardCharsets; 78 import java.util.HashMap; 79 import java.util.List; 80 import java.util.Map; 81 import java.util.concurrent.CountDownLatch; 82 import java.util.concurrent.TimeUnit; 83 84 @SmallTest 85 @RunWith(AndroidJUnit4.class) 86 public class BrightnessTrackerTest { 87 private static final float DEFAULT_INITIAL_BRIGHTNESS = 2.5f; 88 private static final boolean DEFAULT_COLOR_SAMPLING_ENABLED = true; 89 private static final String DEFAULT_DISPLAY_ID = "123"; 90 private static final float FLOAT_DELTA = 0.01f; 91 92 @Mock private InputSensorInfo mInputSensorInfoMock; 93 94 private BrightnessTracker mTracker; 95 private TestInjector mInjector; 96 private Sensor mLightSensorFake; 97 98 private static Object sHandlerLock = new Object(); 99 private static Handler sHandler; 100 private static HandlerThread sThread = 101 new HandlerThread("brightness.test", android.os.Process.THREAD_PRIORITY_BACKGROUND); 102 103 private int mDefaultNightModeColorTemperature; 104 private float mRbcOffsetFactor; 105 ensureHandler()106 private static Handler ensureHandler() { 107 synchronized (sHandlerLock) { 108 if (sHandler == null) { 109 sThread.start(); 110 sHandler = new Handler(sThread.getLooper()); 111 } 112 return sHandler; 113 } 114 } 115 116 117 @Before setUp()118 public void setUp() throws Exception { 119 MockitoAnnotations.initMocks(this); 120 mInjector = new TestInjector(ensureHandler()); 121 mLightSensorFake = new Sensor(mInputSensorInfoMock); 122 123 mTracker = new BrightnessTracker(InstrumentationRegistry.getContext(), mInjector); 124 mTracker.setLightSensor(mLightSensorFake); 125 mDefaultNightModeColorTemperature = 126 InstrumentationRegistry.getContext().getResources().getInteger( 127 R.integer.config_nightDisplayColorTemperatureDefault); 128 mRbcOffsetFactor = InstrumentationRegistry.getContext() 129 .getSystemService(ColorDisplayManager.class).getReduceBrightColorsOffsetFactor(); 130 } 131 132 @Test testStartStopTrackerScreenOnOff()133 public void testStartStopTrackerScreenOnOff() { 134 mInjector.mInteractive = false; 135 startTracker(mTracker); 136 assertNull(mInjector.mSensorListener); 137 assertNotNull(mInjector.mBroadcastReceiver); 138 assertTrue(mInjector.mIdleScheduled); 139 mInjector.sendScreenChange(/* screenOn= */ true); 140 assertNotNull(mInjector.mSensorListener); 141 assertTrue(mInjector.mColorSamplingEnabled); 142 143 mInjector.sendScreenChange(/* screenOn= */ false); 144 assertNull(mInjector.mSensorListener); 145 assertFalse(mInjector.mColorSamplingEnabled); 146 147 // Turn screen on while brightness mode is manual 148 mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ false); 149 mInjector.sendScreenChange(/* screenOn= */ true); 150 assertNull(mInjector.mSensorListener); 151 assertFalse(mInjector.mColorSamplingEnabled); 152 153 // Set brightness mode to automatic while screen is off. 154 mInjector.sendScreenChange(/* screenOn= */ false); 155 mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true); 156 assertNull(mInjector.mSensorListener); 157 assertFalse(mInjector.mColorSamplingEnabled); 158 159 // Turn on screen while brightness mode is automatic. 160 mInjector.sendScreenChange(/* screenOn= */ true); 161 assertNotNull(mInjector.mSensorListener); 162 assertTrue(mInjector.mColorSamplingEnabled); 163 164 mTracker.stop(); 165 assertNull(mInjector.mSensorListener); 166 assertNull(mInjector.mBroadcastReceiver); 167 assertFalse(mInjector.mIdleScheduled); 168 assertFalse(mInjector.mColorSamplingEnabled); 169 } 170 171 @Test testModifyBrightnessConfiguration()172 public void testModifyBrightnessConfiguration() { 173 mInjector.mInteractive = true; 174 // Start with tracker not listening for color samples. 175 startTracker(mTracker, DEFAULT_INITIAL_BRIGHTNESS, /* collectColorSamples= */ false); 176 assertFalse(mInjector.mColorSamplingEnabled); 177 178 // Update brightness config to enabled color sampling. 179 mTracker.setShouldCollectColorSample(/* collectColorSamples= */ true); 180 mInjector.waitForHandler(); 181 assertTrue(mInjector.mColorSamplingEnabled); 182 183 // Update brightness config to disable color sampling. 184 mTracker.setShouldCollectColorSample(/* collectColorSamples= */ false); 185 mInjector.waitForHandler(); 186 assertFalse(mInjector.mColorSamplingEnabled); 187 188 // Pretend screen is off, update config to turn on color sampling. 189 mInjector.sendScreenChange(/* screenOn= */ false); 190 mTracker.setShouldCollectColorSample(/* collectColorSamples= */ true); 191 mInjector.waitForHandler(); 192 assertFalse(mInjector.mColorSamplingEnabled); 193 194 // Pretend screen is on. 195 mInjector.sendScreenChange(/* screenOn= */ true); 196 assertTrue(mInjector.mColorSamplingEnabled); 197 198 mTracker.stop(); 199 assertFalse(mInjector.mColorSamplingEnabled); 200 } 201 202 @Test testNoColorSampling_WrongPixelFormat()203 public void testNoColorSampling_WrongPixelFormat() { 204 mInjector.mDefaultSamplingAttributes = 205 new DisplayedContentSamplingAttributes( 206 0x23, 207 mInjector.mDefaultSamplingAttributes.getDataspace(), 208 mInjector.mDefaultSamplingAttributes.getComponentMask()); 209 startTracker(mTracker); 210 assertFalse(mInjector.mColorSamplingEnabled); 211 assertNull(mInjector.mDisplayListener); 212 } 213 214 @Test testNoColorSampling_MissingComponent()215 public void testNoColorSampling_MissingComponent() { 216 mInjector.mDefaultSamplingAttributes = 217 new DisplayedContentSamplingAttributes( 218 mInjector.mDefaultSamplingAttributes.getPixelFormat(), 219 mInjector.mDefaultSamplingAttributes.getDataspace(), 220 0x2); 221 startTracker(mTracker); 222 assertFalse(mInjector.mColorSamplingEnabled); 223 assertNull(mInjector.mDisplayListener); 224 } 225 226 @Test testNoColorSampling_NoSupport()227 public void testNoColorSampling_NoSupport() { 228 mInjector.mDefaultSamplingAttributes = null; 229 startTracker(mTracker); 230 assertFalse(mInjector.mColorSamplingEnabled); 231 assertNull(mInjector.mDisplayListener); 232 } 233 234 @Test testColorSampling_FrameRateChange()235 public void testColorSampling_FrameRateChange() { 236 startTracker(mTracker); 237 assertTrue(mInjector.mColorSamplingEnabled); 238 assertNotNull(mInjector.mDisplayListener); 239 int noFramesSampled = mInjector.mNoColorSamplingFrames; 240 mInjector.mFrameRate = 120.0f; 241 // Wrong display 242 mInjector.mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY + 10); 243 assertEquals(noFramesSampled, mInjector.mNoColorSamplingFrames); 244 // Correct display 245 mInjector.mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY); 246 assertEquals(noFramesSampled * 2, mInjector.mNoColorSamplingFrames); 247 } 248 249 @Test testAdaptiveOnOff()250 public void testAdaptiveOnOff() { 251 mInjector.mInteractive = true; 252 mInjector.mIsBrightnessModeAutomatic = false; 253 startTracker(mTracker); 254 assertNull(mInjector.mSensorListener); 255 assertNotNull(mInjector.mBroadcastReceiver); 256 assertNotNull(mInjector.mContentObserver); 257 assertTrue(mInjector.mIdleScheduled); 258 assertFalse(mInjector.mColorSamplingEnabled); 259 assertNull(mInjector.mDisplayListener); 260 261 mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true); 262 assertNotNull(mInjector.mSensorListener); 263 assertTrue(mInjector.mColorSamplingEnabled); 264 assertNotNull(mInjector.mDisplayListener); 265 266 SensorEventListener listener = mInjector.mSensorListener; 267 DisplayManager.DisplayListener displayListener = mInjector.mDisplayListener; 268 mInjector.mSensorListener = null; 269 mInjector.mColorSamplingEnabled = false; 270 mInjector.mDisplayListener = null; 271 // Duplicate notification 272 mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true); 273 // Sensor shouldn't have been registered as it was already registered. 274 assertNull(mInjector.mSensorListener); 275 assertFalse(mInjector.mColorSamplingEnabled); 276 assertNull(mInjector.mDisplayListener); 277 mInjector.mDisplayListener = displayListener; 278 mInjector.mColorSamplingEnabled = true; 279 280 mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ false); 281 assertNull(mInjector.mSensorListener); 282 assertFalse(mInjector.mColorSamplingEnabled); 283 assertNull(mInjector.mDisplayListener); 284 285 mTracker.stop(); 286 assertNull(mInjector.mSensorListener); 287 assertNull(mInjector.mBroadcastReceiver); 288 assertNull(mInjector.mContentObserver); 289 assertFalse(mInjector.mIdleScheduled); 290 assertFalse(mInjector.mColorSamplingEnabled); 291 assertNull(mInjector.mDisplayListener); 292 } 293 294 @Test testBrightnessEvent()295 public void testBrightnessEvent() { 296 final float brightness = 0.5f; 297 final String displayId = "1234"; 298 299 startTracker(mTracker); 300 final long sensorTime = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos()); 301 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 302 final long currentTime = mInjector.currentTimeMillis(); 303 notifyBrightnessChanged(mTracker, brightness, displayId, new float[] {1.0f}, 304 new long[] {sensorTime}); 305 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 306 mTracker.stop(); 307 308 assertEquals(1, events.size()); 309 BrightnessChangeEvent event = events.get(0); 310 assertEquals(currentTime, event.timeStamp); 311 assertEquals(displayId, event.uniqueDisplayId); 312 assertEquals(1, event.luxValues.length); 313 assertEquals(1.0f, event.luxValues[0], FLOAT_DELTA); 314 assertEquals(currentTime - TimeUnit.SECONDS.toMillis(2), 315 event.luxTimestamps[0]); 316 assertEquals(brightness, event.brightness, FLOAT_DELTA); 317 assertEquals(DEFAULT_INITIAL_BRIGHTNESS, event.lastBrightness, FLOAT_DELTA); 318 319 // System had no data so these should all be at defaults. 320 assertEquals(Float.NaN, event.batteryLevel, 0.0); 321 assertFalse(event.nightMode); 322 assertEquals(mDefaultNightModeColorTemperature, event.colorTemperature); 323 } 324 325 @Test testMultipleBrightnessEvents()326 public void testMultipleBrightnessEvents() { 327 final float brightnessOne = 0.2f; 328 final float brightnessTwo = 0.4f; 329 final float brightnessThree = 0.6f; 330 final float brightnessFour = 0.3f; 331 final String displayId = "1234"; 332 final float[] luxValues = new float[]{1.0f}; 333 334 startTracker(mTracker); 335 final long sensorTime = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos()); 336 final long sensorTime2 = sensorTime + TimeUnit.SECONDS.toMillis(20); 337 final long sensorTime3 = sensorTime2 + TimeUnit.SECONDS.toMillis(30); 338 final long sensorTime4 = sensorTime3 + TimeUnit.SECONDS.toMillis(40); 339 final long originalTime = mInjector.currentTimeMillis(); 340 341 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 342 notifyBrightnessChanged(mTracker, brightnessOne, displayId, luxValues, 343 new long[] {sensorTime}); 344 345 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(20)); 346 notifyBrightnessChanged(mTracker, brightnessTwo, displayId, luxValues, 347 new long[] {sensorTime2}); 348 349 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(30)); 350 notifyBrightnessChanged(mTracker, brightnessThree, displayId, luxValues, 351 new long[] {sensorTime3}); 352 353 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(40)); 354 notifyBrightnessChanged(mTracker, brightnessFour, displayId, luxValues, 355 new long[] {sensorTime4}); 356 mTracker.stop(); 357 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 358 assertEquals(4, events.size()); 359 BrightnessChangeEvent eventOne = events.get(0); 360 assertEquals(brightnessOne, eventOne.brightness, FLOAT_DELTA); 361 assertEquals(originalTime, 362 eventOne.luxTimestamps[0]); 363 364 BrightnessChangeEvent eventTwo = events.get(1); 365 assertEquals(brightnessTwo, eventTwo.brightness, FLOAT_DELTA); 366 assertEquals(originalTime + TimeUnit.SECONDS.toMillis(20), 367 eventTwo.luxTimestamps[0]); 368 369 BrightnessChangeEvent eventThree = events.get(2); 370 assertEquals(brightnessThree, eventThree.brightness, FLOAT_DELTA); 371 assertEquals(originalTime + TimeUnit.SECONDS.toMillis(50), 372 eventThree.luxTimestamps[0]); 373 374 BrightnessChangeEvent eventFour = events.get(3); 375 assertEquals(brightnessFour, eventFour.brightness, FLOAT_DELTA); 376 assertEquals(originalTime + TimeUnit.SECONDS.toMillis(90), 377 eventFour.luxTimestamps[0]); 378 } 379 380 @Test testBrightnessFullPopulatedEvent()381 public void testBrightnessFullPopulatedEvent() { 382 final int initialBrightness = 230; 383 final int brightness = 130; 384 final String displayId = "1234"; 385 386 mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1); 387 mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3333); 388 389 mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1); 390 mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 40); 391 392 startTracker(mTracker, initialBrightness, DEFAULT_COLOR_SAMPLING_ENABLED); 393 mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(), 394 batteryChangeEvent(30, 60)); 395 final long currentTime = mInjector.currentTimeMillis(); 396 notifyBrightnessChanged(mTracker, brightness, displayId, new float[] {1000.0f}, 397 new long[] {TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos())}); 398 List<BrightnessChangeEvent> eventsNoPackage = 399 mTracker.getEvents(0, false).getList(); 400 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 401 mTracker.stop(); 402 403 assertEquals(1, events.size()); 404 BrightnessChangeEvent event = events.get(0); 405 assertEquals(event.timeStamp, currentTime); 406 assertEquals(displayId, event.uniqueDisplayId); 407 assertArrayEquals(new float[] {1000.0f}, event.luxValues, FLOAT_DELTA); 408 assertArrayEquals(new long[] {currentTime}, event.luxTimestamps); 409 assertEquals(brightness, event.brightness, FLOAT_DELTA); 410 assertEquals(initialBrightness, event.lastBrightness, FLOAT_DELTA); 411 assertEquals(0.5, event.batteryLevel, FLOAT_DELTA); 412 assertTrue(event.nightMode); 413 assertEquals(3333, event.colorTemperature); 414 assertTrue(event.reduceBrightColors); 415 assertEquals(40, event.reduceBrightColorsStrength); 416 assertEquals(brightness * mRbcOffsetFactor, event.reduceBrightColorsOffset, FLOAT_DELTA); 417 assertEquals("a.package", event.packageName); 418 assertEquals(0, event.userId); 419 assertArrayEquals(new long[] {1, 10, 100, 1000, 300, 30, 10, 1}, event.colorValueBuckets); 420 assertEquals(10000, event.colorSampleDuration); 421 422 assertEquals(1, eventsNoPackage.size()); 423 assertNull(eventsNoPackage.get(0).packageName); 424 } 425 426 @Test testIgnoreAutomaticBrightnessChange()427 public void testIgnoreAutomaticBrightnessChange() { 428 final int initialBrightness = 30; 429 startTracker(mTracker, initialBrightness, DEFAULT_COLOR_SAMPLING_ENABLED); 430 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1)); 431 432 final int systemUpdatedBrightness = 20; 433 notifyBrightnessChanged(mTracker, systemUpdatedBrightness, /* userInitiated= */ false, 434 /* powerBrightnessFactor= */ 0.5f, /* isUserSetBrightness= */ false, 435 /* isDefaultBrightnessConfig= */ false, DEFAULT_DISPLAY_ID); 436 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 437 // No events because we filtered out our change. 438 assertEquals(0, events.size()); 439 440 final int firstUserUpdateBrightness = 20; 441 // Then change comes from somewhere else so we shouldn't filter. 442 notifyBrightnessChanged(mTracker, firstUserUpdateBrightness); 443 444 // and with a different brightness value. 445 final int secondUserUpdateBrightness = 34; 446 notifyBrightnessChanged(mTracker, secondUserUpdateBrightness); 447 events = mTracker.getEvents(0, true).getList(); 448 449 assertEquals(2, events.size()); 450 // First event is change from system update (20) to first user update (20) 451 assertEquals(systemUpdatedBrightness, events.get(0).lastBrightness, FLOAT_DELTA); 452 assertEquals(firstUserUpdateBrightness, events.get(0).brightness, FLOAT_DELTA); 453 // Second event is from first to second user update. 454 assertEquals(firstUserUpdateBrightness, events.get(1).lastBrightness, FLOAT_DELTA); 455 assertEquals(secondUserUpdateBrightness, events.get(1).brightness, FLOAT_DELTA); 456 457 mTracker.stop(); 458 } 459 460 @Test testLimitedBufferSize()461 public void testLimitedBufferSize() { 462 startTracker(mTracker); 463 464 for (int brightness = 0; brightness <= 255; ++brightness) { 465 mInjector.incrementTime(TimeUnit.SECONDS.toNanos(1)); 466 notifyBrightnessChanged(mTracker, brightness); 467 } 468 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 469 mTracker.stop(); 470 471 // Should be capped at 100 events, and they should be the most recent 100. 472 assertEquals(100, events.size()); 473 for (int i = 0; i < events.size(); i++) { 474 BrightnessChangeEvent event = events.get(i); 475 assertEquals(156 + i, event.brightness, FLOAT_DELTA); 476 } 477 } 478 479 @Test testReadEvents()480 public void testReadEvents() throws Exception { 481 BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(), 482 mInjector); 483 mInjector.mCurrentTimeMillis = System.currentTimeMillis(); 484 long someTimeAgo = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(12); 485 long twoMonthsAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 486 // 3 Events in the file but one too old to read. 487 String eventFile = 488 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 489 + "<events>\n" 490 + "<event nits=\"194.2\" timestamp=\"" 491 + Long.toString(someTimeAgo) + "\" packageName=\"" 492 + "com.example.app\" user=\"10\" " 493 + "lastNits=\"32.333\" " 494 + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" " 495 + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" " 496 + "reduceBrightColorsOffset=\"0\"\n" 497 + "uniqueDisplayId=\"123\"" 498 + "lux=\"32.2,31.1\" luxTimestamps=\"" 499 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"" 500 + "defaultConfig=\"true\" powerSaveFactor=\"0.5\" userPoint=\"true\" />" 501 + "<event nits=\"71\" timestamp=\"" 502 + Long.toString(someTimeAgo) + "\" packageName=\"" 503 + "com.android.anapp\" user=\"11\" " 504 + "lastNits=\"32\" " 505 + "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\" " 506 + "reduceBrightColors=\"true\" reduceBrightColorsStrength=\"40\" " 507 + "reduceBrightColorsOffset=\"0\"\n" 508 + "uniqueDisplayId=\"456\"" 509 + "lux=\"132.2,131.1\" luxTimestamps=\"" 510 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"" 511 + "colorSampleDuration=\"3456\" colorValueBuckets=\"123,598,23,19\"/>" 512 // Event that is too old so shouldn't show up. 513 + "<event nits=\"142\" timestamp=\"" 514 + Long.toString(twoMonthsAgo) + "\" packageName=\"" 515 + "com.example.app\" user=\"10\" " 516 + "lastNits=\"32\" " 517 + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" " 518 + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" " 519 + "reduceBrightColorsOffset=\"0\"\n" 520 + "uniqueDisplayId=\"789\"" 521 + "lux=\"32.2,31.1\" luxTimestamps=\"" 522 + Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>" 523 + "</events>"; 524 tracker.readEventsLocked(getInputStream(eventFile)); 525 List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList(); 526 assertEquals(1, events.size()); 527 BrightnessChangeEvent event = events.get(0); 528 assertEquals(someTimeAgo, event.timeStamp); 529 assertEquals(194.2, event.brightness, FLOAT_DELTA); 530 assertEquals("123", event.uniqueDisplayId); 531 assertArrayEquals(new float[] {32.2f, 31.1f}, event.luxValues, FLOAT_DELTA); 532 assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps); 533 assertEquals(32.333, event.lastBrightness, FLOAT_DELTA); 534 assertEquals(0, event.userId); 535 assertFalse(event.nightMode); 536 assertFalse(event.reduceBrightColors); 537 assertEquals(1.0f, event.batteryLevel, FLOAT_DELTA); 538 assertEquals("com.example.app", event.packageName); 539 assertTrue(event.isDefaultBrightnessConfig); 540 assertEquals(0.5f, event.powerBrightnessFactor, FLOAT_DELTA); 541 assertTrue(event.isUserSetBrightness); 542 assertNull(event.colorValueBuckets); 543 544 events = tracker.getEvents(1, true).getList(); 545 assertEquals(1, events.size()); 546 event = events.get(0); 547 assertEquals(someTimeAgo, event.timeStamp); 548 assertEquals(71, event.brightness, FLOAT_DELTA); 549 assertEquals("456", event.uniqueDisplayId); 550 assertArrayEquals(new float[] {132.2f, 131.1f}, event.luxValues, FLOAT_DELTA); 551 assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps); 552 assertEquals(32, event.lastBrightness, FLOAT_DELTA); 553 assertEquals(1, event.userId); 554 assertTrue(event.nightMode); 555 assertEquals(3235, event.colorTemperature); 556 assertTrue(event.reduceBrightColors); 557 assertEquals(0.5f, event.batteryLevel, FLOAT_DELTA); 558 assertEquals("com.android.anapp", event.packageName); 559 // Not present in the event so default to false. 560 assertFalse(event.isDefaultBrightnessConfig); 561 assertEquals(1.0, event.powerBrightnessFactor, FLOAT_DELTA); 562 assertFalse(event.isUserSetBrightness); 563 assertEquals(3456L, event.colorSampleDuration); 564 assertArrayEquals(new long[] {123L, 598L, 23L, 19L}, event.colorValueBuckets); 565 566 // Pretend user 1 is a profile of user 0. 567 mInjector.mProfiles = new int[]{0, 1}; 568 events = tracker.getEvents(0, true).getList(); 569 // Both events should now be returned. 570 assertEquals(2, events.size()); 571 BrightnessChangeEvent userZeroEvent; 572 BrightnessChangeEvent userOneEvent; 573 if (events.get(0).userId == 0) { 574 userZeroEvent = events.get(0); 575 userOneEvent = events.get(1); 576 } else { 577 userZeroEvent = events.get(1); 578 userOneEvent = events.get(0); 579 } 580 assertEquals(0, userZeroEvent.userId); 581 assertEquals("com.example.app", userZeroEvent.packageName); 582 assertEquals(1, userOneEvent.userId); 583 // Events from user 1 should have the package name redacted 584 assertNull(userOneEvent.packageName); 585 } 586 587 @Test testFailedRead()588 public void testFailedRead() { 589 String someTimeAgo = 590 Long.toString(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(12)); 591 mInjector.mCurrentTimeMillis = System.currentTimeMillis(); 592 593 BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(), 594 mInjector); 595 String eventFile = "junk in the file"; 596 try { 597 tracker.readEventsLocked(getInputStream(eventFile)); 598 } catch (IOException e) { 599 // Expected; 600 } 601 assertEquals(0, tracker.getEvents(0, true).getList().size()); 602 603 // Missing lux value. 604 eventFile = 605 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 606 + "<events>\n" 607 + "<event nits=\"194\" timestamp=\"" + someTimeAgo + "\" packageName=\"" 608 + "com.example.app\" user=\"10\" " 609 + "batteryLevel=\"0.7\" nightMode=\"false\" colorTemperature=\"0\" />\n" 610 + "</events>"; 611 try { 612 tracker.readEventsLocked(getInputStream(eventFile)); 613 } catch (IOException e) { 614 // Expected; 615 } 616 assertEquals(0, tracker.getEvents(0, true).getList().size()); 617 } 618 619 @Test testWriteThenRead()620 public void testWriteThenRead() throws Exception { 621 final int brightness = 20; 622 final String displayId = "1234"; 623 624 mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1); 625 mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339); 626 627 mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1); 628 mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 40); 629 630 startTracker(mTracker); 631 mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(), 632 batteryChangeEvent(30, 100)); 633 final long elapsedTime1 = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos()); 634 final long currentTime1 = mInjector.currentTimeMillis(); 635 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 636 final long elapsedTime2 = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos()); 637 final long currentTime2 = mInjector.currentTimeMillis(); 638 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(3)); 639 notifyBrightnessChanged(mTracker, brightness, /* userInitiated= */ true, 640 /* powerBrightnessFactor= */ 0.5f, /* isUserSetBrightness= */ true, 641 /* isDefaultBrightnessConfig= */ false, displayId, new float[] {2000.0f, 3000.0f}, 642 new long[] {elapsedTime1, elapsedTime2}); 643 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 644 mTracker.writeEventsLocked(baos); 645 mTracker.stop(); 646 647 baos.flush(); 648 ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray()); 649 BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(), 650 mInjector); 651 tracker.readEventsLocked(input); 652 List<BrightnessChangeEvent> events = tracker.getEvents(0, true).getList(); 653 654 assertEquals(1, events.size()); 655 BrightnessChangeEvent event = events.get(0); 656 assertEquals(displayId, event.uniqueDisplayId); 657 assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA); 658 assertArrayEquals(new long[] {currentTime1, currentTime2}, event.luxTimestamps); 659 assertEquals(brightness, event.brightness, FLOAT_DELTA); 660 assertEquals(0.3, event.batteryLevel, FLOAT_DELTA); 661 assertTrue(event.nightMode); 662 assertEquals(3339, event.colorTemperature); 663 assertTrue(event.reduceBrightColors); 664 assertEquals(40, event.reduceBrightColorsStrength); 665 assertEquals(brightness * mRbcOffsetFactor, event.reduceBrightColorsOffset, FLOAT_DELTA); 666 assertEquals(0.5f, event.powerBrightnessFactor, FLOAT_DELTA); 667 assertTrue(event.isUserSetBrightness); 668 assertFalse(event.isDefaultBrightnessConfig); 669 assertArrayEquals(new long[] {1, 10, 100, 1000, 300, 30, 10, 1}, event.colorValueBuckets); 670 assertEquals(10000, event.colorSampleDuration); 671 } 672 673 @Test testParcelUnParcel()674 public void testParcelUnParcel() { 675 Parcel parcel = Parcel.obtain(); 676 BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder(); 677 builder.setBrightness(23f); 678 builder.setTimeStamp(345L); 679 builder.setPackageName("com.example"); 680 builder.setUserId(12); 681 builder.setUniqueDisplayId("9876"); 682 float[] luxValues = new float[2]; 683 luxValues[0] = 3000.0f; 684 luxValues[1] = 4000.0f; 685 builder.setLuxValues(luxValues); 686 long[] luxTimestamps = new long[2]; 687 luxTimestamps[0] = 325L; 688 luxTimestamps[1] = 315L; 689 builder.setLuxTimestamps(luxTimestamps); 690 builder.setBatteryLevel(0.7f); 691 builder.setNightMode(false); 692 builder.setColorTemperature(345); 693 builder.setReduceBrightColors(false); 694 builder.setReduceBrightColorsStrength(40); 695 builder.setReduceBrightColorsOffset(20f); 696 builder.setLastBrightness(50f); 697 builder.setColorValues(new long[] {23, 34, 45}, 1000L); 698 BrightnessChangeEvent event = builder.build(); 699 700 event.writeToParcel(parcel, 0); 701 byte[] parceled = parcel.marshall(); 702 parcel.recycle(); 703 704 parcel = Parcel.obtain(); 705 parcel.unmarshall(parceled, 0, parceled.length); 706 parcel.setDataPosition(0); 707 708 BrightnessChangeEvent event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel); 709 parcel.recycle(); 710 assertEquals(event.brightness, event2.brightness, FLOAT_DELTA); 711 assertEquals(event.timeStamp, event2.timeStamp); 712 assertEquals(event.packageName, event2.packageName); 713 assertEquals(event.userId, event2.userId); 714 assertEquals(event.uniqueDisplayId, event2.uniqueDisplayId); 715 assertArrayEquals(event.luxValues, event2.luxValues, FLOAT_DELTA); 716 assertArrayEquals(event.luxTimestamps, event2.luxTimestamps); 717 assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA); 718 assertEquals(event.nightMode, event2.nightMode); 719 assertEquals(event.colorTemperature, event2.colorTemperature); 720 assertEquals(event.reduceBrightColors, event2.reduceBrightColors); 721 assertEquals(event.reduceBrightColorsStrength, event2.reduceBrightColorsStrength); 722 assertEquals(event.reduceBrightColorsOffset, event2.reduceBrightColorsOffset, FLOAT_DELTA); 723 assertEquals(event.lastBrightness, event2.lastBrightness, FLOAT_DELTA); 724 assertArrayEquals(event.colorValueBuckets, event2.colorValueBuckets); 725 assertEquals(event.colorSampleDuration, event2.colorSampleDuration); 726 727 parcel = Parcel.obtain(); 728 builder.setBatteryLevel(Float.NaN); 729 event = builder.build(); 730 event.writeToParcel(parcel, 0); 731 parceled = parcel.marshall(); 732 parcel.recycle(); 733 734 parcel = Parcel.obtain(); 735 parcel.unmarshall(parceled, 0, parceled.length); 736 parcel.setDataPosition(0); 737 event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel); 738 assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA); 739 } 740 741 @Test testNonNullAmbientStats()742 public void testNonNullAmbientStats() { 743 // getAmbientBrightnessStats should return an empty list rather than null when 744 // tracker isn't started or hasn't collected any data. 745 ParceledListSlice<AmbientBrightnessDayStats> slice = mTracker.getAmbientBrightnessStats(0); 746 assertNotNull(slice); 747 assertTrue(slice.getList().isEmpty()); 748 startTracker(mTracker); 749 slice = mTracker.getAmbientBrightnessStats(0); 750 assertNotNull(slice); 751 assertTrue(slice.getList().isEmpty()); 752 } 753 754 @Test testBackgroundHandlerDelay()755 public void testBackgroundHandlerDelay() { 756 final int brightness = 20; 757 758 // Setup tracker. 759 startTracker(mTracker); 760 mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f)); 761 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 762 763 // Block handler from running. 764 final CountDownLatch latch = new CountDownLatch(1); 765 mInjector.mHandler.post( 766 () -> { 767 try { 768 latch.await(); 769 } catch (InterruptedException e) { 770 fail(e.getMessage()); 771 } 772 }); 773 774 // Send an event. 775 long eventTime = mInjector.currentTimeMillis(); 776 mTracker.notifyBrightnessChanged(brightness, /* userInitiated= */ true, 777 /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false, 778 /* isDefaultBrightnessConfig= */ false, DEFAULT_DISPLAY_ID, new float[10], 779 new long[10]); 780 781 // Time passes before handler can run. 782 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 783 784 // Let the handler run. 785 latch.countDown(); 786 mInjector.waitForHandler(); 787 788 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 789 mTracker.stop(); 790 791 // Check event was recorded with time it was sent rather than handler ran. 792 assertEquals(1, events.size()); 793 BrightnessChangeEvent event = events.get(0); 794 assertEquals(eventTime, event.timeStamp); 795 } 796 797 @Test testDisplayIdChange()798 public void testDisplayIdChange() { 799 float firstBrightness = 0.5f; 800 float secondBrightness = 0.75f; 801 String firstDisplayId = "123"; 802 String secondDisplayId = "456"; 803 804 startTracker(mTracker); 805 mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f)); 806 807 notifyBrightnessChanged(mTracker, firstBrightness, firstDisplayId); 808 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 809 List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList(); 810 assertEquals(1, events.size()); 811 BrightnessChangeEvent firstEvent = events.get(0); 812 assertEquals(firstDisplayId, firstEvent.uniqueDisplayId); 813 assertEquals(firstBrightness, firstEvent.brightness, 0.001f); 814 815 notifyBrightnessChanged(mTracker, secondBrightness, secondDisplayId); 816 mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2)); 817 events = mTracker.getEvents(0, true).getList(); 818 assertEquals(2, events.size()); 819 BrightnessChangeEvent secondEvent = events.get(1); 820 assertEquals(secondDisplayId, secondEvent.uniqueDisplayId); 821 assertEquals(secondBrightness, secondEvent.brightness, 0.001f); 822 823 mTracker.stop(); 824 } 825 826 @Test testLightSensorChange()827 public void testLightSensorChange() { 828 // verify the tracker started correctly and a listener registered 829 startTracker(mTracker); 830 assertNotNull(mInjector.mSensorListener); 831 assertEquals(mInjector.mLightSensor, mLightSensorFake); 832 833 // Setting the sensor to null should stop the registered listener. 834 mTracker.setLightSensor(null); 835 mInjector.waitForHandler(); 836 assertNull(mInjector.mSensorListener); 837 assertNull(mInjector.mLightSensor); 838 839 // Resetting sensor should start listener again 840 mTracker.setLightSensor(mLightSensorFake); 841 mInjector.waitForHandler(); 842 assertNotNull(mInjector.mSensorListener); 843 assertEquals(mInjector.mLightSensor, mLightSensorFake); 844 845 Sensor secondSensor = new Sensor(mInputSensorInfoMock); 846 // Setting a different listener should keep things working 847 mTracker.setLightSensor(secondSensor); 848 mInjector.waitForHandler(); 849 assertNotNull(mInjector.mSensorListener); 850 assertEquals(mInjector.mLightSensor, secondSensor); 851 } 852 853 @Test testSetLightSensorDoesntStartListener()854 public void testSetLightSensorDoesntStartListener() { 855 mTracker.setLightSensor(mLightSensorFake); 856 assertNull(mInjector.mSensorListener); 857 } 858 859 @Test testNullLightSensorWontRegister()860 public void testNullLightSensorWontRegister() { 861 mTracker.setLightSensor(null); 862 startTracker(mTracker); 863 assertNull(mInjector.mSensorListener); 864 assertNull(mInjector.mLightSensor); 865 } 866 867 @Test testOnlyOneReceiverRegistered()868 public void testOnlyOneReceiverRegistered() { 869 assertNull(mInjector.mLightSensor); 870 assertNull(mInjector.mSensorListener); 871 assertNull(mInjector.mContentObserver); 872 assertNull(mInjector.mBroadcastReceiver); 873 assertFalse(mInjector.mIdleScheduled); 874 startTracker(mTracker, 0.3f, false); 875 876 assertNotNull(mInjector.mLightSensor); 877 assertNotNull(mInjector.mSensorListener); 878 assertNotNull(mInjector.mContentObserver); 879 assertNotNull(mInjector.mBroadcastReceiver); 880 assertTrue(mInjector.mIdleScheduled); 881 Sensor registeredLightSensor = mInjector.mLightSensor; 882 SensorEventListener registeredSensorListener = mInjector.mSensorListener; 883 ContentObserver registeredContentObserver = mInjector.mContentObserver; 884 BroadcastReceiver registeredBroadcastReceiver = mInjector.mBroadcastReceiver; 885 886 mTracker.start(0.3f); 887 assertSame(registeredLightSensor, mInjector.mLightSensor); 888 assertSame(registeredSensorListener, mInjector.mSensorListener); 889 assertSame(registeredContentObserver, mInjector.mContentObserver); 890 assertSame(registeredBroadcastReceiver, mInjector.mBroadcastReceiver); 891 892 mTracker.stop(); 893 assertNull(mInjector.mLightSensor); 894 assertNull(mInjector.mSensorListener); 895 assertNull(mInjector.mContentObserver); 896 assertNull(mInjector.mBroadcastReceiver); 897 assertFalse(mInjector.mIdleScheduled); 898 899 // mInjector asserts that we aren't removing a null receiver 900 mTracker.stop(); 901 } 902 getInputStream(String data)903 private InputStream getInputStream(String data) { 904 return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); 905 } 906 batteryChangeEvent(int level, int scale)907 private Intent batteryChangeEvent(int level, int scale) { 908 Intent intent = new Intent(); 909 intent.setAction(Intent.ACTION_BATTERY_CHANGED); 910 intent.putExtra(BatteryManager.EXTRA_LEVEL, level); 911 intent.putExtra(BatteryManager.EXTRA_SCALE, scale); 912 return intent; 913 } 914 createSensorEvent(float lux)915 private SensorEvent createSensorEvent(float lux) { 916 SensorEvent event; 917 try { 918 Constructor<SensorEvent> constr = 919 SensorEvent.class.getDeclaredConstructor(Integer.TYPE); 920 constr.setAccessible(true); 921 event = constr.newInstance(1); 922 } catch (Exception e) { 923 throw new RuntimeException(e); 924 } 925 event.values[0] = lux; 926 event.timestamp = mInjector.mElapsedRealtimeNanos; 927 928 return event; 929 } 930 startTracker(BrightnessTracker tracker)931 private void startTracker(BrightnessTracker tracker) { 932 startTracker(tracker, DEFAULT_INITIAL_BRIGHTNESS, DEFAULT_COLOR_SAMPLING_ENABLED); 933 } 934 startTracker(BrightnessTracker tracker, float initialBrightness, boolean collectColorSamples)935 private void startTracker(BrightnessTracker tracker, float initialBrightness, 936 boolean collectColorSamples) { 937 tracker.start(initialBrightness); 938 tracker.setShouldCollectColorSample(collectColorSamples); 939 mInjector.waitForHandler(); 940 } 941 notifyBrightnessChanged(BrightnessTracker tracker, float brightness)942 private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness) { 943 notifyBrightnessChanged(tracker, brightness, DEFAULT_DISPLAY_ID); 944 } 945 notifyBrightnessChanged(BrightnessTracker tracker, float brightness, String displayId)946 private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness, 947 String displayId) { 948 notifyBrightnessChanged(tracker, brightness, /* userInitiated= */ true, 949 /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false, 950 /* isDefaultBrightnessConfig= */ false, displayId, new float[10], new long[10]); 951 } 952 notifyBrightnessChanged(BrightnessTracker tracker, float brightness, String displayId, float[] luxValues, long[] luxTimestamps)953 private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness, 954 String displayId, float[] luxValues, long[] luxTimestamps) { 955 notifyBrightnessChanged(tracker, brightness, /* userInitiated= */ true, 956 /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false, 957 /* isDefaultBrightnessConfig= */ false, displayId, luxValues, luxTimestamps); 958 } 959 notifyBrightnessChanged(BrightnessTracker tracker, float brightness, boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness, boolean isDefaultBrightnessConfig, String displayId)960 private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness, 961 boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness, 962 boolean isDefaultBrightnessConfig, String displayId) { 963 tracker.notifyBrightnessChanged(brightness, userInitiated, powerBrightnessFactor, 964 isUserSetBrightness, isDefaultBrightnessConfig, displayId, new float[10], 965 new long[10]); 966 mInjector.waitForHandler(); 967 } 968 notifyBrightnessChanged(BrightnessTracker tracker, float brightness, boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness, boolean isDefaultBrightnessConfig, String displayId, float[] luxValues, long[] luxTimestamps)969 private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness, 970 boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness, 971 boolean isDefaultBrightnessConfig, String displayId, float[] luxValues, 972 long[] luxTimestamps) { 973 tracker.notifyBrightnessChanged(brightness, userInitiated, powerBrightnessFactor, 974 isUserSetBrightness, isDefaultBrightnessConfig, displayId, luxValues, 975 luxTimestamps); 976 mInjector.waitForHandler(); 977 } 978 buildBrightnessConfiguration(boolean collectColorSamples)979 private BrightnessConfiguration buildBrightnessConfiguration(boolean collectColorSamples) { 980 BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( 981 /* lux= */ new float[] {0f, 10f, 100f}, 982 /* nits= */ new float[] {1f, 90f, 100f}); 983 builder.setShouldCollectColorSamples(collectColorSamples); 984 return builder.build(); 985 } 986 987 private static final class Idle implements MessageQueue.IdleHandler { 988 private boolean mIdle; 989 990 @Override queueIdle()991 public boolean queueIdle() { 992 synchronized (this) { 993 mIdle = true; 994 notifyAll(); 995 } 996 return false; 997 } 998 waitForIdle()999 public synchronized void waitForIdle() { 1000 while (!mIdle) { 1001 try { 1002 wait(); 1003 } catch (InterruptedException e) { 1004 } 1005 } 1006 } 1007 } 1008 1009 private class TestInjector extends BrightnessTracker.Injector { 1010 SensorEventListener mSensorListener; 1011 Sensor mLightSensor; 1012 BroadcastReceiver mBroadcastReceiver; 1013 DisplayManager.DisplayListener mDisplayListener; 1014 Map<String, Integer> mSecureIntSettings = new HashMap<>(); 1015 long mCurrentTimeMillis = System.currentTimeMillis(); 1016 long mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); 1017 Handler mHandler; 1018 boolean mIdleScheduled; 1019 boolean mInteractive = true; 1020 int[] mProfiles; 1021 ContentObserver mContentObserver; 1022 boolean mIsBrightnessModeAutomatic = true; 1023 boolean mColorSamplingEnabled = false; 1024 DisplayedContentSamplingAttributes mDefaultSamplingAttributes = 1025 new DisplayedContentSamplingAttributes(0x37, 0, 0x4); 1026 float mFrameRate = 60.0f; 1027 int mNoColorSamplingFrames; 1028 1029 TestInjector(Handler handler)1030 public TestInjector(Handler handler) { 1031 mHandler = handler; 1032 } 1033 incrementTime(long timeMillis)1034 void incrementTime(long timeMillis) { 1035 mCurrentTimeMillis += timeMillis; 1036 mElapsedRealtimeNanos += TimeUnit.MILLISECONDS.toNanos(timeMillis); 1037 } 1038 setBrightnessMode(boolean isBrightnessModeAutomatic)1039 void setBrightnessMode(boolean isBrightnessModeAutomatic) { 1040 mIsBrightnessModeAutomatic = isBrightnessModeAutomatic; 1041 mContentObserver.dispatchChange(false, null); 1042 waitForHandler(); 1043 } 1044 sendScreenChange(boolean screenOn)1045 void sendScreenChange(boolean screenOn) { 1046 mInteractive = screenOn; 1047 Intent intent = new Intent(); 1048 intent.setAction(screenOn ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF); 1049 mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(), intent); 1050 waitForHandler(); 1051 } 1052 waitForHandler()1053 void waitForHandler() { 1054 Idle idle = new Idle(); 1055 mHandler.getLooper().getQueue().addIdleHandler(idle); 1056 mHandler.post(() -> {}); 1057 idle.waitForIdle(); 1058 } 1059 1060 @Override registerSensorListener(Context context, SensorEventListener sensorListener, Sensor lightSensor, Handler handler)1061 public void registerSensorListener(Context context, 1062 SensorEventListener sensorListener, Sensor lightSensor, Handler handler) { 1063 mSensorListener = sensorListener; 1064 mLightSensor = lightSensor; 1065 } 1066 1067 @Override unregisterSensorListener(Context context, SensorEventListener sensorListener)1068 public void unregisterSensorListener(Context context, 1069 SensorEventListener sensorListener) { 1070 mSensorListener = null; 1071 mLightSensor = null; 1072 } 1073 1074 @Override registerBrightnessModeObserver(ContentResolver resolver, ContentObserver settingsObserver)1075 public void registerBrightnessModeObserver(ContentResolver resolver, 1076 ContentObserver settingsObserver) { 1077 mContentObserver = settingsObserver; 1078 } 1079 1080 @Override unregisterBrightnessModeObserver(Context context, ContentObserver settingsObserver)1081 public void unregisterBrightnessModeObserver(Context context, 1082 ContentObserver settingsObserver) { 1083 mContentObserver = null; 1084 } 1085 1086 @Override registerReceiver(Context context, BroadcastReceiver shutdownReceiver, IntentFilter shutdownFilter)1087 public void registerReceiver(Context context, 1088 BroadcastReceiver shutdownReceiver, IntentFilter shutdownFilter) { 1089 mBroadcastReceiver = shutdownReceiver; 1090 } 1091 1092 @Override unregisterReceiver(Context context, BroadcastReceiver broadcastReceiver)1093 public void unregisterReceiver(Context context, 1094 BroadcastReceiver broadcastReceiver) { 1095 assertEquals(mBroadcastReceiver, broadcastReceiver); 1096 mBroadcastReceiver = null; 1097 } 1098 1099 @Override getBackgroundHandler()1100 public Handler getBackgroundHandler() { 1101 return mHandler; 1102 } 1103 1104 @Override isBrightnessModeAutomatic(ContentResolver resolver)1105 public boolean isBrightnessModeAutomatic(ContentResolver resolver) { 1106 return mIsBrightnessModeAutomatic; 1107 } 1108 1109 @Override getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue, int userId)1110 public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue, 1111 int userId) { 1112 Integer value = mSecureIntSettings.get(setting); 1113 if (value == null) { 1114 return defaultValue; 1115 } else { 1116 return value; 1117 } 1118 } 1119 1120 @Override getFile(String filename)1121 public AtomicFile getFile(String filename) { 1122 // Don't have the test write / read from anywhere. 1123 return null; 1124 } 1125 1126 @Override getLegacyFile(String filename)1127 public AtomicFile getLegacyFile(String filename) { 1128 // Don't have the test write / read from anywhere. 1129 return null; 1130 } 1131 1132 @Override currentTimeMillis()1133 public long currentTimeMillis() { 1134 return mCurrentTimeMillis; 1135 } 1136 1137 @Override elapsedRealtimeNanos()1138 public long elapsedRealtimeNanos() { 1139 return mElapsedRealtimeNanos; 1140 } 1141 1142 @Override getUserSerialNumber(UserManager userManager, int userId)1143 public int getUserSerialNumber(UserManager userManager, int userId) { 1144 return userId + 10; 1145 } 1146 1147 @Override getUserId(UserManager userManager, int userSerialNumber)1148 public int getUserId(UserManager userManager, int userSerialNumber) { 1149 return userSerialNumber - 10; 1150 } 1151 1152 @Override getProfileIds(UserManager userManager, int userId)1153 public int[] getProfileIds(UserManager userManager, int userId) { 1154 if (mProfiles != null) { 1155 return mProfiles; 1156 } else { 1157 return new int[]{userId}; 1158 } 1159 } 1160 1161 @Override getFocusedStack()1162 public RootTaskInfo getFocusedStack() throws RemoteException { 1163 RootTaskInfo focusedStack = new RootTaskInfo(); 1164 focusedStack.userId = 0; 1165 focusedStack.topActivity = new ComponentName("a.package", "a.class"); 1166 return focusedStack; 1167 } 1168 1169 @Override scheduleIdleJob(Context context)1170 public void scheduleIdleJob(Context context) { 1171 // Don't actually schedule jobs during unit tests. 1172 mIdleScheduled = true; 1173 } 1174 1175 @Override cancelIdleJob(Context context)1176 public void cancelIdleJob(Context context) { 1177 mIdleScheduled = false; 1178 } 1179 1180 @Override isInteractive(Context context)1181 public boolean isInteractive(Context context) { 1182 return mInteractive; 1183 } 1184 1185 @Override getNightDisplayColorTemperature(Context context)1186 public int getNightDisplayColorTemperature(Context context) { 1187 return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 1188 mDefaultNightModeColorTemperature); 1189 } 1190 1191 @Override isNightDisplayActivated(Context context)1192 public boolean isNightDisplayActivated(Context context) { 1193 return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1194 0) == 1; 1195 } 1196 1197 @Override getReduceBrightColorsStrength(Context context)1198 public int getReduceBrightColorsStrength(Context context) { 1199 return mSecureIntSettings.getOrDefault(Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 1200 0); 1201 } 1202 1203 @Override isReduceBrightColorsActivated(Context context)1204 public boolean isReduceBrightColorsActivated(Context context) { 1205 return mSecureIntSettings.getOrDefault(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1206 0) == 1; 1207 } 1208 1209 @Override sampleColor(int noFramesToSample)1210 public DisplayedContentSample sampleColor(int noFramesToSample) { 1211 return new DisplayedContentSample(600L, 1212 null, 1213 null, 1214 new long[] {1, 10, 100, 1000, 300, 30, 10, 1}, 1215 null); 1216 } 1217 1218 @Override getFrameRate(Context context)1219 public float getFrameRate(Context context) { 1220 return mFrameRate; 1221 } 1222 1223 @Override getSamplingAttributes()1224 public DisplayedContentSamplingAttributes getSamplingAttributes() { 1225 return mDefaultSamplingAttributes; 1226 } 1227 1228 @Override enableColorSampling(boolean enable, int noFrames)1229 public boolean enableColorSampling(boolean enable, int noFrames) { 1230 mColorSamplingEnabled = enable; 1231 mNoColorSamplingFrames = noFrames; 1232 return true; 1233 } 1234 1235 @Override registerDisplayListener(Context context, DisplayManager.DisplayListener listener, Handler handler)1236 public void registerDisplayListener(Context context, 1237 DisplayManager.DisplayListener listener, Handler handler) { 1238 mDisplayListener = listener; 1239 } 1240 1241 @Override unRegisterDisplayListener(Context context, DisplayManager.DisplayListener listener)1242 public void unRegisterDisplayListener(Context context, 1243 DisplayManager.DisplayListener listener) { 1244 mDisplayListener = null; 1245 } 1246 } 1247 } 1248