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