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