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 17package com.android.server.display; 18 19import static org.junit.Assert.assertEquals; 20import static org.junit.Assert.assertNotNull; 21import static org.junit.Assert.assertNull; 22import static org.junit.Assert.assertTrue; 23 24import android.hardware.display.BrightnessConfiguration; 25import android.support.test.filters.SmallTest; 26import android.support.test.runner.AndroidJUnit4; 27import android.util.AtomicFile; 28import android.util.Pair; 29 30import org.junit.Before; 31import org.junit.Test; 32import org.junit.runner.RunWith; 33 34import java.io.FileInputStream; 35import java.io.ByteArrayInputStream; 36import java.io.ByteArrayOutputStream; 37import java.io.FileNotFoundException; 38import java.io.InputStream; 39import java.io.IOException; 40import java.io.OutputStream; 41import java.io.PrintWriter; 42import java.nio.charset.StandardCharsets; 43 44@SmallTest 45@RunWith(AndroidJUnit4.class) 46public class PersistentDataStoreTest { 47 private PersistentDataStore mDataStore; 48 private TestInjector mInjector; 49 50 @Before 51 public void setUp() { 52 mInjector = new TestInjector(); 53 mDataStore = new PersistentDataStore(mInjector); 54 } 55 56 @Test 57 public void testLoadingBrightnessConfigurations() { 58 String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 59 + "<display-manager-state>\n" 60 + " <brightness-configurations>\n" 61 + " <brightness-configuration" 62 + " user-serial=\"1\"" 63 + " package-name=\"example.com\"" 64 + " timestamp=\"123456\">\n" 65 + " <brightness-curve description=\"something\">\n" 66 + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n" 67 + " <brightness-point lux=\"25\" nits=\"35.94\"/>\n" 68 + " </brightness-curve>\n" 69 + " </brightness-configuration>\n" 70 + " <brightness-configuration user-serial=\"3\">\n" 71 + " <brightness-curve>\n" 72 + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n" 73 + " <brightness-point lux=\"10.2\" nits=\"15\"/>\n" 74 + " </brightness-curve>\n" 75 + " </brightness-configuration>\n" 76 + " </brightness-configurations>\n" 77 + "</display-manager-state>\n"; 78 InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); 79 mInjector.setReadStream(is); 80 mDataStore.loadIfNeeded(); 81 BrightnessConfiguration config = mDataStore.getBrightnessConfiguration(1 /*userSerial*/); 82 Pair<float[], float[]> curve = config.getCurve(); 83 float[] expectedLux = { 0f, 25f }; 84 float[] expectedNits = { 13.25f, 35.94f }; 85 assertArrayEquals(expectedLux, curve.first, "lux"); 86 assertArrayEquals(expectedNits, curve.second, "nits"); 87 assertEquals("something", config.getDescription()); 88 89 config = mDataStore.getBrightnessConfiguration(3 /*userSerial*/); 90 curve = config.getCurve(); 91 expectedLux = new float[] { 0f, 10.2f }; 92 expectedNits = new float[] { 13.25f, 15f }; 93 assertArrayEquals(expectedLux, curve.first, "lux"); 94 assertArrayEquals(expectedNits, curve.second, "nits"); 95 assertNull(config.getDescription()); 96 } 97 98 @Test 99 public void testBrightnessConfigWithInvalidCurveIsIgnored() { 100 String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 101 + "<display-manager-state>\n" 102 + " <brightness-configurations>\n" 103 + " <brightness-configuration user-serial=\"0\">\n" 104 + " <brightness-curve>\n" 105 + " <brightness-point lux=\"1\" nits=\"13.25\"/>\n" 106 + " <brightness-point lux=\"25\" nits=\"35.94\"/>\n" 107 + " </brightness-curve>\n" 108 + " </brightness-configuration>\n" 109 + " </brightness-configurations>\n" 110 + "</display-manager-state>\n"; 111 InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); 112 mInjector.setReadStream(is); 113 mDataStore.loadIfNeeded(); 114 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 115 } 116 117 @Test 118 public void testBrightnessConfigWithInvalidFloatsIsIgnored() { 119 String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 120 + "<display-manager-state>\n" 121 + " <brightness-configurations>\n" 122 + " <brightness-configuration user-serial=\"0\">\n" 123 + " <brightness-curve>\n" 124 + " <brightness-point lux=\"0\" nits=\"13.25\"/>\n" 125 + " <brightness-point lux=\"0xFF\" nits=\"foo\"/>\n" 126 + " </brightness-curve>\n" 127 + " </brightness-configuration>\n" 128 + " </brightness-configurations>\n" 129 + "</display-manager-state>\n"; 130 InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); 131 mInjector.setReadStream(is); 132 mDataStore.loadIfNeeded(); 133 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 134 } 135 136 @Test 137 public void testEmptyBrightnessConfigurationsDoesntCrash() { 138 String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 139 + "<display-manager-state>\n" 140 + " <brightness-configurations />\n" 141 + "</display-manager-state>\n"; 142 InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)); 143 mInjector.setReadStream(is); 144 mDataStore.loadIfNeeded(); 145 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 146 } 147 148 @Test 149 public void testStoreAndReloadOfBrightnessConfigurations() { 150 final float[] lux = { 0f, 10f }; 151 final float[] nits = {1f, 100f }; 152 final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits) 153 .setDescription("a description") 154 .build(); 155 mDataStore.loadIfNeeded(); 156 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 157 mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename"); 158 159 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 160 mInjector.setWriteStream(baos); 161 mDataStore.saveIfNeeded(); 162 assertTrue(mInjector.wasWriteSuccessful()); 163 164 TestInjector newInjector = new TestInjector(); 165 PersistentDataStore newDataStore = new PersistentDataStore(newInjector); 166 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 167 newInjector.setReadStream(bais); 168 newDataStore.loadIfNeeded(); 169 assertNotNull(newDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 170 assertEquals(mDataStore.getBrightnessConfiguration(0 /*userSerial*/), 171 newDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 172 } 173 174 @Test 175 public void testNullBrightnessConfiguration() { 176 final float[] lux = { 0f, 10f }; 177 final float[] nits = {1f, 100f }; 178 final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits) 179 .setDescription("a description") 180 .build(); 181 mDataStore.loadIfNeeded(); 182 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 183 184 mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename"); 185 assertNotNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 186 187 mDataStore.setBrightnessConfigurationForUser(null, 0, "packagename"); 188 assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/)); 189 } 190 191 public class TestInjector extends PersistentDataStore.Injector { 192 private InputStream mReadStream; 193 private OutputStream mWriteStream; 194 195 private boolean mWasSuccessful; 196 197 @Override 198 public InputStream openRead() throws FileNotFoundException { 199 if (mReadStream != null) { 200 return mReadStream; 201 } else { 202 throw new FileNotFoundException(); 203 } 204 } 205 206 @Override 207 public OutputStream startWrite() { 208 return mWriteStream; 209 } 210 211 @Override 212 public void finishWrite(OutputStream os, boolean success) { 213 mWasSuccessful = success; 214 try { 215 os.close(); 216 } catch (IOException e) { 217 // This method can't throw IOException since the super implementation doesn't, so 218 // we just wrap it in a RuntimeException so we end up crashing the test all the 219 // same. 220 throw new RuntimeException(e); 221 } 222 } 223 224 public void setReadStream(InputStream is) { 225 mReadStream = is; 226 } 227 228 public void setWriteStream(OutputStream os) { 229 mWriteStream = os; 230 } 231 232 public boolean wasWriteSuccessful() { 233 return mWasSuccessful; 234 } 235 } 236 237 private static void assertArrayEquals(float[] expected, float[] actual, String name) { 238 assertEquals("Expected " + name + " arrays to be the same length!", 239 expected.length, actual.length); 240 for (int i = 0; i < expected.length; i++) { 241 assertEquals("Expected " + name + " arrays to be equivalent when value " + i 242 + "differs", expected[i], actual[i], 0.01 /*tolerance*/); 243 } 244 } 245} 246