1 /* 2 * Copyright (C) 2015 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 package android.app.cts; 17 18 import static android.Manifest.permission.WRITE_SECURE_SETTINGS; 19 import static android.app.UiModeManager.MODE_NIGHT_AUTO; 20 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM; 21 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME; 22 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE; 23 import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN; 24 import static android.app.UiModeManager.MODE_NIGHT_NO; 25 import static android.app.UiModeManager.MODE_NIGHT_YES; 26 27 import static androidx.test.InstrumentationRegistry.getInstrumentation; 28 29 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; 30 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 31 32 import static com.google.common.truth.Truth.assertThat; 33 34 import static org.testng.Assert.assertThrows; 35 36 import android.Manifest; 37 import android.app.UiAutomation; 38 import android.app.UiModeManager; 39 import android.app.UiModeManager.ContrastChangeListener; 40 import android.content.Context; 41 import android.content.pm.PackageManager; 42 import android.content.res.Configuration; 43 import android.os.Handler; 44 import android.os.HandlerThread; 45 import android.os.ParcelFileDescriptor; 46 import android.os.UserHandle; 47 import android.provider.Settings; 48 import android.test.AndroidTestCase; 49 import android.text.TextUtils; 50 import android.util.ArraySet; 51 import android.util.Log; 52 53 import com.android.compatibility.common.util.BatteryUtils; 54 import com.android.compatibility.common.util.CommonTestUtils; 55 import com.android.compatibility.common.util.TestUtils; 56 import com.android.compatibility.common.util.UserSettings; 57 58 import com.google.common.util.concurrent.MoreExecutors; 59 60 import junit.framework.Assert; 61 62 import java.io.FileInputStream; 63 import java.io.IOException; 64 import java.io.InputStream; 65 import java.time.LocalTime; 66 import java.util.ArrayList; 67 import java.util.List; 68 import java.util.Set; 69 import java.util.concurrent.Executor; 70 import java.util.concurrent.atomic.AtomicBoolean; 71 import java.util.concurrent.atomic.AtomicInteger; 72 import java.util.concurrent.atomic.AtomicReference; 73 74 75 public class UiModeManagerTest extends AndroidTestCase { 76 private static final String TAG = "UiModeManagerTest"; 77 private static final long MAX_WAIT_TIME_SECS = 2; 78 private static final long MAX_WAIT_TIME_MS = MAX_WAIT_TIME_SECS * 1000; 79 private static final long WAIT_TIME_INCR_MS = 100; 80 81 private static final String CONTRAST_LEVEL = "contrast_level"; 82 83 private final UserSettings mSystemUserSettings = new UserSettings(UserHandle.USER_SYSTEM); 84 private UiModeManager mUiModeManager; 85 private boolean mHasModifiedNightModePermissionAcquired = false; 86 87 @Override setUp()88 protected void setUp() throws Exception { 89 super.setUp(); 90 mUiModeManager = (UiModeManager) getContext().getSystemService(Context.UI_MODE_SERVICE); 91 assertNotNull(mUiModeManager); 92 resetNightMode(); 93 // Make sure automotive projection is not set by this package at the beginning of the test. 94 releaseAutomotiveProjection(); 95 } 96 97 @Override tearDown()98 protected void tearDown() throws Exception { 99 resetNightMode(); 100 BatteryUtils.runDumpsysBatteryReset(); 101 BatteryUtils.resetBatterySaver(); 102 } 103 resetNightMode()104 private void resetNightMode() { 105 try { 106 if (!mHasModifiedNightModePermissionAcquired) { 107 acquireModifyNightModePermission(); 108 } 109 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 110 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 111 false /* active */); 112 } finally { 113 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 114 mHasModifiedNightModePermissionAcquired = false; 115 } 116 } 117 testUiMode()118 public void testUiMode() throws Exception { 119 if (isAutomotive()) { 120 Log.i(TAG, "testUiMode automotive"); 121 doTestUiModeForAutomotive(); 122 } else if (isTelevision()) { 123 assertEquals(Configuration.UI_MODE_TYPE_TELEVISION, 124 mUiModeManager.getCurrentModeType()); 125 doTestLockedUiMode(); 126 } else if (isWatch()) { 127 assertEquals(Configuration.UI_MODE_TYPE_WATCH, 128 mUiModeManager.getCurrentModeType()); 129 doTestLockedUiMode(); 130 } else { 131 Log.i(TAG, "testUiMode generic"); 132 doTestUiModeGeneric(); 133 } 134 } 135 testNightMode()136 public void testNightMode() throws Exception { 137 if (isAutomotive()) { 138 assertTrue(mUiModeManager.isNightModeLocked()); 139 doTestLockedNightMode(); 140 } else { 141 if (mUiModeManager.isNightModeLocked()) { 142 doTestLockedNightMode(); 143 } else { 144 doTestUnlockedNightMode(); 145 } 146 } 147 } 148 testSetAndGetCustomTimeStart()149 public void testSetAndGetCustomTimeStart() { 150 LocalTime time = mUiModeManager.getCustomNightModeStart(); 151 // decrease time 152 LocalTime timeNew = LocalTime.of( 153 (time.getHour() + 1) % 12, 154 (time.getMinute() + 30) % 60); 155 setStartTime(timeNew); 156 assertNotSame(time, timeNew); 157 assertEquals(timeNew, mUiModeManager.getCustomNightModeStart()); 158 } 159 testSetAndGetCustomTimeEnd()160 public void testSetAndGetCustomTimeEnd() { 161 LocalTime time = mUiModeManager.getCustomNightModeEnd(); 162 // decrease time 163 LocalTime timeNew = LocalTime.of( 164 (time.getHour() + 1) % 12, 165 (time.getMinute() + 30) % 60); 166 setEndTime(timeNew); 167 assertNotSame(time, timeNew); 168 assertEquals(timeNew, mUiModeManager.getCustomNightModeEnd()); 169 } 170 testNightModeYesPersisted()171 public void testNightModeYesPersisted() throws InterruptedException { 172 if (mUiModeManager.isNightModeLocked()) { 173 Log.i(TAG, "testNightModeYesPersisted skipped: night mode is locked"); 174 return; 175 } 176 177 // Reset the mode to no if it is set to another value 178 setNightMode(UiModeManager.MODE_NIGHT_NO); 179 180 setNightMode(UiModeManager.MODE_NIGHT_YES); 181 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_YES); 182 } 183 testNightModeAutoPersisted()184 public void testNightModeAutoPersisted() throws InterruptedException { 185 if (mUiModeManager.isNightModeLocked()) { 186 Log.i(TAG, "testNightModeAutoPersisted skipped: night mode is locked"); 187 return; 188 } 189 190 // Reset the mode to no if it is set to another value 191 setNightMode(UiModeManager.MODE_NIGHT_NO); 192 193 setNightMode(UiModeManager.MODE_NIGHT_AUTO); 194 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_AUTO); 195 } 196 testSetNightModeCustomType_noPermission_bedtime_shouldThrow()197 public void testSetNightModeCustomType_noPermission_bedtime_shouldThrow() { 198 assertThrows(SecurityException.class, 199 () -> mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME)); 200 } 201 testSetNightModeCustomType_customTypeUnknown_bedtime_shouldThrow()202 public void testSetNightModeCustomType_customTypeUnknown_bedtime_shouldThrow() { 203 acquireModifyNightModePermission(); 204 205 assertThrows(IllegalArgumentException.class, 206 () -> mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN)); 207 } 208 testSetNightModeCustomType_bedtime_shouldPersist()209 public void testSetNightModeCustomType_bedtime_shouldPersist() { 210 acquireModifyNightModePermission(); 211 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 212 213 assertThat(mUiModeManager.getNightMode()).isEqualTo(MODE_NIGHT_CUSTOM); 214 assertThat(mUiModeManager.getNightModeCustomType()) 215 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 216 } 217 testSetNightModeCustomType_schedule_shouldPersist()218 public void testSetNightModeCustomType_schedule_shouldPersist() { 219 acquireModifyNightModePermission(); 220 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 221 222 assertThat(mUiModeManager.getNightMode()).isEqualTo(MODE_NIGHT_CUSTOM); 223 assertThat(mUiModeManager.getNightModeCustomType()) 224 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 225 } 226 testGetNightModeCustomType_nightModeNo_shouldReturnUnknown()227 public void testGetNightModeCustomType_nightModeNo_shouldReturnUnknown() { 228 acquireModifyNightModePermission(); 229 mUiModeManager.setNightMode(MODE_NIGHT_NO); 230 231 assertThat(mUiModeManager.getNightModeCustomType()) 232 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 233 } 234 testGetNightModeCustomType_nightModeYes_shouldReturnUnknown()235 public void testGetNightModeCustomType_nightModeYes_shouldReturnUnknown() { 236 acquireModifyNightModePermission(); 237 mUiModeManager.setNightMode(MODE_NIGHT_YES); 238 239 assertThat(mUiModeManager.getNightModeCustomType()) 240 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 241 } 242 testGetNightModeCustomType_nightModeAuto_shouldReturnUnknown()243 public void testGetNightModeCustomType_nightModeAuto_shouldReturnUnknown() { 244 acquireModifyNightModePermission(); 245 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 246 247 assertThat(mUiModeManager.getNightModeCustomType()) 248 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 249 } 250 testGetNightModeCustomType_nightModeCustom_shouldReturnScheduleAsDefault()251 public void testGetNightModeCustomType_nightModeCustom_shouldReturnScheduleAsDefault() { 252 acquireModifyNightModePermission(); 253 mUiModeManager.setNightMode(MODE_NIGHT_CUSTOM); 254 255 assertThat(mUiModeManager.getNightModeCustomType()) 256 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 257 } 258 testSetNightModeCustomType_hasPermission_bedtime_shouldNotActivateNightMode()259 public void testSetNightModeCustomType_hasPermission_bedtime_shouldNotActivateNightMode() { 260 acquireModifyNightModePermission(); 261 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 262 263 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 264 } 265 testSetNightModeActivatedForCustomMode_noPermission_customTypeBedtime_activateAtBedtime_shouldNotActivateNightMode()266 public void testSetNightModeActivatedForCustomMode_noPermission_customTypeBedtime_activateAtBedtime_shouldNotActivateNightMode() { 267 acquireModifyNightModePermission(); 268 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 269 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 270 mHasModifiedNightModePermissionAcquired = false; 271 272 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 273 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 274 275 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 276 } 277 testSetNightModeActivatedForCustomMode_customTypeBedtime_activateAtBedtime_shouldActivateNightMode()278 public void testSetNightModeActivatedForCustomMode_customTypeBedtime_activateAtBedtime_shouldActivateNightMode() { 279 acquireModifyNightModePermission(); 280 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 281 282 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 283 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isTrue(); 284 285 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 286 } 287 testSetNightModeActivatedForCustomMode_customTypeBedtime_deactivateAtBedtime_shouldDeactivateNightMode()288 public void testSetNightModeActivatedForCustomMode_customTypeBedtime_deactivateAtBedtime_shouldDeactivateNightMode() { 289 acquireModifyNightModePermission(); 290 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 291 292 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 293 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */)).isTrue(); 294 295 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 296 } 297 testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_shouldNotActivateNightMode()298 public void testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_shouldNotActivateNightMode() { 299 acquireModifyNightModePermission(); 300 mUiModeManager.setNightMode(MODE_NIGHT_NO); 301 302 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 303 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 304 305 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 306 } 307 testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_shouldKeepNightModeActivated()308 public void testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_shouldKeepNightModeActivated() { 309 acquireModifyNightModePermission(); 310 mUiModeManager.setNightMode(MODE_NIGHT_YES); 311 312 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 313 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 314 315 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 316 } 317 testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_shouldNotActivateNightMode()318 public void testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_shouldNotActivateNightMode() { 319 acquireModifyNightModePermission(); 320 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 321 int uiMode = getContext().getResources().getConfiguration().uiMode & 322 Configuration.UI_MODE_NIGHT_MASK; 323 324 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 325 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 326 327 assertVisibleNightModeInConfiguration(uiMode); 328 } 329 testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_shouldNotActivateNightMode()330 public void testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_shouldNotActivateNightMode() { 331 acquireModifyNightModePermission(); 332 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 333 int uiMode = getContext().getResources().getConfiguration().uiMode & 334 Configuration.UI_MODE_NIGHT_MASK; 335 336 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 337 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 338 339 assertVisibleNightModeInConfiguration(uiMode); 340 } 341 testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()342 public void testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 343 acquireModifyNightModePermission(); 344 mUiModeManager.setNightMode(MODE_NIGHT_NO); 345 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 346 true /* active */); 347 348 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 349 350 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 351 } 352 testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_thenCustomTypeBedtime_shouldActiveNightMode()353 public void testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_thenCustomTypeBedtime_shouldActiveNightMode() { 354 acquireModifyNightModePermission(); 355 mUiModeManager.setNightMode(MODE_NIGHT_YES); 356 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 357 true /* active */); 358 359 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 360 361 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 362 } 363 testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()364 public void testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 365 acquireModifyNightModePermission(); 366 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 367 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 368 true /* active */); 369 370 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 371 372 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 373 } 374 testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()375 public void testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 376 acquireModifyNightModePermission(); 377 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 378 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 379 true /* active */); 380 381 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 382 383 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 384 } 385 testNightModeAutoNotPersistedCarMode()386 public void testNightModeAutoNotPersistedCarMode() { 387 if (mUiModeManager.isNightModeLocked()) { 388 Log.i(TAG, "testNightModeAutoNotPersistedCarMode skipped: night mode is locked"); 389 return; 390 } 391 392 // Reset the mode to no if it is set to another value 393 setNightMode(UiModeManager.MODE_NIGHT_NO); 394 mUiModeManager.enableCarMode(0); 395 396 setNightMode(UiModeManager.MODE_NIGHT_AUTO); 397 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 398 mUiModeManager.disableCarMode(0); 399 } 400 testNightModeCustomTypeBedtimeNotPersistedInCarMode()401 public void testNightModeCustomTypeBedtimeNotPersistedInCarMode() throws InterruptedException { 402 if (mUiModeManager.isNightModeLocked()) { 403 Log.i(TAG, "testNightModeCustomTypeBedtimeNotPersistedInCarMode skipped: night mode is " 404 + "locked"); 405 return; 406 } 407 408 acquireModifyNightModePermission(); 409 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 410 mUiModeManager.enableCarMode(0); 411 412 // We don't expect users modifing bedtime features when driving. 413 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 414 415 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 416 mUiModeManager.disableCarMode(0); 417 } 418 testNightModeInCarModeIsTransient()419 public void testNightModeInCarModeIsTransient() { 420 if (mUiModeManager.isNightModeLocked()) { 421 Log.i(TAG, "testNightModeInCarModeIsTransient skipped: night mode is locked"); 422 return; 423 } 424 425 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 426 427 mUiModeManager.enableCarMode(0); 428 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 429 430 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 431 432 mUiModeManager.disableCarMode(0); 433 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 434 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 435 } 436 testNightModeToggleInCarModeDoesNotChangeSetting()437 public void testNightModeToggleInCarModeDoesNotChangeSetting() { 438 if (mUiModeManager.isNightModeLocked()) { 439 Log.i(TAG, "testNightModeToggleInCarModeDoesNotChangeSetting skipped: " 440 + "night mode is locked"); 441 return; 442 } 443 444 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 445 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 446 447 mUiModeManager.enableCarMode(0); 448 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 449 450 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 451 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 452 453 mUiModeManager.disableCarMode(0); 454 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 455 } 456 testNightModeInCarModeOnPowerSaveIsTransient()457 public void testNightModeInCarModeOnPowerSaveIsTransient() throws Throwable { 458 if (mUiModeManager.isNightModeLocked() || !BatteryUtils.isBatterySaverSupported()) { 459 Log.i(TAG, "testNightModeInCarModeOnPowerSaveIsTransient skipped: " 460 + "night mode is locked or battery saver is not supported"); 461 return; 462 } 463 464 BatteryUtils.runDumpsysBatteryUnplug(); 465 466 // Turn off battery saver, disable night mode 467 BatteryUtils.enableBatterySaver(false); 468 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 469 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 470 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 471 472 // Then enable battery saver to check night mode is made visible 473 BatteryUtils.enableBatterySaver(true); 474 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 475 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 476 477 // Then disable it, enable car mode, and check night mode is not visible 478 BatteryUtils.enableBatterySaver(false); 479 mUiModeManager.enableCarMode(0); 480 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 481 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 482 483 // Enable battery saver, check that night mode is still not visible, overridden by car mode 484 BatteryUtils.enableBatterySaver(true); 485 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 486 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 487 488 // Disable car mode 489 mUiModeManager.disableCarMode(0); 490 491 // Toggle night mode to force propagation of uiMode update, since disabling car mode 492 // is deferred to a broadcast. 493 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES); 494 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 495 496 // Check battery saver mode now shows night mode 497 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 498 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 499 500 // Disable battery saver and check night mode back to not visible 501 BatteryUtils.enableBatterySaver(false); 502 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 503 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 504 } 505 506 /** 507 * Verifies that an app holding the ENTER_CAR_MODE_PRIORITIZED permission can enter car mode 508 * while specifying a priority. 509 */ testEnterCarModePrioritized()510 public void testEnterCarModePrioritized() { 511 if (mUiModeManager.isUiModeLocked()) { 512 return; 513 } 514 515 runWithShellPermissionIdentity(() -> mUiModeManager.enableCarMode(100, 0), 516 Manifest.permission.ENTER_CAR_MODE_PRIORITIZED); 517 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 518 519 runWithShellPermissionIdentity(() -> mUiModeManager.disableCarMode(0), 520 Manifest.permission.ENTER_CAR_MODE_PRIORITIZED); 521 assertEquals(Configuration.UI_MODE_TYPE_NORMAL, mUiModeManager.getCurrentModeType()); 522 } 523 524 /** 525 * Attempts to use the prioritized car mode API when the caller does not hold the correct 526 * permission to use that API. 527 */ testEnterCarModePrioritizedDenied()528 public void testEnterCarModePrioritizedDenied() { 529 if (mUiModeManager.isUiModeLocked()) { 530 return; 531 } 532 try { 533 mUiModeManager.enableCarMode(100, 0); 534 } catch (SecurityException se) { 535 // Expect exception. 536 return; 537 } 538 fail("Expected SecurityException"); 539 } 540 541 /** 542 * Verifies that an app holding the TOGGLE_AUTOMOTIVE_PROJECTION permission can request/release 543 * automotive projection. 544 */ testToggleAutomotiveProjection()545 public void testToggleAutomotiveProjection() throws Exception { 546 // If we didn't hold it in the first place, we didn't release it, so expect false. 547 assertFalse(releaseAutomotiveProjection()); 548 assertTrue(requestAutomotiveProjection()); 549 // Multiple calls are OK. 550 assertTrue(requestAutomotiveProjection()); 551 assertTrue(releaseAutomotiveProjection()); 552 // Once it's released, further calls return false since it was already released. 553 assertFalse(releaseAutomotiveProjection()); 554 } 555 556 /** 557 * Verifies that the system can correctly read the projection state. 558 */ testReadProjectionState()559 public void testReadProjectionState() throws Exception { 560 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, getActiveProjectionTypes()); 561 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE).isEmpty()); 562 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL).isEmpty()); 563 requestAutomotiveProjection(); 564 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, getActiveProjectionTypes()); 565 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) 566 .contains(getContext().getPackageName())); 567 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL) 568 .contains(getContext().getPackageName())); 569 releaseAutomotiveProjection(); 570 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, getActiveProjectionTypes()); 571 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE).isEmpty()); 572 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL).isEmpty()); 573 } 574 575 /** Verifies that the system receives callbacks about the projection state at expected times. */ testReadProjectionState_listener()576 public void testReadProjectionState_listener() throws Exception { 577 // Use AtomicInteger so it can be effectively final. 578 AtomicInteger activeProjectionTypes = new AtomicInteger(); 579 Set<String> projectingPackages = new ArraySet<>(); 580 AtomicInteger callbackInvocations = new AtomicInteger(); 581 UiModeManager.OnProjectionStateChangedListener listener = (t, pkgs) -> { 582 Log.i(TAG, "onProjectionStateChanged(" + t + "," + pkgs + ")"); 583 activeProjectionTypes.set(t); 584 projectingPackages.clear(); 585 projectingPackages.addAll(pkgs); 586 callbackInvocations.incrementAndGet(); 587 }; 588 589 requestAutomotiveProjection(); 590 runWithShellPermissionIdentity(() -> mUiModeManager.addOnProjectionStateChangedListener( 591 UiModeManager.PROJECTION_TYPE_ALL, MoreExecutors.directExecutor(), listener), 592 Manifest.permission.READ_PROJECTION_STATE); 593 594 // Should have called back immediately, but the call might not have gotten here yet. 595 CommonTestUtils.waitUntil("Callback wasn't invoked on listener addition!", 596 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 1); 597 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, activeProjectionTypes.get()); 598 assertEquals(1, projectingPackages.size()); 599 assertTrue(projectingPackages.contains(getContext().getPackageName())); 600 601 // Callback should not be invoked again. 602 requestAutomotiveProjection(); 603 Thread.sleep(MAX_WAIT_TIME_MS); 604 assertEquals(1, callbackInvocations.get()); 605 606 releaseAutomotiveProjection(); 607 CommonTestUtils.waitUntil("Callback wasn't invoked on projection release!", 608 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 2); 609 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, activeProjectionTypes.get()); 610 assertEquals(0, projectingPackages.size()); 611 612 // Again, no callback for noop call. 613 releaseAutomotiveProjection(); 614 Thread.sleep(MAX_WAIT_TIME_MS); 615 assertEquals(2, callbackInvocations.get()); 616 617 // Test the case that isn't at time of registration. 618 requestAutomotiveProjection(); 619 CommonTestUtils.waitUntil("Callback wasn't invoked on projection set!", 620 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 3); 621 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, activeProjectionTypes.get()); 622 assertEquals(1, projectingPackages.size()); 623 assertTrue(projectingPackages.contains(getContext().getPackageName())); 624 625 // Unregister and shouldn't receive further callbacks. 626 runWithShellPermissionIdentity(() -> mUiModeManager.removeOnProjectionStateChangedListener( 627 listener), Manifest.permission.READ_PROJECTION_STATE); 628 629 releaseAutomotiveProjection(); 630 requestAutomotiveProjection(); 631 releaseAutomotiveProjection(); // Just to clean up. 632 Thread.sleep(MAX_WAIT_TIME_MS); 633 assertEquals(3, callbackInvocations.get()); 634 } 635 requestAutomotiveProjection()636 private boolean requestAutomotiveProjection() throws Exception { 637 return callWithShellPermissionIdentity( 638 () -> mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), 639 Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, 640 Manifest.permission.INTERACT_ACROSS_USERS); 641 } 642 releaseAutomotiveProjection()643 private boolean releaseAutomotiveProjection() throws Exception { 644 return callWithShellPermissionIdentity( 645 () -> mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), 646 Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, 647 Manifest.permission.INTERACT_ACROSS_USERS); 648 } 649 getActiveProjectionTypes()650 private int getActiveProjectionTypes() throws Exception { 651 return callWithShellPermissionIdentity(mUiModeManager::getActiveProjectionTypes, 652 Manifest.permission.READ_PROJECTION_STATE); 653 } 654 getProjectingPackages(int projectionType)655 private Set<String> getProjectingPackages(int projectionType) throws Exception { 656 return callWithShellPermissionIdentity( 657 () -> mUiModeManager.getProjectingPackages(projectionType), 658 Manifest.permission.READ_PROJECTION_STATE); 659 } 660 661 /** 662 * Attempts to request automotive projection without TOGGLE_AUTOMOTIVE_PROJECTION permission. 663 */ testRequestAutomotiveProjectionDenied()664 public void testRequestAutomotiveProjectionDenied() { 665 try { 666 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE); 667 } catch (SecurityException se) { 668 // Expect exception. 669 return; 670 } 671 fail("Expected SecurityException"); 672 } 673 674 /** 675 * Attempts to request automotive projection without TOGGLE_AUTOMOTIVE_PROJECTION permission. 676 */ testReleaseAutomotiveProjectionDenied()677 public void testReleaseAutomotiveProjectionDenied() { 678 try { 679 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE); 680 } catch (SecurityException se) { 681 // Expect exception. 682 return; 683 } 684 fail("Expected SecurityException"); 685 } 686 687 /** 688 * Attempts to request more than one projection type at once. 689 */ testRequestAllProjectionTypes()690 public void testRequestAllProjectionTypes() { 691 try { 692 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_ALL); 693 } catch (IllegalArgumentException iae) { 694 // Expect exception. 695 return; 696 } 697 fail("Expected IllegalArgumentException"); 698 } 699 700 /** 701 * Attempts to release more than one projection type. 702 */ testReleaseAllProjectionTypes()703 public void testReleaseAllProjectionTypes() { 704 try { 705 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_ALL); 706 } catch (IllegalArgumentException iae) { 707 // Expect exception. 708 return; 709 } 710 fail("Expected IllegalArgumentException"); 711 } 712 713 /** Attempts to request no projection types. */ testRequestNoProjectionTypes()714 public void testRequestNoProjectionTypes() { 715 try { 716 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_NONE); 717 } catch (IllegalArgumentException iae) { 718 // Expect exception. 719 return; 720 } 721 fail("Expected IllegalArgumentException"); 722 } 723 724 /** Attempts to release no projection types. */ testReleaseNoProjectionTypes()725 public void testReleaseNoProjectionTypes() { 726 try { 727 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_NONE); 728 } catch (IllegalArgumentException iae) { 729 // Expect exception. 730 return; 731 } 732 fail("Expected IllegalArgumentException"); 733 } 734 735 /** Attempts to call getActiveProjectionTypes without READ_PROJECTION_STATE permission. */ testReadProjectionState_getActiveProjectionTypesDenied()736 public void testReadProjectionState_getActiveProjectionTypesDenied() { 737 try { 738 mUiModeManager.getActiveProjectionTypes(); 739 } catch (SecurityException se) { 740 // Expect exception. 741 return; 742 } 743 fail("Expected SecurityException"); 744 } 745 746 /** Attempts to call getProjectingPackages without READ_PROJECTION_STATE permission. */ testReadProjectionState_getProjectingPackagesDenied()747 public void testReadProjectionState_getProjectingPackagesDenied() { 748 try { 749 mUiModeManager.getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL); 750 } catch (SecurityException se) { 751 // Expect exception. 752 return; 753 } 754 fail("Expected SecurityException"); 755 } 756 757 /** 758 * Attempts to call addOnProjectionStateChangedListener without 759 * READ_PROJECTION_STATE permission. 760 */ testReadProjectionState_addOnProjectionStateChangedListenerDenied()761 public void testReadProjectionState_addOnProjectionStateChangedListenerDenied() { 762 try { 763 mUiModeManager.addOnProjectionStateChangedListener(UiModeManager.PROJECTION_TYPE_ALL, 764 getContext().getMainExecutor(), (t, pkgs) -> { }); 765 } catch (SecurityException se) { 766 // Expect exception. 767 return; 768 } 769 fail("Expected SecurityException"); 770 } 771 772 /** 773 * Attempts to call removeOnProjectionStateChangedListener without 774 * READ_PROJECTION_STATE permission. 775 */ testReadProjectionState_removeOnProjectionStateChangedListenerDenied()776 public void testReadProjectionState_removeOnProjectionStateChangedListenerDenied() { 777 UiModeManager.OnProjectionStateChangedListener listener = (t, pkgs) -> { }; 778 runWithShellPermissionIdentity(() -> mUiModeManager.addOnProjectionStateChangedListener( 779 UiModeManager.PROJECTION_TYPE_ALL, getContext().getMainExecutor(), listener), 780 Manifest.permission.READ_PROJECTION_STATE); 781 try { 782 mUiModeManager.removeOnProjectionStateChangedListener(listener); 783 } catch (SecurityException se) { 784 // Expect exception. 785 return; 786 } 787 fail("Expected SecurityException"); 788 } 789 testGetContrast()790 public void testGetContrast() throws Exception { 791 float initialContrast = mUiModeManager.getContrast(); 792 putContrastInSettings(0f); 793 try { 794 for (float testContrast : List.of(-1f, 0.5f)) { 795 putContrastInSettings(testContrast); 796 TestUtils.waitUntil("getContrast() should return the new contrast value", 797 (int) MAX_WAIT_TIME_SECS, 798 () -> Math.abs(mUiModeManager.getContrast() - testContrast) < 1e-10); 799 } 800 } finally { 801 putContrastInSettings(initialContrast); 802 } 803 } 804 testAddContrastChangeListener()805 public void testAddContrastChangeListener() { 806 float initialContrast = mUiModeManager.getContrast(); 807 putContrastInSettings(0f); 808 final Object waitObject = new Object(); 809 final List<ContrastChangeListener> listeners = new ArrayList<>(); 810 811 // store callback errors here to avoid crashing the whole test suite 812 final AtomicReference<AssertionError> error = new AtomicReference<>(null); 813 final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 814 815 String handlerThreadName = "UiModeManagerTestBackgroundThread"; 816 final HandlerThread backgroundThread = new HandlerThread(handlerThreadName); 817 backgroundThread.start(); 818 Handler backgroundHandler = new Handler(backgroundThread.getLooper()); 819 Executor backgroundExecutor = backgroundHandler::post; 820 821 try { 822 for (float testContrast : List.of(-1f, 0f)) { 823 ContrastChangeListener listener = (float contrast) -> { 824 synchronized (waitObject) { 825 try { 826 assertEquals("Wrong value received by the color contrast listener", 827 testContrast, contrast, 1e-10); 828 assertEquals("The executor should be used to invoke the callback", 829 backgroundThread, Thread.currentThread()); 830 } catch (AssertionError e) { 831 error.set(e); 832 } 833 atomicBoolean.set(true); 834 waitObject.notifyAll(); 835 } 836 }; 837 listeners.add(listener); 838 mUiModeManager.addContrastChangeListener(backgroundExecutor, listener); 839 putContrastInSettings(testContrast); 840 waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject, 841 "The color contrast listener should be called when the setting changes"); 842 if (error.get() != null) throw error.get(); 843 mUiModeManager.removeContrastChangeListener(listener); 844 } 845 } finally { 846 backgroundThread.quitSafely(); 847 putContrastInSettings(initialContrast); 848 listeners.forEach(mUiModeManager::removeContrastChangeListener); 849 } 850 } 851 testRemoveContrastChangeListener()852 public void testRemoveContrastChangeListener() { 853 float initialContrast = mUiModeManager.getContrast(); 854 putContrastInSettings(0f); 855 final Object waitObject = new Object(); 856 857 // store callback errors here to avoid crashing the whole test suite 858 final AtomicReference<AssertionError> error = new AtomicReference<>(null); 859 final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 860 Executor mainExecutor = mContext.getMainExecutor(); 861 ContrastChangeListener listener = (float value) -> { 862 synchronized (waitObject) { 863 atomicBoolean.set(true); 864 waitObject.notifyAll(); 865 } 866 }; 867 868 ContrastChangeListener removedListener = (float contrast) -> error.set(new AssertionError( 869 "The listener should not be invoked after being removed")); 870 871 final List<ContrastChangeListener> listeners = List.of(listener, removedListener); 872 try { 873 for (float testContrast: List.of(0.5f, 1f)) { 874 mUiModeManager.addContrastChangeListener(mainExecutor, removedListener); 875 mUiModeManager.addContrastChangeListener(mainExecutor, listener); 876 mUiModeManager.removeContrastChangeListener(removedListener); 877 878 putContrastInSettings(testContrast); 879 waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject, 880 "The color contrast listener should be called when the setting changes"); 881 if (error.get() != null) throw error.get(); 882 mUiModeManager.removeContrastChangeListener(listener); 883 } 884 } finally { 885 putContrastInSettings(initialContrast); 886 listeners.forEach(mUiModeManager::removeContrastChangeListener); 887 } 888 } 889 isAutomotive()890 private boolean isAutomotive() { 891 return getContext().getPackageManager().hasSystemFeature( 892 PackageManager.FEATURE_AUTOMOTIVE); 893 } 894 isTelevision()895 private boolean isTelevision() { 896 PackageManager pm = getContext().getPackageManager(); 897 return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) 898 || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); 899 } 900 isWatch()901 private boolean isWatch() { 902 return getContext().getPackageManager().hasSystemFeature( 903 PackageManager.FEATURE_WATCH); 904 } 905 doTestUiModeForAutomotive()906 private void doTestUiModeForAutomotive() throws Exception { 907 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 908 assertTrue(mUiModeManager.isUiModeLocked()); 909 doTestLockedUiMode(); 910 } 911 doTestUiModeGeneric()912 private void doTestUiModeGeneric() throws Exception { 913 if (mUiModeManager.isUiModeLocked()) { 914 doTestLockedUiMode(); 915 } else { 916 doTestUnlockedUiMode(); 917 } 918 } 919 doTestLockedUiMode()920 private void doTestLockedUiMode() throws Exception { 921 int originalMode = mUiModeManager.getCurrentModeType(); 922 mUiModeManager.enableCarMode(0); 923 assertEquals(originalMode, mUiModeManager.getCurrentModeType()); 924 mUiModeManager.disableCarMode(0); 925 assertEquals(originalMode, mUiModeManager.getCurrentModeType()); 926 } 927 doTestUnlockedUiMode()928 private void doTestUnlockedUiMode() throws Exception { 929 mUiModeManager.enableCarMode(0); 930 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 931 mUiModeManager.disableCarMode(0); 932 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 933 } 934 doTestLockedNightMode()935 private void doTestLockedNightMode() throws Exception { 936 int currentMode = mUiModeManager.getNightMode(); 937 if (currentMode == UiModeManager.MODE_NIGHT_YES) { 938 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 939 assertEquals(currentMode, mUiModeManager.getNightMode()); 940 } else { 941 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES); 942 assertEquals(currentMode, mUiModeManager.getNightMode()); 943 } 944 } 945 doTestUnlockedNightMode()946 private void doTestUnlockedNightMode() throws Exception { 947 // day night mode should be settable regardless of car mode. 948 mUiModeManager.enableCarMode(0); 949 doTestAllNightModes(); 950 mUiModeManager.disableCarMode(0); 951 doTestAllNightModes(); 952 } 953 doTestAllNightModes()954 private void doTestAllNightModes() { 955 assertNightModeChange(UiModeManager.MODE_NIGHT_AUTO); 956 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 957 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 958 } 959 assertNightModeChange(int mode)960 private void assertNightModeChange(int mode) { 961 mUiModeManager.setNightMode(mode); 962 assertEquals(mode, mUiModeManager.getNightMode()); 963 } 964 assertVisibleNightModeInConfiguration(int mode)965 private void assertVisibleNightModeInConfiguration(int mode) { 966 int uiMode = getContext().getResources().getConfiguration().uiMode; 967 int flags = uiMode & Configuration.UI_MODE_NIGHT_MASK; 968 assertEquals(mode, flags); 969 } 970 assertStoredNightModeSetting(int mode)971 private void assertStoredNightModeSetting(int mode) { 972 int storedModeInt = -1; 973 // Settings.Secure.UI_NIGHT_MODE 974 for (int i = 0; i < MAX_WAIT_TIME_MS; i += WAIT_TIME_INCR_MS) { 975 String storedMode = getUiNightModeFromSetting(); 976 if (!TextUtils.isEmpty(storedMode)) { 977 storedModeInt = Integer.parseInt(storedMode); 978 } 979 if (mode == storedModeInt) break; 980 try { 981 Thread.sleep(WAIT_TIME_INCR_MS); 982 } catch (InterruptedException e) { 983 e.printStackTrace(); 984 } 985 } 986 assertEquals(mode, storedModeInt); 987 } 988 setNightMode(int mode)989 private void setNightMode(int mode) { 990 String modeString = "unknown"; 991 switch (mode) { 992 case UiModeManager.MODE_NIGHT_AUTO: 993 modeString = "auto"; 994 break; 995 case UiModeManager.MODE_NIGHT_NO: 996 modeString = "no"; 997 break; 998 case UiModeManager.MODE_NIGHT_YES: 999 modeString = "yes"; 1000 break; 1001 } 1002 final String command = " cmd uimode night " + modeString; 1003 applyCommand(command); 1004 } 1005 setStartTime(LocalTime t)1006 private void setStartTime(LocalTime t) { 1007 final String command = " cmd uimode time start " + t.toString(); 1008 applyCommand(command); 1009 } 1010 setEndTime(LocalTime t)1011 private void setEndTime(LocalTime t) { 1012 final String command = " cmd uimode time end " + t.toString(); 1013 applyCommand(command); 1014 } 1015 applyCommand(String command)1016 private void applyCommand(String command) { 1017 final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 1018 uiAutomation.adoptShellPermissionIdentity(Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1019 try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) { 1020 Assert.assertNotNull("Failed to execute shell command: " + command, fd); 1021 // Wait for the command to finish by reading until EOF 1022 try (InputStream in = new FileInputStream(fd.getFileDescriptor())) { 1023 byte[] buffer = new byte[4096]; 1024 while (in.read(buffer) > 0) continue; 1025 } catch (IOException e) { 1026 throw new IOException("Could not read stdout of command: " + command, e); 1027 } 1028 } catch (IOException e) { 1029 fail(); 1030 } finally { 1031 uiAutomation.destroy(); 1032 } 1033 } 1034 getUiNightModeFromSetting()1035 private String getUiNightModeFromSetting() { 1036 return mSystemUserSettings.get("ui_night_mode"); 1037 } 1038 acquireModifyNightModePermission()1039 private void acquireModifyNightModePermission() { 1040 getInstrumentation().getUiAutomation() 1041 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_DAY_NIGHT_MODE); 1042 mHasModifiedNightModePermissionAcquired = true; 1043 } 1044 waitForAtomicBooleanBecomes(AtomicBoolean atomicBoolean, boolean expectedValue, Object waitObject, String condition)1045 private void waitForAtomicBooleanBecomes(AtomicBoolean atomicBoolean, 1046 boolean expectedValue, Object waitObject, String condition) { 1047 TestUtils.waitOn(waitObject, () -> atomicBoolean.get() == expectedValue, 1048 MAX_WAIT_TIME_MS, condition); 1049 } 1050 putContrastInSettings(float contrast)1051 private void putContrastInSettings(float contrast) { 1052 runWithShellPermissionIdentity(() -> Settings.Secure.putFloat( 1053 mContext.getContentResolver(), CONTRAST_LEVEL, contrast), WRITE_SECURE_SETTINGS); 1054 } 1055 } 1056