1 /* 2 * Copyright 2018 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.assertNull; 23 import static org.junit.Assert.assertTrue; 24 25 import android.hardware.display.AmbientBrightnessDayStats; 26 import android.os.SystemClock; 27 import android.os.UserManager; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.filters.SmallTest; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.io.ByteArrayInputStream; 38 import java.io.ByteArrayOutputStream; 39 import java.io.IOException; 40 import java.io.InputStream; 41 import java.nio.charset.StandardCharsets; 42 import java.time.LocalDate; 43 import java.util.ArrayList; 44 45 @SmallTest 46 @RunWith(AndroidJUnit4.class) 47 public class AmbientBrightnessStatsTrackerTest { 48 49 private TestInjector mTestInjector; 50 51 @Before setUp()52 public void setUp() { 53 mTestInjector = new TestInjector(); 54 } 55 56 @Test testBrightnessStatsTrackerOverSingleDay()57 public void testBrightnessStatsTrackerOverSingleDay() { 58 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 59 ArrayList<AmbientBrightnessDayStats> userStats; 60 float[] expectedStats; 61 // Test case where no user data 62 userStats = statsTracker.getUserStats(0); 63 assertNull(userStats); 64 // Test after adding some user data 65 statsTracker.start(); 66 statsTracker.add(0, 0); 67 mTestInjector.incrementTime(1000); 68 statsTracker.stop(); 69 userStats = statsTracker.getUserStats(0); 70 assertEquals(1, userStats.size()); 71 assertEquals(mTestInjector.getLocalDate(), userStats.get(0).getLocalDate()); 72 expectedStats = getEmptyStatsArray(); 73 expectedStats[0] = 1; 74 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 75 // Test after adding some more user data 76 statsTracker.start(); 77 statsTracker.add(0, 0.05f); 78 mTestInjector.incrementTime(1000); 79 statsTracker.add(0, 0.2f); 80 mTestInjector.incrementTime(1500); 81 statsTracker.add(0, 50000); 82 mTestInjector.incrementTime(2500); 83 statsTracker.stop(); 84 userStats = statsTracker.getUserStats(0); 85 assertEquals(1, userStats.size()); 86 assertEquals(mTestInjector.getLocalDate(), userStats.get(0).getLocalDate()); 87 expectedStats = getEmptyStatsArray(); 88 expectedStats[0] = 2; 89 expectedStats[1] = 1.5f; 90 expectedStats[11] = 2.5f; 91 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 92 } 93 94 @Test testBrightnessStatsTrackerOverMultipleDays()95 public void testBrightnessStatsTrackerOverMultipleDays() { 96 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 97 ArrayList<AmbientBrightnessDayStats> userStats; 98 float[] expectedStats; 99 // Add data for day 1 100 statsTracker.start(); 101 statsTracker.add(0, 0.05f); 102 mTestInjector.incrementTime(1000); 103 statsTracker.add(0, 0.2f); 104 mTestInjector.incrementTime(1500); 105 statsTracker.add(0, 1); 106 mTestInjector.incrementTime(2500); 107 statsTracker.stop(); 108 // Add data for day 2 109 mTestInjector.incrementDate(1); 110 statsTracker.start(); 111 statsTracker.add(0, 0); 112 mTestInjector.incrementTime(3500); 113 statsTracker.add(0, 5); 114 mTestInjector.incrementTime(5000); 115 statsTracker.stop(); 116 // Test that the data is tracked as expected 117 userStats = statsTracker.getUserStats(0); 118 assertEquals(2, userStats.size()); 119 assertEquals(mTestInjector.getLocalDate().minusDays(1), userStats.get(0).getLocalDate()); 120 expectedStats = getEmptyStatsArray(); 121 expectedStats[0] = 1; 122 expectedStats[1] = 1.5f; 123 expectedStats[3] = 2.5f; 124 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 125 assertEquals(mTestInjector.getLocalDate(), userStats.get(1).getLocalDate()); 126 expectedStats = getEmptyStatsArray(); 127 expectedStats[0] = 3.5f; 128 expectedStats[4] = 5; 129 assertArrayEquals(expectedStats, userStats.get(1).getStats(), 0); 130 } 131 132 @Test testBrightnessStatsTrackerOverMultipleUsers()133 public void testBrightnessStatsTrackerOverMultipleUsers() { 134 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 135 ArrayList<AmbientBrightnessDayStats> userStats; 136 float[] expectedStats; 137 // Add data for user 1 138 statsTracker.start(); 139 statsTracker.add(0, 0.05f); 140 mTestInjector.incrementTime(1000); 141 statsTracker.add(0, 0.2f); 142 mTestInjector.incrementTime(1500); 143 statsTracker.add(0, 1); 144 mTestInjector.incrementTime(2500); 145 statsTracker.stop(); 146 // Add data for user 2 147 mTestInjector.incrementDate(1); 148 statsTracker.start(); 149 statsTracker.add(1, 0); 150 mTestInjector.incrementTime(3500); 151 statsTracker.add(1, 5); 152 mTestInjector.incrementTime(5000); 153 statsTracker.stop(); 154 // Test that the data is tracked as expected 155 userStats = statsTracker.getUserStats(0); 156 assertEquals(1, userStats.size()); 157 assertEquals(mTestInjector.getLocalDate().minusDays(1), userStats.get(0).getLocalDate()); 158 expectedStats = getEmptyStatsArray(); 159 expectedStats[0] = 1; 160 expectedStats[1] = 1.5f; 161 expectedStats[3] = 2.5f; 162 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 163 userStats = statsTracker.getUserStats(1); 164 assertEquals(1, userStats.size()); 165 assertEquals(mTestInjector.getLocalDate(), userStats.get(0).getLocalDate()); 166 expectedStats = getEmptyStatsArray(); 167 expectedStats[0] = 3.5f; 168 expectedStats[4] = 5; 169 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 170 } 171 172 @Test testBrightnessStatsTrackerOverMaxDays()173 public void testBrightnessStatsTrackerOverMaxDays() { 174 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 175 ArrayList<AmbientBrightnessDayStats> userStats; 176 // Add 10 extra days of data over the buffer limit 177 for (int i = 0; i < AmbientBrightnessStatsTracker.MAX_DAYS_TO_TRACK + 10; i++) { 178 mTestInjector.incrementDate(1); 179 statsTracker.start(); 180 statsTracker.add(0, 10); 181 mTestInjector.incrementTime(1000); 182 statsTracker.add(0, 20); 183 mTestInjector.incrementTime(1000); 184 statsTracker.stop(); 185 } 186 // Assert that we are only tracking last "MAX_DAYS_TO_TRACK" 187 userStats = statsTracker.getUserStats(0); 188 assertEquals(AmbientBrightnessStatsTracker.MAX_DAYS_TO_TRACK, userStats.size()); 189 LocalDate runningDate = mTestInjector.getLocalDate(); 190 for (int i = AmbientBrightnessStatsTracker.MAX_DAYS_TO_TRACK - 1; i >= 0; i--) { 191 assertEquals(runningDate, userStats.get(i).getLocalDate()); 192 runningDate = runningDate.minusDays(1); 193 } 194 } 195 196 @Test testReadAmbientBrightnessStats()197 public void testReadAmbientBrightnessStats() throws IOException { 198 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 199 LocalDate date = mTestInjector.getLocalDate(); 200 ArrayList<AmbientBrightnessDayStats> userStats; 201 String statsFile = 202 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\r\n" 203 + "<ambient-brightness-stats>\r\n" 204 // Old stats that shouldn't be read 205 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" 206 + date.minusDays(AmbientBrightnessStatsTracker.MAX_DAYS_TO_TRACK) 207 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 208 + "3000.0,10000.0\" bucket-stats=\"1.088,0.0,0.726,0.0,25.868,0.0,0.0," 209 + "0.0,0.0,0.0\" />\r\n" 210 // Valid stats that should get read 211 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" 212 + date.minusDays(1) 213 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 214 + "3000.0,10000.0\" bucket-stats=\"1.088,0.0,0.726,0.0,25.868,0.0,0.0," 215 + "0.0,0.0,0.0\" />\r\n" 216 // Valid stats that should get read 217 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" + date 218 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 219 + "3000.0,10000.0\" bucket-stats=\"0.0,0.0,0.0,0.0,4.482,0.0,0.0,0.0,0.0," 220 + "0.0\" />\r\n" 221 + "</ambient-brightness-stats>"; 222 statsTracker.readStats(getInputStream(statsFile)); 223 userStats = statsTracker.getUserStats(0); 224 assertEquals(2, userStats.size()); 225 assertEquals(new AmbientBrightnessDayStats(date.minusDays(1), 226 new float[]{0, 1, 3, 10, 30, 100, 300, 1000, 3000, 10000}, 227 new float[]{1.088f, 0, 0.726f, 0, 25.868f, 0, 0, 0, 0, 0}), userStats.get(0)); 228 assertEquals(new AmbientBrightnessDayStats(date, 229 new float[]{0, 1, 3, 10, 30, 100, 300, 1000, 3000, 10000}, 230 new float[]{0, 0, 0, 0, 4.482f, 0, 0, 0, 0, 0}), userStats.get(1)); 231 } 232 233 @Test testFailedReadAmbientBrightnessStatsWithException()234 public void testFailedReadAmbientBrightnessStatsWithException() { 235 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 236 LocalDate date = mTestInjector.getLocalDate(); 237 String statsFile; 238 // Test with parse error 239 statsFile = 240 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\r\n" 241 + "<ambient-brightness-stats>\r\n" 242 // Incorrect since bucket boundaries not parsable 243 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" + date 244 + "\" bucket-boundaries=\"asdf,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 245 + "3000.0,10000.0\" bucket-stats=\"1.088,0.0,0.726,0.0,25.868,0.0,0.0," 246 + "0.0,0.0,0.0\" />\r\n" 247 + "</ambient-brightness-stats>"; 248 try { 249 statsTracker.readStats(getInputStream(statsFile)); 250 } catch (IOException e) { 251 // Expected 252 } 253 assertNull(statsTracker.getUserStats(0)); 254 // Test with incorrect data (bucket boundaries length not equal to stats length) 255 statsFile = 256 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\r\n" 257 + "<ambient-brightness-stats>\r\n" 258 // Correct data 259 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" 260 + date.minusDays(1) 261 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 262 + "3000.0,10000.0\" bucket-stats=\"0.0,0.0,0.0,0.0,4.482,0.0,0.0,0.0,0.0," 263 + "0.0\" />\r\n" 264 // Incorrect data 265 + "<ambient-brightness-day-stats user=\"10\" local-date=\"" + date 266 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,1000.0," 267 + "3000.0,10000.0\" bucket-stats=\"1.088,0.0,0.726,0.0,25.868,0.0,0.0," 268 + "0.0,0.0,0.0\" />\r\n" 269 + "</ambient-brightness-stats>"; 270 try { 271 statsTracker.readStats(getInputStream(statsFile)); 272 } catch (Exception e) { 273 // Expected 274 } 275 assertNull(statsTracker.getUserStats(0)); 276 // Test with missing attribute 277 statsFile = 278 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\r\n" 279 + "<ambient-brightness-stats>\r\n" 280 + "<ambientBrightnessDayStats user=\"10\" local-date=\"" + date 281 + "\" bucket-boundaries=\"0.0,1.0,3.0,10.0,30.0,100.0,300.0,1000.0," 282 + "3000.0,10000.0\" />\r\n" 283 + "</ambient-brightness-stats>"; 284 try { 285 statsTracker.readStats(getInputStream(statsFile)); 286 } catch (Exception e) { 287 // Expected 288 } 289 assertNull(statsTracker.getUserStats(0)); 290 } 291 292 @Test testWriteThenReadAmbientBrightnessStats()293 public void testWriteThenReadAmbientBrightnessStats() throws IOException { 294 AmbientBrightnessStatsTracker statsTracker = getTestStatsTracker(); 295 ArrayList<AmbientBrightnessDayStats> userStats; 296 float[] expectedStats; 297 // Generate some placeholder data 298 // Data: very old which should not be read 299 statsTracker.start(); 300 statsTracker.add(0, 0.05f); 301 mTestInjector.incrementTime(1000); 302 statsTracker.add(0, 0.2f); 303 mTestInjector.incrementTime(1500); 304 statsTracker.add(0, 1); 305 mTestInjector.incrementTime(2500); 306 statsTracker.stop(); 307 // Data: day 1 user 1 308 mTestInjector.incrementDate(AmbientBrightnessStatsTracker.MAX_DAYS_TO_TRACK - 1); 309 statsTracker.start(); 310 statsTracker.add(0, 0.05f); 311 mTestInjector.incrementTime(1000); 312 statsTracker.add(0, 0.2f); 313 mTestInjector.incrementTime(1500); 314 statsTracker.add(0, 1); 315 mTestInjector.incrementTime(2500); 316 statsTracker.stop(); 317 // Data: day 1 user 2 318 statsTracker.start(); 319 statsTracker.add(1, 0); 320 mTestInjector.incrementTime(3500); 321 statsTracker.add(1, 5); 322 mTestInjector.incrementTime(5000); 323 statsTracker.stop(); 324 // Data: day 2 user 1 325 mTestInjector.incrementDate(1); 326 statsTracker.start(); 327 statsTracker.add(0, 0); 328 mTestInjector.incrementTime(3500); 329 statsTracker.add(0, 50000); 330 mTestInjector.incrementTime(5000); 331 statsTracker.stop(); 332 // Write them 333 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 334 statsTracker.writeStats(baos); 335 baos.flush(); 336 // Read them back and assert that it's the same 337 ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray()); 338 AmbientBrightnessStatsTracker newStatsTracker = getTestStatsTracker(); 339 newStatsTracker.readStats(input); 340 userStats = newStatsTracker.getUserStats(0); 341 assertEquals(2, userStats.size()); 342 // Check day 1 user 1 343 assertEquals(mTestInjector.getLocalDate().minusDays(1), userStats.get(0).getLocalDate()); 344 expectedStats = getEmptyStatsArray(); 345 expectedStats[0] = 1; 346 expectedStats[1] = 1.5f; 347 expectedStats[3] = 2.5f; 348 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 349 // Check day 2 user 1 350 assertEquals(mTestInjector.getLocalDate(), userStats.get(1).getLocalDate()); 351 expectedStats = getEmptyStatsArray(); 352 expectedStats[0] = 3.5f; 353 expectedStats[11] = 5; 354 assertArrayEquals(expectedStats, userStats.get(1).getStats(), 0); 355 userStats = newStatsTracker.getUserStats(1); 356 assertEquals(1, userStats.size()); 357 // Check day 1 user 2 358 assertEquals(mTestInjector.getLocalDate().minusDays(1), userStats.get(0).getLocalDate()); 359 expectedStats = getEmptyStatsArray(); 360 expectedStats[0] = 3.5f; 361 expectedStats[4] = 5; 362 assertArrayEquals(expectedStats, userStats.get(0).getStats(), 0); 363 } 364 365 @Test testTimer()366 public void testTimer() { 367 AmbientBrightnessStatsTracker.Timer timer = new AmbientBrightnessStatsTracker.Timer( 368 () -> mTestInjector.elapsedRealtimeMillis()); 369 assertEquals(0, timer.totalDurationSec(), 0); 370 mTestInjector.incrementTime(1000); 371 assertEquals(0, timer.totalDurationSec(), 0); 372 assertFalse(timer.isRunning()); 373 // Start timer 374 timer.start(); 375 assertTrue(timer.isRunning()); 376 assertEquals(0, timer.totalDurationSec(), 0); 377 mTestInjector.incrementTime(1000); 378 assertTrue(timer.isRunning()); 379 assertEquals(1, timer.totalDurationSec(), 0); 380 // Reset timer 381 timer.reset(); 382 assertEquals(0, timer.totalDurationSec(), 0); 383 assertFalse(timer.isRunning()); 384 // Start again 385 timer.start(); 386 assertTrue(timer.isRunning()); 387 assertEquals(0, timer.totalDurationSec(), 0); 388 mTestInjector.incrementTime(2000); 389 assertTrue(timer.isRunning()); 390 assertEquals(2, timer.totalDurationSec(), 0); 391 // Reset again 392 timer.reset(); 393 assertEquals(0, timer.totalDurationSec(), 0); 394 assertFalse(timer.isRunning()); 395 } 396 397 private class TestInjector extends AmbientBrightnessStatsTracker.Injector { 398 399 private long mElapsedRealtimeMillis = SystemClock.elapsedRealtime(); 400 private LocalDate mLocalDate = LocalDate.now(); 401 incrementTime(long timeMillis)402 public void incrementTime(long timeMillis) { 403 mElapsedRealtimeMillis += timeMillis; 404 } 405 incrementDate(int numDays)406 public void incrementDate(int numDays) { 407 mLocalDate = mLocalDate.plusDays(numDays); 408 } 409 410 @Override elapsedRealtimeMillis()411 public long elapsedRealtimeMillis() { 412 return mElapsedRealtimeMillis; 413 } 414 415 @Override getUserSerialNumber(UserManager userManager, int userId)416 public int getUserSerialNumber(UserManager userManager, int userId) { 417 return userId + 10; 418 } 419 420 @Override getUserId(UserManager userManager, int userSerialNumber)421 public int getUserId(UserManager userManager, int userSerialNumber) { 422 return userSerialNumber - 10; 423 } 424 425 @Override getLocalDate()426 public LocalDate getLocalDate() { 427 return mLocalDate; 428 } 429 } 430 getTestStatsTracker()431 private AmbientBrightnessStatsTracker getTestStatsTracker() { 432 return new AmbientBrightnessStatsTracker( 433 InstrumentationRegistry.getContext().getSystemService(UserManager.class), 434 mTestInjector); 435 } 436 getEmptyStatsArray()437 private float[] getEmptyStatsArray() { 438 return new float[AmbientBrightnessStatsTracker.BUCKET_BOUNDARIES_FOR_NEW_STATS.length]; 439 } 440 getInputStream(String data)441 private InputStream getInputStream(String data) { 442 return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); 443 } 444 } 445