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