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