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.junit.Assert.assertEquals; 35 import static org.junit.Assert.assertFalse; 36 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertNotSame; 38 import static org.junit.Assert.assertTrue; 39 import static org.junit.Assert.fail; 40 import static org.testng.Assert.assertThrows; 41 42 import android.Manifest; 43 import android.app.UiAutomation; 44 import android.app.UiModeManager; 45 import android.app.UiModeManager.ContrastChangeListener; 46 import android.content.Context; 47 import android.content.pm.PackageManager; 48 import android.content.res.Configuration; 49 import android.os.Handler; 50 import android.os.HandlerThread; 51 import android.os.ParcelFileDescriptor; 52 import android.os.UserHandle; 53 import android.provider.Settings; 54 import android.text.TextUtils; 55 import android.util.ArraySet; 56 import android.util.Log; 57 58 import androidx.test.runner.AndroidJUnit4; 59 60 import com.android.bedstead.harrier.DeviceState; 61 import com.android.bedstead.multiuser.annotations.RequireRunNotOnVisibleBackgroundNonProfileUser; 62 import com.android.bedstead.multiuser.annotations.RequireRunOnVisibleBackgroundNonProfileUser; 63 import com.android.compatibility.common.util.BatteryUtils; 64 import com.android.compatibility.common.util.CommonTestUtils; 65 import com.android.compatibility.common.util.TestUtils; 66 import com.android.compatibility.common.util.UserHelper; 67 import com.android.compatibility.common.util.UserSettings; 68 69 import com.google.common.util.concurrent.MoreExecutors; 70 71 import junit.framework.Assert; 72 73 import org.junit.After; 74 import org.junit.Before; 75 import org.junit.ClassRule; 76 import org.junit.Rule; 77 import org.junit.Test; 78 import org.junit.runner.RunWith; 79 80 import java.io.FileInputStream; 81 import java.io.IOException; 82 import java.io.InputStream; 83 import java.time.LocalTime; 84 import java.util.ArrayList; 85 import java.util.List; 86 import java.util.Set; 87 import java.util.concurrent.Executor; 88 import java.util.concurrent.atomic.AtomicBoolean; 89 import java.util.concurrent.atomic.AtomicInteger; 90 import java.util.concurrent.atomic.AtomicReference; 91 92 @RunWith(AndroidJUnit4.class) 93 public class UiModeManagerTest { 94 @ClassRule @Rule 95 public static final DeviceState sDeviceState = new DeviceState(); 96 97 private static final String TAG = "UiModeManagerTest"; 98 private static final long MAX_WAIT_TIME_SECS = 2; 99 private static final long MAX_WAIT_TIME_MS = MAX_WAIT_TIME_SECS * 1000; 100 private static final long WAIT_TIME_INCR_MS = 100; 101 102 private static final String CONTRAST_LEVEL = "contrast_level"; 103 104 private final UserHelper mUserHelper = new UserHelper(); 105 106 private Context mContext; 107 private Context mTargetContext; 108 109 private final UserSettings mSystemUserSettings = new UserSettings(UserHandle.USER_SYSTEM); 110 private UiModeManager mUiModeManager; 111 private boolean mHasModifiedNightModePermissionAcquired = false; 112 113 @Before setUp()114 public void setUp() throws Exception { 115 mContext = getInstrumentation().getContext(); 116 mTargetContext = getInstrumentation().getTargetContext(); 117 mUiModeManager = mContext.getSystemService(UiModeManager.class); 118 assertNotNull(mUiModeManager); 119 resetNightMode(); 120 // Make sure automotive projection is not set by this package at the beginning of the test. 121 releaseAutomotiveProjection(); 122 } 123 124 @After tearDown()125 public void tearDown() throws Exception { 126 resetNightMode(); 127 BatteryUtils.runDumpsysBatteryReset(); 128 BatteryUtils.resetBatterySaver(); 129 } 130 resetNightMode()131 private void resetNightMode() { 132 try { 133 if (!mHasModifiedNightModePermissionAcquired) { 134 acquireModifyNightModePermission(); 135 } 136 if (mUserHelper.isVisibleBackgroundUser()) { 137 // TODO(b/340960913): remove it once uimode supports visible background users. 138 return; 139 } 140 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 141 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 142 false /* active */); 143 } finally { 144 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 145 mHasModifiedNightModePermissionAcquired = false; 146 } 147 } 148 149 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 150 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 151 + " visible background users at the moment, so skipping these tests for" 152 + " secondary_user_on_secondary_display.") 153 @Test testUiMode()154 public void testUiMode() throws Exception { 155 if (isAutomotive()) { 156 Log.i(TAG, "testUiMode automotive"); 157 doTestUiModeForAutomotive(); 158 } else if (isTelevision()) { 159 assertEquals(Configuration.UI_MODE_TYPE_TELEVISION, 160 mUiModeManager.getCurrentModeType()); 161 doTestLockedUiMode(); 162 } else if (isWatch()) { 163 assertEquals(Configuration.UI_MODE_TYPE_WATCH, 164 mUiModeManager.getCurrentModeType()); 165 doTestLockedUiMode(); 166 } else { 167 Log.i(TAG, "testUiMode generic"); 168 doTestUiModeGeneric(); 169 } 170 } 171 172 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 173 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 174 + " visible background users at the moment, so skipping these tests for" 175 + " secondary_user_on_secondary_display.") 176 @Test testNightMode()177 public void testNightMode() throws Exception { 178 if (isAutomotive()) { 179 assertTrue(mUiModeManager.isNightModeLocked()); 180 doTestLockedNightMode(); 181 } else { 182 if (mUiModeManager.isNightModeLocked()) { 183 doTestLockedNightMode(); 184 } else { 185 doTestUnlockedNightMode(); 186 } 187 } 188 } 189 190 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 191 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 192 + " visible background users at the moment, so skipping these tests for" 193 + " secondary_user_on_secondary_display.") 194 @Test testSetAndGetCustomTimeStart()195 public void testSetAndGetCustomTimeStart() { 196 LocalTime time = mUiModeManager.getCustomNightModeStart(); 197 // decrease time 198 LocalTime timeNew = LocalTime.of( 199 (time.getHour() + 1) % 12, 200 (time.getMinute() + 30) % 60); 201 setStartTime(timeNew); 202 assertNotSame(time, timeNew); 203 assertEquals(timeNew, mUiModeManager.getCustomNightModeStart()); 204 } 205 206 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 207 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 208 + " visible background users at the moment, so skipping these tests for" 209 + " secondary_user_on_secondary_display.") 210 @Test testSetAndGetCustomTimeEnd()211 public void testSetAndGetCustomTimeEnd() { 212 LocalTime time = mUiModeManager.getCustomNightModeEnd(); 213 // decrease time 214 LocalTime timeNew = LocalTime.of( 215 (time.getHour() + 1) % 12, 216 (time.getMinute() + 30) % 60); 217 setEndTime(timeNew); 218 assertNotSame(time, timeNew); 219 assertEquals(timeNew, mUiModeManager.getCustomNightModeEnd()); 220 } 221 222 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 223 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 224 + " visible background users at the moment, so skipping these tests for" 225 + " secondary_user_on_secondary_display.") 226 @Test testNightModeYesPersisted()227 public void testNightModeYesPersisted() throws InterruptedException { 228 if (mUiModeManager.isNightModeLocked()) { 229 Log.i(TAG, "testNightModeYesPersisted skipped: night mode is locked"); 230 return; 231 } 232 233 // Reset the mode to no if it is set to another value 234 setNightMode(UiModeManager.MODE_NIGHT_NO); 235 236 setNightMode(UiModeManager.MODE_NIGHT_YES); 237 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_YES); 238 } 239 240 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 241 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 242 + " visible background users at the moment, so skipping these tests for" 243 + " secondary_user_on_secondary_display.") 244 @Test testNightModeAutoPersisted()245 public void testNightModeAutoPersisted() throws InterruptedException { 246 if (mUiModeManager.isNightModeLocked()) { 247 Log.i(TAG, "testNightModeAutoPersisted skipped: night mode is locked"); 248 return; 249 } 250 251 // Reset the mode to no if it is set to another value 252 setNightMode(UiModeManager.MODE_NIGHT_NO); 253 254 setNightMode(UiModeManager.MODE_NIGHT_AUTO); 255 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_AUTO); 256 } 257 258 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 259 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 260 + " visible background users at the moment, so skipping these tests for" 261 + " secondary_user_on_secondary_display.") 262 @Test testSetNightModeCustomType_noPermission_bedtime_shouldThrow()263 public void testSetNightModeCustomType_noPermission_bedtime_shouldThrow() { 264 assertThrows(SecurityException.class, 265 () -> mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME)); 266 } 267 268 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 269 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 270 + " visible background users at the moment, so skipping these tests for" 271 + " secondary_user_on_secondary_display.") 272 @Test testSetNightModeCustomType_customTypeUnknown_bedtime_shouldThrow()273 public void testSetNightModeCustomType_customTypeUnknown_bedtime_shouldThrow() { 274 acquireModifyNightModePermission(); 275 276 assertThrows(IllegalArgumentException.class, 277 () -> mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN)); 278 } 279 280 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 281 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 282 + " visible background users at the moment, so skipping these tests for" 283 + " secondary_user_on_secondary_display.") 284 @Test testSetNightModeCustomType_bedtime_shouldPersist()285 public void testSetNightModeCustomType_bedtime_shouldPersist() { 286 acquireModifyNightModePermission(); 287 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 288 289 assertThat(mUiModeManager.getNightMode()).isEqualTo(MODE_NIGHT_CUSTOM); 290 assertThat(mUiModeManager.getNightModeCustomType()) 291 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 292 } 293 294 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 295 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 296 + " visible background users at the moment, so skipping these tests for" 297 + " secondary_user_on_secondary_display.") 298 @Test testSetNightModeCustomType_schedule_shouldPersist()299 public void testSetNightModeCustomType_schedule_shouldPersist() { 300 acquireModifyNightModePermission(); 301 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 302 303 assertThat(mUiModeManager.getNightMode()).isEqualTo(MODE_NIGHT_CUSTOM); 304 assertThat(mUiModeManager.getNightModeCustomType()) 305 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 306 } 307 308 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 309 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 310 + " visible background users at the moment, so skipping these tests for" 311 + " secondary_user_on_secondary_display.") 312 @Test testGetNightModeCustomType_nightModeNo_shouldReturnUnknown()313 public void testGetNightModeCustomType_nightModeNo_shouldReturnUnknown() { 314 acquireModifyNightModePermission(); 315 mUiModeManager.setNightMode(MODE_NIGHT_NO); 316 317 assertThat(mUiModeManager.getNightModeCustomType()) 318 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 319 } 320 321 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 322 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 323 + " visible background users at the moment, so skipping these tests for" 324 + " secondary_user_on_secondary_display.") 325 @Test testGetNightModeCustomType_nightModeYes_shouldReturnUnknown()326 public void testGetNightModeCustomType_nightModeYes_shouldReturnUnknown() { 327 acquireModifyNightModePermission(); 328 mUiModeManager.setNightMode(MODE_NIGHT_YES); 329 330 assertThat(mUiModeManager.getNightModeCustomType()) 331 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 332 } 333 334 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 335 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 336 + " visible background users at the moment, so skipping these tests for" 337 + " secondary_user_on_secondary_display.") 338 @Test testGetNightModeCustomType_nightModeAuto_shouldReturnUnknown()339 public void testGetNightModeCustomType_nightModeAuto_shouldReturnUnknown() { 340 acquireModifyNightModePermission(); 341 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 342 343 assertThat(mUiModeManager.getNightModeCustomType()) 344 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN); 345 } 346 347 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 348 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 349 + " visible background users at the moment, so skipping these tests for" 350 + " secondary_user_on_secondary_display.") 351 @Test testGetNightModeCustomType_nightModeCustom_shouldReturnScheduleAsDefault()352 public void testGetNightModeCustomType_nightModeCustom_shouldReturnScheduleAsDefault() { 353 acquireModifyNightModePermission(); 354 mUiModeManager.setNightMode(MODE_NIGHT_CUSTOM); 355 356 assertThat(mUiModeManager.getNightModeCustomType()) 357 .isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 358 } 359 360 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 361 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 362 + " visible background users at the moment, so skipping these tests for" 363 + " secondary_user_on_secondary_display.") 364 @Test testSetNightModeCustomType_hasPermission_bedtime_shouldNotActivateNightMode()365 public void testSetNightModeCustomType_hasPermission_bedtime_shouldNotActivateNightMode() { 366 acquireModifyNightModePermission(); 367 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 368 369 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 370 } 371 372 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 373 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 374 + " visible background users at the moment, so skipping these tests for" 375 + " secondary_user_on_secondary_display.") 376 @Test testSetNightModeActivatedForCustomMode_noPermission_customTypeBedtime_activateAtBedtime_shouldNotActivateNightMode()377 public void testSetNightModeActivatedForCustomMode_noPermission_customTypeBedtime_activateAtBedtime_shouldNotActivateNightMode() { 378 acquireModifyNightModePermission(); 379 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 380 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 381 mHasModifiedNightModePermissionAcquired = false; 382 383 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 384 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 385 386 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 387 } 388 389 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 390 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 391 + " visible background users at the moment, so skipping these tests for" 392 + " secondary_user_on_secondary_display.") 393 @Test testSetNightModeActivatedForCustomMode_customTypeBedtime_activateAtBedtime_shouldActivateNightMode()394 public void testSetNightModeActivatedForCustomMode_customTypeBedtime_activateAtBedtime_shouldActivateNightMode() { 395 acquireModifyNightModePermission(); 396 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 397 398 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 399 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isTrue(); 400 401 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 402 } 403 404 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 405 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 406 + " visible background users at the moment, so skipping these tests for" 407 + " secondary_user_on_secondary_display.") 408 @Test testSetNightModeActivatedForCustomMode_customTypeBedtime_deactivateAtBedtime_shouldDeactivateNightMode()409 public void testSetNightModeActivatedForCustomMode_customTypeBedtime_deactivateAtBedtime_shouldDeactivateNightMode() { 410 acquireModifyNightModePermission(); 411 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 412 413 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 414 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */)).isTrue(); 415 416 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 417 } 418 419 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 420 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 421 + " visible background users at the moment, so skipping these tests for" 422 + " secondary_user_on_secondary_display.") 423 @Test testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_shouldNotActivateNightMode()424 public void testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_shouldNotActivateNightMode() { 425 acquireModifyNightModePermission(); 426 mUiModeManager.setNightMode(MODE_NIGHT_NO); 427 428 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 429 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 430 431 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 432 } 433 434 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 435 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 436 + " visible background users at the moment, so skipping these tests for" 437 + " secondary_user_on_secondary_display.") 438 @Test testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_shouldKeepNightModeActivated()439 public void testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_shouldKeepNightModeActivated() { 440 acquireModifyNightModePermission(); 441 mUiModeManager.setNightMode(MODE_NIGHT_YES); 442 443 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 444 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 445 446 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 447 } 448 449 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 450 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 451 + " visible background users at the moment, so skipping these tests for" 452 + " secondary_user_on_secondary_display.") 453 @Test testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_shouldNotActivateNightMode()454 public void testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_shouldNotActivateNightMode() { 455 acquireModifyNightModePermission(); 456 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 457 int uiMode = mContext.getResources().getConfiguration().uiMode 458 & Configuration.UI_MODE_NIGHT_MASK; 459 460 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 461 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 462 463 assertVisibleNightModeInConfiguration(uiMode); 464 } 465 466 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 467 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 468 + " visible background users at the moment, so skipping these tests for" 469 + " secondary_user_on_secondary_display.") 470 @Test testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_shouldNotActivateNightMode()471 public void testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_shouldNotActivateNightMode() { 472 acquireModifyNightModePermission(); 473 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 474 int uiMode = mContext.getResources().getConfiguration().uiMode 475 & Configuration.UI_MODE_NIGHT_MASK; 476 477 assertThat(mUiModeManager.setNightModeActivatedForCustomMode( 478 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)).isFalse(); 479 480 assertVisibleNightModeInConfiguration(uiMode); 481 } 482 483 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 484 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 485 + " visible background users at the moment, so skipping these tests for" 486 + " secondary_user_on_secondary_display.") 487 @Test testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()488 public void testSetNightModeActivatedForCustomMode_modeNo_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 489 acquireModifyNightModePermission(); 490 mUiModeManager.setNightMode(MODE_NIGHT_NO); 491 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 492 true /* active */); 493 494 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 495 496 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 497 } 498 499 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 500 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 501 + " visible background users at the moment, so skipping these tests for" 502 + " secondary_user_on_secondary_display.") 503 @Test testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_thenCustomTypeBedtime_shouldActiveNightMode()504 public void testSetNightModeActivatedForCustomMode_modeYes_activateAtBedtime_thenCustomTypeBedtime_shouldActiveNightMode() { 505 acquireModifyNightModePermission(); 506 mUiModeManager.setNightMode(MODE_NIGHT_YES); 507 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 508 true /* active */); 509 510 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 511 512 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 513 } 514 515 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 516 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 517 + " visible background users at the moment, so skipping these tests for" 518 + " secondary_user_on_secondary_display.") 519 @Test testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()520 public void testSetNightModeActivatedForCustomMode_modeAuto_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 521 acquireModifyNightModePermission(); 522 mUiModeManager.setNightMode(MODE_NIGHT_AUTO); 523 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 524 true /* active */); 525 526 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 527 528 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 529 } 530 531 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 532 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 533 + " visible background users at the moment, so skipping these tests for" 534 + " secondary_user_on_secondary_display.") 535 @Test testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode()536 public void testSetNightModeActivatedForCustomMode_customTypeSchedule_activateAtBedtime_thenCustomTypeBedtime_shouldActivateNightMode() { 537 acquireModifyNightModePermission(); 538 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE); 539 mUiModeManager.setNightModeActivatedForCustomMode(MODE_NIGHT_CUSTOM_TYPE_BEDTIME, 540 true /* active */); 541 542 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 543 544 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 545 } 546 547 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 548 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 549 + " visible background users at the moment, so skipping these tests for" 550 + " secondary_user_on_secondary_display.") 551 @Test testNightModeAutoNotPersistedCarMode()552 public void testNightModeAutoNotPersistedCarMode() { 553 if (mUiModeManager.isNightModeLocked()) { 554 Log.i(TAG, "testNightModeAutoNotPersistedCarMode skipped: night mode is locked"); 555 return; 556 } 557 558 // Reset the mode to no if it is set to another value 559 setNightMode(UiModeManager.MODE_NIGHT_NO); 560 mUiModeManager.enableCarMode(0); 561 562 setNightMode(UiModeManager.MODE_NIGHT_AUTO); 563 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 564 mUiModeManager.disableCarMode(0); 565 } 566 567 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 568 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 569 + " visible background users at the moment, so skipping these tests for" 570 + " secondary_user_on_secondary_display.") 571 @Test testNightModeCustomTypeBedtimeNotPersistedInCarMode()572 public void testNightModeCustomTypeBedtimeNotPersistedInCarMode() throws InterruptedException { 573 if (mUiModeManager.isNightModeLocked()) { 574 Log.i(TAG, "testNightModeCustomTypeBedtimeNotPersistedInCarMode skipped: night mode is " 575 + "locked"); 576 return; 577 } 578 579 acquireModifyNightModePermission(); 580 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 581 mUiModeManager.enableCarMode(0); 582 583 // We don't expect users modifing bedtime features when driving. 584 mUiModeManager.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME); 585 586 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 587 mUiModeManager.disableCarMode(0); 588 } 589 590 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 591 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 592 + " visible background users at the moment, so skipping these tests for" 593 + " secondary_user_on_secondary_display.") 594 @Test testNightModeInCarModeIsTransient()595 public void testNightModeInCarModeIsTransient() { 596 if (mUiModeManager.isNightModeLocked()) { 597 Log.i(TAG, "testNightModeInCarModeIsTransient skipped: night mode is locked"); 598 return; 599 } 600 601 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 602 603 mUiModeManager.enableCarMode(0); 604 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 605 606 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 607 608 mUiModeManager.disableCarMode(0); 609 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 610 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 611 } 612 613 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 614 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 615 + " visible background users at the moment, so skipping these tests for" 616 + " secondary_user_on_secondary_display.") 617 @Test testNightModeToggleInCarModeDoesNotChangeSetting()618 public void testNightModeToggleInCarModeDoesNotChangeSetting() { 619 if (mUiModeManager.isNightModeLocked()) { 620 Log.i(TAG, "testNightModeToggleInCarModeDoesNotChangeSetting skipped: " 621 + "night mode is locked"); 622 return; 623 } 624 625 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 626 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 627 628 mUiModeManager.enableCarMode(0); 629 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 630 631 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 632 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 633 634 mUiModeManager.disableCarMode(0); 635 assertStoredNightModeSetting(UiModeManager.MODE_NIGHT_NO); 636 } 637 638 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 639 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 640 + " visible background users at the moment, so skipping these tests for" 641 + " secondary_user_on_secondary_display.") 642 @Test testNightModeInCarModeOnPowerSaveIsTransient()643 public void testNightModeInCarModeOnPowerSaveIsTransient() throws Throwable { 644 if (mUiModeManager.isNightModeLocked() || !BatteryUtils.isBatterySaverSupported()) { 645 Log.i(TAG, "testNightModeInCarModeOnPowerSaveIsTransient skipped: " 646 + "night mode is locked or battery saver is not supported"); 647 return; 648 } 649 650 BatteryUtils.runDumpsysBatteryUnplug(); 651 652 // Turn off battery saver, disable night mode 653 BatteryUtils.enableBatterySaver(false); 654 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 655 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 656 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 657 658 // Then enable battery saver to check night mode is made visible 659 BatteryUtils.enableBatterySaver(true); 660 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 661 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 662 663 // Then disable it, enable car mode, and check night mode is not visible 664 BatteryUtils.enableBatterySaver(false); 665 mUiModeManager.enableCarMode(0); 666 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 667 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 668 669 // Enable battery saver, check that night mode is still not visible, overridden by car mode 670 BatteryUtils.enableBatterySaver(true); 671 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 672 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 673 674 // Disable car mode 675 mUiModeManager.disableCarMode(0); 676 677 // Toggle night mode to force propagation of uiMode update, since disabling car mode 678 // is deferred to a broadcast. 679 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES); 680 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 681 682 // Check battery saver mode now shows night mode 683 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 684 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_YES); 685 686 // Disable battery saver and check night mode back to not visible 687 BatteryUtils.enableBatterySaver(false); 688 assertEquals(UiModeManager.MODE_NIGHT_NO, mUiModeManager.getNightMode()); 689 assertVisibleNightModeInConfiguration(Configuration.UI_MODE_NIGHT_NO); 690 } 691 692 /** 693 * Verifies that an app holding the ENTER_CAR_MODE_PRIORITIZED permission can enter car mode 694 * while specifying a priority. 695 */ 696 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 697 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 698 + " visible background users at the moment, so skipping these tests for" 699 + " secondary_user_on_secondary_display.") 700 @Test testEnterCarModePrioritized()701 public void testEnterCarModePrioritized() { 702 if (mUiModeManager.isUiModeLocked()) { 703 return; 704 } 705 706 runWithShellPermissionIdentity(() -> mUiModeManager.enableCarMode(100, 0), 707 Manifest.permission.ENTER_CAR_MODE_PRIORITIZED); 708 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 709 710 runWithShellPermissionIdentity(() -> mUiModeManager.disableCarMode(0), 711 Manifest.permission.ENTER_CAR_MODE_PRIORITIZED); 712 assertEquals(Configuration.UI_MODE_TYPE_NORMAL, mUiModeManager.getCurrentModeType()); 713 } 714 715 /** 716 * Attempts to use the prioritized car mode API when the caller does not hold the correct 717 * permission to use that API. 718 */ 719 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 720 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 721 + " visible background users at the moment, so skipping these tests for" 722 + " secondary_user_on_secondary_display.") 723 @Test testEnterCarModePrioritizedDenied()724 public void testEnterCarModePrioritizedDenied() { 725 if (mUiModeManager.isUiModeLocked()) { 726 return; 727 } 728 try { 729 mUiModeManager.enableCarMode(100, 0); 730 } catch (SecurityException se) { 731 // Expect exception. 732 return; 733 } 734 fail("Expected SecurityException"); 735 } 736 737 /** 738 * Verifies that an app holding the TOGGLE_AUTOMOTIVE_PROJECTION permission can request/release 739 * automotive projection. 740 */ 741 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 742 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 743 + " visible background users at the moment, so skipping these tests for" 744 + " secondary_user_on_secondary_display.") 745 @Test testToggleAutomotiveProjection()746 public void testToggleAutomotiveProjection() throws Exception { 747 // If we didn't hold it in the first place, we didn't release it, so expect false. 748 assertFalse(releaseAutomotiveProjection()); 749 assertTrue(requestAutomotiveProjection()); 750 // Multiple calls are OK. 751 assertTrue(requestAutomotiveProjection()); 752 assertTrue(releaseAutomotiveProjection()); 753 // Once it's released, further calls return false since it was already released. 754 assertFalse(releaseAutomotiveProjection()); 755 } 756 757 /** 758 * Verifies that the system can correctly read the projection state. 759 */ 760 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 761 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 762 + " visible background users at the moment, so skipping these tests for" 763 + " secondary_user_on_secondary_display.") 764 @Test testReadProjectionState()765 public void testReadProjectionState() throws Exception { 766 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, getActiveProjectionTypes()); 767 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE).isEmpty()); 768 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL).isEmpty()); 769 requestAutomotiveProjection(); 770 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, getActiveProjectionTypes()); 771 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE) 772 .contains(mTargetContext.getPackageName())); 773 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL) 774 .contains(mTargetContext.getPackageName())); 775 releaseAutomotiveProjection(); 776 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, getActiveProjectionTypes()); 777 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE).isEmpty()); 778 assertTrue(getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL).isEmpty()); 779 } 780 781 /** Verifies that the system receives callbacks about the projection state at expected times. */ 782 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 783 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 784 + " visible background users at the moment, so skipping these tests for" 785 + " secondary_user_on_secondary_display.") 786 @Test testReadProjectionState_listener()787 public void testReadProjectionState_listener() throws Exception { 788 // Use AtomicInteger so it can be effectively final. 789 AtomicInteger activeProjectionTypes = new AtomicInteger(); 790 Set<String> projectingPackages = new ArraySet<>(); 791 AtomicInteger callbackInvocations = new AtomicInteger(); 792 UiModeManager.OnProjectionStateChangedListener listener = (t, pkgs) -> { 793 Log.i(TAG, "onProjectionStateChanged(" + t + "," + pkgs + ")"); 794 activeProjectionTypes.set(t); 795 projectingPackages.clear(); 796 projectingPackages.addAll(pkgs); 797 callbackInvocations.incrementAndGet(); 798 }; 799 800 requestAutomotiveProjection(); 801 runWithShellPermissionIdentity(() -> mUiModeManager.addOnProjectionStateChangedListener( 802 UiModeManager.PROJECTION_TYPE_ALL, MoreExecutors.directExecutor(), listener), 803 Manifest.permission.READ_PROJECTION_STATE); 804 805 // Should have called back immediately, but the call might not have gotten here yet. 806 CommonTestUtils.waitUntil("Callback wasn't invoked on listener addition!", 807 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 1); 808 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, activeProjectionTypes.get()); 809 assertEquals(1, projectingPackages.size()); 810 assertTrue(projectingPackages.contains(mTargetContext.getPackageName())); 811 812 // Callback should not be invoked again. 813 requestAutomotiveProjection(); 814 Thread.sleep(MAX_WAIT_TIME_MS); 815 assertEquals(1, callbackInvocations.get()); 816 817 releaseAutomotiveProjection(); 818 CommonTestUtils.waitUntil("Callback wasn't invoked on projection release!", 819 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 2); 820 assertEquals(UiModeManager.PROJECTION_TYPE_NONE, activeProjectionTypes.get()); 821 assertEquals(0, projectingPackages.size()); 822 823 // Again, no callback for noop call. 824 releaseAutomotiveProjection(); 825 Thread.sleep(MAX_WAIT_TIME_MS); 826 assertEquals(2, callbackInvocations.get()); 827 828 // Test the case that isn't at time of registration. 829 requestAutomotiveProjection(); 830 CommonTestUtils.waitUntil("Callback wasn't invoked on projection set!", 831 MAX_WAIT_TIME_SECS, () -> callbackInvocations.get() == 3); 832 assertEquals(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, activeProjectionTypes.get()); 833 assertEquals(1, projectingPackages.size()); 834 assertTrue(projectingPackages.contains(mTargetContext.getPackageName())); 835 836 // Unregister and shouldn't receive further callbacks. 837 runWithShellPermissionIdentity(() -> mUiModeManager.removeOnProjectionStateChangedListener( 838 listener), Manifest.permission.READ_PROJECTION_STATE); 839 840 releaseAutomotiveProjection(); 841 requestAutomotiveProjection(); 842 releaseAutomotiveProjection(); // Just to clean up. 843 Thread.sleep(MAX_WAIT_TIME_MS); 844 assertEquals(3, callbackInvocations.get()); 845 } 846 requestAutomotiveProjection()847 private boolean requestAutomotiveProjection() throws Exception { 848 return callWithShellPermissionIdentity( 849 () -> mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), 850 Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, 851 Manifest.permission.INTERACT_ACROSS_USERS); 852 } 853 releaseAutomotiveProjection()854 private boolean releaseAutomotiveProjection() throws Exception { 855 if (mUserHelper.isVisibleBackgroundUser()) { 856 // TODO(b/340960913): remove it once uimode supports visible background users. 857 return false; 858 } 859 return callWithShellPermissionIdentity( 860 () -> mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE), 861 Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, 862 Manifest.permission.INTERACT_ACROSS_USERS); 863 } 864 getActiveProjectionTypes()865 private int getActiveProjectionTypes() throws Exception { 866 return callWithShellPermissionIdentity(mUiModeManager::getActiveProjectionTypes, 867 Manifest.permission.READ_PROJECTION_STATE); 868 } 869 getProjectingPackages(int projectionType)870 private Set<String> getProjectingPackages(int projectionType) throws Exception { 871 return callWithShellPermissionIdentity( 872 () -> mUiModeManager.getProjectingPackages(projectionType), 873 Manifest.permission.READ_PROJECTION_STATE); 874 } 875 876 /** 877 * Attempts to request automotive projection without TOGGLE_AUTOMOTIVE_PROJECTION permission. 878 */ 879 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 880 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 881 + " visible background users at the moment, so skipping these tests for" 882 + " secondary_user_on_secondary_display.") 883 @Test testRequestAutomotiveProjectionDenied()884 public void testRequestAutomotiveProjectionDenied() { 885 try { 886 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE); 887 } catch (SecurityException se) { 888 // Expect exception. 889 return; 890 } 891 fail("Expected SecurityException"); 892 } 893 894 /** 895 * Attempts to request automotive projection without TOGGLE_AUTOMOTIVE_PROJECTION permission. 896 */ 897 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 898 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 899 + " visible background users at the moment, so skipping these tests for" 900 + " secondary_user_on_secondary_display.") 901 @Test testReleaseAutomotiveProjectionDenied()902 public void testReleaseAutomotiveProjectionDenied() { 903 try { 904 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE); 905 } catch (SecurityException se) { 906 // Expect exception. 907 return; 908 } 909 fail("Expected SecurityException"); 910 } 911 912 /** 913 * Attempts to request more than one projection type at once. 914 */ 915 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 916 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 917 + " visible background users at the moment, so skipping these tests for" 918 + " secondary_user_on_secondary_display.") 919 @Test testRequestAllProjectionTypes()920 public void testRequestAllProjectionTypes() { 921 try { 922 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_ALL); 923 } catch (IllegalArgumentException iae) { 924 // Expect exception. 925 return; 926 } 927 fail("Expected IllegalArgumentException"); 928 } 929 930 /** 931 * Attempts to release more than one projection type. 932 */ 933 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 934 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 935 + " visible background users at the moment, so skipping these tests for" 936 + " secondary_user_on_secondary_display.") 937 @Test testReleaseAllProjectionTypes()938 public void testReleaseAllProjectionTypes() { 939 try { 940 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_ALL); 941 } catch (IllegalArgumentException iae) { 942 // Expect exception. 943 return; 944 } 945 fail("Expected IllegalArgumentException"); 946 } 947 948 /** Attempts to request no projection types. */ 949 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 950 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 951 + " visible background users at the moment, so skipping these tests for" 952 + " secondary_user_on_secondary_display.") 953 @Test testRequestNoProjectionTypes()954 public void testRequestNoProjectionTypes() { 955 try { 956 mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_NONE); 957 } catch (IllegalArgumentException iae) { 958 // Expect exception. 959 return; 960 } 961 fail("Expected IllegalArgumentException"); 962 } 963 964 /** Attempts to release no projection types. */ 965 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 966 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 967 + " visible background users at the moment, so skipping these tests for" 968 + " secondary_user_on_secondary_display.") 969 @Test testReleaseNoProjectionTypes()970 public void testReleaseNoProjectionTypes() { 971 try { 972 mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_NONE); 973 } catch (IllegalArgumentException iae) { 974 // Expect exception. 975 return; 976 } 977 fail("Expected IllegalArgumentException"); 978 } 979 980 /** Attempts to call getActiveProjectionTypes without READ_PROJECTION_STATE permission. */ 981 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 982 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 983 + " visible background users at the moment, so skipping these tests for" 984 + " secondary_user_on_secondary_display.") 985 @Test testReadProjectionState_getActiveProjectionTypesDenied()986 public void testReadProjectionState_getActiveProjectionTypesDenied() { 987 try { 988 mUiModeManager.getActiveProjectionTypes(); 989 } catch (SecurityException se) { 990 // Expect exception. 991 return; 992 } 993 fail("Expected SecurityException"); 994 } 995 996 /** Attempts to call getProjectingPackages without READ_PROJECTION_STATE permission. */ 997 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 998 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 999 + " visible background users at the moment, so skipping these tests for" 1000 + " secondary_user_on_secondary_display.") 1001 @Test testReadProjectionState_getProjectingPackagesDenied()1002 public void testReadProjectionState_getProjectingPackagesDenied() { 1003 try { 1004 mUiModeManager.getProjectingPackages(UiModeManager.PROJECTION_TYPE_ALL); 1005 } catch (SecurityException se) { 1006 // Expect exception. 1007 return; 1008 } 1009 fail("Expected SecurityException"); 1010 } 1011 1012 /** 1013 * Attempts to call addOnProjectionStateChangedListener without 1014 * READ_PROJECTION_STATE permission. 1015 */ 1016 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 1017 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 1018 + " visible background users at the moment, so skipping these tests for" 1019 + " secondary_user_on_secondary_display.") 1020 @Test testReadProjectionState_addOnProjectionStateChangedListenerDenied()1021 public void testReadProjectionState_addOnProjectionStateChangedListenerDenied() { 1022 try { 1023 mUiModeManager.addOnProjectionStateChangedListener(UiModeManager.PROJECTION_TYPE_ALL, 1024 mContext.getMainExecutor(), (t, pkgs) -> { }); 1025 } catch (SecurityException se) { 1026 // Expect exception. 1027 return; 1028 } 1029 fail("Expected SecurityException"); 1030 } 1031 1032 /** 1033 * Attempts to call removeOnProjectionStateChangedListener without 1034 * READ_PROJECTION_STATE permission. 1035 */ 1036 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 1037 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 1038 + " visible background users at the moment, so skipping these tests for" 1039 + " secondary_user_on_secondary_display.") 1040 @Test testReadProjectionState_removeOnProjectionStateChangedListenerDenied()1041 public void testReadProjectionState_removeOnProjectionStateChangedListenerDenied() { 1042 UiModeManager.OnProjectionStateChangedListener listener = (t, pkgs) -> { }; 1043 runWithShellPermissionIdentity(() -> mUiModeManager.addOnProjectionStateChangedListener( 1044 UiModeManager.PROJECTION_TYPE_ALL, mContext.getMainExecutor(), listener), 1045 Manifest.permission.READ_PROJECTION_STATE); 1046 try { 1047 mUiModeManager.removeOnProjectionStateChangedListener(listener); 1048 } catch (SecurityException se) { 1049 // Expect exception. 1050 return; 1051 } 1052 fail("Expected SecurityException"); 1053 } 1054 1055 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 1056 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 1057 + " visible background users at the moment, so skipping these tests for" 1058 + " secondary_user_on_secondary_display.") 1059 @Test testGetContrast()1060 public void testGetContrast() throws Exception { 1061 float initialContrast = mUiModeManager.getContrast(); 1062 putContrastInSettings(0f); 1063 try { 1064 for (float testContrast : List.of(-1f, 0.5f)) { 1065 putContrastInSettings(testContrast); 1066 TestUtils.waitUntil("getContrast() should return the new contrast value", 1067 (int) MAX_WAIT_TIME_SECS, 1068 () -> Math.abs(mUiModeManager.getContrast() - testContrast) < 1e-10); 1069 } 1070 } finally { 1071 putContrastInSettings(initialContrast); 1072 } 1073 } 1074 1075 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 1076 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 1077 + " visible background users at the moment, so skipping these tests for" 1078 + " secondary_user_on_secondary_display.") 1079 @Test testAddContrastChangeListener()1080 public void testAddContrastChangeListener() { 1081 float initialContrast = mUiModeManager.getContrast(); 1082 putContrastInSettings(0f); 1083 final Object waitObject = new Object(); 1084 final List<ContrastChangeListener> listeners = new ArrayList<>(); 1085 1086 // store callback errors here to avoid crashing the whole test suite 1087 final AtomicReference<AssertionError> error = new AtomicReference<>(null); 1088 final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 1089 1090 String handlerThreadName = "UiModeManagerTestBackgroundThread"; 1091 final HandlerThread backgroundThread = new HandlerThread(handlerThreadName); 1092 backgroundThread.start(); 1093 Handler backgroundHandler = new Handler(backgroundThread.getLooper()); 1094 Executor backgroundExecutor = backgroundHandler::post; 1095 1096 try { 1097 for (float testContrast : List.of(-1f, 0f)) { 1098 ContrastChangeListener listener = (float contrast) -> { 1099 synchronized (waitObject) { 1100 try { 1101 assertEquals("Wrong value received by the color contrast listener", 1102 testContrast, contrast, 1e-10); 1103 assertEquals("The executor should be used to invoke the callback", 1104 backgroundThread, Thread.currentThread()); 1105 } catch (AssertionError e) { 1106 error.set(e); 1107 } 1108 atomicBoolean.set(true); 1109 waitObject.notifyAll(); 1110 } 1111 }; 1112 listeners.add(listener); 1113 mUiModeManager.addContrastChangeListener(backgroundExecutor, listener); 1114 putContrastInSettings(testContrast); 1115 waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject, 1116 "The color contrast listener should be called when the setting changes"); 1117 if (error.get() != null) throw error.get(); 1118 mUiModeManager.removeContrastChangeListener(listener); 1119 } 1120 } finally { 1121 backgroundThread.quitSafely(); 1122 putContrastInSettings(initialContrast); 1123 listeners.forEach(mUiModeManager::removeContrastChangeListener); 1124 } 1125 } 1126 1127 // TODO(b/340960913): remove the annotation once uimode supports visible background users. 1128 @RequireRunNotOnVisibleBackgroundNonProfileUser(reason = "The uimode does not support" 1129 + " visible background users at the moment, so skipping these tests for" 1130 + " secondary_user_on_secondary_display.") 1131 @Test testRemoveContrastChangeListener()1132 public void testRemoveContrastChangeListener() { 1133 float initialContrast = mUiModeManager.getContrast(); 1134 putContrastInSettings(0f); 1135 final Object waitObject = new Object(); 1136 1137 // store callback errors here to avoid crashing the whole test suite 1138 final AtomicReference<AssertionError> error = new AtomicReference<>(null); 1139 final AtomicBoolean atomicBoolean = new AtomicBoolean(false); 1140 Executor mainExecutor = mContext.getMainExecutor(); 1141 ContrastChangeListener listener = (float value) -> { 1142 synchronized (waitObject) { 1143 atomicBoolean.set(true); 1144 waitObject.notifyAll(); 1145 } 1146 }; 1147 1148 ContrastChangeListener removedListener = (float contrast) -> error.set(new AssertionError( 1149 "The listener should not be invoked after being removed")); 1150 1151 final List<ContrastChangeListener> listeners = List.of(listener, removedListener); 1152 try { 1153 for (float testContrast: List.of(0.5f, 1f)) { 1154 mUiModeManager.addContrastChangeListener(mainExecutor, removedListener); 1155 mUiModeManager.addContrastChangeListener(mainExecutor, listener); 1156 mUiModeManager.removeContrastChangeListener(removedListener); 1157 1158 putContrastInSettings(testContrast); 1159 waitForAtomicBooleanBecomes(atomicBoolean, true, waitObject, 1160 "The color contrast listener should be called when the setting changes"); 1161 if (error.get() != null) throw error.get(); 1162 mUiModeManager.removeContrastChangeListener(listener); 1163 } 1164 } finally { 1165 putContrastInSettings(initialContrast); 1166 listeners.forEach(mUiModeManager::removeContrastChangeListener); 1167 } 1168 } 1169 1170 // TODO(b/340960913): remove the test once uimode supports visible background users. 1171 @RequireRunOnVisibleBackgroundNonProfileUser 1172 @Test testSetNightMode_visibleBackgroundUser_shouldThrow()1173 public void testSetNightMode_visibleBackgroundUser_shouldThrow() { 1174 acquireModifyNightModePermission(); 1175 1176 assertThrows(SecurityException.class, 1177 () -> mUiModeManager.setNightMode(MODE_NIGHT_NO)); 1178 } 1179 1180 // TODO(b/340960913): remove the test once uimode supports visible background users. 1181 @RequireRunOnVisibleBackgroundNonProfileUser 1182 @Test testSetNightModeActivatedForCustomMode_visibleBackgroundUser_shouldThrow()1183 public void testSetNightModeActivatedForCustomMode_visibleBackgroundUser_shouldThrow() { 1184 acquireModifyNightModePermission(); 1185 1186 assertThrows(SecurityException.class, 1187 () -> mUiModeManager.setNightModeActivatedForCustomMode( 1188 MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */)); 1189 } 1190 1191 // TODO(b/340960913): remove the test once uimode supports visible background users. 1192 @RequireRunOnVisibleBackgroundNonProfileUser 1193 @Test testSetCustomNightModeStart_visibleBackgroundUser_shouldThrow()1194 public void testSetCustomNightModeStart_visibleBackgroundUser_shouldThrow() { 1195 acquireModifyNightModePermission(); 1196 1197 LocalTime now = LocalTime.now(); 1198 assertThrows(SecurityException.class, 1199 () -> mUiModeManager.setCustomNightModeStart(now)); 1200 } 1201 1202 // TODO(b/340960913): remove the test once uimode supports visible background users. 1203 @RequireRunOnVisibleBackgroundNonProfileUser 1204 @Test testSetCustomNightModeEnd_visibleBackgroundUser_shouldThrow()1205 public void testSetCustomNightModeEnd_visibleBackgroundUser_shouldThrow() { 1206 acquireModifyNightModePermission(); 1207 1208 LocalTime now = LocalTime.now(); 1209 assertThrows(SecurityException.class, 1210 () -> mUiModeManager.setCustomNightModeEnd(now)); 1211 } 1212 1213 // TODO(b/340960913): remove the test once uimode supports visible background users. 1214 @RequireRunOnVisibleBackgroundNonProfileUser 1215 @Test testRequestProjection_visibleBackgroundUser_shouldThrow()1216 public void testRequestProjection_visibleBackgroundUser_shouldThrow() { 1217 getInstrumentation().getUiAutomation() 1218 .adoptShellPermissionIdentity(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION); 1219 1220 assertThrows(SecurityException.class, 1221 () -> mUiModeManager.requestProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE)); 1222 } 1223 1224 // TODO(b/340960913): remove the test once uimode supports visible background users. 1225 @RequireRunOnVisibleBackgroundNonProfileUser 1226 @Test testReleaseProjection_visibleBackgroundUser_shouldThrow()1227 public void testReleaseProjection_visibleBackgroundUser_shouldThrow() { 1228 getInstrumentation().getUiAutomation() 1229 .adoptShellPermissionIdentity(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION); 1230 1231 assertThrows(SecurityException.class, 1232 () -> mUiModeManager.releaseProjection(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE)); 1233 } 1234 1235 // TODO(b/340960913): remove the test once uimode supports visible background users. 1236 @RequireRunOnVisibleBackgroundNonProfileUser 1237 @Test testAddOnProjectionStateChangedListener_visibleBackgroundUser_shouldThrow()1238 public void testAddOnProjectionStateChangedListener_visibleBackgroundUser_shouldThrow() { 1239 getInstrumentation().getUiAutomation() 1240 .adoptShellPermissionIdentity(Manifest.permission.READ_PROJECTION_STATE); 1241 1242 assertThrows(SecurityException.class, 1243 () -> mUiModeManager.addOnProjectionStateChangedListener( 1244 UiModeManager.PROJECTION_TYPE_ALL, 1245 mContext.getMainExecutor(), (t, pkgs) -> { })); 1246 } 1247 isAutomotive()1248 private boolean isAutomotive() { 1249 return mContext.getPackageManager().hasSystemFeature( 1250 PackageManager.FEATURE_AUTOMOTIVE); 1251 } 1252 isTelevision()1253 private boolean isTelevision() { 1254 PackageManager pm = mContext.getPackageManager(); 1255 return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) 1256 || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); 1257 } 1258 isWatch()1259 private boolean isWatch() { 1260 return mContext.getPackageManager().hasSystemFeature( 1261 PackageManager.FEATURE_WATCH); 1262 } 1263 doTestUiModeForAutomotive()1264 private void doTestUiModeForAutomotive() throws Exception { 1265 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 1266 assertTrue(mUiModeManager.isUiModeLocked()); 1267 doTestLockedUiMode(); 1268 } 1269 doTestUiModeGeneric()1270 private void doTestUiModeGeneric() throws Exception { 1271 if (mUiModeManager.isUiModeLocked()) { 1272 doTestLockedUiMode(); 1273 } else { 1274 doTestUnlockedUiMode(); 1275 } 1276 } 1277 doTestLockedUiMode()1278 private void doTestLockedUiMode() throws Exception { 1279 int originalMode = mUiModeManager.getCurrentModeType(); 1280 mUiModeManager.enableCarMode(0); 1281 assertEquals(originalMode, mUiModeManager.getCurrentModeType()); 1282 mUiModeManager.disableCarMode(0); 1283 assertEquals(originalMode, mUiModeManager.getCurrentModeType()); 1284 } 1285 doTestUnlockedUiMode()1286 private void doTestUnlockedUiMode() throws Exception { 1287 mUiModeManager.enableCarMode(0); 1288 assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 1289 mUiModeManager.disableCarMode(0); 1290 assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType()); 1291 } 1292 doTestLockedNightMode()1293 private void doTestLockedNightMode() throws Exception { 1294 int currentMode = mUiModeManager.getNightMode(); 1295 if (currentMode == UiModeManager.MODE_NIGHT_YES) { 1296 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); 1297 assertEquals(currentMode, mUiModeManager.getNightMode()); 1298 } else { 1299 mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES); 1300 assertEquals(currentMode, mUiModeManager.getNightMode()); 1301 } 1302 } 1303 doTestUnlockedNightMode()1304 private void doTestUnlockedNightMode() throws Exception { 1305 // day night mode should be settable regardless of car mode. 1306 mUiModeManager.enableCarMode(0); 1307 doTestAllNightModes(); 1308 mUiModeManager.disableCarMode(0); 1309 doTestAllNightModes(); 1310 } 1311 doTestAllNightModes()1312 private void doTestAllNightModes() { 1313 assertNightModeChange(UiModeManager.MODE_NIGHT_AUTO); 1314 assertNightModeChange(UiModeManager.MODE_NIGHT_YES); 1315 assertNightModeChange(UiModeManager.MODE_NIGHT_NO); 1316 } 1317 assertNightModeChange(int mode)1318 private void assertNightModeChange(int mode) { 1319 mUiModeManager.setNightMode(mode); 1320 assertEquals(mode, mUiModeManager.getNightMode()); 1321 } 1322 assertVisibleNightModeInConfiguration(int mode)1323 private void assertVisibleNightModeInConfiguration(int mode) { 1324 int uiMode = mContext.getResources().getConfiguration().uiMode; 1325 int flags = uiMode & Configuration.UI_MODE_NIGHT_MASK; 1326 assertEquals(mode, flags); 1327 } 1328 assertStoredNightModeSetting(int mode)1329 private void assertStoredNightModeSetting(int mode) { 1330 int storedModeInt = -1; 1331 // Settings.Secure.UI_NIGHT_MODE 1332 for (int i = 0; i < MAX_WAIT_TIME_MS; i += WAIT_TIME_INCR_MS) { 1333 String storedMode = getUiNightModeFromSetting(); 1334 if (!TextUtils.isEmpty(storedMode)) { 1335 storedModeInt = Integer.parseInt(storedMode); 1336 } 1337 if (mode == storedModeInt) break; 1338 try { 1339 Thread.sleep(WAIT_TIME_INCR_MS); 1340 } catch (InterruptedException e) { 1341 e.printStackTrace(); 1342 } 1343 } 1344 assertEquals(mode, storedModeInt); 1345 } 1346 setNightMode(int mode)1347 private void setNightMode(int mode) { 1348 String modeString = "unknown"; 1349 switch (mode) { 1350 case UiModeManager.MODE_NIGHT_AUTO: 1351 modeString = "auto"; 1352 break; 1353 case UiModeManager.MODE_NIGHT_NO: 1354 modeString = "no"; 1355 break; 1356 case UiModeManager.MODE_NIGHT_YES: 1357 modeString = "yes"; 1358 break; 1359 } 1360 final String command = " cmd uimode night " + modeString; 1361 applyCommand(command); 1362 } 1363 setStartTime(LocalTime t)1364 private void setStartTime(LocalTime t) { 1365 final String command = " cmd uimode time start " + t.toString(); 1366 applyCommand(command); 1367 } 1368 setEndTime(LocalTime t)1369 private void setEndTime(LocalTime t) { 1370 final String command = " cmd uimode time end " + t.toString(); 1371 applyCommand(command); 1372 } 1373 applyCommand(String command)1374 private void applyCommand(String command) { 1375 final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); 1376 uiAutomation.adoptShellPermissionIdentity(Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1377 try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) { 1378 Assert.assertNotNull("Failed to execute shell command: " + command, fd); 1379 // Wait for the command to finish by reading until EOF 1380 try (InputStream in = new FileInputStream(fd.getFileDescriptor())) { 1381 byte[] buffer = new byte[4096]; 1382 while (in.read(buffer) > 0) continue; 1383 } catch (IOException e) { 1384 throw new IOException("Could not read stdout of command: " + command, e); 1385 } 1386 } catch (IOException e) { 1387 fail(); 1388 } finally { 1389 uiAutomation.destroy(); 1390 } 1391 } 1392 getUiNightModeFromSetting()1393 private String getUiNightModeFromSetting() { 1394 return mSystemUserSettings.get("ui_night_mode"); 1395 } 1396 acquireModifyNightModePermission()1397 private void acquireModifyNightModePermission() { 1398 getInstrumentation().getUiAutomation() 1399 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_DAY_NIGHT_MODE); 1400 mHasModifiedNightModePermissionAcquired = true; 1401 } 1402 waitForAtomicBooleanBecomes(AtomicBoolean atomicBoolean, boolean expectedValue, Object waitObject, String condition)1403 private void waitForAtomicBooleanBecomes(AtomicBoolean atomicBoolean, 1404 boolean expectedValue, Object waitObject, String condition) { 1405 TestUtils.waitOn(waitObject, () -> atomicBoolean.get() == expectedValue, 1406 MAX_WAIT_TIME_MS, condition); 1407 } 1408 putContrastInSettings(float contrast)1409 private void putContrastInSettings(float contrast) { 1410 runWithShellPermissionIdentity(() -> Settings.Secure.putFloat( 1411 mContext.getContentResolver(), CONTRAST_LEVEL, contrast), WRITE_SECURE_SETTINGS); 1412 } 1413 } 1414