• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.display;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.content.Context;
26 import android.hardware.display.BrightnessConfiguration;
27 import android.os.Handler;
28 import android.os.test.TestLooper;
29 import android.util.Pair;
30 
31 import androidx.test.InstrumentationRegistry;
32 import androidx.test.filters.SmallTest;
33 import androidx.test.runner.AndroidJUnit4;
34 
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 
39 import java.io.ByteArrayInputStream;
40 import java.io.ByteArrayOutputStream;
41 import java.io.FileNotFoundException;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.OutputStream;
45 import java.nio.charset.StandardCharsets;
46 
47 @SmallTest
48 @RunWith(AndroidJUnit4.class)
49 public class PersistentDataStoreTest {
50     private PersistentDataStore mDataStore;
51     private TestInjector mInjector;
52     private TestLooper mTestLooper;
53 
54     @Before
setUp()55     public void setUp() {
56         mInjector = new TestInjector();
57         mTestLooper = new TestLooper();
58         Handler handler = new Handler(mTestLooper.getLooper());
59         mDataStore = new PersistentDataStore(mInjector, handler);
60     }
61 
62     @Test
testLoadingBrightnessConfigurations()63     public void testLoadingBrightnessConfigurations() {
64         String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
65                 + "<display-manager-state>\n"
66                 + "  <brightness-configurations>\n"
67                 + "    <brightness-configuration"
68                 + "         user-serial=\"1\""
69                 + "         package-name=\"example.com\""
70                 + "         timestamp=\"123456\">\n"
71                 + "      <brightness-curve description=\"something\">\n"
72                 + "        <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
73                 + "        <brightness-point lux=\"25\" nits=\"35.94\"/>\n"
74                 + "      </brightness-curve>\n"
75                 + "    </brightness-configuration>\n"
76                 + "    <brightness-configuration user-serial=\"3\">\n"
77                 + "      <brightness-curve>\n"
78                 + "        <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
79                 + "        <brightness-point lux=\"10.2\" nits=\"15\"/>\n"
80                 + "      </brightness-curve>\n"
81                 + "    </brightness-configuration>\n"
82                 + "  </brightness-configurations>\n"
83                 + "</display-manager-state>\n";
84         InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
85         mInjector.setReadStream(is);
86         mDataStore.loadIfNeeded();
87         BrightnessConfiguration config = mDataStore.getBrightnessConfiguration(1 /*userSerial*/);
88         Pair<float[], float[]> curve = config.getCurve();
89         float[] expectedLux = { 0f, 25f };
90         float[] expectedNits = { 13.25f, 35.94f };
91         assertArrayEquals(expectedLux, curve.first, "lux");
92         assertArrayEquals(expectedNits, curve.second, "nits");
93         assertEquals("something", config.getDescription());
94 
95         config = mDataStore.getBrightnessConfiguration(3 /*userSerial*/);
96         curve = config.getCurve();
97         expectedLux = new float[] { 0f, 10.2f };
98         expectedNits = new float[] { 13.25f, 15f };
99         assertArrayEquals(expectedLux, curve.first, "lux");
100         assertArrayEquals(expectedNits, curve.second, "nits");
101         assertNull(config.getDescription());
102     }
103 
104     @Test
testBrightnessConfigWithInvalidCurveIsIgnored()105     public void testBrightnessConfigWithInvalidCurveIsIgnored() {
106         String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
107                 + "<display-manager-state>\n"
108                 + "  <brightness-configurations>\n"
109                 + "    <brightness-configuration user-serial=\"0\">\n"
110                 + "      <brightness-curve>\n"
111                 + "        <brightness-point lux=\"1\" nits=\"13.25\"/>\n"
112                 + "        <brightness-point lux=\"25\" nits=\"35.94\"/>\n"
113                 + "      </brightness-curve>\n"
114                 + "    </brightness-configuration>\n"
115                 + "  </brightness-configurations>\n"
116                 + "</display-manager-state>\n";
117         InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
118         mInjector.setReadStream(is);
119         mDataStore.loadIfNeeded();
120         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
121     }
122 
123     @Test
testBrightnessConfigWithInvalidFloatsIsIgnored()124     public void testBrightnessConfigWithInvalidFloatsIsIgnored() {
125         String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
126                 + "<display-manager-state>\n"
127                 + "  <brightness-configurations>\n"
128                 + "    <brightness-configuration user-serial=\"0\">\n"
129                 + "      <brightness-curve>\n"
130                 + "        <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
131                 + "        <brightness-point lux=\"0xFF\" nits=\"foo\"/>\n"
132                 + "      </brightness-curve>\n"
133                 + "    </brightness-configuration>\n"
134                 + "  </brightness-configurations>\n"
135                 + "</display-manager-state>\n";
136         InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
137         mInjector.setReadStream(is);
138         mDataStore.loadIfNeeded();
139         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
140     }
141 
142     @Test
testEmptyBrightnessConfigurationsDoesntCrash()143     public void testEmptyBrightnessConfigurationsDoesntCrash() {
144         String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
145                 + "<display-manager-state>\n"
146                 + "  <brightness-configurations />\n"
147                 + "</display-manager-state>\n";
148         InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
149         mInjector.setReadStream(is);
150         mDataStore.loadIfNeeded();
151         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
152     }
153 
154     @Test
testStoreAndReloadOfDisplayBrightnessConfigurations()155     public void testStoreAndReloadOfDisplayBrightnessConfigurations() throws InterruptedException {
156         final String uniqueDisplayId = "test:123";
157         int userSerial = 0;
158         String packageName = "pdsTestPackage";
159         final float[] lux = { 0f, 10f };
160         final float[] nits = {1f, 100f };
161         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
162                 .setDescription("a description")
163                 .build();
164         mDataStore.loadIfNeeded();
165         assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
166                 userSerial));
167 
168         DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
169             @Override
170             public boolean hasStableUniqueId() {
171                 return true;
172             }
173 
174             @Override
175             public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
176                 return null;
177             }
178         };
179 
180         mDataStore.setBrightnessConfigurationForDisplayLocked(config, testDisplayDevice, userSerial,
181                 packageName);
182 
183         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
184         mInjector.setWriteStream(baos);
185         mDataStore.saveIfNeeded();
186         mTestLooper.dispatchAll();
187         assertTrue(mInjector.wasWriteSuccessful());
188         TestInjector newInjector = new TestInjector();
189         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
190         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
191         newInjector.setReadStream(bais);
192         newDataStore.loadIfNeeded();
193         assertNotNull(newDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
194                 userSerial));
195         assertEquals(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
196                 userSerial), newDataStore.getBrightnessConfigurationForDisplayLocked(
197                         uniqueDisplayId, userSerial));
198     }
199 
200     @Test
testSetBrightnessConfigurationFailsWithUnstableId()201     public void testSetBrightnessConfigurationFailsWithUnstableId() {
202         final String uniqueDisplayId = "test:123";
203         int userSerial = 0;
204         String packageName = "pdsTestPackage";
205         final float[] lux = { 0f, 10f };
206         final float[] nits = {1f, 100f };
207         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
208                 .setDescription("a description")
209                 .build();
210         mDataStore.loadIfNeeded();
211         assertNull(mDataStore.getBrightnessConfigurationForDisplayLocked(uniqueDisplayId,
212                 userSerial));
213 
214         DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
215             @Override
216             public boolean hasStableUniqueId() {
217                 return false;
218             }
219 
220             @Override
221             public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
222                 return null;
223             }
224         };
225 
226         assertFalse(mDataStore.setBrightnessConfigurationForDisplayLocked(
227                 config, testDisplayDevice, userSerial, packageName));
228     }
229 
230     @Test
testStoreAndReloadOfBrightnessConfigurations()231     public void testStoreAndReloadOfBrightnessConfigurations() throws InterruptedException {
232         final float[] lux = { 0f, 10f };
233         final float[] nits = {1f, 100f };
234         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
235                 .setDescription("a description")
236                 .build();
237         Context context = InstrumentationRegistry.getInstrumentation().getContext();
238         String packageName = context.getPackageName();
239 
240         mDataStore.loadIfNeeded();
241         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
242         mDataStore.setBrightnessConfigurationForUser(config, 0, packageName);
243 
244         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
245         mInjector.setWriteStream(baos);
246         mDataStore.saveIfNeeded();
247         mTestLooper.dispatchAll();
248         assertTrue(mInjector.wasWriteSuccessful());
249 
250         TestInjector newInjector = new TestInjector();
251         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
252         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
253         newInjector.setReadStream(bais);
254         newDataStore.loadIfNeeded();
255         assertNotNull(newDataStore.getBrightnessConfiguration(0 /*userSerial*/));
256         assertEquals(mDataStore.getBrightnessConfiguration(0 /*userSerial*/),
257                 newDataStore.getBrightnessConfiguration(0 /*userSerial*/));
258     }
259 
260     @Test
testNullBrightnessConfiguration()261     public void testNullBrightnessConfiguration() {
262         final float[] lux = { 0f, 10f };
263         final float[] nits = {1f, 100f };
264         int userSerial = 0;
265         final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
266                 .setDescription("a description")
267                 .build();
268         mDataStore.loadIfNeeded();
269         assertNull(mDataStore.getBrightnessConfiguration(userSerial));
270 
271         mDataStore.setBrightnessConfigurationForUser(config, userSerial, "packagename");
272         assertNotNull(mDataStore.getBrightnessConfiguration(userSerial));
273 
274         mDataStore.setBrightnessConfigurationForUser(null, userSerial, "packagename");
275         assertNull(mDataStore.getBrightnessConfiguration(userSerial));
276     }
277 
278     @Test
testStoreAndRestoreResolution()279     public void testStoreAndRestoreResolution() {
280         final String uniqueDisplayId = "test:123";
281         DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
282             @Override
283             public boolean hasStableUniqueId() {
284                 return true;
285             }
286 
287             @Override
288             public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
289                 return null;
290             }
291         };
292         int width = 35;
293         int height = 45;
294         mDataStore.loadIfNeeded();
295         mDataStore.setUserPreferredResolution(testDisplayDevice, width, height);
296 
297         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
298         mInjector.setWriteStream(baos);
299         mDataStore.saveIfNeeded();
300         mTestLooper.dispatchAll();
301         assertTrue(mInjector.wasWriteSuccessful());
302         TestInjector newInjector = new TestInjector();
303         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
304         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
305         newInjector.setReadStream(bais);
306         newDataStore.loadIfNeeded();
307         assertNotNull(newDataStore.getUserPreferredResolution(testDisplayDevice));
308         assertEquals(35, newDataStore.getUserPreferredResolution(testDisplayDevice).x);
309         assertEquals(35, mDataStore.getUserPreferredResolution(testDisplayDevice).x);
310         assertEquals(45, newDataStore.getUserPreferredResolution(testDisplayDevice).y);
311         assertEquals(45, mDataStore.getUserPreferredResolution(testDisplayDevice).y);
312     }
313 
314     @Test
testStoreAndRestoreRefreshRate()315     public void testStoreAndRestoreRefreshRate() {
316         final String uniqueDisplayId = "test:123";
317         DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
318             @Override
319             public boolean hasStableUniqueId() {
320                 return true;
321             }
322 
323             @Override
324             public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
325                 return null;
326             }
327         };
328         float refreshRate = 85.3f;
329         mDataStore.loadIfNeeded();
330         mDataStore.setUserPreferredRefreshRate(testDisplayDevice, refreshRate);
331 
332         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
333         mInjector.setWriteStream(baos);
334         mDataStore.saveIfNeeded();
335         mTestLooper.dispatchAll();
336         assertTrue(mInjector.wasWriteSuccessful());
337         TestInjector newInjector = new TestInjector();
338         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
339         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
340         newInjector.setReadStream(bais);
341         newDataStore.loadIfNeeded();
342         assertNotNull(newDataStore.getUserPreferredRefreshRate(testDisplayDevice));
343         assertEquals(85.3f, mDataStore.getUserPreferredRefreshRate(testDisplayDevice), 01.f);
344         assertEquals(85.3f, newDataStore.getUserPreferredRefreshRate(testDisplayDevice), 0.1f);
345     }
346 
347     @Test
testBrightnessInitialisesWithInvalidFloat()348     public void testBrightnessInitialisesWithInvalidFloat() {
349         final String uniqueDisplayId = "test:123";
350         DisplayDevice testDisplayDevice = new DisplayDevice(null, null, uniqueDisplayId, null) {
351             @Override
352             public boolean hasStableUniqueId() {
353                 return true;
354             }
355 
356             @Override
357             public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
358                 return null;
359             }
360         };
361 
362         // Set any value which initialises Display state
363         float refreshRate = 85.3f;
364         mDataStore.loadIfNeeded();
365         mDataStore.setUserPreferredRefreshRate(testDisplayDevice, refreshRate);
366 
367         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
368         mInjector.setWriteStream(baos);
369         mDataStore.saveIfNeeded();
370         mTestLooper.dispatchAll();
371         assertTrue(mInjector.wasWriteSuccessful());
372         TestInjector newInjector = new TestInjector();
373         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
374         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
375         newInjector.setReadStream(bais);
376         newDataStore.loadIfNeeded();
377         assertTrue(Float.isNaN(mDataStore.getBrightness(testDisplayDevice)));
378     }
379 
380     @Test
testStoreAndRestoreBrightnessNitsForDefaultDisplay()381     public void testStoreAndRestoreBrightnessNitsForDefaultDisplay() {
382         float brightnessNitsForDefaultDisplay = 190;
383         mDataStore.loadIfNeeded();
384         mDataStore.setBrightnessNitsForDefaultDisplay(brightnessNitsForDefaultDisplay);
385 
386         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
387         mInjector.setWriteStream(baos);
388         mDataStore.saveIfNeeded();
389         mTestLooper.dispatchAll();
390         assertTrue(mInjector.wasWriteSuccessful());
391         TestInjector newInjector = new TestInjector();
392         PersistentDataStore newDataStore = new PersistentDataStore(newInjector);
393         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
394         newInjector.setReadStream(bais);
395         newDataStore.loadIfNeeded();
396         assertEquals(brightnessNitsForDefaultDisplay,
397                 mDataStore.getBrightnessNitsForDefaultDisplay(), 0);
398         assertEquals(brightnessNitsForDefaultDisplay,
399                 newDataStore.getBrightnessNitsForDefaultDisplay(), 0);
400     }
401 
402     @Test
testInitialBrightnessNitsForDefaultDisplay()403     public void testInitialBrightnessNitsForDefaultDisplay() {
404         mDataStore.loadIfNeeded();
405         assertEquals(-1, mDataStore.getBrightnessNitsForDefaultDisplay(), 0);
406     }
407 
408     public class TestInjector extends PersistentDataStore.Injector {
409         private InputStream mReadStream;
410         private OutputStream mWriteStream;
411 
412         private boolean mWasSuccessful;
413 
414         @Override
openRead()415         public InputStream openRead() throws FileNotFoundException {
416             if (mReadStream != null) {
417                 return mReadStream;
418             } else {
419                 throw new FileNotFoundException();
420             }
421         }
422 
423         @Override
startWrite()424         public OutputStream startWrite() {
425             return mWriteStream;
426         }
427 
428         @Override
finishWrite(OutputStream os, boolean success)429         public void finishWrite(OutputStream os, boolean success) {
430             mWasSuccessful = success;
431             try {
432                 os.close();
433             } catch (IOException e) {
434                 // This method can't throw IOException since the super implementation doesn't, so
435                 // we just wrap it in a RuntimeException so we end up crashing the test all the
436                 // same.
437                 throw new RuntimeException(e);
438             }
439         }
440 
setReadStream(InputStream is)441         public void setReadStream(InputStream is) {
442             mReadStream = is;
443         }
444 
setWriteStream(OutputStream os)445         public void setWriteStream(OutputStream os) {
446             mWriteStream = os;
447         }
448 
wasWriteSuccessful()449         public boolean wasWriteSuccessful() {
450             return mWasSuccessful;
451         }
452     }
453 
assertArrayEquals(float[] expected, float[] actual, String name)454     private static void assertArrayEquals(float[] expected, float[] actual, String name) {
455         assertEquals("Expected " + name + " arrays to be the same length!",
456                 expected.length, actual.length);
457         for (int i = 0; i < expected.length; i++) {
458             assertEquals("Expected " + name + " arrays to be equivalent when value " + i
459                     + "differs", expected[i], actual[i], 0.01 /*tolerance*/);
460         }
461     }
462 }
463