1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 20 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 21 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 22 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 23 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 24 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 29 import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID; 30 import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID; 31 import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_LAST_ORDERED_ID; 32 import static com.android.server.wm.ActivityRecord.State.PAUSED; 33 import static com.android.server.wm.ActivityRecord.State.PAUSING; 34 import static com.android.server.wm.ActivityRecord.State.RESUMED; 35 import static com.android.server.wm.ActivityRecord.State.STOPPING; 36 37 import static org.junit.Assert.assertEquals; 38 import static org.junit.Assert.assertFalse; 39 import static org.junit.Assert.assertNotEquals; 40 import static org.junit.Assert.assertNotNull; 41 import static org.junit.Assert.assertNull; 42 import static org.junit.Assert.assertTrue; 43 import static org.mockito.ArgumentMatchers.anyBoolean; 44 import static org.mockito.ArgumentMatchers.anyInt; 45 import static org.mockito.ArgumentMatchers.anyString; 46 import static org.mockito.Mockito.atLeast; 47 import static org.mockito.Mockito.doCallRealMethod; 48 import static org.mockito.Mockito.when; 49 50 import android.annotation.NonNull; 51 import android.annotation.Nullable; 52 import android.app.Activity; 53 import android.app.ActivityManager; 54 import android.app.IApplicationThread; 55 import android.app.PictureInPictureParams; 56 import android.app.servertransaction.ClientTransaction; 57 import android.app.servertransaction.EnterPipRequestedItem; 58 import android.content.pm.ActivityInfo; 59 import android.content.pm.ApplicationInfo; 60 import android.content.res.Configuration; 61 import android.graphics.Rect; 62 import android.os.Binder; 63 import android.os.IBinder; 64 import android.os.LocaleList; 65 import android.os.RemoteException; 66 import android.platform.test.annotations.Presubmit; 67 import android.view.Display; 68 import android.view.DisplayInfo; 69 import android.view.IDisplayWindowListener; 70 import android.view.WindowManager; 71 72 import androidx.test.filters.MediumTest; 73 74 import org.junit.Before; 75 import org.junit.Test; 76 import org.junit.runner.RunWith; 77 import org.mockito.ArgumentCaptor; 78 import org.mockito.Mockito; 79 import org.mockito.MockitoSession; 80 81 import java.util.ArrayList; 82 import java.util.List; 83 import java.util.function.Consumer; 84 85 /** 86 * Tests for the {@link ActivityTaskManagerService} class. 87 * 88 * Build/Install/Run: 89 * atest WmTests:ActivityTaskManagerServiceTests 90 */ 91 @Presubmit 92 @MediumTest 93 @RunWith(WindowTestRunner.class) 94 public class ActivityTaskManagerServiceTests extends WindowTestsBase { 95 96 private final ArgumentCaptor<ClientTransaction> mClientTransactionCaptor = 97 ArgumentCaptor.forClass(ClientTransaction.class); 98 99 private static final String DEFAULT_PACKAGE_NAME = "my.application.package"; 100 private static final int DEFAULT_USER_ID = 100; 101 102 @Before setUp()103 public void setUp() throws Exception { 104 setBooted(mAtm); 105 } 106 107 /** Verify that activity is finished correctly upon request. */ 108 @Test testActivityFinish()109 public void testActivityFinish() { 110 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 111 final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); 112 assertTrue("Activity must be finished", mAtm.mActivityClientController.finishActivity( 113 activity.token, 0 /* resultCode */, null /* resultData */, 114 Activity.DONT_FINISH_TASK_WITH_ACTIVITY)); 115 assertTrue(activity.finishing); 116 117 assertTrue("Duplicate activity finish request must also return 'true'", 118 mAtm.mActivityClientController.finishActivity(activity.token, 0 /* resultCode */, 119 null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY)); 120 } 121 122 @Test testOnPictureInPictureRequested()123 public void testOnPictureInPictureRequested() throws RemoteException { 124 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 125 final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); 126 final ClientLifecycleManager mockLifecycleManager = mock(ClientLifecycleManager.class); 127 doReturn(mockLifecycleManager).when(mAtm).getLifecycleManager(); 128 doReturn(true).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean()); 129 130 mAtm.mActivityClientController.requestPictureInPictureMode(activity); 131 132 verify(mockLifecycleManager).scheduleTransaction(mClientTransactionCaptor.capture()); 133 final ClientTransaction transaction = mClientTransactionCaptor.getValue(); 134 // Check that only an enter pip request item callback was scheduled. 135 assertEquals(1, transaction.getCallbacks().size()); 136 assertTrue(transaction.getCallbacks().get(0) instanceof EnterPipRequestedItem); 137 // Check the activity lifecycle state remains unchanged. 138 assertNull(transaction.getLifecycleStateRequest()); 139 } 140 141 @Test testOnPictureInPictureRequested_cannotEnterPip()142 public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException { 143 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 144 final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); 145 ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager(); 146 doReturn(false).when(activity).inPinnedWindowingMode(); 147 doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean()); 148 149 mAtm.mActivityClientController.requestPictureInPictureMode(activity); 150 151 verify(lifecycleManager, atLeast(0)) 152 .scheduleTransaction(mClientTransactionCaptor.capture()); 153 final ClientTransaction transaction = mClientTransactionCaptor.getValue(); 154 // Check that none are enter pip request items. 155 transaction.getCallbacks().forEach(clientTransactionItem -> { 156 assertFalse(clientTransactionItem instanceof EnterPipRequestedItem); 157 }); 158 } 159 160 @Test testOnPictureInPictureRequested_alreadyInPIPMode()161 public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException { 162 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 163 final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); 164 ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager(); 165 doReturn(true).when(activity).inPinnedWindowingMode(); 166 167 mAtm.mActivityClientController.requestPictureInPictureMode(activity); 168 169 verify(lifecycleManager, atLeast(0)) 170 .scheduleTransaction(mClientTransactionCaptor.capture()); 171 final ClientTransaction transaction = mClientTransactionCaptor.getValue(); 172 // Check that none are enter pip request items. 173 transaction.getCallbacks().forEach(clientTransactionItem -> { 174 assertFalse(clientTransactionItem instanceof EnterPipRequestedItem); 175 }); 176 } 177 178 @Test testDisplayWindowListener()179 public void testDisplayWindowListener() { 180 final ArrayList<Integer> added = new ArrayList<>(); 181 final ArrayList<Integer> changed = new ArrayList<>(); 182 final ArrayList<Integer> removed = new ArrayList<>(); 183 IDisplayWindowListener listener = new IDisplayWindowListener.Stub() { 184 @Override 185 public void onDisplayAdded(int displayId) { 186 added.add(displayId); 187 } 188 189 @Override 190 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { 191 changed.add(displayId); 192 } 193 194 @Override 195 public void onDisplayRemoved(int displayId) { 196 removed.add(displayId); 197 } 198 199 @Override 200 public void onFixedRotationStarted(int displayId, int newRotation) {} 201 202 @Override 203 public void onFixedRotationFinished(int displayId) {} 204 205 @Override 206 public void onKeepClearAreasChanged(int displayId, List<Rect> restricted, 207 List<Rect> unrestricted) {} 208 }; 209 int[] displayIds = mAtm.mWindowManager.registerDisplayWindowListener(listener); 210 for (int i = 0; i < displayIds.length; i++) { 211 added.add(displayIds[i]); 212 } 213 // Check that existing displays call added 214 assertEquals(mRootWindowContainer.getChildCount(), added.size()); 215 assertEquals(0, changed.size()); 216 assertEquals(0, removed.size()); 217 added.clear(); 218 // Check adding a display 219 DisplayContent newDisp1 = new TestDisplayContent.Builder(mAtm, 600, 800).build(); 220 assertEquals(1, added.size()); 221 assertEquals(0, changed.size()); 222 assertEquals(0, removed.size()); 223 added.clear(); 224 // Check that changes are reported 225 Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration()); 226 c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300)); 227 newDisp1.performDisplayOverrideConfigUpdate(c); 228 assertEquals(0, added.size()); 229 assertEquals(1, changed.size()); 230 assertEquals(0, removed.size()); 231 changed.clear(); 232 // Check that removal is reported 233 newDisp1.remove(); 234 assertEquals(0, added.size()); 235 assertEquals(0, changed.size()); 236 assertEquals(1, removed.size()); 237 } 238 239 @Test testSetLockScreenShownWithVirtualDisplay()240 public void testSetLockScreenShownWithVirtualDisplay() { 241 DisplayInfo displayInfo = new DisplayInfo(); 242 displayInfo.copyFrom(mDisplayInfo); 243 displayInfo.type = Display.TYPE_VIRTUAL; 244 DisplayContent virtualDisplay = createNewDisplay(displayInfo); 245 final KeyguardController keyguardController = mSupervisor.getKeyguardController(); 246 247 // Make sure we're starting out with 2 unlocked displays 248 assertEquals(2, mRootWindowContainer.getChildCount()); 249 mRootWindowContainer.forAllDisplays(displayContent -> { 250 assertFalse(displayContent.isKeyguardLocked()); 251 assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); 252 }); 253 254 // Check that setLockScreenShown locks both displays 255 mAtm.setLockScreenShown(true, true); 256 mRootWindowContainer.forAllDisplays(displayContent -> { 257 assertTrue(displayContent.isKeyguardLocked()); 258 assertTrue(keyguardController.isAodShowing(displayContent.mDisplayId)); 259 }); 260 261 // Check setLockScreenShown unlocking both displays 262 mAtm.setLockScreenShown(false, false); 263 mRootWindowContainer.forAllDisplays(displayContent -> { 264 assertFalse(displayContent.isKeyguardLocked()); 265 assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); 266 }); 267 } 268 269 @Test testSetLockScreenShownWithAlwaysUnlockedVirtualDisplay()270 public void testSetLockScreenShownWithAlwaysUnlockedVirtualDisplay() { 271 assertEquals(Display.DEFAULT_DISPLAY, mRootWindowContainer.getChildAt(0).getDisplayId()); 272 273 DisplayInfo displayInfo = new DisplayInfo(); 274 displayInfo.copyFrom(mDisplayInfo); 275 displayInfo.type = Display.TYPE_VIRTUAL; 276 displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; 277 displayInfo.flags = Display.FLAG_OWN_DISPLAY_GROUP | Display.FLAG_ALWAYS_UNLOCKED; 278 DisplayContent newDisplay = createNewDisplay(displayInfo); 279 final KeyguardController keyguardController = mSupervisor.getKeyguardController(); 280 281 // Make sure we're starting out with 2 unlocked displays 282 assertEquals(2, mRootWindowContainer.getChildCount()); 283 mRootWindowContainer.forAllDisplays(displayContent -> { 284 assertFalse(displayContent.isKeyguardLocked()); 285 assertFalse(keyguardController.isAodShowing(displayContent.mDisplayId)); 286 }); 287 288 // setLockScreenShown should only lock the default display, not the virtual one 289 mAtm.setLockScreenShown(true, true); 290 291 assertTrue(mDefaultDisplay.isKeyguardLocked()); 292 assertTrue(keyguardController.isAodShowing(mDefaultDisplay.mDisplayId)); 293 294 DisplayContent virtualDisplay = mRootWindowContainer.getDisplayContent( 295 newDisplay.getDisplayId()); 296 assertNotEquals(Display.DEFAULT_DISPLAY, virtualDisplay.getDisplayId()); 297 assertFalse(virtualDisplay.isKeyguardLocked()); 298 assertFalse(keyguardController.isAodShowing(virtualDisplay.mDisplayId)); 299 } 300 301 /* 302 a test to verify b/144045134 - ignore PIP mode request for destroyed activity. 303 mocks r.getParent() to return null to cause NPE inside enterPipRunnable#run() in 304 ActivityTaskMangerservice#enterPictureInPictureMode(), which rebooted the device. 305 It doesn't fully simulate the issue's reproduce steps, but this should suffice. 306 */ 307 @Test testEnterPipModeWhenRecordParentChangesToNull()308 public void testEnterPipModeWhenRecordParentChangesToNull() { 309 MockitoSession mockSession = mockitoSession() 310 .initMocks(this) 311 .mockStatic(ActivityRecord.class) 312 .startMocking(); 313 314 ActivityRecord record = mock(ActivityRecord.class); 315 IBinder token = mock(IBinder.class); 316 PictureInPictureParams params = mock(PictureInPictureParams.class); 317 record.pictureInPictureArgs = params; 318 319 //mock operations in private method ensureValidPictureInPictureActivityParamsLocked() 320 when(ActivityRecord.forTokenLocked(token)).thenReturn(record); 321 doReturn(true).when(record).supportsPictureInPicture(); 322 doReturn(false).when(params).hasSetAspectRatio(); 323 324 //mock other operations 325 doReturn(true).when(record) 326 .checkEnterPictureInPictureState("enterPictureInPictureMode", false); 327 doReturn(false).when(record).inPinnedWindowingMode(); 328 doReturn(false).when(mAtm).isKeyguardLocked(anyInt()); 329 330 //to simulate NPE 331 doReturn(null).when(record).getParent(); 332 333 mAtm.mActivityClientController.enterPictureInPictureMode(token, params); 334 //if record's null parent is not handled gracefully, test will fail with NPE 335 336 mockSession.finishMocking(); 337 } 338 339 @Test testResumeNextActivityOnCrashedAppDied()340 public void testResumeNextActivityOnCrashedAppDied() { 341 mSupervisor.beginDeferResume(); 342 final ActivityRecord homeActivity = new ActivityBuilder(mAtm) 343 .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) 344 .build(); 345 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 346 activity.setState(RESUMED, "test"); 347 mSupervisor.endDeferResume(); 348 349 assertEquals(activity.app, mAtm.mInternal.getTopApp()); 350 351 // Assume the activity is finishing and hidden because it was crashed. 352 activity.finishing = true; 353 activity.setVisibleRequested(false); 354 activity.setVisible(false); 355 activity.getTask().setPausingActivity(activity); 356 homeActivity.setState(PAUSED, "test"); 357 358 // Even the visibility states are invisible, the next activity should be resumed because 359 // the crashed activity was pausing. 360 mAtm.mInternal.handleAppDied(activity.app, false /* restarting */, 361 null /* finishInstrumentationCallback */); 362 assertEquals(RESUMED, homeActivity.getState()); 363 assertEquals(homeActivity.app, mAtm.mInternal.getTopApp()); 364 } 365 366 @Test testUpdateSleep()367 public void testUpdateSleep() { 368 doCallRealMethod().when(mWm.mRoot).hasAwakeDisplay(); 369 mSupervisor.mGoingToSleepWakeLock = 370 mSystemServicesTestRule.createStubbedWakeLock(true /* needVerification */); 371 final Task rootHomeTask = mWm.mRoot.getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); 372 final ActivityRecord homeActivity = new ActivityBuilder(mAtm).setTask(rootHomeTask).build(); 373 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 374 topActivity.setState(RESUMED, "test"); 375 376 final Consumer<ActivityRecord> assertTopNonSleeping = activity -> { 377 assertFalse(mAtm.mInternal.isSleeping()); 378 assertEquals(ActivityManager.PROCESS_STATE_TOP, mAtm.mInternal.getTopProcessState()); 379 assertEquals(activity.app, mAtm.mInternal.getTopApp()); 380 }; 381 assertTopNonSleeping.accept(topActivity); 382 383 // Sleep all displays. 384 mWm.mRoot.forAllDisplays(display -> doReturn(true).when(display).shouldSleep()); 385 mAtm.updateSleepIfNeededLocked(); 386 // Simulate holding sleep wake lock if it is acquired. 387 verify(mSupervisor.mGoingToSleepWakeLock).acquire(); 388 doReturn(true).when(mSupervisor.mGoingToSleepWakeLock).isHeld(); 389 390 assertEquals(PAUSING, topActivity.getState()); 391 assertTrue(mAtm.mInternal.isSleeping()); 392 assertEquals(ActivityManager.PROCESS_STATE_TOP_SLEEPING, 393 mAtm.mInternal.getTopProcessState()); 394 // The top app should not change while sleeping. 395 assertEquals(topActivity.app, mAtm.mInternal.getTopApp()); 396 397 mAtm.startLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY 398 | ActivityTaskManagerService.POWER_MODE_REASON_UNKNOWN_VISIBILITY); 399 assertEquals(ActivityManager.PROCESS_STATE_TOP, mAtm.mInternal.getTopProcessState()); 400 // Because there is no unknown visibility record, the state will be restored if other 401 // reasons are all done. 402 mAtm.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY); 403 assertEquals(ActivityManager.PROCESS_STATE_TOP_SLEEPING, 404 mAtm.mInternal.getTopProcessState()); 405 406 // If all activities are stopped, the sleep wake lock must be released. 407 final Task topRootTask = topActivity.getRootTask(); 408 doReturn(true).when(rootHomeTask).goToSleepIfPossible(anyBoolean()); 409 doReturn(true).when(topRootTask).goToSleepIfPossible(anyBoolean()); 410 topActivity.setState(STOPPING, "test"); 411 topActivity.activityStopped(null /* newIcicle */, null /* newPersistentState */, 412 null /* description */); 413 verify(mSupervisor.mGoingToSleepWakeLock).release(); 414 415 // Move the current top to back, the top app should update to the next activity. 416 topRootTask.moveToBack("test", null /* self */); 417 assertEquals(homeActivity.app, mAtm.mInternal.getTopApp()); 418 419 // Wake all displays. 420 mWm.mRoot.forAllDisplays(display -> doReturn(false).when(display).shouldSleep()); 421 mAtm.updateSleepIfNeededLocked(); 422 423 assertTopNonSleeping.accept(homeActivity); 424 } 425 426 @Test testSupportsMultiWindow_resizable()427 public void testSupportsMultiWindow_resizable() { 428 final ActivityRecord activity = new ActivityBuilder(mAtm) 429 .setCreateTask(true) 430 .setResizeMode(RESIZE_MODE_RESIZEABLE) 431 .build(); 432 final Task task = activity.getTask(); 433 434 assertTrue(activity.supportsMultiWindow()); 435 assertTrue(task.supportsMultiWindow()); 436 } 437 438 @Test testSupportsMultiWindow_nonResizable()439 public void testSupportsMultiWindow_nonResizable() { 440 final ActivityRecord activity = new ActivityBuilder(mAtm) 441 .setCreateTask(true) 442 .setResizeMode(RESIZE_MODE_UNRESIZEABLE) 443 .build(); 444 final Task task = activity.getTask(); 445 final TaskDisplayArea tda = task.getDisplayArea(); 446 447 // Device config as not support. 448 mAtm.mSupportsNonResizableMultiWindow = -1; 449 450 assertFalse(activity.supportsMultiWindow()); 451 assertFalse(task.supportsMultiWindow()); 452 453 // Device config as always support. 454 mAtm.mSupportsNonResizableMultiWindow = 1; 455 456 assertTrue(activity.supportsMultiWindow()); 457 assertTrue(task.supportsMultiWindow()); 458 459 // The default config is relying on the screen size. 460 mAtm.mSupportsNonResizableMultiWindow = 0; 461 462 // Supports on large screen. 463 tda.getConfiguration().smallestScreenWidthDp = 464 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; 465 466 assertTrue(activity.supportsMultiWindow()); 467 assertTrue(task.supportsMultiWindow()); 468 469 // Not supports on small screen. 470 tda.getConfiguration().smallestScreenWidthDp = 471 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 472 473 assertFalse(activity.supportsMultiWindow()); 474 assertFalse(task.supportsMultiWindow()); 475 } 476 477 @Test testSupportsMultiWindow_activityMinWidthHeight_largerThanSupport()478 public void testSupportsMultiWindow_activityMinWidthHeight_largerThanSupport() { 479 final float density = mContext.getResources().getDisplayMetrics().density; 480 final ActivityInfo.WindowLayout windowLayout = 481 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, 482 // This is larger than the min dimensions device support in multi window, 483 // the activity will not be supported in multi window if the device respects 484 /* minWidth= */ 485 (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density), 486 /* minHeight= */ 487 (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP * density)); 488 final ActivityRecord activity = new ActivityBuilder(mAtm) 489 .setCreateTask(true) 490 .setWindowLayout(windowLayout) 491 .setResizeMode(RESIZE_MODE_RESIZEABLE) 492 .build(); 493 final Task task = activity.getTask(); 494 final TaskDisplayArea tda = task.getDisplayArea(); 495 496 // Ignore the activity min width/height for determine multi window eligibility. 497 mAtm.mRespectsActivityMinWidthHeightMultiWindow = -1; 498 499 assertTrue(activity.supportsMultiWindow()); 500 assertTrue(task.supportsMultiWindow()); 501 502 // Always check the activity min width/height. 503 mAtm.mRespectsActivityMinWidthHeightMultiWindow = 1; 504 505 assertFalse(activity.supportsMultiWindow()); 506 assertFalse(task.supportsMultiWindow()); 507 508 // The default config is relying on the screen size. 509 mAtm.mRespectsActivityMinWidthHeightMultiWindow = 0; 510 511 // Ignore on large screen. 512 tda.getConfiguration().smallestScreenWidthDp = 513 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; 514 515 assertTrue(activity.supportsMultiWindow()); 516 assertTrue(task.supportsMultiWindow()); 517 518 // Check on small screen. 519 tda.getConfiguration().smallestScreenWidthDp = 520 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 521 522 assertFalse(activity.supportsMultiWindow()); 523 assertFalse(task.supportsMultiWindow()); 524 } 525 526 @Test testSupportsMultiWindow_landscape_checkActivityMinWidth()527 public void testSupportsMultiWindow_landscape_checkActivityMinWidth() { 528 // This is smaller than the min dimensions device support in multi window, 529 // the activity will be supported in multi window 530 final float density = mContext.getResources().getDisplayMetrics().density; 531 final int supportedWidth = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP 532 * mAtm.mMinPercentageMultiWindowSupportWidth * density); 533 final ActivityInfo.WindowLayout windowLayout = 534 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, 535 /* minWidth= */ supportedWidth, 536 /* minHeight= */ 0); 537 final ActivityRecord activity = new ActivityBuilder(mAtm) 538 .setCreateTask(true) 539 .setWindowLayout(windowLayout) 540 .setResizeMode(RESIZE_MODE_RESIZEABLE) 541 .build(); 542 final Task task = activity.getTask(); 543 final TaskDisplayArea tda = task.getDisplayArea(); 544 tda.getConfiguration().smallestScreenWidthDp = 545 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 546 tda.getConfiguration().screenWidthDp = 547 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 548 tda.getConfiguration().orientation = ORIENTATION_LANDSCAPE; 549 550 assertFalse(activity.supportsMultiWindow()); 551 assertFalse(task.supportsMultiWindow()); 552 553 tda.getConfiguration().screenWidthDp = (int) Math.ceil( 554 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP 555 / mAtm.mMinPercentageMultiWindowSupportWidth); 556 557 assertTrue(activity.supportsMultiWindow()); 558 assertTrue(task.supportsMultiWindow()); 559 } 560 561 @Test testSupportsMultiWindow_portrait_checkActivityMinHeight()562 public void testSupportsMultiWindow_portrait_checkActivityMinHeight() { 563 // This is smaller than the min dimensions device support in multi window, 564 // the activity will be supported in multi window 565 final float density = mContext.getResources().getDisplayMetrics().density; 566 final int supportedHeight = (int) (WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP 567 * mAtm.mMinPercentageMultiWindowSupportHeight * density); 568 final ActivityInfo.WindowLayout windowLayout = 569 new ActivityInfo.WindowLayout(0, 0, 0, 0, 0, 570 /* minWidth= */ 0, 571 /* minHeight= */ supportedHeight); 572 final ActivityRecord activity = new ActivityBuilder(mAtm) 573 .setCreateTask(true) 574 .setWindowLayout(windowLayout) 575 .setResizeMode(RESIZE_MODE_RESIZEABLE) 576 .build(); 577 final Task task = activity.getTask(); 578 final TaskDisplayArea tda = task.getDisplayArea(); 579 tda.getConfiguration().smallestScreenWidthDp = 580 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 581 tda.getConfiguration().screenHeightDp = 582 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP - 1; 583 tda.getConfiguration().orientation = ORIENTATION_PORTRAIT; 584 585 assertFalse(activity.supportsMultiWindow()); 586 assertFalse(task.supportsMultiWindow()); 587 588 tda.getConfiguration().screenHeightDp = (int) Math.ceil( 589 WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP 590 / mAtm.mMinPercentageMultiWindowSupportHeight); 591 592 assertTrue(activity.supportsMultiWindow()); 593 assertTrue(task.supportsMultiWindow()); 594 } 595 596 @Test testPackageConfigUpdate_locales_successfullyApplied()597 public void testPackageConfigUpdate_locales_successfullyApplied() { 598 Configuration config = mAtm.getGlobalConfiguration(); 599 config.setLocales(LocaleList.forLanguageTags("en-XC")); 600 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 601 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 602 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 603 604 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 605 mAtm.mInternal.createPackageConfigurationUpdater(); 606 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit(); 607 608 WindowProcessController wpcAfterConfigChange = createWindowProcessController( 609 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 610 611 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 612 wpcAfterConfigChange.getConfiguration().getLocales()); 613 assertFalse(wpcAfterConfigChange.getConfiguration().isNightModeActive()); 614 } 615 616 @Test testPackageConfigUpdate_nightMode_successfullyApplied()617 public void testPackageConfigUpdate_nightMode_successfullyApplied() { 618 Configuration config = mAtm.getGlobalConfiguration(); 619 config.setLocales(LocaleList.forLanguageTags("en-XC")); 620 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 621 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 622 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 623 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 624 mAtm.mInternal.createPackageConfigurationUpdater(); 625 626 packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 627 628 WindowProcessController wpcAfterConfigChange = createWindowProcessController( 629 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 630 assertTrue(wpcAfterConfigChange.getConfiguration().isNightModeActive()); 631 assertEquals(LocaleList.forLanguageTags("en-XC"), 632 wpcAfterConfigChange.getConfiguration().getLocales()); 633 } 634 635 @Test testPackageConfigUpdate_multipleLocaleUpdates_successfullyApplied()636 public void testPackageConfigUpdate_multipleLocaleUpdates_successfullyApplied() { 637 Configuration config = mAtm.getGlobalConfiguration(); 638 config.setLocales(LocaleList.forLanguageTags("en-XC")); 639 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 640 WindowProcessController wpc = createWindowProcessController( 641 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 642 mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); 643 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 644 mAtm.mInternal.createPackageConfigurationUpdater(); 645 646 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 647 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 648 649 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 650 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 651 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 652 wpcAfterConfigChange1.getConfiguration().getLocales()); 653 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 654 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 655 wpc.getConfiguration().getLocales()); 656 657 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("ja-XC,en-XC")).commit(); 658 659 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 660 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 661 662 assertEquals(LocaleList.forLanguageTags("ja-XC,en-XC"), 663 wpcAfterConfigChange2.getConfiguration().getLocales()); 664 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 665 assertEquals(LocaleList.forLanguageTags("ja-XC,en-XC"), 666 wpc.getConfiguration().getLocales()); 667 } 668 669 @Test testPackageConfigUpdate_multipleNightModeUpdates_successfullyApplied()670 public void testPackageConfigUpdate_multipleNightModeUpdates_successfullyApplied() { 671 Configuration config = mAtm.getGlobalConfiguration(); 672 config.setLocales(LocaleList.forLanguageTags("en-XC")); 673 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 674 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 675 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 676 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 677 mAtm.mInternal.createPackageConfigurationUpdater(); 678 679 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 680 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 681 682 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 683 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 684 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 685 wpcAfterConfigChange1.getConfiguration().getLocales()); 686 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 687 688 packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_NO).commit(); 689 690 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 691 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 692 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 693 wpcAfterConfigChange2.getConfiguration().getLocales()); 694 assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 695 } 696 697 @Test testPackageConfigUpdate_onPackageUninstall_configShouldNotApply()698 public void testPackageConfigUpdate_onPackageUninstall_configShouldNotApply() { 699 Configuration config = mAtm.getGlobalConfiguration(); 700 config.setLocales(LocaleList.forLanguageTags("en-XC")); 701 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 702 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 703 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 704 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 705 mAtm.mInternal.createPackageConfigurationUpdater(); 706 707 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 708 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 709 710 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 711 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 712 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 713 wpcAfterConfigChange1.getConfiguration().getLocales()); 714 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 715 716 mAtm.mInternal.onPackageUninstalled(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 717 718 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 719 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 720 assertEquals(LocaleList.forLanguageTags("en-XC"), 721 wpcAfterConfigChange2.getConfiguration().getLocales()); 722 assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 723 } 724 725 @Test testPackageConfigUpdate_LocalesEmptyAndNightModeUndefined_configShouldNotApply()726 public void testPackageConfigUpdate_LocalesEmptyAndNightModeUndefined_configShouldNotApply() { 727 Configuration config = mAtm.getGlobalConfiguration(); 728 config.setLocales(LocaleList.forLanguageTags("en-XC")); 729 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 730 WindowProcessController wpc = createWindowProcessController( 731 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 732 mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); 733 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 734 mAtm.mInternal.createPackageConfigurationUpdater(); 735 736 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 737 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 738 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 739 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 740 741 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 742 wpcAfterConfigChange1.getConfiguration().getLocales()); 743 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 744 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 745 wpc.getConfiguration().getLocales()); 746 747 packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()) 748 .setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit(); 749 750 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 751 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 752 assertEquals(LocaleList.forLanguageTags("en-XC"), 753 wpcAfterConfigChange2.getConfiguration().getLocales()); 754 assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 755 assertEquals(LocaleList.forLanguageTags("en-XC"), 756 wpc.getConfiguration().getLocales()); 757 } 758 759 @Test testPackageConfigUpdate_WhenUserRemoved_configShouldNotApply()760 public void testPackageConfigUpdate_WhenUserRemoved_configShouldNotApply() { 761 Configuration config = mAtm.getGlobalConfiguration(); 762 config.setLocales(LocaleList.forLanguageTags("en-XC")); 763 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 764 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 765 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 766 767 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 768 mAtm.mInternal.createPackageConfigurationUpdater(); 769 770 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 771 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 772 773 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 774 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 775 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 776 wpcAfterConfigChange1.getConfiguration().getLocales()); 777 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 778 779 mAtm.mInternal.removeUser(DEFAULT_USER_ID); 780 781 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 782 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 783 assertEquals(LocaleList.forLanguageTags("en-XC"), 784 wpcAfterConfigChange2.getConfiguration().getLocales()); 785 assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 786 } 787 788 @Test testPackageConfigUpdate_setLocaleListToEmpty_doesNotOverlayLocaleListInWpc()789 public void testPackageConfigUpdate_setLocaleListToEmpty_doesNotOverlayLocaleListInWpc() { 790 Configuration config = mAtm.getGlobalConfiguration(); 791 config.setLocales(LocaleList.forLanguageTags("en-XC")); 792 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 793 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 794 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 795 796 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 797 mAtm.mInternal.createPackageConfigurationUpdater(); 798 799 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 800 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 801 802 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 803 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 804 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 805 wpcAfterConfigChange1.getConfiguration().getLocales()); 806 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 807 808 packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()).commit(); 809 810 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 811 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 812 assertEquals(LocaleList.forLanguageTags("en-XC"), 813 wpcAfterConfigChange2.getConfiguration().getLocales()); 814 assertTrue(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 815 } 816 817 @Test testPackageConfigUpdate_resetNightMode_doesNotOverrideNightModeInWpc()818 public void testPackageConfigUpdate_resetNightMode_doesNotOverrideNightModeInWpc() { 819 Configuration config = mAtm.getGlobalConfiguration(); 820 config.setLocales(LocaleList.forLanguageTags("en-XC")); 821 mAtm.updateGlobalConfigurationLocked(config, true, true, DEFAULT_USER_ID); 822 mAtm.mProcessMap.put(Binder.getCallingPid(), createWindowProcessController( 823 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID)); 824 825 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 826 mAtm.mInternal.createPackageConfigurationUpdater(); 827 828 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 829 .setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 830 831 WindowProcessController wpcAfterConfigChange1 = createWindowProcessController( 832 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 833 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 834 wpcAfterConfigChange1.getConfiguration().getLocales()); 835 assertTrue(wpcAfterConfigChange1.getConfiguration().isNightModeActive()); 836 837 packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit(); 838 839 WindowProcessController wpcAfterConfigChange2 = createWindowProcessController( 840 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 841 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 842 wpcAfterConfigChange2.getConfiguration().getLocales()); 843 assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); 844 } 845 846 @Test testPackageConfigUpdate_localesNotSet_localeConfigRetrievedNull()847 public void testPackageConfigUpdate_localesNotSet_localeConfigRetrievedNull() { 848 Configuration config = mAtm.getGlobalConfiguration(); 849 config.setLocales(LocaleList.forLanguageTags("en-XC")); 850 mAtm.updateGlobalConfigurationLocked(config, true, true, 851 DEFAULT_USER_ID); 852 WindowProcessController wpc = createWindowProcessController( 853 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 854 mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); 855 mAtm.mInternal.onProcessAdded(wpc); 856 857 ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal 858 .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 859 // when no configuration is set we get a null object. 860 assertNull(appSpecificConfig); 861 862 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 863 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, 864 DEFAULT_USER_ID); 865 packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); 866 867 ActivityTaskManagerInternal.PackageConfig appSpecificConfig2 = mAtm.mInternal 868 .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 869 assertNotNull(appSpecificConfig2); 870 assertNull(appSpecificConfig2.mLocales); 871 assertEquals(appSpecificConfig2.mNightMode.intValue(), Configuration.UI_MODE_NIGHT_YES); 872 } 873 874 @Test testPackageConfigUpdate_appNotRunning_configSuccessfullyApplied()875 public void testPackageConfigUpdate_appNotRunning_configSuccessfullyApplied() { 876 Configuration config = mAtm.getGlobalConfiguration(); 877 config.setLocales(LocaleList.forLanguageTags("en-XC")); 878 mAtm.updateGlobalConfigurationLocked(config, true, true, 879 DEFAULT_USER_ID); 880 881 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 882 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, 883 DEFAULT_USER_ID); 884 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit(); 885 886 // Verifies if the persisted app-specific configuration is same as the committed 887 // configuration. 888 ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal 889 .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 890 assertNotNull(appSpecificConfig); 891 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB"), appSpecificConfig.mLocales); 892 893 // Verifies if the persisted configuration for an arbitrary app is applied correctly when 894 // a new WindowProcessController is created for it. 895 WindowProcessController wpcAfterConfigChange = createWindowProcessController( 896 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 897 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 898 wpcAfterConfigChange.getConfiguration().getLocales()); 899 } 900 901 @Test testPackageConfigUpdate_appRunning_configSuccessfullyApplied()902 public void testPackageConfigUpdate_appRunning_configSuccessfullyApplied() { 903 Configuration config = mAtm.getGlobalConfiguration(); 904 config.setLocales(LocaleList.forLanguageTags("en-XC")); 905 mAtm.updateGlobalConfigurationLocked(config, true, true, 906 DEFAULT_USER_ID); 907 WindowProcessController wpc = createWindowProcessController( 908 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 909 mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); 910 mAtm.mInternal.onProcessAdded(wpc); 911 912 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 913 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, 914 DEFAULT_USER_ID); 915 916 packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit(); 917 918 ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal 919 .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 920 921 // Verifies if the persisted app-specific configuration is same as the committed 922 // configuration. 923 assertNotNull(appSpecificConfig); 924 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB"), appSpecificConfig.mLocales); 925 926 // Verifies if the committed configuration is successfully applied to the required 927 // application while it is currently running. 928 assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), 929 wpc.getConfiguration().getLocales()); 930 } 931 932 @Test testPackageConfigUpdate_commitConfig_configSuccessfullyApplied()933 public void testPackageConfigUpdate_commitConfig_configSuccessfullyApplied() { 934 Configuration config = mAtm.getGlobalConfiguration(); 935 config.setLocales(LocaleList.forLanguageTags("en-XC")); 936 mAtm.updateGlobalConfigurationLocked(config, true, true, 937 DEFAULT_USER_ID); 938 WindowProcessController wpc = createWindowProcessController( 939 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); 940 mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); 941 mAtm.mInternal.onProcessAdded(wpc); 942 943 ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = 944 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, 945 DEFAULT_USER_ID); 946 947 // committing empty locales, when no config is set should return false. 948 assertFalse(packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()).commit()); 949 950 // committing new configuration returns true; 951 assertTrue(packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 952 .commit()); 953 // applying the same configuration returns false. 954 assertFalse(packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")) 955 .commit()); 956 957 // committing empty locales and undefined nightMode should return true (deletes the 958 // pre-existing record) if some config was previously set. 959 assertTrue(packageConfigUpdater.setLocales(LocaleList.getEmptyLocaleList()) 960 .setNightMode(Configuration.UI_MODE_NIGHT_UNDEFINED).commit()); 961 } 962 createWindowProcessController(String packageName, int userId)963 private WindowProcessController createWindowProcessController(String packageName, 964 int userId) { 965 WindowProcessListener mMockListener = Mockito.mock(WindowProcessListener.class); 966 ApplicationInfo info = mock(ApplicationInfo.class); 967 info.packageName = packageName; 968 WindowProcessController wpc = new WindowProcessController( 969 mAtm, info, packageName, 0, userId, null, mMockListener); 970 wpc.setThread(mock(IApplicationThread.class)); 971 return wpc; 972 } 973 974 @Test(expected = IllegalArgumentException.class) testRegisterActivityStartInterceptor_IndexTooSmall()975 public void testRegisterActivityStartInterceptor_IndexTooSmall() { 976 mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID - 1, 977 new ActivityInterceptorCallback() { 978 @Nullable 979 @Override 980 public ActivityInterceptResult onInterceptActivityLaunch( 981 @NonNull ActivityInterceptorInfo info) { 982 return null; 983 } 984 }); 985 } 986 987 @Test(expected = IllegalArgumentException.class) testRegisterActivityStartInterceptor_IndexTooLarge()988 public void testRegisterActivityStartInterceptor_IndexTooLarge() { 989 mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_LAST_ORDERED_ID + 1, 990 new ActivityInterceptorCallback() { 991 @Nullable 992 @Override 993 public ActivityInterceptResult onInterceptActivityLaunch( 994 @NonNull ActivityInterceptorInfo info) { 995 return null; 996 } 997 }); 998 } 999 1000 @Test(expected = IllegalArgumentException.class) testRegisterActivityStartInterceptor_DuplicateId()1001 public void testRegisterActivityStartInterceptor_DuplicateId() { 1002 mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID, 1003 new ActivityInterceptorCallback() { 1004 @Nullable 1005 @Override 1006 public ActivityInterceptResult onInterceptActivityLaunch( 1007 @NonNull ActivityInterceptorInfo info) { 1008 return null; 1009 } 1010 }); 1011 mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID, 1012 new ActivityInterceptorCallback() { 1013 @Nullable 1014 @Override 1015 public ActivityInterceptResult onInterceptActivityLaunch( 1016 @NonNull ActivityInterceptorInfo info) { 1017 return null; 1018 } 1019 }); 1020 } 1021 1022 @Test testRegisterActivityStartInterceptor()1023 public void testRegisterActivityStartInterceptor() { 1024 assertEquals(0, mAtm.getActivityInterceptorCallbacks().size()); 1025 1026 mAtm.mInternal.registerActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID, 1027 new ActivityInterceptorCallback() { 1028 @Nullable 1029 @Override 1030 public ActivityInterceptResult onInterceptActivityLaunch( 1031 @NonNull ActivityInterceptorInfo info) { 1032 return null; 1033 } 1034 }); 1035 1036 assertEquals(1, mAtm.getActivityInterceptorCallbacks().size()); 1037 assertTrue(mAtm.getActivityInterceptorCallbacks().contains(SYSTEM_FIRST_ORDERED_ID)); 1038 } 1039 1040 @Test testSystemAndMainlineOrderIdsNotOverlapping()1041 public void testSystemAndMainlineOrderIdsNotOverlapping() { 1042 assertTrue(MAINLINE_FIRST_ORDERED_ID - SYSTEM_LAST_ORDERED_ID > 1); 1043 } 1044 1045 @Test testUnregisterActivityStartInterceptor()1046 public void testUnregisterActivityStartInterceptor() { 1047 int size = mAtm.getActivityInterceptorCallbacks().size(); 1048 int orderId = SYSTEM_FIRST_ORDERED_ID; 1049 1050 mAtm.mInternal.registerActivityStartInterceptor(orderId, 1051 (ActivityInterceptorCallback) info -> null); 1052 assertEquals(size + 1, mAtm.getActivityInterceptorCallbacks().size()); 1053 assertTrue(mAtm.getActivityInterceptorCallbacks().contains(orderId)); 1054 1055 mAtm.mInternal.unregisterActivityStartInterceptor(orderId); 1056 assertEquals(size, mAtm.getActivityInterceptorCallbacks().size()); 1057 assertFalse(mAtm.getActivityInterceptorCallbacks().contains(orderId)); 1058 } 1059 1060 @Test(expected = IllegalArgumentException.class) testUnregisterActivityStartInterceptor_IdNotExist()1061 public void testUnregisterActivityStartInterceptor_IdNotExist() { 1062 assertEquals(0, mAtm.getActivityInterceptorCallbacks().size()); 1063 mAtm.mInternal.unregisterActivityStartInterceptor(SYSTEM_FIRST_ORDERED_ID); 1064 } 1065 1066 @Test testFocusTopTask()1067 public void testFocusTopTask() { 1068 final ActivityRecord homeActivity = new ActivityBuilder(mAtm) 1069 .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) 1070 .build(); 1071 final Task pinnedTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 1072 .setWindowingMode(WINDOWING_MODE_PINNED) 1073 .build(); 1074 mAtm.focusTopTask(mDisplayContent.mDisplayId); 1075 1076 assertTrue(homeActivity.getTask().isFocused()); 1077 assertFalse(pinnedTask.isFocused()); 1078 } 1079 } 1080