1 /*
2  * Copyright (C) 2016 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.ACTIVITY_TYPE_HOME;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
24 import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
25 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
26 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
27 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
30 import static android.os.Build.VERSION_CODES.P;
31 import static android.os.Build.VERSION_CODES.Q;
32 import static android.view.Display.DEFAULT_DISPLAY;
33 import static android.view.Display.FLAG_PRIVATE;
34 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
35 import static android.view.DisplayCutout.fromBoundingRect;
36 import static android.view.Surface.ROTATION_0;
37 import static android.view.Surface.ROTATION_180;
38 import static android.view.Surface.ROTATION_270;
39 import static android.view.Surface.ROTATION_90;
40 import static android.view.WindowInsets.Type.ime;
41 import static android.view.WindowInsets.Type.navigationBars;
42 import static android.view.WindowInsets.Type.statusBars;
43 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
44 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
45 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
46 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
47 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
48 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
49 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
50 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
51 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
52 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
53 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
54 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
55 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
56 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
57 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
58 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
59 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
60 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
61 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
62 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
63 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
64 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
65 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
66 import static android.view.WindowManager.TRANSIT_CLOSE;
67 import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
68 import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
69 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
70 
71 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
72 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
73 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
74 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
75 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
76 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
77 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
78 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
79 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
80 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
81 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
82 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM;
83 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
84 import static com.android.server.wm.WindowContainer.POSITION_TOP;
85 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
86 import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
87 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
88 
89 import static com.google.common.truth.Truth.assertThat;
90 
91 import static org.hamcrest.Matchers.is;
92 import static org.junit.Assert.assertEquals;
93 import static org.junit.Assert.assertFalse;
94 import static org.junit.Assert.assertNotEquals;
95 import static org.junit.Assert.assertNotNull;
96 import static org.junit.Assert.assertNull;
97 import static org.junit.Assert.assertThat;
98 import static org.junit.Assert.assertTrue;
99 import static org.mockito.ArgumentMatchers.anyInt;
100 import static org.mockito.ArgumentMatchers.eq;
101 import static org.mockito.Mockito.atLeast;
102 import static org.mockito.Mockito.clearInvocations;
103 import static org.mockito.Mockito.doAnswer;
104 import static org.mockito.Mockito.doCallRealMethod;
105 import static org.mockito.Mockito.when;
106 
107 import android.annotation.NonNull;
108 import android.app.ActivityTaskManager;
109 import android.app.WindowConfiguration;
110 import android.content.res.Configuration;
111 import android.graphics.Insets;
112 import android.graphics.Rect;
113 import android.graphics.Region;
114 import android.hardware.HardwareBuffer;
115 import android.metrics.LogMaker;
116 import android.os.Binder;
117 import android.os.RemoteException;
118 import android.os.UserHandle;
119 import android.os.UserManager;
120 import android.platform.test.annotations.EnableFlags;
121 import android.platform.test.annotations.DisableFlags;
122 import android.platform.test.annotations.Presubmit;
123 import android.util.ArraySet;
124 import android.view.Display;
125 import android.view.DisplayCutout;
126 import android.view.DisplayInfo;
127 import android.view.Gravity;
128 import android.view.IDisplayChangeWindowCallback;
129 import android.view.IDisplayChangeWindowController;
130 import android.view.ISystemGestureExclusionListener;
131 import android.view.IWindowManager;
132 import android.view.InsetsState;
133 import android.view.Surface;
134 import android.view.SurfaceControl;
135 import android.view.SurfaceControl.Transaction;
136 import android.view.View;
137 import android.view.WindowManager;
138 import android.window.DisplayAreaInfo;
139 import android.window.IDisplayAreaOrganizer;
140 import android.window.ScreenCapture;
141 import android.window.WindowContainerToken;
142 import android.window.WindowContainerTransaction;
143 
144 import androidx.test.filters.SmallTest;
145 
146 import com.android.internal.logging.MetricsLogger;
147 import com.android.internal.logging.nano.MetricsProto;
148 import com.android.server.LocalServices;
149 import com.android.server.policy.WindowManagerPolicy;
150 import com.android.server.wm.utils.WmDisplayCutout;
151 
152 import org.junit.Test;
153 import org.junit.runner.RunWith;
154 import org.mockito.ArgumentCaptor;
155 import org.mockito.Mockito;
156 
157 import java.util.ArrayList;
158 import java.util.Arrays;
159 import java.util.Collections;
160 import java.util.LinkedList;
161 import java.util.List;
162 import java.util.concurrent.CompletableFuture;
163 import java.util.concurrent.ExecutionException;
164 import java.util.concurrent.TimeUnit;
165 import java.util.concurrent.TimeoutException;
166 
167 /**
168  * Tests for the {@link DisplayContent} class.
169  *
170  * Build/Install/Run:
171  *  atest WmTests:DisplayContentTests
172  */
173 @SmallTest
174 @Presubmit
175 @RunWith(WindowTestRunner.class)
176 public class DisplayContentTests extends WindowTestsBase {
177 
178     @SetupWindows(addAllCommonWindows = true)
179     @Test
testForAllWindows()180     public void testForAllWindows() {
181         final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
182                 mDisplayContent, "exiting app");
183         final ActivityRecord exitingApp = exitingAppWindow.mActivityRecord;
184         exitingApp.startAnimation(exitingApp.getPendingTransaction(), mock(AnimationAdapter.class),
185                 false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION);
186         exitingApp.mIsExiting = true;
187         // If the activity is animating, its window should not be removed.
188         mDisplayContent.handleCompleteDeferredRemoval();
189 
190         final ArrayList<WindowState> windows = new ArrayList<>(Arrays.asList(
191                 mWallpaperWindow,
192                 mChildAppWindowBelow,
193                 mAppWindow,
194                 mChildAppWindowAbove,
195                 exitingAppWindow,
196                 mDockedDividerWindow,
197                 mImeWindow,
198                 mImeDialogWindow,
199                 mStatusBarWindow,
200                 mNotificationShadeWindow,
201                 mNavBarWindow));
202         assertForAllWindowsOrder(windows);
203 
204         exitingApp.cancelAnimation();
205         // The exiting window will be removed because its parent is no longer animating.
206         mDisplayContent.handleCompleteDeferredRemoval();
207         windows.remove(exitingAppWindow);
208         assertForAllWindowsOrder(windows);
209     }
210 
211     @SetupWindows(addAllCommonWindows = true)
212     @Test
testForAllWindows_WithAppImeTarget()213     public void testForAllWindows_WithAppImeTarget() {
214         final WindowState imeAppTarget =
215                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
216 
217         mDisplayContent.setImeLayeringTarget(imeAppTarget);
218 
219         assertForAllWindowsOrder(Arrays.asList(
220                 mWallpaperWindow,
221                 mChildAppWindowBelow,
222                 mAppWindow,
223                 mChildAppWindowAbove,
224                 imeAppTarget,
225                 mImeWindow,
226                 mImeDialogWindow,
227                 mDockedDividerWindow,
228                 mStatusBarWindow,
229                 mNotificationShadeWindow,
230                 mNavBarWindow));
231     }
232 
233     @SetupWindows(addAllCommonWindows = true)
234     @Test
testForAllWindows_WithChildWindowImeTarget()235     public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
236         mDisplayContent.setImeLayeringTarget(mChildAppWindowAbove);
237 
238         assertForAllWindowsOrder(Arrays.asList(
239                 mWallpaperWindow,
240                 mChildAppWindowBelow,
241                 mAppWindow,
242                 mChildAppWindowAbove,
243                 mImeWindow,
244                 mImeDialogWindow,
245                 mDockedDividerWindow,
246                 mStatusBarWindow,
247                 mNotificationShadeWindow,
248                 mNavBarWindow));
249     }
250 
251     @SetupWindows(addAllCommonWindows = true)
252     @Test
testForAllWindows_WithStatusBarImeTarget()253     public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
254         mDisplayContent.setImeLayeringTarget(mStatusBarWindow);
255 
256         assertForAllWindowsOrder(Arrays.asList(
257                 mWallpaperWindow,
258                 mChildAppWindowBelow,
259                 mAppWindow,
260                 mChildAppWindowAbove,
261                 mDockedDividerWindow,
262                 mStatusBarWindow,
263                 mImeWindow,
264                 mImeDialogWindow,
265                 mNotificationShadeWindow,
266                 mNavBarWindow));
267     }
268 
269     @SetupWindows(addAllCommonWindows = true)
270     @Test
testForAllWindows_WithNotificationShadeImeTarget()271     public void testForAllWindows_WithNotificationShadeImeTarget() throws Exception {
272         mDisplayContent.setImeLayeringTarget(mNotificationShadeWindow);
273 
274         assertForAllWindowsOrder(Arrays.asList(
275                 mWallpaperWindow,
276                 mChildAppWindowBelow,
277                 mAppWindow,
278                 mChildAppWindowAbove,
279                 mDockedDividerWindow,
280                 mStatusBarWindow,
281                 mNotificationShadeWindow,
282                 mImeWindow,
283                 mImeDialogWindow,
284                 mNavBarWindow));
285     }
286 
287     @SetupWindows(addAllCommonWindows = true)
288     @Test
testForAllWindows_WithInBetweenWindowToken()289     public void testForAllWindows_WithInBetweenWindowToken() {
290         // This window is set-up to be z-ordered between some windows that go in the same token like
291         // the nav bar and status bar.
292         final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
293                 mDisplayContent, "voiceInteractionWindow");
294 
295         assertForAllWindowsOrder(Arrays.asList(
296                 mWallpaperWindow,
297                 mChildAppWindowBelow,
298                 mAppWindow,
299                 mChildAppWindowAbove,
300                 mDockedDividerWindow,
301                 mImeWindow,
302                 mImeDialogWindow,
303                 mStatusBarWindow,
304                 mNotificationShadeWindow,
305                 voiceInteractionWindow, // It can show above lock screen.
306                 mNavBarWindow));
307     }
308 
309     @SetupWindows(addAllCommonWindows = true)
310     @Test
testComputeImeTarget()311     public void testComputeImeTarget() {
312         // Verify that an app window can be an ime target.
313         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
314         appWin.setHasSurface(true);
315         assertTrue(appWin.canBeImeTarget());
316         WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
317         assertEquals(appWin, imeTarget);
318         appWin.mHidden = false;
319 
320         // Verify that an child window can be an ime target.
321         final WindowState childWin = createWindow(appWin,
322                 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
323         childWin.setHasSurface(true);
324         assertTrue(childWin.canBeImeTarget());
325         imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
326         assertEquals(childWin, imeTarget);
327     }
328 
329     @SetupWindows(addAllCommonWindows = true)
330     @Test
testComputeImeTarget_startingWindow()331     public void testComputeImeTarget_startingWindow() {
332         ActivityRecord activity = createActivityRecord(mDisplayContent);
333 
334         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
335                 "startingWin");
336         startingWin.setHasSurface(true);
337         assertTrue(startingWin.canBeImeTarget());
338 
339         WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
340         assertEquals(startingWin, imeTarget);
341         startingWin.mHidden = false;
342 
343         // Verify that the starting window still be an ime target even an app window launching
344         // behind it.
345         final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "appWin");
346         appWin.setHasSurface(true);
347         assertTrue(appWin.canBeImeTarget());
348 
349         imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
350         assertEquals(startingWin, imeTarget);
351         appWin.mHidden = false;
352 
353         // Verify that the starting window still be an ime target even the child window behind a
354         // launching app window
355         final WindowState childWin = createWindow(appWin,
356                 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
357         childWin.setHasSurface(true);
358         assertTrue(childWin.canBeImeTarget());
359         imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
360         assertEquals(startingWin, imeTarget);
361     }
362 
363     @Test
testUpdateImeParent_forceUpdateRelativeLayer()364     public void testUpdateImeParent_forceUpdateRelativeLayer() {
365         final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
366         final ActivityRecord activity = createActivityRecord(mDisplayContent);
367 
368         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
369                 "startingWin");
370         startingWin.setHasSurface(true);
371         assertTrue(startingWin.canBeImeTarget());
372         final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
373         doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
374         spyOn(imeContainer);
375 
376         mDisplayContent.setImeInputTarget(startingWin);
377         mDisplayContent.onConfigurationChanged(new Configuration());
378         verify(mDisplayContent).updateImeParent();
379 
380         // Force reassign the relative layer when the IME surface parent is changed.
381         verify(imeContainer).assignRelativeLayer(any(), eq(imeSurfaceParent), anyInt(), eq(true));
382     }
383 
384     @Test
testComputeImeTargetReturnsNull_windowDidntRequestIme()385     public void testComputeImeTargetReturnsNull_windowDidntRequestIme() {
386         final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION,
387                 new ActivityBuilder(mAtm).setCreateTask(true).build(), "app");
388         final WindowState win2 = createWindow(null, TYPE_BASE_APPLICATION,
389                 new ActivityBuilder(mAtm).setCreateTask(true).build(), "app2");
390 
391         mDisplayContent.setImeInputTarget(win1);
392         mDisplayContent.setImeLayeringTarget(win2);
393 
394         doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
395         // Compute IME parent returns nothing if current target and window receiving input
396         // are different i.e. if current window didn't request IME.
397         assertNull("computeImeParent() should be null", mDisplayContent.computeImeParent());
398     }
399 
400     @Test
testUpdateImeParent_skipForOrganizedImeContainer()401     public void testUpdateImeParent_skipForOrganizedImeContainer() {
402         final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
403         final ActivityRecord activity = createActivityRecord(mDisplayContent);
404 
405         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
406                 "startingWin");
407         startingWin.setHasSurface(true);
408         assertTrue(startingWin.canBeImeTarget());
409         final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
410         doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
411 
412         // Main precondition for this test: organize the ImeContainer.
413         final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
414         when(mockImeOrganizer.asBinder()).thenReturn(new Binder());
415         imeContainer.setOrganizer(mockImeOrganizer);
416 
417         mDisplayContent.updateImeParent();
418 
419         assertNull("Don't reparent the surface of an organized ImeContainer.",
420                 mDisplayContent.mInputMethodSurfaceParent);
421 
422         // Clean up organizer.
423         imeContainer.setOrganizer(null);
424     }
425 
426     @Test
testImeContainerIsReparentedUnderParentWhenOrganized()427     public void testImeContainerIsReparentedUnderParentWhenOrganized() {
428         final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
429         final ActivityRecord activity = createActivityRecord(mDisplayContent);
430 
431         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
432                 "startingWin");
433         startingWin.setHasSurface(true);
434         assertTrue(startingWin.canBeImeTarget());
435 
436         final Transaction transaction = mDisplayContent.getPendingTransaction();
437         spyOn(transaction);
438 
439         // Organized the ime container.
440         final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
441         when(mockImeOrganizer.asBinder()).thenReturn(new Binder());
442         imeContainer.setOrganizer(mockImeOrganizer);
443 
444         // Verify that the ime container surface is reparented under
445         // its parent surface as a consequence of the setOrganizer call.
446         SurfaceControl imeParentSurfaceControl = imeContainer.getParentSurfaceControl();
447         verify(transaction).reparent(imeContainer.getSurfaceControl(), imeParentSurfaceControl);
448 
449         // Clean up organizer.
450         imeContainer.setOrganizer(null);
451     }
452 
453     /**
454      * This tests root task movement between displays and proper root task's, task's and app token's
455      * display container references updates.
456      */
457     @Test
testMoveRootTaskBetweenDisplays()458     public void testMoveRootTaskBetweenDisplays() {
459         // Create a second display.
460         final DisplayContent dc = createNewDisplay();
461 
462         // Add root task with activity.
463         final Task rootTask = createTask(dc);
464         assertEquals(dc.getDisplayId(), rootTask.getDisplayContent().getDisplayId());
465         assertEquals(dc, rootTask.getDisplayContent());
466 
467         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
468         final ActivityRecord activity = createNonAttachedActivityRecord(dc);
469         task.addChild(activity, 0);
470         assertEquals(dc, task.getDisplayContent());
471         assertEquals(dc, activity.getDisplayContent());
472 
473         // Move root task to first display.
474         rootTask.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */);
475         assertEquals(mDisplayContent.getDisplayId(), rootTask.getDisplayContent().getDisplayId());
476         assertEquals(mDisplayContent, rootTask.getDisplayContent());
477         assertEquals(mDisplayContent, task.getDisplayContent());
478         assertEquals(mDisplayContent, activity.getDisplayContent());
479     }
480 
481     /**
482      * This tests global configuration updates when default display config is updated.
483      */
484     @Test
testDefaultDisplayOverrideConfigUpdate()485     public void testDefaultDisplayOverrideConfigUpdate() {
486         DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
487         final Configuration currentConfig = defaultDisplay.getConfiguration();
488 
489         // Create new, slightly changed override configuration and apply it to the display.
490         final Configuration newOverrideConfig = new Configuration(currentConfig);
491         newOverrideConfig.densityDpi += 120;
492         newOverrideConfig.fontScale += 0.3;
493 
494         defaultDisplay.updateDisplayOverrideConfigurationLocked(newOverrideConfig,
495                 null /* starting */, false /* deferResume */);
496 
497         // Check that global configuration is updated, as we've updated default display's config.
498         Configuration globalConfig = mWm.mRoot.getConfiguration();
499         assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
500         assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
501 
502         // Return back to original values.
503         defaultDisplay.updateDisplayOverrideConfigurationLocked(currentConfig,
504                 null /* starting */, false /* deferResume */);
505         globalConfig = mWm.mRoot.getConfiguration();
506         assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
507         assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
508     }
509 
510     @Test
testFocusedWindowMultipleDisplays()511     public void testFocusedWindowMultipleDisplays() {
512         doTestFocusedWindowMultipleDisplays(false /* perDisplayFocusEnabled */, Q);
513     }
514 
515     @Test
testFocusedWindowMultipleDisplaysPerDisplayFocusEnabled()516     public void testFocusedWindowMultipleDisplaysPerDisplayFocusEnabled() {
517         doTestFocusedWindowMultipleDisplays(true /* perDisplayFocusEnabled */, Q);
518     }
519 
520     @Test
testFocusedWindowMultipleDisplaysPerDisplayFocusEnabledLegacyApp()521     public void testFocusedWindowMultipleDisplaysPerDisplayFocusEnabledLegacyApp() {
522         doTestFocusedWindowMultipleDisplays(true /* perDisplayFocusEnabled */, P);
523     }
524 
doTestFocusedWindowMultipleDisplays(boolean perDisplayFocusEnabled, int targetSdk)525     private void doTestFocusedWindowMultipleDisplays(boolean perDisplayFocusEnabled,
526             int targetSdk) {
527         mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled;
528 
529         // Create a focusable window and check that focus is calculated correctly
530         final WindowState window1 =
531                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
532         window1.mActivityRecord.mTargetSdk = targetSdk;
533         updateFocusedWindow();
534         assertTrue(window1.isFocused());
535         assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
536 
537         // Check that a new display doesn't affect focus
538         final DisplayContent dc = createNewDisplay();
539         updateFocusedWindow();
540         assertTrue(window1.isFocused());
541         assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
542 
543         // Add a window to the second display, and it should be focused
544         final ActivityRecord app2 = new ActivityBuilder(mAtm)
545                 .setTask(new TaskBuilder(mSupervisor).setDisplay(dc).build())
546                 .setUseProcess(window1.getProcess()).setOnTop(true).build();
547         final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, app2, "window2");
548         window2.mActivityRecord.mTargetSdk = targetSdk;
549         updateFocusedWindow();
550         assertTrue(window2.isFocused());
551         assertEquals(perDisplayFocusEnabled && targetSdk >= Q, window1.isFocused());
552         assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
553 
554         // Move the first window to top including parents, and make sure focus is updated
555         window1.getParent().positionChildAt(POSITION_TOP, window1, true);
556         updateFocusedWindow();
557         assertTrue(window1.isFocused());
558         assertEquals(perDisplayFocusEnabled && targetSdk >= Q, window2.isFocused());
559         assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
560 
561         // Make sure top focused display not changed if there is a focused app.
562         window1.mActivityRecord.setVisibleRequested(false);
563         window1.getDisplayContent().setFocusedApp(window1.mActivityRecord);
564         updateFocusedWindow();
565         assertTrue(!window1.isFocused());
566         assertEquals(window1.getDisplayId(),
567                 mWm.mRoot.getTopFocusedDisplayContent().getDisplayId());
568     }
569 
570     @Test
testShouldWaitForSystemDecorWindowsOnBoot_OnDefaultDisplay()571     public void testShouldWaitForSystemDecorWindowsOnBoot_OnDefaultDisplay() {
572         mWm.mSystemBooted = true;
573         final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
574         final WindowState[] windows = createNotDrawnWindowsOn(defaultDisplay,
575                 TYPE_WALLPAPER, TYPE_APPLICATION);
576         final WindowState wallpaper = windows[0];
577         assertTrue(wallpaper.mIsWallpaper);
578         wallpaper.mToken.asWallpaperToken().setVisibility(false);
579         // By default WindowState#mWallpaperVisible is false.
580         assertFalse(wallpaper.isVisible());
581 
582         // Verify waiting for windows to be drawn.
583         assertTrue(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot());
584 
585         // Verify not waiting for drawn window and invisible wallpaper.
586         setDrawnState(WindowStateAnimator.READY_TO_SHOW, wallpaper);
587         setDrawnState(WindowStateAnimator.HAS_DRAWN, windows[1]);
588         assertFalse(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot());
589     }
590 
591     @Test
testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay()592     public void testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay() {
593         mWm.mSystemBooted = true;
594         final DisplayContent secondaryDisplay = createNewDisplay();
595         final WindowState[] windows = createNotDrawnWindowsOn(secondaryDisplay,
596                 TYPE_WALLPAPER, TYPE_APPLICATION);
597 
598         // Verify not waiting for display without system decorations.
599         doReturn(false).when(secondaryDisplay).supportsSystemDecorations();
600         assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
601 
602         // Verify waiting for non-drawn windows on display with system decorations.
603         reset(secondaryDisplay);
604         doReturn(true).when(secondaryDisplay).supportsSystemDecorations();
605         assertTrue(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
606 
607         // Verify not waiting for drawn windows on display with system decorations.
608         setDrawnState(WindowStateAnimator.HAS_DRAWN, windows);
609         assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
610     }
611 
612     @Test
testDisplayHasContent()613     public void testDisplayHasContent() {
614         final WindowState window = createWindow(null, TYPE_APPLICATION_OVERLAY, "window");
615         setDrawnState(WindowStateAnimator.COMMIT_DRAW_PENDING, window);
616         assertFalse(mDisplayContent.getLastHasContent());
617         // The pending draw state should be committed and the has-content state is also updated.
618         mDisplayContent.applySurfaceChangesTransaction();
619         assertTrue(window.isDrawn());
620         assertTrue(mDisplayContent.getLastHasContent());
621         // If the only window is no longer visible, has-content will be false.
622         setDrawnState(WindowStateAnimator.NO_SURFACE, window);
623         mDisplayContent.applySurfaceChangesTransaction();
624         assertFalse(mDisplayContent.getLastHasContent());
625     }
626 
627     @Test
testImeIsAttachedToDisplayForLetterboxedApp()628     public void testImeIsAttachedToDisplayForLetterboxedApp() {
629         final DisplayContent dc = mDisplayContent;
630         final WindowState ws = createWindow(null, TYPE_APPLICATION, dc, "app window");
631         dc.setImeLayeringTarget(ws);
632         dc.setImeInputTarget(ws);
633 
634         // Adjust bounds so that matchesRootDisplayAreaBounds() returns false.
635         final Rect bounds = new Rect(dc.getBounds());
636         bounds.scale(0.5f);
637         ws.mActivityRecord.setBounds(bounds);
638         assertFalse("matchesRootDisplayAreaBounds() should return false",
639                 ws.matchesDisplayAreaBounds());
640 
641         assertTrue("IME shouldn't be attached to app",
642                 dc.computeImeParent() != dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
643                         .mActivityRecord.getSurfaceControl());
644         assertEquals("IME should be attached to display",
645                 dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
646     }
647 
createNotDrawnWindowsOn(DisplayContent displayContent, int... types)648     private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) {
649         final WindowState[] windows = new WindowState[types.length];
650         for (int i = 0; i < types.length; i++) {
651             final int type = types[i];
652             windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type);
653             windows[i].setHasSurface(true);
654             windows[i].mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
655         }
656         return windows;
657     }
658 
setDrawnState(int state, WindowState... windows)659     private static void setDrawnState(int state, WindowState... windows) {
660         for (WindowState window : windows) {
661             window.mHasSurface = state != WindowStateAnimator.NO_SURFACE;
662             window.mWinAnimator.mDrawState = state;
663         }
664     }
665 
666     /**
667      * This tests setting the maximum ui width on a display.
668      */
669     @Test
testMaxUiWidth()670     public void testMaxUiWidth() {
671         // Prevent base display metrics for test from being updated to the value of real display.
672         final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
673         final int baseWidth = 1440;
674         final int baseHeight = 2560;
675         final int baseDensity = 300;
676         final float baseXDpi = 60;
677         final float baseYDpi = 60;
678 
679         displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseYDpi,
680                 baseYDpi);
681 
682         final int maxWidth = 300;
683         final float ratioChange = maxWidth / (float) baseWidth;
684         final int resultingHeight = (int) (baseHeight * ratioChange);
685         final int resultingDensity = (int) (baseDensity * ratioChange);
686         final float resultingXDpi = baseXDpi * ratioChange;
687         final float resultingYDpi = baseYDpi * ratioChange;
688 
689         displayContent.setMaxUiWidth(maxWidth);
690         verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity, resultingXDpi,
691                 resultingYDpi);
692 
693         // Assert setting values again does not change;
694         displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
695                 baseYDpi);
696         verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity, resultingXDpi,
697                 resultingYDpi);
698 
699         final int smallerWidth = 200;
700         final int smallerHeight = 400;
701         final int smallerDensity = 100;
702 
703         // Specify smaller dimension, verify that it is honored
704         displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity,
705                 baseXDpi, baseYDpi);
706         verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity, baseXDpi,
707                 baseYDpi);
708 
709         // Verify that setting the max width to a greater value than the base width has no effect
710         displayContent.setMaxUiWidth(maxWidth);
711         verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity, baseXDpi,
712                 baseYDpi);
713     }
714 
715     @Test
testSetForcedSize()716     public void testSetForcedSize() {
717         // Prevent base display metrics for test from being updated to the value of real display.
718         final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
719         final int baseWidth = 1280;
720         final int baseHeight = 720;
721         final int baseDensity = 320;
722         final float baseXDpi = 60;
723         final float baseYDpi = 60;
724 
725         displayContent.mInitialDisplayWidth = baseWidth;
726         displayContent.mInitialDisplayHeight = baseHeight;
727         displayContent.mInitialDisplayDensity = baseDensity;
728         displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
729                 baseYDpi);
730 
731         final int forcedWidth = 1920;
732         final int forcedHeight = 1080;
733 
734         // Verify that forcing the size is honored and the density doesn't change.
735         displayContent.setForcedSize(forcedWidth, forcedHeight);
736         verifySizes(displayContent, forcedWidth, forcedHeight, baseDensity);
737 
738         // Verify that forcing the size is idempotent.
739         displayContent.setForcedSize(forcedWidth, forcedHeight);
740         verifySizes(displayContent, forcedWidth, forcedHeight, baseDensity);
741     }
742 
743     @Test
testSetForcedSize_WithMaxUiWidth()744     public void testSetForcedSize_WithMaxUiWidth() {
745         // Prevent base display metrics for test from being updated to the value of real display.
746         final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
747         final int baseWidth = 1280;
748         final int baseHeight = 720;
749         final int baseDensity = 320;
750         final float baseXDpi = 60;
751         final float baseYDpi = 60;
752 
753         displayContent.mInitialDisplayWidth = baseWidth;
754         displayContent.mInitialDisplayHeight = baseHeight;
755         displayContent.mInitialDisplayDensity = baseDensity;
756         displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
757                 baseYDpi);
758 
759         displayContent.setMaxUiWidth(baseWidth);
760 
761         final int forcedWidth = 1920;
762         final int forcedHeight = 1080;
763 
764         // Verify that forcing bigger size doesn't work and density doesn't change.
765         displayContent.setForcedSize(forcedWidth, forcedHeight);
766         verifySizes(displayContent, baseWidth, baseHeight, baseDensity);
767 
768         // Verify that forcing the size is idempotent.
769         displayContent.setForcedSize(forcedWidth, forcedHeight);
770         verifySizes(displayContent, baseWidth, baseHeight, baseDensity);
771     }
772 
773     @Test
testSetForcedDensity()774     public void testSetForcedDensity() {
775         final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
776         final int baseWidth = 1280;
777         final int baseHeight = 720;
778         final int baseDensity = 320;
779         final float baseXDpi = 60;
780         final float baseYDpi = 60;
781         final int originalMinTaskSizeDp = displayContent.mMinSizeOfResizeableTaskDp;
782 
783         displayContent.mInitialDisplayWidth = baseWidth;
784         displayContent.mInitialDisplayHeight = baseHeight;
785         displayContent.mInitialDisplayDensity = baseDensity;
786         displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity, baseXDpi,
787                 baseYDpi);
788 
789         final int forcedDensity = 600;
790 
791         // Verify that forcing the density is honored and the size doesn't change.
792         displayContent.setForcedDensity(forcedDensity, 0 /* userId */);
793         verifySizes(displayContent, baseWidth, baseHeight, forcedDensity);
794 
795         // Verify that forcing the density is idempotent.
796         displayContent.setForcedDensity(forcedDensity, 0 /* userId */);
797         verifySizes(displayContent, baseWidth, baseHeight, forcedDensity);
798 
799         // Verify that minimal task size (dp) doesn't change with density of display.
800         assertEquals(originalMinTaskSizeDp, displayContent.mMinSizeOfResizeableTaskDp);
801 
802         // Verify that forcing resolution won't affect the already forced density.
803         displayContent.setForcedSize(1800, 1200);
804         verifySizes(displayContent, 1800, 1200, forcedDensity);
805     }
806 
807     @Test
testDisplayCutout_rot0()808     public void testDisplayCutout_rot0() {
809         final DisplayContent dc = createNewDisplay();
810         dc.mInitialDisplayWidth = 200;
811         dc.mInitialDisplayHeight = 400;
812         final Rect r = new Rect(80, 0, 120, 10);
813         final DisplayCutout cutout = new WmDisplayCutout(
814                 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
815                         .computeSafeInsets(200, 400).getDisplayCutout();
816 
817         dc.mInitialDisplayCutout = cutout;
818         dc.getDisplayRotation().setRotation(Surface.ROTATION_0);
819         dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
820 
821         assertEquals(cutout, dc.getDisplayInfo().displayCutout);
822     }
823 
824     @Test
testDisplayCutout_rot90()825     public void testDisplayCutout_rot90() {
826         // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
827         // if the device has no cutout).
828         final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
829         // This test assumes it's a top cutout on a portrait display, so if it happens to be a
830         // landscape display let's rotate it.
831         if (dc.mInitialDisplayHeight < dc.mInitialDisplayWidth) {
832             int tmp = dc.mInitialDisplayHeight;
833             dc.mInitialDisplayHeight = dc.mInitialDisplayWidth;
834             dc.mInitialDisplayWidth = tmp;
835         }
836         // Rotation may use real display info to compute bound, so here also uses the
837         // same width and height.
838         final int displayWidth = dc.mInitialDisplayWidth;
839         final int displayHeight = dc.mInitialDisplayHeight;
840         final float density = dc.mInitialDisplayDensity;
841         final int cutoutWidth = 40;
842         final int cutoutHeight = 10;
843         final int left = (displayWidth - cutoutWidth) / 2;
844         final int top = 0;
845         final int right = (displayWidth + cutoutWidth) / 2;
846         final int bottom = cutoutHeight;
847 
848         final Rect zeroRect = new Rect();
849         final Rect[] bounds = new Rect[]{zeroRect, new Rect(left, top, right, bottom), zeroRect,
850                 zeroRect};
851         final DisplayCutout.CutoutPathParserInfo info = new DisplayCutout.CutoutPathParserInfo(
852                 displayWidth, displayHeight, displayWidth, displayHeight, density, "",
853                 Surface.ROTATION_0, 1f, 1f);
854         final DisplayCutout cutout = new WmDisplayCutout(
855                 DisplayCutout.constructDisplayCutout(bounds, Insets.NONE, info), null)
856                         .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
857 
858         dc.mInitialDisplayCutout = cutout;
859         dc.getDisplayRotation().setRotation(Surface.ROTATION_90);
860         dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
861 
862         // ----o----------      -------------
863         // |   |     |   |      |
864         // |   ------o   |      o---
865         // |             |      |  |
866         // |             |  ->  |  |
867         // |             |      ---o
868         // |             |      |
869         // |             |      -------------
870         final Rect[] bounds90 = new Rect[]{new Rect(top, left, bottom, right), zeroRect, zeroRect,
871                 zeroRect};
872         final DisplayCutout.CutoutPathParserInfo info90 = new DisplayCutout.CutoutPathParserInfo(
873                 displayWidth, displayHeight, displayWidth, displayHeight, density, "",
874                 Surface.ROTATION_90, 1f, 1f);
875         assertEquals(new WmDisplayCutout(
876                         DisplayCutout.constructDisplayCutout(bounds90, Insets.NONE, info90), null)
877                         .computeSafeInsets(displayHeight, displayWidth).getDisplayCutout(),
878                 dc.getDisplayInfo().displayCutout);
879     }
880 
881     @Test
testLayoutSeq_assignedDuringLayout()882     public void testLayoutSeq_assignedDuringLayout() {
883         final DisplayContent dc = createNewDisplay();
884         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
885 
886         performLayout(dc);
887 
888         assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
889     }
890 
891     @Test
testOrientationDefinedByKeyguard()892     public void testOrientationDefinedByKeyguard() {
893         final DisplayContent dc = mDisplayContent;
894         dc.getDisplayPolicy().setAwake(true);
895 
896         // Create a window that requests landscape orientation. It will define device orientation
897         // by default.
898         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
899         window.mActivityRecord.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
900 
901         final WindowState keyguard = createWindow(null, TYPE_NOTIFICATION_SHADE , dc, "keyguard");
902         keyguard.mHasSurface = true;
903         keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
904 
905         assertEquals("Screen orientation must be defined by the app window by default",
906                 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
907 
908         keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
909         mAtm.mKeyguardController.setKeyguardShown(window.getDisplayId(), true /* keyguardShowing */,
910                 false /* aodShowing */);
911         assertEquals("Visible keyguard must influence device orientation",
912                 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
913 
914         mAtm.mKeyguardController.keyguardGoingAway(window.getDisplayId(), 0 /* flags */);
915         assertEquals("Keyguard that is going away must not influence device orientation",
916                 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
917     }
918 
919     @Test
testOrientationForAspectRatio()920     public void testOrientationForAspectRatio() {
921         final DisplayContent dc = createNewDisplay();
922 
923         // When display content is created its configuration is not yet initialized, which could
924         // cause unnecessary configuration propagation, so initialize it here.
925         final Configuration config = new Configuration();
926         dc.computeScreenConfiguration(config);
927         dc.onRequestedOverrideConfigurationChanged(config);
928 
929         // Create a window that requests a fixed orientation. It will define device orientation
930         // by default.
931         final WindowState window = createWindow(null /* parent */, TYPE_APPLICATION_OVERLAY, dc,
932                 "window");
933         window.mHasSurface = true;
934         window.mAttrs.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
935 
936         // --------------------------------
937         // Test non-close-to-square display
938         // --------------------------------
939         dc.mBaseDisplayWidth = 1000;
940         dc.mBaseDisplayHeight = (int) (dc.mBaseDisplayWidth * dc.mCloseToSquareMaxAspectRatio * 2f);
941         dc.configureDisplayPolicy();
942 
943         assertEquals("Screen orientation must be defined by the window by default.",
944                 window.mAttrs.screenOrientation, dc.getOrientation());
945 
946         // ----------------------------
947         // Test close-to-square display - should be handled in the same way
948         // ----------------------------
949         dc.mBaseDisplayHeight = dc.mBaseDisplayWidth;
950         dc.configureDisplayPolicy();
951 
952         assertEquals(
953                 "Screen orientation must be defined by the window even on close-to-square display.",
954                 window.mAttrs.screenOrientation, dc.getOrientation());
955 
956         // Assume that a decor window occupies the display height, so the configuration orientation
957         // should be landscape.
958         dc.getDisplayPolicy().getDecorInsetsInfo(ROTATION_0, dc.mBaseDisplayHeight,
959                 dc.mBaseDisplayWidth).mConfigFrame.set(0, 0, 1000, 990);
960         dc.computeScreenConfiguration(config, ROTATION_0);
961         dc.onRequestedOverrideConfigurationChanged(config);
962         assertEquals(Configuration.ORIENTATION_LANDSCAPE, config.orientation);
963         assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getNaturalConfigurationOrientation());
964         window.setOverrideOrientation(SCREEN_ORIENTATION_NOSENSOR);
965         assertEquals(Configuration.ORIENTATION_LANDSCAPE,
966                 window.getRequestedConfigurationOrientation());
967         // Note that getNaturalOrientation is based on logical display size. So it is portrait if
968         // the display width equals to height.
969         assertEquals(Configuration.ORIENTATION_PORTRAIT, dc.getNaturalOrientation());
970     }
971 
972     @Test
testGetPreferredOptionsPanelGravityFromDifferentDisplays()973     public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
974         final DisplayContent portraitDisplay = createNewDisplay();
975         portraitDisplay.mInitialDisplayHeight = 2000;
976         portraitDisplay.mInitialDisplayWidth = 1000;
977 
978         portraitDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
979         assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
980         portraitDisplay.getDisplayRotation().setRotation(ROTATION_90);
981         assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
982 
983         final DisplayContent landscapeDisplay = createNewDisplay();
984         landscapeDisplay.mInitialDisplayHeight = 1000;
985         landscapeDisplay.mInitialDisplayWidth = 2000;
986 
987         landscapeDisplay.getDisplayRotation().setRotation(Surface.ROTATION_0);
988         assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
989         landscapeDisplay.getDisplayRotation().setRotation(ROTATION_90);
990         assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
991     }
992 
993     @SetupWindows(addWindows = W_INPUT_METHOD)
994     @Test
testInputMethodTargetUpdateWhenSwitchingOnDisplays()995     public void testInputMethodTargetUpdateWhenSwitchingOnDisplays() {
996         final DisplayContent newDisplay = createNewDisplay();
997 
998         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
999         final Task rootTask = mDisplayContent.getTopRootTask();
1000         final ActivityRecord activity = rootTask.topRunningActivity();
1001         doReturn(true).when(activity).shouldBeVisibleUnchecked();
1002 
1003         final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
1004         final Task rootTask1 = newDisplay.getTopRootTask();
1005         final ActivityRecord activity1 = rootTask1.topRunningActivity();
1006         doReturn(true).when(activity1).shouldBeVisibleUnchecked();
1007         appWin.setHasSurface(true);
1008         appWin1.setHasSurface(true);
1009 
1010         // Set current input method window on default display, make sure the input method target
1011         // is appWin & null on the other display.
1012         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
1013         newDisplay.setInputMethodWindowLocked(null);
1014         assertEquals("appWin should be IME target window",
1015                 appWin, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
1016         assertNull("newDisplay Ime target: ", newDisplay.getImeTarget(IME_TARGET_LAYERING));
1017 
1018         // Switch input method window on new display & make sure the input method target also
1019         // switched as expected.
1020         newDisplay.setInputMethodWindowLocked(mImeWindow);
1021         mDisplayContent.setInputMethodWindowLocked(null);
1022         assertEquals("appWin1 should be IME target window", appWin1,
1023                 newDisplay.getImeTarget(IME_TARGET_LAYERING));
1024         assertNull("default display Ime target: ",
1025                 mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
1026     }
1027 
1028     @Test
testAllowsTopmostFullscreenOrientation()1029     public void testAllowsTopmostFullscreenOrientation() {
1030         final DisplayContent dc = createNewDisplay();
1031         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, dc.getOrientation());
1032         dc.getDisplayRotation().setFixedToUserRotation(
1033                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
1034 
1035         final Task rootTask = new TaskBuilder(mSupervisor)
1036                 .setDisplay(dc)
1037                 .setCreateActivity(true)
1038                 .build();
1039         doReturn(true).when(rootTask).isVisible();
1040 
1041         final Task freeformRootTask = new TaskBuilder(mSupervisor)
1042                 .setDisplay(dc)
1043                 .setCreateActivity(true)
1044                 .setWindowingMode(WINDOWING_MODE_FREEFORM)
1045                 .build();
1046         doReturn(true).when(freeformRootTask).isVisible();
1047         freeformRootTask.getTopChild().setBounds(100, 100, 300, 400);
1048 
1049         assertTrue(dc.getDefaultTaskDisplayArea().isRootTaskVisible(WINDOWING_MODE_FREEFORM));
1050 
1051         freeformRootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
1052         rootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
1053         assertEquals(SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
1054 
1055         rootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
1056         freeformRootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
1057         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
1058     }
1059 
updateAllDisplayContentAndRotation(DisplayContent dc)1060     private void updateAllDisplayContentAndRotation(DisplayContent dc) {
1061         // NB updateOrientation will not revert the user orientation until a settings change
1062         // takes effect.
1063         dc.updateOrientation();
1064         dc.onDisplayChanged(dc);
1065         dc.mWmService.updateRotation(true /* alwaysSendConfiguration */,
1066                 false /* forceRelayout */);
1067         waitUntilHandlersIdle();
1068     }
1069 
1070     @Test
testNoSensorRevert()1071     public void testNoSensorRevert() {
1072         final DisplayContent dc = mDisplayContent;
1073         spyOn(dc);
1074         doReturn(true).when(dc).getIgnoreOrientationRequest();
1075         final DisplayRotation dr = dc.getDisplayRotation();
1076         spyOn(dr);
1077         doReturn(false).when(dr).useDefaultSettingsProvider();
1078         final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
1079         app.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, app);
1080 
1081         assertFalse(dc.getRotationReversionController().isAnyOverrideActive());
1082         dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED,
1083                 ROTATION_90, /* caller= */ "DisplayContentTests");
1084         updateAllDisplayContentAndRotation(dc);
1085         assertEquals(ROTATION_90, dc.getDisplayRotation()
1086                 .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_90));
1087 
1088         app.setOrientation(SCREEN_ORIENTATION_NOSENSOR);
1089         updateAllDisplayContentAndRotation(dc);
1090         assertTrue(dc.getRotationReversionController().isAnyOverrideActive());
1091         assertEquals(ROTATION_0, dc.getRotation());
1092 
1093         app.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
1094         updateAllDisplayContentAndRotation(dc);
1095         assertFalse(dc.getRotationReversionController().isAnyOverrideActive());
1096         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED,
1097                 dc.getDisplayRotation().getUserRotationMode());
1098         assertEquals(ROTATION_90, dc.getDisplayRotation().getUserRotation());
1099         assertEquals(ROTATION_90, dc.getDisplayRotation()
1100                 .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_0));
1101         dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE,
1102                 ROTATION_0, /* caller= */ "DisplayContentTests");
1103     }
1104 
1105     @Test
testOnDescendantOrientationRequestChanged()1106     public void testOnDescendantOrientationRequestChanged() {
1107         final DisplayContent dc = createNewDisplay();
1108         dc.getDisplayRotation().setFixedToUserRotation(
1109                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
1110         dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
1111         final int newOrientation = getRotatedOrientation(dc);
1112 
1113         final Task task = new TaskBuilder(mSupervisor)
1114                 .setDisplay(dc).setCreateActivity(true).build();
1115         final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
1116         dc.setFocusedApp(activity);
1117 
1118         activity.setRequestedOrientation(newOrientation);
1119 
1120         assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1);
1121     }
1122 
1123     @Test
testOnDescendantOrientationRequestChanged_FrozenToUserRotation()1124     public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
1125         final DisplayContent dc = createNewDisplay();
1126         dc.getDisplayRotation().setFixedToUserRotation(
1127                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
1128         dc.getDisplayRotation().setUserRotation(
1129                 WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_180,
1130                 /* caller= */ "DisplayContentTests");
1131         final int newOrientation = getRotatedOrientation(dc);
1132 
1133         final Task task = new TaskBuilder(mSupervisor)
1134                 .setDisplay(dc).setCreateActivity(true).build();
1135         final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
1136         dc.setFocusedApp(activity);
1137 
1138         activity.setRequestedOrientation(newOrientation);
1139 
1140         verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity),
1141                 anyBoolean());
1142         assertEquals(ROTATION_180, dc.getRotation());
1143     }
1144 
1145     @Test
testOrientationBehind()1146     public void testOrientationBehind() {
1147         final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true)
1148                 .setScreenOrientation(getRotatedOrientation(mDisplayContent)).build();
1149         prev.setVisibleRequested(false);
1150         final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true)
1151                 .setScreenOrientation(SCREEN_ORIENTATION_BEHIND).build();
1152         assertNotEquals(WindowConfiguration.ROTATION_UNDEFINED,
1153                 mDisplayContent.rotationForActivityInDifferentOrientation(top));
1154 
1155         mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
1156         top.setVisibility(true);
1157         mDisplayContent.updateOrientation();
1158         // The top uses "behind", so the orientation is decided by the previous.
1159         assertEquals(prev, mDisplayContent.getLastOrientationSource());
1160         // The top will use the rotation from "prev" with fixed rotation.
1161         assertTrue(top.hasFixedRotationTransform());
1162     }
1163 
1164     @Test
testFixedToUserRotationChanged()1165     public void testFixedToUserRotationChanged() {
1166         final DisplayContent dc = createNewDisplay();
1167         dc.getDisplayRotation().setFixedToUserRotation(
1168                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
1169         dc.getDisplayRotation().setUserRotation(
1170                 WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0,
1171                 /* caller= */ "DisplayContentTests");
1172         dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
1173         final int newOrientation = getRotatedOrientation(dc);
1174 
1175         final Task task = new TaskBuilder(mSupervisor)
1176                 .setDisplay(dc).setCreateActivity(true).build();
1177         final ActivityRecord activity = task.getTopMostTask().getTopNonFinishingActivity();
1178         dc.setFocusedApp(activity);
1179 
1180         activity.setRequestedOrientation(newOrientation);
1181 
1182         dc.getDisplayRotation().setFixedToUserRotation(
1183                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
1184 
1185         assertTrue("The display should be rotated.", dc.getRotation() % 2 == 1);
1186     }
1187 
1188     @Test
testComputeImeParent_app()1189     public void testComputeImeParent_app() throws Exception {
1190         final DisplayContent dc = createNewDisplay();
1191         dc.setImeLayeringTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
1192         dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
1193         assertEquals(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
1194                         .mActivityRecord.getSurfaceControl(), dc.computeImeParent());
1195     }
1196 
1197     @Test
testComputeImeParent_app_notFullscreen()1198     public void testComputeImeParent_app_notFullscreen() throws Exception {
1199         final DisplayContent dc = createNewDisplay();
1200         dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "app"));
1201         dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode(
1202                 WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
1203         dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
1204         assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
1205     }
1206 
1207     @SetupWindows(addWindows = W_ACTIVITY)
1208     @Test
testComputeImeParent_app_notMatchParentBounds()1209     public void testComputeImeParent_app_notMatchParentBounds() {
1210         spyOn(mAppWindow.mActivityRecord);
1211         doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds();
1212         mDisplayContent.setImeLayeringTarget(mAppWindow);
1213         // The surface parent of IME should be the display instead of app window.
1214         assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
1215                 mDisplayContent.computeImeParent());
1216     }
1217 
1218     @Test
testComputeImeParent_noApp()1219     public void testComputeImeParent_noApp() throws Exception {
1220         final DisplayContent dc = createNewDisplay();
1221         dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "statusBar"));
1222         dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
1223         assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
1224     }
1225 
1226     @SetupWindows(addWindows = W_ACTIVITY)
1227     @Test
testComputeImeParent_inputTargetNotUpdate()1228     public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
1229         WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
1230         WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
1231         doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
1232         mDisplayContent.setImeLayeringTarget(app1);
1233         mDisplayContent.setImeInputTarget(app1);
1234         assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
1235         mDisplayContent.setImeLayeringTarget(app2);
1236         // Expect null means no change IME parent when the IME layering target not yet
1237         // request IME to be the input target.
1238         assertNull(mDisplayContent.computeImeParent());
1239     }
1240 
1241     @SetupWindows(addWindows = W_ACTIVITY)
1242     @Test
testComputeImeParent_updateParentWhenTargetNotUseIme()1243     public void testComputeImeParent_updateParentWhenTargetNotUseIme() throws Exception {
1244         WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay");
1245         overlay.setBounds(100, 100, 200, 200);
1246         overlay.mAttrs.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM;
1247         WindowState app = createWindow(null, TYPE_BASE_APPLICATION, "app");
1248         mDisplayContent.setImeLayeringTarget(overlay);
1249         mDisplayContent.setImeInputTarget(app);
1250         assertFalse(mDisplayContent.shouldImeAttachedToApp());
1251         assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
1252                 mDisplayContent.computeImeParent());
1253     }
1254 
1255     @Test
testComputeImeParent_remoteControlTarget()1256     public void testComputeImeParent_remoteControlTarget() throws Exception {
1257         final DisplayContent dc = mDisplayContent;
1258         WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
1259         WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
1260 
1261         dc.setImeLayeringTarget(app1);
1262         dc.setImeInputTarget(app2);
1263         dc.setRemoteInsetsController(createDisplayWindowInsetsController());
1264         dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode(
1265                 WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
1266         dc.getImeInputTarget().getWindowState().setWindowingMode(
1267                 WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
1268 
1269         // Expect ImeParent is null since ImeLayeringTarget and ImeInputTarget are different.
1270         assertNull(dc.computeImeParent());
1271 
1272         // ImeLayeringTarget and ImeInputTarget are updated to the same.
1273         dc.setImeInputTarget(app1);
1274         assertEquals(dc.getImeTarget(IME_TARGET_LAYERING), dc.getImeInputTarget());
1275 
1276         // The ImeParent should be the display.
1277         assertEquals(dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
1278     }
1279 
1280     @Test
testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved()1281     public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
1282         final DisplayContent dc = createNewDisplay();
1283 
1284         WindowState app = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
1285 
1286         dc.setImeInputTarget(app);
1287         assertEquals(app, dc.computeImeControlTarget());
1288 
1289         app.removeImmediately();
1290 
1291         assertNull(dc.getImeInputTarget());
1292         assertNull(dc.computeImeControlTarget());
1293     }
1294 
1295     @Test
testComputeImeControlTarget()1296     public void testComputeImeControlTarget() throws Exception {
1297         final DisplayContent dc = createNewDisplay();
1298         dc.setRemoteInsetsController(createDisplayWindowInsetsController());
1299         dc.mCurrentFocus = createWindow(null, TYPE_BASE_APPLICATION, "app");
1300 
1301         // Expect returning null IME control target when the focus window has not yet been the
1302         // IME input target (e.g. IME is restarting) in fullscreen windowing mode.
1303         dc.setImeInputTarget(null);
1304         assertFalse(dc.mCurrentFocus.inMultiWindowMode());
1305         assertNull(dc.computeImeControlTarget());
1306 
1307         dc.setImeInputTarget(dc.mCurrentFocus);
1308         dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState());
1309         assertEquals(dc.getImeInputTarget().getWindowState(), dc.computeImeControlTarget());
1310     }
1311 
1312     @Test
testComputeImeControlTarget_splitscreen()1313     public void testComputeImeControlTarget_splitscreen() throws Exception {
1314         final DisplayContent dc = createNewDisplay();
1315         dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
1316         dc.getImeInputTarget().getWindowState().setWindowingMode(
1317                 WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
1318         dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState());
1319         dc.setRemoteInsetsController(createDisplayWindowInsetsController());
1320         assertNotEquals(dc.getImeInputTarget().getWindowState(),
1321                 dc.computeImeControlTarget());
1322     }
1323 
1324     @SetupWindows(addWindows = W_INPUT_METHOD)
1325     @Test
testImeSecureFlagGetUpdatedAfterImeInputTarget()1326     public void testImeSecureFlagGetUpdatedAfterImeInputTarget() {
1327         // Verify IME window can get up-to-date secure flag update when the IME input target
1328         // set before setCanScreenshot called.
1329         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
1330         SurfaceControl.Transaction t = mDisplayContent.mInputMethodWindow.getPendingTransaction();
1331         spyOn(t);
1332         mDisplayContent.setImeInputTarget(app);
1333         mDisplayContent.mInputMethodWindow.setCanScreenshot(t, false /* canScreenshot */);
1334 
1335         verify(t).setSecure(eq(mDisplayContent.mInputMethodWindow.mSurfaceControl), eq(true));
1336     }
1337 
1338     @SetupWindows(addWindows = W_ACTIVITY)
1339     @Test
testComputeImeControlTarget_notMatchParentBounds()1340     public void testComputeImeControlTarget_notMatchParentBounds() throws Exception {
1341         spyOn(mAppWindow.mActivityRecord);
1342         doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds();
1343         mDisplayContent.setImeInputTarget(mAppWindow);
1344         mDisplayContent.setImeLayeringTarget(
1345             mDisplayContent.getImeInputTarget().getWindowState());
1346         mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
1347         assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget());
1348     }
1349 
1350     @SetupWindows(addWindows = W_ACTIVITY)
1351     @Test
testShouldImeAttachedToApp_targetBoundsDifferentFromImeContainer_returnsFalse()1352     public void testShouldImeAttachedToApp_targetBoundsDifferentFromImeContainer_returnsFalse()
1353             throws Exception {
1354         Rect imeContainerBounds = new Rect(0, 0, 100, 100);
1355         Rect imeTargetBounds = new Rect(0, 0, 100, 200);
1356         spyOn(mAppWindow);
1357         spyOn(mAppWindow.mActivityRecord);
1358         doReturn(imeTargetBounds).when(mAppWindow).getBounds();
1359         doReturn(true).when(mAppWindow.mActivityRecord).matchParentBounds();
1360         mDisplayContent.setImeInputTarget(mAppWindow);
1361         mDisplayContent.setImeLayeringTarget(
1362                 mDisplayContent.getImeInputTarget().getWindowState());
1363         mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
1364         final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer();
1365         spyOn(imeContainer);
1366         doReturn(imeContainerBounds).when(imeContainer).getBounds();
1367 
1368         assertFalse(mDisplayContent.shouldImeAttachedToApp());
1369     }
1370 
1371     @Test
testUpdateSystemGestureExclusion()1372     public void testUpdateSystemGestureExclusion() throws Exception {
1373         final DisplayContent dc = createNewDisplay();
1374         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
1375         win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1376         win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
1377 
1378         performLayout(dc);
1379 
1380         win.setHasSurface(true);
1381         dc.updateSystemGestureExclusion();
1382 
1383         final boolean[] invoked = { false };
1384         final ISystemGestureExclusionListener.Stub verifier =
1385                 new ISystemGestureExclusionListener.Stub() {
1386             @Override
1387             public void onSystemGestureExclusionChanged(int displayId, Region actual,
1388                     Region unrestricted) {
1389                 Region expected = Region.obtain();
1390                 expected.set(10, 20, 30, 40);
1391                 assertEquals(expected, actual);
1392                 invoked[0] = true;
1393             }
1394         };
1395         try {
1396             dc.registerSystemGestureExclusionListener(verifier);
1397         } finally {
1398             dc.unregisterSystemGestureExclusionListener(verifier);
1399         }
1400         assertTrue("SystemGestureExclusionListener was not invoked", invoked[0]);
1401     }
1402 
1403     @Test
testCalculateSystemGestureExclusion()1404     public void testCalculateSystemGestureExclusion() throws Exception {
1405         final DisplayContent dc = createNewDisplay();
1406         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
1407         win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1408         win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
1409 
1410         final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2");
1411         win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1412         win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
1413 
1414         performLayout(dc);
1415 
1416         win.setHasSurface(true);
1417         win2.setHasSurface(true);
1418 
1419         final Region expected = Region.obtain();
1420         expected.set(20, 30, 40, 50);
1421         assertEquals(expected, calculateSystemGestureExclusion(dc));
1422     }
1423 
calculateSystemGestureExclusion(DisplayContent dc)1424     private Region calculateSystemGestureExclusion(DisplayContent dc) {
1425         Region out = Region.obtain();
1426         Region unrestricted = Region.obtain();
1427         dc.calculateSystemGestureExclusion(out, unrestricted);
1428         return out;
1429     }
1430 
1431     @Test
testCalculateSystemGestureExclusion_modal()1432     public void testCalculateSystemGestureExclusion_modal() throws Exception {
1433         final DisplayContent dc = createNewDisplay();
1434         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "base");
1435         win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1436         win.setSystemGestureExclusion(Collections.singletonList(new Rect(0, 0, 1000, 1000)));
1437 
1438         final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "modal");
1439         win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1440         win2.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
1441         win2.getAttrs().width = 10;
1442         win2.getAttrs().height = 10;
1443         win2.setSystemGestureExclusion(Collections.emptyList());
1444 
1445         performLayout(dc);
1446 
1447         win.setHasSurface(true);
1448         win2.setHasSurface(true);
1449 
1450         final Region expected = Region.obtain();
1451         assertEquals(expected, calculateSystemGestureExclusion(dc));
1452     }
1453 
1454     @Test
testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow()1455     public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
1456         mWm.mConstants.mSystemGestureExcludedByPreQStickyImmersive = true;
1457 
1458         final DisplayContent dc = createNewDisplay();
1459         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
1460         win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1461         win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
1462         win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
1463         win.getAttrs().insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
1464         win.setRequestedVisibleTypes(0, navigationBars() | statusBars());
1465         win.mActivityRecord.mTargetSdk = P;
1466 
1467         performLayout(dc);
1468 
1469         win.setHasSurface(true);
1470 
1471         final Region expected = Region.obtain();
1472         expected.set(dc.getBounds());
1473         assertEquals(expected, calculateSystemGestureExclusion(dc));
1474 
1475         win.setHasSurface(false);
1476     }
1477 
1478     @Test
testCalculateSystemGestureExclusion_unrestricted()1479     public void testCalculateSystemGestureExclusion_unrestricted() throws Exception {
1480         mWm.mConstants.mSystemGestureExcludedByPreQStickyImmersive = true;
1481 
1482         final DisplayContent dc = createNewDisplay();
1483         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
1484         win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
1485         win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
1486         win.getAttrs().privateFlags |= PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
1487         win.setSystemGestureExclusion(Collections.singletonList(dc.getBounds()));
1488 
1489         performLayout(dc);
1490 
1491         win.setHasSurface(true);
1492 
1493         final Region expected = Region.obtain();
1494         expected.set(dc.getBounds());
1495         assertEquals(expected, calculateSystemGestureExclusion(dc));
1496 
1497         win.setHasSurface(false);
1498     }
1499 
1500     @SetupWindows(addWindows = { W_ABOVE_ACTIVITY, W_ACTIVITY })
1501     @Test
testRequestResizeForEmptyFrames()1502     public void testRequestResizeForEmptyFrames() {
1503         final WindowState win = mChildAppWindowAbove;
1504         makeWindowVisible(win, win.getParentWindow());
1505         win.setRequestedSize(mDisplayContent.mBaseDisplayWidth, 0 /* height */);
1506         win.mAttrs.width = win.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
1507         win.mAttrs.gravity = Gravity.CENTER;
1508         performLayout(mDisplayContent);
1509 
1510         // The frame is empty because the requested height is zero.
1511         assertTrue(win.getFrame().isEmpty());
1512         // The window should be scheduled to resize then the client may report a new non-empty size.
1513         win.updateResizingWindowIfNeeded();
1514         assertThat(mWm.mResizingWindows).contains(win);
1515     }
1516 
1517     @Test
testOrientationChangeLogging()1518     public void testOrientationChangeLogging() {
1519         MetricsLogger mockLogger = mock(MetricsLogger.class);
1520         Configuration oldConfig = new Configuration();
1521         oldConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
1522 
1523         Configuration newConfig = new Configuration();
1524         newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
1525         final DisplayContent displayContent = createNewDisplay();
1526         Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger();
1527         Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration();
1528 
1529         displayContent.onConfigurationChanged(newConfig);
1530 
1531         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
1532         verify(mockLogger).write(logMakerCaptor.capture());
1533         assertThat(logMakerCaptor.getValue().getCategory(),
1534                 is(MetricsProto.MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED));
1535         assertThat(logMakerCaptor.getValue().getSubtype(),
1536                 is(Configuration.ORIENTATION_PORTRAIT));
1537     }
1538 
1539     @Test
testHybridRotationAnimation()1540     public void testHybridRotationAnimation() {
1541         final DisplayContent displayContent = mDefaultDisplay;
1542         final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
1543         final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
1544         final WindowState app = createWindow(null, TYPE_BASE_APPLICATION, "app");
1545         final WindowState[] windows = { statusBar, navBar, app };
1546         makeWindowVisible(windows);
1547         final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
1548         displayPolicy.addWindowLw(statusBar, statusBar.mAttrs);
1549         displayPolicy.addWindowLw(navBar, navBar.mAttrs);
1550         final ScreenRotationAnimation rotationAnim = new ScreenRotationAnimation(displayContent,
1551                 displayContent.getRotation());
1552         spyOn(rotationAnim);
1553         // Assume that the display rotation is changed so it is frozen in preparation for animation.
1554         doReturn(true).when(rotationAnim).hasScreenshot();
1555         displayContent.getDisplayRotation().setRotation((displayContent.getRotation() + 1) % 4);
1556         displayContent.setRotationAnimation(rotationAnim);
1557         // The fade rotation animation also starts to hide some non-app windows.
1558         assertNotNull(displayContent.getAsyncRotationController());
1559         assertTrue(statusBar.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
1560 
1561         for (WindowState w : windows) {
1562             w.setOrientationChanging(true);
1563         }
1564         // The display only waits for the app window to unfreeze.
1565         assertFalse(displayContent.shouldSyncRotationChange(statusBar));
1566         assertFalse(displayContent.shouldSyncRotationChange(navBar));
1567         assertTrue(displayContent.shouldSyncRotationChange(app));
1568         // If all windows animated by fade rotation animation have done the orientation change,
1569         // the animation controller should be cleared.
1570         statusBar.setOrientationChanging(false);
1571         navBar.setOrientationChanging(false);
1572         assertNull(displayContent.getAsyncRotationController());
1573     }
1574 
1575     @SetupWindows(addWindows = { W_ACTIVITY, W_WALLPAPER, W_STATUS_BAR, W_NAVIGATION_BAR,
1576             W_INPUT_METHOD, W_NOTIFICATION_SHADE })
1577     @Test
testApplyTopFixedRotationTransform()1578     public void testApplyTopFixedRotationTransform() {
1579         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
1580         spyOn(displayPolicy);
1581         // Only non-movable (gesture) navigation bar will be animated by fixed rotation animation.
1582         doReturn(false).when(displayPolicy).navigationBarCanMove();
1583         displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs);
1584         displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
1585         displayPolicy.addWindowLw(mNotificationShadeWindow, mNotificationShadeWindow.mAttrs);
1586         makeWindowVisible(mStatusBarWindow, mNavBarWindow);
1587         final Configuration config90 = new Configuration();
1588         mDisplayContent.computeScreenConfiguration(config90, ROTATION_90);
1589 
1590         final Configuration config = new Configuration();
1591         mDisplayContent.getDisplayRotation().setRotation(ROTATION_0);
1592         mDisplayContent.computeScreenConfiguration(config);
1593         mDisplayContent.onRequestedOverrideConfigurationChanged(config);
1594         assertNotEquals(config90.windowConfiguration.getMaxBounds(),
1595                 config.windowConfiguration.getMaxBounds());
1596 
1597         final ActivityRecord app = mAppWindow.mActivityRecord;
1598         app.setVisible(false);
1599         mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
1600         mDisplayContent.mOpeningApps.add(app);
1601         final int newOrientation = getRotatedOrientation(mDisplayContent);
1602         app.setRequestedOrientation(newOrientation);
1603 
1604         assertTrue(app.isFixedRotationTransforming());
1605         assertTrue(mAppWindow.matchesDisplayAreaBounds());
1606         assertFalse(mAppWindow.areAppWindowBoundsLetterboxed());
1607         assertTrue(mDisplayContent.getDisplayRotation().shouldRotateSeamlessly(
1608                 ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
1609                 false /* forceUpdate */));
1610 
1611         final AsyncRotationController asyncRotationController =
1612                 mDisplayContent.getAsyncRotationController();
1613         assertNotNull(asyncRotationController);
1614         assertTrue(mStatusBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
1615         assertTrue(mNavBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
1616         // Notification shade may have its own view animation in real case so do not fade out it.
1617         assertFalse(mNotificationShadeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
1618 
1619         // If the visibility of insets state is changed, the rotated state should be updated too.
1620         final int statusBarId = mStatusBarWindow.getControllableInsetProvider().getSource().getId();
1621         final InsetsState rotatedState = app.getFixedRotationTransformInsetsState();
1622         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
1623         assertEquals(state.isSourceOrDefaultVisible(statusBarId, statusBars()),
1624                 rotatedState.isSourceOrDefaultVisible(statusBarId, statusBars()));
1625         state.setSourceVisible(statusBarId,
1626                 !rotatedState.isSourceOrDefaultVisible(statusBarId, statusBars()));
1627         mDisplayContent.getInsetsStateController().notifyInsetsChanged();
1628         assertEquals(state.isSourceOrDefaultVisible(statusBarId, statusBars()),
1629                 rotatedState.isSourceOrDefaultVisible(statusBarId, statusBars()));
1630 
1631         final Rect outFrame = new Rect();
1632         final Rect outInsets = new Rect();
1633         final Rect outStableInsets = new Rect();
1634         final Rect outSurfaceInsets = new Rect();
1635         mAppWindow.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
1636         // The animation frames should not be rotated because display hasn't rotated.
1637         assertEquals(mDisplayContent.getBounds(), outFrame);
1638 
1639         // The display should keep current orientation and the rotated configuration should apply
1640         // to the activity.
1641         assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);
1642         assertEquals(config90.orientation, app.getConfiguration().orientation);
1643         assertEquals(config90.windowConfiguration.getBounds(), app.getBounds());
1644 
1645         // Associate wallpaper with the fixed rotation transform.
1646         final WindowToken wallpaperToken = mWallpaperWindow.mToken;
1647         wallpaperToken.linkFixedRotationTransform(app);
1648 
1649         // Force the negative offset to verify it can be updated.
1650         mWallpaperWindow.mXOffset = mWallpaperWindow.mYOffset = -1;
1651         assertTrue(mDisplayContent.mWallpaperController.updateWallpaperOffset(mWallpaperWindow,
1652                 false /* sync */));
1653         assertThat(mWallpaperWindow.mXOffset).isNotEqualTo(-1);
1654         assertThat(mWallpaperWindow.mYOffset).isNotEqualTo(-1);
1655 
1656         // The wallpaper need to animate with transformed position, so its surface position should
1657         // not be reset.
1658         final Transaction t = wallpaperToken.getPendingTransaction();
1659         spyOn(t);
1660         mWallpaperWindow.mToken.onAnimationLeashCreated(t, null /* leash */);
1661         verify(t, never()).setPosition(any(), eq(0), eq(0));
1662 
1663         // Launch another activity before the transition is finished.
1664         final Task task2 = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
1665         final ActivityRecord app2 = new ActivityBuilder(mAtm).setTask(task2)
1666                 .setUseProcess(app.app).build();
1667         app2.setVisible(false);
1668         mDisplayContent.mOpeningApps.add(app2);
1669         app2.setRequestedOrientation(newOrientation);
1670 
1671         // The activity should share the same transform state as the existing one. The activity
1672         // should also be the fixed rotation launching app because it is the latest top.
1673         assertTrue(app.hasFixedRotationTransform(app2));
1674         assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));
1675 
1676         final Configuration expectedProcConfig = new Configuration(app2.app.getConfiguration());
1677         expectedProcConfig.windowConfiguration.setActivityType(
1678                 WindowConfiguration.ACTIVITY_TYPE_UNDEFINED);
1679         assertEquals("The process should receive rotated configuration for compatibility",
1680                 expectedProcConfig, app2.app.getConfiguration());
1681 
1682         // If the rotated activity requests to show IME, the IME window should use the
1683         // transformation from activity to lay out in the same orientation.
1684         LocalServices.getService(WindowManagerInternal.class).onToggleImeRequested(true /* show */,
1685                 app.token, app.token, mDisplayContent.mDisplayId);
1686         assertTrue(asyncRotationController.isTargetToken(mImeWindow.mToken));
1687         assertTrue(mImeWindow.mToken.hasFixedRotationTransform());
1688         assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));
1689 
1690         // The fixed rotation transform can only be finished when all animation finished.
1691         doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
1692         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
1693         assertTrue(app.hasFixedRotationTransform());
1694         assertTrue(app2.hasFixedRotationTransform());
1695 
1696         // The display should be rotated after the launch is finished.
1697         doReturn(false).when(app).isAnimating(anyInt(), anyInt());
1698         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
1699         mStatusBarWindow.finishSeamlessRotation(t);
1700         mNavBarWindow.finishSeamlessRotation(t);
1701 
1702         // The fixed rotation should be cleared and the new rotation is applied to display.
1703         assertFalse(app.hasFixedRotationTransform());
1704         assertFalse(app2.hasFixedRotationTransform());
1705         assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation);
1706         assertNull(mDisplayContent.getAsyncRotationController());
1707     }
1708 
1709     @Test
testFinishFixedRotationNoAppTransitioningTask()1710     public void testFinishFixedRotationNoAppTransitioningTask() {
1711         unblockDisplayRotation(mDisplayContent);
1712         final ActivityRecord app = createActivityRecord(mDisplayContent);
1713         final Task task = app.getTask();
1714         final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
1715         mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
1716         doReturn(true).when(app).inTransitionSelfOrParent();
1717         // If the task contains a transition, this should be no-op.
1718         mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
1719 
1720         assertTrue(app2.hasFixedRotationTransform());
1721         assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
1722 
1723         // The display should be unlikely to be in transition, but if it happens, the fixed
1724         // rotation should proceed to finish because the activity/task level transition is finished.
1725         doReturn(true).when(mDisplayContent).inTransition();
1726         doReturn(false).when(app).inTransitionSelfOrParent();
1727         // Although this notifies app instead of app2 that uses the fixed rotation, app2 should
1728         // still finish the transform because there is no more transition event.
1729         mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
1730 
1731         assertFalse(app2.hasFixedRotationTransform());
1732         assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
1733     }
1734 
1735     @SetupWindows(addWindows = W_ACTIVITY)
1736     @Test
testRotateSeamlesslyWithFixedRotation()1737     public void testRotateSeamlesslyWithFixedRotation() {
1738         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
1739         final ActivityRecord app = mAppWindow.mActivityRecord;
1740         mDisplayContent.setFixedRotationLaunchingAppUnchecked(app);
1741         mAppWindow.mAttrs.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
1742 
1743         // Use seamless rotation if the top app is rotated.
1744         assertTrue(displayRotation.shouldRotateSeamlessly(ROTATION_0 /* oldRotation */,
1745                 ROTATION_90 /* newRotation */, false /* forceUpdate */));
1746 
1747         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(app);
1748 
1749         // Use normal rotation because animating recents is an intermediate state.
1750         assertFalse(displayRotation.shouldRotateSeamlessly(ROTATION_0 /* oldRotation */,
1751                 ROTATION_90 /* newRotation */, false /* forceUpdate */));
1752     }
1753 
1754     @Test
testFixedRotationWithPip()1755     public void testFixedRotationWithPip() {
1756         final DisplayContent displayContent = mDefaultDisplay;
1757         unblockDisplayRotation(displayContent);
1758         // Unblock the condition in PinnedTaskController#continueOrientationChangeIfNeeded.
1759         doNothing().when(displayContent).prepareAppTransition(anyInt());
1760         // Make resume-top really update the activity state.
1761         setBooted(mAtm);
1762         clearInvocations(mWm);
1763         // Speed up the test by a few seconds.
1764         mAtm.deferWindowLayout();
1765 
1766         final ActivityRecord homeActivity = createActivityRecord(
1767                 displayContent.getDefaultTaskDisplayArea().getRootHomeTask());
1768         final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
1769         final Task pinnedTask = pinnedActivity.getRootTask();
1770         doReturn((displayContent.getRotation() + 1) % 4).when(displayContent)
1771                 .rotationForActivityInDifferentOrientation(eq(homeActivity));
1772         // Enter PiP from fullscreen.
1773         pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED);
1774 
1775         assertTrue(displayContent.hasTopFixedRotationLaunchingApp());
1776         assertTrue(displayContent.mPinnedTaskController.shouldDeferOrientationChange());
1777         verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
1778         clearInvocations(pinnedTask);
1779 
1780         // Assume that the PiP enter animation is done then the new bounds are set. Expect the
1781         // orientation update is no longer deferred.
1782         displayContent.mPinnedTaskController.setEnterPipBounds(pinnedTask.getBounds());
1783         // The Task Configuration was frozen to skip the change of orientation.
1784         verify(pinnedTask, never()).onConfigurationChanged(any());
1785         assertFalse(displayContent.mPinnedTaskController.shouldDeferOrientationChange());
1786         assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
1787         assertEquals(homeActivity.getConfiguration().orientation,
1788                 displayContent.getConfiguration().orientation);
1789 
1790         doReturn((displayContent.getRotation() + 1) % 4).when(displayContent)
1791                 .rotationForActivityInDifferentOrientation(eq(pinnedActivity));
1792         // Leave PiP to fullscreen. Simulate the step of PipTaskOrganizer that sets the activity
1793         // to fullscreen, so fixed rotation will apply on it.
1794         pinnedActivity.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
1795         assertTrue(displayContent.hasTopFixedRotationLaunchingApp());
1796 
1797         // Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task.
1798         pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
1799         displayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
1800         assertFalse(displayContent.mPinnedTaskController.isFreezingTaskConfig(pinnedTask));
1801         assertEquals(pinnedActivity.getConfiguration().orientation,
1802                 displayContent.getConfiguration().orientation);
1803 
1804         // No need to apply rotation if the display ignores orientation request.
1805         doCallRealMethod().when(displayContent).rotationForActivityInDifferentOrientation(any());
1806         pinnedActivity.setOverrideOrientation(SCREEN_ORIENTATION_LANDSCAPE);
1807         displayContent.setIgnoreOrientationRequest(true);
1808         assertEquals(WindowConfiguration.ROTATION_UNDEFINED,
1809                 displayContent.rotationForActivityInDifferentOrientation(pinnedActivity));
1810     }
1811 
1812     @Test
testNoFixedRotationOnResumedScheduledApp()1813     public void testNoFixedRotationOnResumedScheduledApp() {
1814         unblockDisplayRotation(mDisplayContent);
1815         final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
1816         app.setVisible(false);
1817         app.setState(ActivityRecord.State.RESUMED, "test");
1818         mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
1819         mDisplayContent.mOpeningApps.add(app);
1820         final int newOrientation = getRotatedOrientation(mDisplayContent);
1821         app.setRequestedOrientation(newOrientation);
1822 
1823         // The condition should reject using fixed rotation because the resumed client in real case
1824         // might get display info immediately. And the fixed rotation adjustments haven't arrived
1825         // client side so the info may be inconsistent with the requested orientation.
1826         verify(mDisplayContent).updateOrientation(eq(app), anyBoolean());
1827         assertFalse(app.isFixedRotationTransforming());
1828         assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp());
1829     }
1830 
1831     @Test
testRecentsNotRotatingWithFixedRotation()1832     public void testRecentsNotRotatingWithFixedRotation() {
1833         unblockDisplayRotation(mDisplayContent);
1834         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
1835         // Skip freezing so the unrelated conditions in updateRotationUnchecked won't disturb.
1836         doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
1837 
1838         final ActivityRecord activity = createActivityRecord(mDisplayContent);
1839         final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent);
1840         recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
1841         doReturn(mock(RecentsAnimationController.class)).when(mWm).getRecentsAnimationController();
1842 
1843         // Do not rotate if the recents animation is animating on top.
1844         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
1845         displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
1846         assertFalse(displayRotation.updateRotationUnchecked(false));
1847 
1848         // Rotation can be updated if the recents animation is finished.
1849         mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
1850         assertTrue(displayRotation.updateRotationUnchecked(false));
1851 
1852         // Rotation can be updated if the policy is not ok to animate (e.g. going to sleep).
1853         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
1854         displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
1855         ((TestWindowManagerPolicy) mWm.mPolicy).mOkToAnimate = false;
1856         assertTrue(displayRotation.updateRotationUnchecked(false));
1857 
1858         // Rotation can be updated if the recents animation is animating but it is not on top, e.g.
1859         // switching activities in different orientations by quickstep gesture.
1860         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
1861         mDisplayContent.setFixedRotationLaunchingAppUnchecked(activity);
1862         displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
1863         assertTrue(displayRotation.updateRotationUnchecked(false));
1864 
1865         // The recents activity should not apply fixed rotation if the top activity is not opaque.
1866         mDisplayContent.mFocusedApp = activity;
1867         doReturn(false).when(mDisplayContent.mFocusedApp).occludesParent();
1868         doReturn(ROTATION_90).when(mDisplayContent).rotationForActivityInDifferentOrientation(
1869                 eq(recentsActivity));
1870         mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
1871         assertFalse(recentsActivity.hasFixedRotationTransform());
1872     }
1873 
1874     @Test
testSecondaryInternalDisplayRotationFollowsDefaultDisplay()1875     public void testSecondaryInternalDisplayRotationFollowsDefaultDisplay() {
1876         // Skip freezing so the unrelated conditions in updateRotationUnchecked won't disturb.
1877         doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
1878 
1879         final DisplayRotationCoordinator coordinator =
1880                 mRootWindowContainer.getDisplayRotationCoordinator();
1881         final DisplayContent defaultDisplayContent = mDisplayContent;
1882         final DisplayRotation defaultDisplayRotation = defaultDisplayContent.getDisplayRotation();
1883         coordinator.removeDefaultDisplayRotationChangedCallback();
1884 
1885         DeviceStateController deviceStateController = mock(DeviceStateController.class);
1886         when(deviceStateController.shouldMatchBuiltInDisplayOrientationToReverseDefaultDisplay())
1887                 .thenReturn(true);
1888 
1889         // Create secondary display
1890         final DisplayContent secondaryDisplayContent =
1891                 createSecondaryDisplayContent(Display.TYPE_INTERNAL, deviceStateController);
1892         final DisplayRotation secondaryDisplayRotation =
1893                 secondaryDisplayContent.getDisplayRotation();
1894         try {
1895             // TestDisplayContent bypasses this method but we need it for this test
1896             doCallRealMethod().when(secondaryDisplayRotation).updateRotationUnchecked(anyBoolean());
1897 
1898             // TestDisplayContent creates this as a mock. Lets set it up to test our use case.
1899             when(secondaryDisplayContent.mDeviceStateController
1900                     .shouldMatchBuiltInDisplayOrientationToReverseDefaultDisplay()).thenReturn(
1901                     true);
1902 
1903             // Check that secondary display registered callback
1904             assertEquals(secondaryDisplayRotation.mDefaultDisplayRotationChangedCallback,
1905                     coordinator.mDefaultDisplayRotationChangedCallback);
1906 
1907             // Set the default display to a known orientation. This may be a zero or non-zero
1908             // rotation since mDisplayInfo.logicalWidth/Height depends on the DUT's default display
1909             defaultDisplayRotation.updateOrientation(SCREEN_ORIENTATION_PORTRAIT, false);
1910             assertEquals(defaultDisplayRotation.mPortraitRotation,
1911                     defaultDisplayRotation.getRotation());
1912             assertEquals(defaultDisplayRotation.mPortraitRotation,
1913                     coordinator.getDefaultDisplayCurrentRotation());
1914 
1915             // Check that in the initial state, the secondary display is in the right rotation
1916             assertRotationsAreCorrectlyReversed(defaultDisplayRotation.getRotation(),
1917                     secondaryDisplayRotation.getRotation());
1918 
1919             // Update primary display rotation, check display coordinator rotation is the default
1920             // display's landscape rotation, and that the secondary display rotation is correct.
1921             defaultDisplayRotation.updateOrientation(SCREEN_ORIENTATION_LANDSCAPE, false);
1922             assertEquals(defaultDisplayRotation.mLandscapeRotation,
1923                     defaultDisplayRotation.getRotation());
1924             assertEquals(defaultDisplayRotation.mLandscapeRotation,
1925                     coordinator.getDefaultDisplayCurrentRotation());
1926             assertRotationsAreCorrectlyReversed(defaultDisplayRotation.getRotation(),
1927                     secondaryDisplayRotation.getRotation());
1928         } finally {
1929             secondaryDisplayRotation.removeDefaultDisplayRotationChangedCallback();
1930         }
1931     }
1932 
1933     @Test
testSecondaryNonInternalDisplayDoesNotFollowDefaultDisplay()1934     public void testSecondaryNonInternalDisplayDoesNotFollowDefaultDisplay() {
1935         // Skip freezing so the unrelated conditions in updateRotationUnchecked won't disturb.
1936         doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
1937 
1938         final DisplayRotationCoordinator coordinator =
1939                 mRootWindowContainer.getDisplayRotationCoordinator();
1940         coordinator.removeDefaultDisplayRotationChangedCallback();
1941 
1942         DeviceStateController deviceStateController = mock(DeviceStateController.class);
1943         when(deviceStateController.shouldMatchBuiltInDisplayOrientationToReverseDefaultDisplay())
1944                 .thenReturn(true);
1945 
1946         // Create secondary non-internal displays
1947         createSecondaryDisplayContent(Display.TYPE_EXTERNAL, deviceStateController);
1948         assertNull(coordinator.mDefaultDisplayRotationChangedCallback);
1949         createSecondaryDisplayContent(Display.TYPE_VIRTUAL, deviceStateController);
1950         assertNull(coordinator.mDefaultDisplayRotationChangedCallback);
1951     }
1952 
createSecondaryDisplayContent(int displayType, @NonNull DeviceStateController deviceStateController)1953     private DisplayContent createSecondaryDisplayContent(int displayType,
1954             @NonNull DeviceStateController deviceStateController) {
1955         final DisplayInfo secondaryDisplayInfo = new DisplayInfo();
1956         secondaryDisplayInfo.copyFrom(mDisplayInfo);
1957         secondaryDisplayInfo.type = displayType;
1958 
1959         return new TestDisplayContent.Builder(mAtm, secondaryDisplayInfo)
1960                 .setDeviceStateController(deviceStateController)
1961                 .build();
1962     }
1963 
assertRotationsAreCorrectlyReversed(@urface.Rotation int rotation1, @Surface.Rotation int rotation2)1964     private static void assertRotationsAreCorrectlyReversed(@Surface.Rotation int rotation1,
1965             @Surface.Rotation int rotation2) {
1966         if (rotation1 == ROTATION_0) {
1967             assertEquals(rotation1, rotation2);
1968         } else if (rotation1 == ROTATION_180) {
1969             assertEquals(rotation1, rotation2);
1970         } else if (rotation1 == ROTATION_90) {
1971             assertEquals(ROTATION_270, rotation2);
1972         } else if (rotation1 == ROTATION_270) {
1973             assertEquals(ROTATION_90, rotation2);
1974         } else {
1975             throw new IllegalArgumentException("Unknown rotation: " + rotation1 + ", " + rotation2);
1976         }
1977     }
1978 
1979     @Test
testRemoteRotation()1980     public void testRemoteRotation() {
1981         final DisplayContent dc = mDisplayContent;
1982         final DisplayRotation dr = dc.getDisplayRotation();
1983         spyOn(dr);
1984         doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
1985         final boolean[] continued = new boolean[1];
1986         doAnswer(invocation -> {
1987             continued[0] = true;
1988             mDisplayContent.mWaitingForConfig = false;
1989             mAtm.addWindowLayoutReasons(ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
1990             return true;
1991         }).when(dc).updateDisplayOverrideConfigurationLocked();
1992         final boolean[] called = new boolean[1];
1993         mWm.mDisplayChangeController =
1994                 new IDisplayChangeWindowController.Stub() {
1995                     @Override
1996                     public void onDisplayChange(int displayId, int fromRotation, int toRotation,
1997                             DisplayAreaInfo newDisplayAreaInfo,
1998                             IDisplayChangeWindowCallback callback) throws RemoteException {
1999                         called[0] = true;
2000 
2001                         try {
2002                             callback.continueDisplayChange(null);
2003                         } catch (RemoteException e) {
2004                             assertTrue(false);
2005                         }
2006                     }
2007                 };
2008 
2009         // kill any existing rotation animation (vestigial from test setup).
2010         dc.setRotationAnimation(null);
2011 
2012         mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
2013         // If remote rotation is not finished, the display should not be able to unfreeze.
2014         mWm.stopFreezingDisplayLocked();
2015         assertTrue(mWm.mDisplayFrozen);
2016 
2017         assertTrue(called[0]);
2018         waitUntilHandlersIdle();
2019         assertTrue(continued[0]);
2020 
2021         mWm.stopFreezingDisplayLocked();
2022         assertFalse(mWm.mDisplayFrozen);
2023     }
2024 
2025     @Test
testRemoteDisplayChange()2026     public void testRemoteDisplayChange() {
2027         mWm.mDisplayChangeController = mock(IDisplayChangeWindowController.class);
2028         final Boolean[] isWaitingForRemote = new Boolean[2];
2029         final var callbacks = new RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback[
2030                 isWaitingForRemote.length];
2031         for (int i = 0; i < isWaitingForRemote.length; i++) {
2032             final int index = i;
2033             var callback = new RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback() {
2034                 @Override
2035                 public void onContinueRemoteDisplayChange(WindowContainerTransaction transaction) {
2036                     isWaitingForRemote[index] =
2037                             mDisplayContent.mRemoteDisplayChangeController
2038                                     .isWaitingForRemoteDisplayChange();
2039                 }
2040             };
2041             mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
2042                     ROTATION_0, ROTATION_0, null /* newDisplayAreaInfo */, callback);
2043             callbacks[i] = callback;
2044         }
2045 
2046         // The last callback is completed, all callbacks should be notified.
2047         mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[1],
2048                 null /* transaction */);
2049         // When notifying 0, the callback 1 still exists.
2050         assertTrue(isWaitingForRemote[0]);
2051         assertFalse(isWaitingForRemote[1]);
2052 
2053         // The first callback is completed, other callbacks after it should remain.
2054         for (int i = 0; i < isWaitingForRemote.length; i++) {
2055             isWaitingForRemote[i] = null;
2056             mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
2057                     ROTATION_0, ROTATION_0, null /* newDisplayAreaInfo */, callbacks[i]);
2058         }
2059         mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[0],
2060                 null /* transaction */);
2061         assertTrue(isWaitingForRemote[0]);
2062         assertNull(isWaitingForRemote[1]);
2063 
2064         // Complete the last callback. It should be able to consume pending config change.
2065         mDisplayContent.mWaitingForConfig = true;
2066         mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[1],
2067                 null /* transaction */);
2068         assertFalse(isWaitingForRemote[1]);
2069         assertFalse(mDisplayContent.mWaitingForConfig);
2070     }
2071 
2072     @Test
testShellTransitRotation()2073     public void testShellTransitRotation() {
2074         final DisplayContent dc = mDisplayContent;
2075         // Create 2 visible activities to verify that they can both receive the new configuration.
2076         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2077         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2078         doReturn(true).when(activity1).isSyncFinished(any());
2079         doReturn(true).when(activity2).isSyncFinished(any());
2080 
2081         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
2082         final DisplayRotation dr = dc.getDisplayRotation();
2083         spyOn(dr);
2084         doReturn((dr.getRotation() + 1) % 4).when(dr).rotationForOrientation(anyInt(), anyInt());
2085         mWm.mDisplayChangeController =
2086                 new IDisplayChangeWindowController.Stub() {
2087                     @Override
2088                     public void onDisplayChange(int displayId, int fromRotation, int toRotation,
2089                             DisplayAreaInfo newDisplayAreaInfo,
2090                             IDisplayChangeWindowCallback callback) throws RemoteException {
2091                         try {
2092                             callback.continueDisplayChange(null);
2093                         } catch (RemoteException e) {
2094                             assertTrue(false);
2095                         }
2096                     }
2097                 };
2098 
2099         final int origRot = dc.getConfiguration().windowConfiguration.getRotation();
2100         dc.setLastHasContent();
2101         mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */);
2102         // Should create a transition request without performing rotation
2103         assertNotNull(testPlayer.mLastRequest);
2104         assertEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
2105 
2106         // Once transition starts, rotation is applied and transition shows DC rotating.
2107         testPlayer.startTransition();
2108         waitUntilHandlersIdle();
2109         verify(activity1).ensureActivityConfiguration(anyBoolean());
2110         verify(activity2).ensureActivityConfiguration(anyBoolean());
2111         assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
2112         assertNotNull(testPlayer.mLastReady);
2113         assertTrue(testPlayer.mController.isPlaying());
2114         WindowContainerToken dcToken = dc.mRemoteToken.toWindowContainerToken();
2115         assertNotEquals(testPlayer.mLastReady.getChange(dcToken).getEndRotation(),
2116                 testPlayer.mLastReady.getChange(dcToken).getStartRotation());
2117         testPlayer.finish();
2118 
2119         // The AsyncRotationController should only exist if there is an ongoing rotation change.
2120         dc.finishAsyncRotationIfPossible();
2121         dc.setLastHasContent();
2122         doReturn(dr.getRotation() + 1).when(dr).rotationForOrientation(anyInt(), anyInt());
2123         dr.updateRotationUnchecked(true /* forceUpdate */);
2124         assertNotNull(dc.getAsyncRotationController());
2125         doReturn(dr.getRotation() - 1).when(dr).rotationForOrientation(anyInt(), anyInt());
2126         dr.updateRotationUnchecked(true /* forceUpdate */);
2127         assertNull("Cancel AsyncRotationController for the intermediate rotation changes 0->1->0",
2128                 dc.getAsyncRotationController());
2129     }
2130 
2131     @Test
testValidWindowingLayer()2132     public void testValidWindowingLayer() {
2133         final SurfaceControl windowingLayer = mDisplayContent.getWindowingLayer();
2134         assertNotNull(windowingLayer);
2135 
2136         final List<DisplayArea<?>> windowedMagnificationAreas =
2137                 mDisplayContent.mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
2138         if (windowedMagnificationAreas != null) {
2139             assertEquals("There should be only one DisplayArea for FEATURE_WINDOWED_MAGNIFICATION",
2140                     1, windowedMagnificationAreas.size());
2141             assertEquals(windowedMagnificationAreas.get(0).mSurfaceControl, windowingLayer);
2142             assertEquals(windowingLayer,
2143                     mDisplayContent.mDisplayAreaPolicy.getWindowingArea().mSurfaceControl);
2144         } else {
2145             assertNotEquals(mDisplayContent.mSurfaceControl, windowingLayer);
2146         }
2147 
2148         // When migrating the surface of default trusted display, the children should belong to the
2149         // surface of DisplayContent directly.
2150         clearInvocations(mTransaction);
2151         mDisplayContent.migrateToNewSurfaceControl(mTransaction);
2152         for (int i = mDisplayContent.getChildCount() - 1; i >= 0; i--) {
2153             final SurfaceControl childSc = mDisplayContent.getChildAt(i).mSurfaceControl;
2154             verify(mTransaction).reparent(eq(childSc), eq(mDisplayContent.mSurfaceControl));
2155             verify(mTransaction, never()).reparent(eq(childSc), eq(windowingLayer));
2156         }
2157 
2158         // If a display doesn't have WINDOWED_MAGNIFICATION (e.g. untrusted), it will have an
2159         // additional windowing layer to put the window content.
2160         clearInvocations(mTransaction);
2161         final DisplayInfo info = new DisplayInfo(mDisplayInfo);
2162         info.flags &= ~Display.FLAG_TRUSTED;
2163         final DisplayContent dc2 = createNewDisplay(info);
2164         final SurfaceControl dc2WinLayer = dc2.getWindowingLayer();
2165         final DisplayArea<?> dc2WinArea = dc2.mDisplayAreaPolicy.getWindowingArea();
2166         assertEquals(dc2WinLayer, dc2WinArea.mSurfaceControl);
2167 
2168         // When migrating the surface of a display with additional windowing layer, the children
2169         // layer of display should still belong to the display.
2170         clearInvocations(mTransaction);
2171         dc2.migrateToNewSurfaceControl(mTransaction);
2172         verify(mTransaction).reparent(eq(dc2WinLayer), eq(dc2.mSurfaceControl));
2173         for (int i = dc2.getChildCount() - 1; i >= 0; i--) {
2174             verify(mTransaction).reparent(eq(dc2.getChildAt(i).mSurfaceControl),
2175                     eq(dc2.mSurfaceControl));
2176         }
2177 
2178         // When migrating the surface of child area under windowing area, the new child surfaces
2179         // should reparent to the windowing layer.
2180         clearInvocations(mTransaction);
2181         for (int i = dc2WinArea.getChildCount() - 1; i >= 0; i--) {
2182             final WindowContainer<?> child = dc2WinArea.getChildAt(i);
2183             child.migrateToNewSurfaceControl(mTransaction);
2184             verify(mTransaction).reparent(eq(child.mSurfaceControl), eq(dc2WinLayer));
2185         }
2186     }
2187 
2188     @Test
testFindScrollCaptureTargetWindow_behindWindow()2189     public void testFindScrollCaptureTargetWindow_behindWindow() {
2190         DisplayContent display = createNewDisplay();
2191         Task rootTask = createTask(display);
2192         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2193         WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window");
2194         WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
2195 
2196         WindowState result = display.findScrollCaptureTargetWindow(behindWindow,
2197                 ActivityTaskManager.INVALID_TASK_ID);
2198         assertEquals(activityWindow, result);
2199     }
2200 
2201     @Test
testFindScrollCaptureTargetWindow_cantReceiveKeys()2202     public void testFindScrollCaptureTargetWindow_cantReceiveKeys() {
2203         DisplayContent display = createNewDisplay();
2204         Task rootTask = createTask(display);
2205         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2206         WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window");
2207         WindowState invisible = createWindow(null, TYPE_APPLICATION, "invisible");
2208         invisible.mViewVisibility = View.INVISIBLE;  // make canReceiveKeys return false
2209 
2210         WindowState result = display.findScrollCaptureTargetWindow(null,
2211                 ActivityTaskManager.INVALID_TASK_ID);
2212         assertEquals(activityWindow, result);
2213     }
2214 
2215     @Test
testFindScrollCaptureTargetWindow_secure()2216     public void testFindScrollCaptureTargetWindow_secure() {
2217         DisplayContent display = createNewDisplay();
2218         Task rootTask = createTask(display);
2219         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2220         WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
2221         secureWindow.mAttrs.flags |= FLAG_SECURE;
2222 
2223         WindowState result = display.findScrollCaptureTargetWindow(null,
2224                 ActivityTaskManager.INVALID_TASK_ID);
2225         assertNull(result);
2226     }
2227 
2228     @Test
testFindScrollCaptureTargetWindow_secureTaskId()2229     public void testFindScrollCaptureTargetWindow_secureTaskId() {
2230         DisplayContent display = createNewDisplay();
2231         Task rootTask = createTask(display);
2232         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2233         WindowState secureWindow = createWindow(null, TYPE_APPLICATION, "Secure Window");
2234         secureWindow.mAttrs.flags |= FLAG_SECURE;
2235 
2236         WindowState result = display.findScrollCaptureTargetWindow(null,  task.mTaskId);
2237         assertNull(result);
2238     }
2239 
2240     @Test
testFindScrollCaptureTargetWindow_taskId()2241     public void testFindScrollCaptureTargetWindow_taskId() {
2242         DisplayContent display = createNewDisplay();
2243         Task rootTask = createTask(display);
2244         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2245         WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window");
2246         WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
2247 
2248         WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId);
2249         assertEquals(window, result);
2250     }
2251 
2252     @Test
testFindScrollCaptureTargetWindow_taskIdCantReceiveKeys()2253     public void testFindScrollCaptureTargetWindow_taskIdCantReceiveKeys() {
2254         DisplayContent display = createNewDisplay();
2255         Task rootTask = createTask(display);
2256         Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2257         WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window");
2258         window.mViewVisibility = View.INVISIBLE;  // make canReceiveKeys return false
2259         WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
2260 
2261         WindowState result = display.findScrollCaptureTargetWindow(null, task.mTaskId);
2262         assertEquals(window, result);
2263     }
2264 
2265     @Test
testEnsureActivitiesVisibleNotRecursive()2266     public void testEnsureActivitiesVisibleNotRecursive() {
2267         final TaskDisplayArea mockTda = mock(TaskDisplayArea.class);
2268         final boolean[] called = { false };
2269         doAnswer(invocation -> {
2270             // The assertion will fail if DisplayArea#ensureActivitiesVisible is called twice.
2271             assertFalse(called[0]);
2272             called[0] = true;
2273             mDisplayContent.ensureActivitiesVisible(null, false);
2274             return null;
2275         }).when(mockTda).ensureActivitiesVisible(any(), anyBoolean());
2276 
2277         mDisplayContent.ensureActivitiesVisible(null, false);
2278     }
2279 
2280     @Test
testForceDesktopMode()2281     public void testForceDesktopMode() {
2282         mWm.mForceDesktopModeOnExternalDisplays = true;
2283         // Not applicable for default display
2284         assertFalse(mDefaultDisplay.forceDesktopMode());
2285 
2286         // Not applicable for private secondary display.
2287         final DisplayInfo displayInfo = new DisplayInfo();
2288         displayInfo.copyFrom(mDisplayInfo);
2289         displayInfo.flags = FLAG_PRIVATE;
2290         final DisplayContent privateDc = createNewDisplay(displayInfo);
2291         assertFalse(privateDc.forceDesktopMode());
2292 
2293         // Applicable for public secondary display.
2294         final DisplayContent publicDc = createNewDisplay();
2295         assertTrue(publicDc.forceDesktopMode());
2296 
2297         // Make sure forceDesktopMode() is false when the force config is disabled.
2298         mWm.mForceDesktopModeOnExternalDisplays = false;
2299         assertFalse(publicDc.forceDesktopMode());
2300     }
2301 
2302     @Test
testDisplaySettingsReappliedWhenDisplayChanged()2303     public void testDisplaySettingsReappliedWhenDisplayChanged() {
2304         final DisplayInfo displayInfo = new DisplayInfo();
2305         displayInfo.copyFrom(mDisplayInfo);
2306         final DisplayContent dc = createNewDisplay(displayInfo);
2307 
2308         // Generate width/height/density values different from the default of the display.
2309         final int forcedWidth = dc.mBaseDisplayWidth + 1;
2310         final int forcedHeight = dc.mBaseDisplayHeight + 1;;
2311         final int forcedDensity = dc.mBaseDisplayDensity + 1;;
2312         // Update the forced size and density in settings and the unique id to simualate a display
2313         // remap.
2314         dc.mWmService.mDisplayWindowSettings.setForcedSize(dc, forcedWidth, forcedHeight);
2315         dc.mWmService.mDisplayWindowSettings.setForcedDensity(displayInfo, forcedDensity,
2316                 0 /* userId */);
2317         dc.mCurrentUniqueDisplayId = mDisplayInfo.uniqueId + "-test";
2318         // Trigger display changed.
2319         updateDisplay(dc);
2320         // Ensure overridden size and denisty match the most up-to-date values in settings for the
2321         // display.
2322         verifySizes(dc, forcedWidth, forcedHeight, forcedDensity);
2323     }
2324 
2325     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
2326     @Test
testComputeImeTarget_shouldNotCheckOutdatedImeTargetLayerWhenRemoved()2327     public void testComputeImeTarget_shouldNotCheckOutdatedImeTargetLayerWhenRemoved() {
2328         final WindowState child1 = createWindow(mAppWindow, FIRST_SUB_WINDOW, "child1");
2329         final WindowState nextImeTargetApp = createWindow(null /* parent */,
2330                 TYPE_BASE_APPLICATION, "nextImeTargetApp");
2331         spyOn(child1);
2332         doReturn(false).when(mDisplayContent).shouldImeAttachedToApp();
2333         mDisplayContent.setImeLayeringTarget(child1);
2334 
2335         spyOn(nextImeTargetApp);
2336         spyOn(mAppWindow);
2337         doReturn(true).when(nextImeTargetApp).canBeImeTarget();
2338         doReturn(true).when(nextImeTargetApp).isActivityTypeHome();
2339         doReturn(false).when(mAppWindow).canBeImeTarget();
2340 
2341         child1.removeImmediately();
2342 
2343         verify(mDisplayContent).computeImeTarget(true);
2344         assertNull(mDisplayContent.getImeInputTarget());
2345         verify(child1, never()).needsRelativeLayeringToIme();
2346     }
2347 
2348     @SetupWindows(addWindows = W_INPUT_METHOD)
2349     @Test
testAttachAndShowImeScreenshotOnTarget()2350     public void testAttachAndShowImeScreenshotOnTarget() {
2351         // Preparation: Simulate screen state is on.
2352         spyOn(mWm.mPolicy);
2353         doReturn(true).when(mWm.mPolicy).isScreenOn();
2354 
2355         // Preparation: Simulate snapshot IME surface.
2356         spyOn(mWm.mTaskSnapshotController);
2357         ScreenCapture.ScreenshotHardwareBuffer mockHwBuffer = mock(
2358                 ScreenCapture.ScreenshotHardwareBuffer.class);
2359         doReturn(mock(HardwareBuffer.class)).when(mockHwBuffer).getHardwareBuffer();
2360         doReturn(mockHwBuffer).when(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(any());
2361 
2362         // Preparation: Simulate snapshot Task.
2363         ActivityRecord act1 = createActivityRecord(mDisplayContent);
2364         final WindowState appWin1 = createWindow(null, TYPE_BASE_APPLICATION, act1, "appWin1");
2365         spyOn(appWin1);
2366         spyOn(appWin1.mWinAnimator);
2367         appWin1.setHasSurface(true);
2368         assertTrue(appWin1.canBeImeTarget());
2369         doReturn(true).when(appWin1.mWinAnimator).getShown();
2370         doReturn(true).when(appWin1.mActivityRecord).isSurfaceShowing();
2371         appWin1.mWinAnimator.mLastAlpha = 1f;
2372 
2373         // Test step 1: appWin1 is the current IME target and soft-keyboard is visible.
2374         mDisplayContent.computeImeTarget(true);
2375         assertEquals(appWin1, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
2376         mDisplayContent.setImeInputTarget(appWin1);
2377         spyOn(mDisplayContent.mInputMethodWindow);
2378         doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
2379         mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
2380 
2381         // Test step 2: Simulate launching appWin2 and appWin1 is in app transition.
2382         ActivityRecord act2 = createActivityRecord(mDisplayContent);
2383         final WindowState appWin2 = createWindow(null, TYPE_BASE_APPLICATION, act2, "appWin2");
2384         appWin2.setHasSurface(true);
2385         assertTrue(appWin2.canBeImeTarget());
2386         doReturn(true).when(appWin1).inTransitionSelfOrParent();
2387 
2388         // Test step 3: Verify appWin2 will be the next IME target and the IME snapshot surface will
2389         // be attached and shown on the display at this time.
2390         mDisplayContent.computeImeTarget(true);
2391         assertEquals(appWin2, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
2392         assertTrue(mDisplayContent.shouldImeAttachedToApp());
2393 
2394         verify(mDisplayContent, atLeast(1)).showImeScreenshot();
2395         verify(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(appWin1.getTask());
2396         assertNotNull(mDisplayContent.mImeScreenshot);
2397     }
2398 
2399     @SetupWindows(addWindows = W_INPUT_METHOD)
2400     @Test
testShowImeScreenshot()2401     public void testShowImeScreenshot() {
2402         final Task rootTask = createTask(mDisplayContent);
2403         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2404         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
2405         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
2406         task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
2407         doReturn(true).when(task).okToAnimate();
2408         ArrayList<WindowContainer> sources = new ArrayList<>();
2409         sources.add(activity);
2410 
2411         mDisplayContent.setImeLayeringTarget(win);
2412         spyOn(mDisplayContent);
2413 
2414         // Expecting the IME screenshot only be attached when performing task closing transition.
2415         task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
2416                 false /* isVoiceInteraction */, sources);
2417         verify(mDisplayContent).showImeScreenshot();
2418 
2419         clearInvocations(mDisplayContent);
2420         activity.applyAnimation(null, TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, false /* enter */,
2421                 false /* isVoiceInteraction */, sources);
2422         verify(mDisplayContent, never()).showImeScreenshot();
2423     }
2424 
2425     @SetupWindows(addWindows = W_INPUT_METHOD)
2426     @Test
testShowImeScreenshot_removeCurSnapshotBeforeCreateNext()2427     public void testShowImeScreenshot_removeCurSnapshotBeforeCreateNext() {
2428         final Task rootTask = createTask(mDisplayContent);
2429         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2430         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
2431         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
2432 
2433         mDisplayContent.setImeLayeringTarget(win);
2434         mDisplayContent.setImeInputTarget(win);
2435         spyOn(mDisplayContent);
2436         spyOn(mDisplayContent.mInputMethodWindow);
2437         doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
2438         mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
2439 
2440         // Verify when the timing of 2 showImeScreenshot invocations are very close, will first
2441         // detach the current snapshot then create the next one.
2442         mDisplayContent.showImeScreenshot();
2443         DisplayContent.ImeScreenshot curSnapshot = mDisplayContent.mImeScreenshot;
2444         spyOn(curSnapshot);
2445         mDisplayContent.showImeScreenshot();
2446         verify(curSnapshot).detach(any());
2447         assertNotNull(mDisplayContent.mImeScreenshot);
2448         assertNotEquals(curSnapshot, mDisplayContent.mImeScreenshot);
2449     }
2450 
2451     @UseTestDisplay(addWindows = {W_INPUT_METHOD})
2452     @Test
testRemoveImeScreenshot_whenTargetSurfaceWasInvisible()2453     public void testRemoveImeScreenshot_whenTargetSurfaceWasInvisible() {
2454         final Task rootTask = createTask(mDisplayContent);
2455         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2456         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
2457         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
2458         win.onSurfaceShownChanged(true);
2459         makeWindowVisible(win, mDisplayContent.mInputMethodWindow);
2460         task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
2461         doReturn(true).when(task).okToAnimate();
2462         ArrayList<WindowContainer> sources = new ArrayList<>();
2463         sources.add(activity);
2464 
2465         mDisplayContent.setImeLayeringTarget(win);
2466         mDisplayContent.setImeInputTarget(win);
2467         mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
2468         task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
2469                 false /* isVoiceInteraction */, sources);
2470         assertNotNull(mDisplayContent.mImeScreenshot);
2471 
2472         win.onSurfaceShownChanged(false);
2473         assertNull(mDisplayContent.mImeScreenshot);
2474     }
2475 
2476     @UseTestDisplay(addWindows = {W_INPUT_METHOD})
2477     @Test
testRemoveImeScreenshot_whenWindowRemoveImmediately()2478     public void testRemoveImeScreenshot_whenWindowRemoveImmediately() {
2479         final Task rootTask = createTask(mDisplayContent);
2480         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
2481         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
2482         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
2483         makeWindowVisible(mDisplayContent.mInputMethodWindow);
2484 
2485         mDisplayContent.setImeLayeringTarget(win);
2486         mDisplayContent.setImeInputTarget(win);
2487         mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true);
2488         mDisplayContent.showImeScreenshot();
2489         assertNotNull(mDisplayContent.mImeScreenshot);
2490 
2491         // Expect IME snapshot will be removed when the win is IME layering target and invoked
2492         // removeImeSurfaceByTarget.
2493         win.removeImmediately();
2494         assertNull(mDisplayContent.mImeScreenshot);
2495     }
2496 
2497     @Test
testRotateBounds_keepSamePhysicalPosition()2498     public void testRotateBounds_keepSamePhysicalPosition() {
2499         final DisplayContent dc =
2500                 new TestDisplayContent.Builder(mAtm, 1000, 2000).build();
2501         final Rect initBounds = new Rect(0, 0, 700, 1500);
2502         final Rect rotateBounds = new Rect(initBounds);
2503 
2504         // Rotate from 0 to 0
2505         dc.rotateBounds(ROTATION_0, ROTATION_0, rotateBounds);
2506 
2507         assertEquals(new Rect(0, 0, 700, 1500), rotateBounds);
2508 
2509         // Rotate from 0 to 90
2510         rotateBounds.set(initBounds);
2511         dc.rotateBounds(ROTATION_0, ROTATION_90, rotateBounds);
2512 
2513         assertEquals(new Rect(0, 300, 1500, 1000), rotateBounds);
2514 
2515         // Rotate from 0 to 180
2516         rotateBounds.set(initBounds);
2517         dc.rotateBounds(ROTATION_0, ROTATION_180, rotateBounds);
2518 
2519         assertEquals(new Rect(300, 500, 1000, 2000), rotateBounds);
2520 
2521         // Rotate from 0 to 270
2522         rotateBounds.set(initBounds);
2523         dc.rotateBounds(ROTATION_0, ROTATION_270, rotateBounds);
2524 
2525         assertEquals(new Rect(500, 0, 2000, 700), rotateBounds);
2526     }
2527 
2528     /**
2529      * Creates a TestDisplayContent using the constructor that takes in display width and height as
2530      * parameters and validates that the newly-created TestDisplayContent's DisplayInfo and
2531      * WindowConfiguration match the parameters passed into the constructor. Additionally, this test
2532      * checks that device-specific overrides are not applied.
2533      */
2534     @Test
testCreateTestDisplayContentFromDimensions()2535     public void testCreateTestDisplayContentFromDimensions() {
2536         final int displayWidth = 540;
2537         final int displayHeight = 960;
2538         final int density = 192;
2539         final int expectedWidthDp = 450; // = 540/(192/160)
2540         final int expectedHeightDp = 800; // = 960/(192/160)
2541         final int windowingMode = WINDOWING_MODE_FULLSCREEN;
2542         final boolean ignoreOrientationRequests = false;
2543         final float fixedOrientationLetterboxRatio = 0;
2544         final DisplayContent testDisplayContent = new TestDisplayContent.Builder(mAtm, displayWidth,
2545                 displayHeight).setDensityDpi(density).build();
2546 
2547         // test display info
2548         final DisplayInfo di = testDisplayContent.getDisplayInfo();
2549         assertEquals(displayWidth, di.logicalWidth);
2550         assertEquals(displayHeight, di.logicalHeight);
2551         assertEquals(density, di.logicalDensityDpi);
2552 
2553         // test configuration
2554         final Configuration config = testDisplayContent.getConfiguration();
2555         assertEquals(expectedWidthDp, config.screenWidthDp);
2556         assertEquals(expectedHeightDp, config.screenHeightDp);
2557         final WindowConfiguration windowConfig = config.windowConfiguration;
2558         assertEquals(displayWidth, windowConfig.getBounds().width());
2559         assertEquals(displayHeight, windowConfig.getBounds().height());
2560         assertEquals(windowingMode, windowConfig.getWindowingMode());
2561         assertEquals(Configuration.SCREENLAYOUT_SIZE_NORMAL,
2562                 config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK);
2563 
2564         // test misc display overrides
2565         assertEquals(ignoreOrientationRequests, testDisplayContent.mSetIgnoreOrientationRequest);
2566         assertEquals(fixedOrientationLetterboxRatio,
2567                 mWm.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(),
2568                 0 /* delta */);
2569     }
2570 
2571     /**
2572      * Creates a TestDisplayContent using the constructor that takes in a DisplayInfo as a parameter
2573      * and validates that the newly-created TestDisplayContent's DisplayInfo and WindowConfiguration
2574      * match the width, height, and density values set in the DisplayInfo passed as a parameter.
2575      * Additionally, this test checks that device-specific overrides are not applied.
2576      */
2577     @Test
testCreateTestDisplayContentFromDisplayInfo()2578     public void testCreateTestDisplayContentFromDisplayInfo() {
2579         final int displayWidth = 1000;
2580         final int displayHeight = 2000;
2581         final int windowingMode = WINDOWING_MODE_FULLSCREEN;
2582         final boolean ignoreOrientationRequests = false;
2583         final float fixedOrientationLetterboxRatio = 0;
2584         final DisplayInfo testDisplayInfo = new DisplayInfo();
2585         mContext.getDisplay().getDisplayInfo(testDisplayInfo);
2586         testDisplayInfo.logicalWidth = displayWidth;
2587         testDisplayInfo.logicalHeight = displayHeight;
2588         testDisplayInfo.logicalDensityDpi = TestDisplayContent.DEFAULT_LOGICAL_DISPLAY_DENSITY;
2589         final DisplayContent testDisplayContent = new TestDisplayContent.Builder(mAtm,
2590                 testDisplayInfo).build();
2591 
2592         // test display info
2593         final DisplayInfo di = testDisplayContent.getDisplayInfo();
2594         assertEquals(displayWidth, di.logicalWidth);
2595         assertEquals(displayHeight, di.logicalHeight);
2596         assertEquals(TestDisplayContent.DEFAULT_LOGICAL_DISPLAY_DENSITY, di.logicalDensityDpi);
2597 
2598         // test configuration
2599         final WindowConfiguration windowConfig = testDisplayContent.getConfiguration()
2600                 .windowConfiguration;
2601         assertEquals(displayWidth, windowConfig.getBounds().width());
2602         assertEquals(displayHeight, windowConfig.getBounds().height());
2603         assertEquals(windowingMode, windowConfig.getWindowingMode());
2604         assertEquals(Configuration.SCREENLAYOUT_SIZE_LARGE, testDisplayContent
2605                 .getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK);
2606 
2607         // test misc display overrides
2608         assertEquals(ignoreOrientationRequests, testDisplayContent.mSetIgnoreOrientationRequest);
2609         assertEquals(fixedOrientationLetterboxRatio,
2610                 mWm.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(),
2611                 0 /* delta */);
2612     }
2613 
2614     /**
2615      * Verifies {@link DisplayContent#remove} should not resume home root task on the removing
2616      * display.
2617      */
2618     @Test
testNotResumeHomeRootTaskOnRemovingDisplay()2619     public void testNotResumeHomeRootTaskOnRemovingDisplay() {
2620         // Create a display which supports system decoration and allows reparenting root tasks to
2621         // another display when the display is removed.
2622         final DisplayContent display = new TestDisplayContent.Builder(
2623                 mAtm, 1000, 1500).setSystemDecorations(true).build();
2624         doReturn(false).when(display).shouldDestroyContentOnRemove();
2625 
2626         // Put home root task on the display.
2627         final Task homeRootTask = new TaskBuilder(mSupervisor)
2628                 .setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build();
2629 
2630         // Put a finishing standard activity which will be reparented.
2631         final Task rootTask = createTaskWithActivity(display.getDefaultTaskDisplayArea(),
2632                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP, true /* twoLevelTask */);
2633         rootTask.topRunningActivity().makeFinishingLocked();
2634 
2635         clearInvocations(homeRootTask);
2636         display.remove();
2637 
2638         // The removed display should have no focused root task and its home root task should never
2639         // resume.
2640         assertNull(display.getFocusedRootTask());
2641         verify(homeRootTask, never()).resumeTopActivityUncheckedLocked(any(), any());
2642     }
2643 
2644     /**
2645      * Verifies the correct activity is returned when querying the top running activity.
2646      */
2647     @Test
testTopRunningActivity()2648     public void testTopRunningActivity() {
2649         final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
2650         final KeyguardController keyguard = mSupervisor.getKeyguardController();
2651         final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
2652         final ActivityRecord activity = rootTask.getTopNonFinishingActivity();
2653 
2654         // Create empty root task on top.
2655         final Task emptyRootTask = new TaskBuilder(mSupervisor).build();
2656 
2657         // Make sure the top running activity is not affected when keyguard is not locked.
2658         assertTopRunningActivity(activity, display);
2659 
2660         // Check to make sure activity not reported when it cannot show on lock and lock is on.
2661         doReturn(true).when(keyguard).isKeyguardLocked(anyInt());
2662         assertEquals(activity, display.topRunningActivity());
2663         assertNull(display.topRunningActivity(true /* considerKeyguardState */));
2664 
2665         // Move root task with activity to top.
2666         rootTask.moveToFront("testRootTaskToFront");
2667         assertEquals(rootTask, display.getFocusedRootTask());
2668         assertEquals(activity, display.topRunningActivity());
2669         assertNull(display.topRunningActivity(true /* considerKeyguardState */));
2670 
2671         // Add activity that should be shown on the keyguard.
2672         final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
2673                 .setTask(rootTask)
2674                 .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
2675                 .build();
2676 
2677         // Ensure the show when locked activity is returned.
2678         assertTopRunningActivity(showWhenLockedActivity, display);
2679 
2680         // Move empty root task to front. The running activity in focusable root task which below
2681         // the empty root task should be returned.
2682         emptyRootTask.moveToFront("emptyRootTaskToFront");
2683         assertEquals(rootTask, display.getFocusedRootTask());
2684         assertTopRunningActivity(showWhenLockedActivity, display);
2685     }
2686 
assertTopRunningActivity(ActivityRecord top, DisplayContent display)2687     private static void assertTopRunningActivity(ActivityRecord top, DisplayContent display) {
2688         assertEquals(top, display.topRunningActivity());
2689         assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
2690     }
2691 
2692     @Test
testKeyguardGoingAwayWhileAodShown()2693     public void testKeyguardGoingAwayWhileAodShown() {
2694         mDisplayContent.getDisplayPolicy().setAwake(true);
2695 
2696         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
2697         final ActivityRecord activity = appWin.mActivityRecord;
2698 
2699         mAtm.mKeyguardController.setKeyguardShown(appWin.getDisplayId(), true /* keyguardShowing */,
2700                 true /* aodShowing */);
2701         assertFalse(activity.isVisibleRequested());
2702 
2703         mAtm.mKeyguardController.keyguardGoingAway(appWin.getDisplayId(), 0 /* flags */);
2704         assertTrue(activity.isVisibleRequested());
2705     }
2706 
2707     @Test
testRemoveRootTaskInWindowingModes()2708     public void testRemoveRootTaskInWindowingModes() {
2709         removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksInWindowingModes(
2710                 WINDOWING_MODE_FULLSCREEN));
2711     }
2712 
2713     @Test
testRemoveRootTaskWithActivityTypes()2714     public void testRemoveRootTaskWithActivityTypes() {
2715         removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksWithActivityTypes(
2716                 ACTIVITY_TYPE_STANDARD));
2717     }
2718 
2719     @SetupWindows(addWindows = W_INPUT_METHOD)
2720     @Test
testImeChildWindowFocusWhenImeLayeringTargetChanges()2721     public void testImeChildWindowFocusWhenImeLayeringTargetChanges() {
2722         final WindowState imeChildWindow =
2723                 createWindow(mImeWindow, TYPE_APPLICATION_ATTACHED_DIALOG, "imeChildWindow");
2724         makeWindowVisibleAndDrawn(imeChildWindow, mImeWindow);
2725         assertTrue(imeChildWindow.canReceiveKeys());
2726         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
2727 
2728         // Verify imeChildWindow can be focused window if the next IME target requests IME visible.
2729         final WindowState imeAppTarget =
2730                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
2731         mDisplayContent.setImeLayeringTarget(imeAppTarget);
2732         spyOn(imeAppTarget);
2733         doReturn(true).when(imeAppTarget).isRequestedVisible(ime());
2734         assertEquals(imeChildWindow, mDisplayContent.findFocusedWindow());
2735 
2736         // Verify imeChildWindow doesn't be focused window if the next IME target does not
2737         // request IME visible.
2738         final WindowState nextImeAppTarget =
2739                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
2740         mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
2741         assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow());
2742     }
2743 
2744     @SetupWindows(addWindows = W_INPUT_METHOD)
2745     @Test
testImeMenuDialogFocusWhenImeLayeringTargetChanges()2746     public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() {
2747         final WindowState imeMenuDialog =
2748                 createWindow(null, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog");
2749         makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow);
2750         assertTrue(imeMenuDialog.canReceiveKeys());
2751         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
2752 
2753         // Verify imeMenuDialog can be focused window if the next IME target requests IME visible.
2754         final WindowState imeAppTarget =
2755                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
2756         mDisplayContent.setImeLayeringTarget(imeAppTarget);
2757         spyOn(imeAppTarget);
2758         doReturn(true).when(imeAppTarget).isRequestedVisible(ime());
2759         assertEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
2760 
2761         // Verify imeMenuDialog doesn't be focused window if the next IME target is closing.
2762         final WindowState nextImeAppTarget =
2763                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
2764         makeWindowVisibleAndDrawn(nextImeAppTarget);
2765         nextImeAppTarget.mActivityRecord.commitVisibility(false, false);
2766         mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
2767         assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
2768     }
2769 
2770     @Test
testKeepClearAreasMultipleWindows()2771     public void testKeepClearAreasMultipleWindows() {
2772         final WindowState w1 = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent, "w1");
2773         final Rect rect1 = new Rect(0, 0, 10, 10);
2774         w1.setKeepClearAreas(Arrays.asList(rect1), Collections.emptyList());
2775         final WindowState w2 = createWindow(null, TYPE_NOTIFICATION_SHADE, mDisplayContent, "w2");
2776         final Rect rect2 = new Rect(10, 10, 20, 20);
2777         w2.setKeepClearAreas(Arrays.asList(rect2), Collections.emptyList());
2778 
2779         // No keep clear areas on display, because the windows are not visible
2780         assertEquals(Collections.emptySet(), mDisplayContent.getKeepClearAreas());
2781 
2782         makeWindowVisible(w1);
2783 
2784         // The returned keep-clear areas contain the areas just from the visible window
2785         assertEquals(new ArraySet(Arrays.asList(rect1)), mDisplayContent.getKeepClearAreas());
2786 
2787         makeWindowVisible(w1, w2);
2788 
2789         // The returned keep-clear areas contain the areas from all visible windows
2790         assertEquals(new ArraySet(Arrays.asList(rect1, rect2)),
2791                 mDisplayContent.getKeepClearAreas());
2792     }
2793 
2794     @Test
testHasAccessConsidersUserVisibilityForBackgroundVisibleUsers()2795     public void testHasAccessConsidersUserVisibilityForBackgroundVisibleUsers() {
2796         doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled());
2797         final int appId = 1234;
2798         final int userId1 = 11;
2799         final int userId2 = 12;
2800         final int uid1 = UserHandle.getUid(userId1, appId);
2801         final int uid2 = UserHandle.getUid(userId2, appId);
2802         final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
2803         final DisplayContent dc = createNewDisplay(displayInfo);
2804         int displayId = dc.getDisplayId();
2805         doReturn(true).when(mWm.mUmInternal).isUserVisible(userId1, displayId);
2806         doReturn(false).when(mWm.mUmInternal).isUserVisible(userId2, displayId);
2807 
2808         assertTrue(dc.hasAccess(uid1));
2809         assertFalse(dc.hasAccess(uid2));
2810     }
2811 
2812     @Test
testHasAccessIgnoresUserVisibilityForPrivateDisplay()2813     public void testHasAccessIgnoresUserVisibilityForPrivateDisplay() {
2814         doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled());
2815         final int appId = 1234;
2816         final int userId2 = 12;
2817         final int uid2 = UserHandle.getUid(userId2, appId);
2818         final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
2819         displayInfo.flags = FLAG_PRIVATE;
2820         displayInfo.ownerUid = uid2;
2821         final DisplayContent dc = createNewDisplay(displayInfo);
2822         int displayId = dc.getDisplayId();
2823 
2824         assertTrue(dc.hasAccess(uid2));
2825 
2826         verify(mWm.mUmInternal, never()).isUserVisible(userId2, displayId);
2827     }
2828 
2829     @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
2830     @Test
cameraCompatFreeformFlagEnabled_cameraCompatFreeformPolicyNotNull()2831     public void cameraCompatFreeformFlagEnabled_cameraCompatFreeformPolicyNotNull() {
2832         doReturn(true).when(() ->
2833                 DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
2834 
2835         assertNotNull(createNewDisplay().mCameraCompatFreeformPolicy);
2836     }
2837 
2838     @DisableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
2839     @Test
cameraCompatFreeformFlagNotEnabled_cameraCompatFreeformPolicyIsNull()2840     public void cameraCompatFreeformFlagNotEnabled_cameraCompatFreeformPolicyIsNull() {
2841         doReturn(true).when(() ->
2842                 DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
2843 
2844         assertNull(createNewDisplay().mCameraCompatFreeformPolicy);
2845     }
2846 
2847     @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
2848     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
2849     @Test
desktopWindowingFlagNotEnabled_cameraCompatFreeformPolicyIsNull()2850     public void desktopWindowingFlagNotEnabled_cameraCompatFreeformPolicyIsNull() {
2851         assertNull(createNewDisplay().mCameraCompatFreeformPolicy);
2852     }
2853 
removeRootTaskTests(Runnable runnable)2854     private void removeRootTaskTests(Runnable runnable) {
2855         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
2856         final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
2857                 ACTIVITY_TYPE_STANDARD, ON_TOP);
2858         final Task rootTask2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
2859                 ACTIVITY_TYPE_STANDARD, ON_TOP);
2860         final Task rootTask3 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
2861                 ACTIVITY_TYPE_STANDARD, ON_TOP);
2862         final Task rootTask4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
2863                 ACTIVITY_TYPE_STANDARD, ON_TOP);
2864         final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask1).build();
2865         final Task task2 = new TaskBuilder(mSupervisor).setParentTask(rootTask2).build();
2866         final Task task3 = new TaskBuilder(mSupervisor).setParentTask(rootTask3).build();
2867         final Task task4 = new TaskBuilder(mSupervisor).setParentTask(rootTask4).build();
2868 
2869         // Reordering root tasks while removing root tasks.
2870         doAnswer(invocation -> {
2871             taskDisplayArea.positionChildAt(POSITION_TOP, rootTask3, false /*includingParents*/);
2872             return true;
2873         }).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
2874 
2875         // Removing root tasks from the display while removing root tasks.
2876         doAnswer(invocation -> {
2877             taskDisplayArea.removeRootTask(rootTask2);
2878             return true;
2879         }).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
2880 
2881         runnable.run();
2882         verify(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
2883         verify(mSupervisor).removeTask(eq(task3), anyBoolean(), anyBoolean(), any());
2884         verify(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
2885         verify(mSupervisor).removeTask(eq(task1), anyBoolean(), anyBoolean(), any());
2886     }
2887 
isOptionsPanelAtRight(int displayId)2888     private boolean isOptionsPanelAtRight(int displayId) {
2889         return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
2890     }
2891 
verifySizes(DisplayContent displayContent, int expectedBaseWidth, int expectedBaseHeight, int expectedBaseDensity)2892     private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
2893                              int expectedBaseHeight, int expectedBaseDensity) {
2894         assertEquals(expectedBaseWidth, displayContent.mBaseDisplayWidth);
2895         assertEquals(expectedBaseHeight, displayContent.mBaseDisplayHeight);
2896         assertEquals(expectedBaseDensity, displayContent.mBaseDisplayDensity);
2897     }
2898 
verifySizes(DisplayContent displayContent, int expectedBaseWidth, int expectedBaseHeight, int expectedBaseDensity, float expectedBaseXDpi, float expectedBaseYDpi)2899     private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
2900             int expectedBaseHeight, int expectedBaseDensity, float expectedBaseXDpi,
2901             float expectedBaseYDpi) {
2902         assertEquals(expectedBaseWidth, displayContent.mBaseDisplayWidth);
2903         assertEquals(expectedBaseHeight, displayContent.mBaseDisplayHeight);
2904         assertEquals(expectedBaseDensity, displayContent.mBaseDisplayDensity);
2905         assertEquals(expectedBaseXDpi, displayContent.mBaseDisplayPhysicalXDpi, 1.0f /* delta */);
2906         assertEquals(expectedBaseYDpi, displayContent.mBaseDisplayPhysicalYDpi, 1.0f /* delta */);
2907     }
2908 
updateFocusedWindow()2909     private void updateFocusedWindow() {
2910         mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
2911     }
2912 
performLayout(DisplayContent dc)2913     static void performLayout(DisplayContent dc) {
2914         dc.setLayoutNeeded();
2915         dc.performLayout(true /* initial */, false /* updateImeWindows */);
2916     }
2917 
2918     /**
2919      * Create DisplayContent that does not update display base/initial values from device to keep
2920      * the values set by test.
2921      */
createDisplayNoUpdateDisplayInfo()2922     private DisplayContent createDisplayNoUpdateDisplayInfo() {
2923         final DisplayContent displayContent = createNewDisplay();
2924         doNothing().when(displayContent).updateDisplayInfo(any());
2925         return displayContent;
2926     }
2927 
assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop)2928     private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
2929         final LinkedList<WindowState> actualWindows = new LinkedList<>();
2930 
2931         // Test forward traversal.
2932         mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
2933         assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
2934 
2935         actualWindows.clear();
2936 
2937         // Test backward traversal.
2938         mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
2939         assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
2940     }
2941 
getRotatedOrientation(DisplayContent dc)2942     static int getRotatedOrientation(DisplayContent dc) {
2943         return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight
2944                 ? SCREEN_ORIENTATION_PORTRAIT
2945                 : SCREEN_ORIENTATION_LANDSCAPE;
2946     }
2947 
reverseList(List<WindowState> list)2948     private static List<WindowState> reverseList(List<WindowState> list) {
2949         final ArrayList<WindowState> result = new ArrayList<>(list);
2950         Collections.reverse(result);
2951         return result;
2952     }
2953 
updateDisplay(DisplayContent displayContent)2954     private void updateDisplay(DisplayContent displayContent) {
2955         CompletableFuture<Object> future = new CompletableFuture<>();
2956         displayContent.requestDisplayUpdate(() -> future.complete(new Object()));
2957         try {
2958             future.get(15, TimeUnit.SECONDS);
2959         } catch (InterruptedException | ExecutionException | TimeoutException e) {
2960             throw new RuntimeException(e);
2961         }
2962     }
2963 }
2964