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