• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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