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