xref: /aosp_15_r20/frameworks/base/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
23 import static android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION;
24 import static android.view.Display.DEFAULT_DISPLAY;
25 import static android.view.InsetsSource.ID_IME;
26 import static android.view.Surface.ROTATION_0;
27 import static android.view.Surface.ROTATION_270;
28 import static android.view.Surface.ROTATION_90;
29 import static android.view.WindowInsets.Type.ime;
30 import static android.view.WindowInsets.Type.navigationBars;
31 import static android.view.WindowInsets.Type.statusBars;
32 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
33 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
34 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
35 import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
36 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
37 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
38 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
39 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
40 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
41 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
42 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
43 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
44 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
45 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
46 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
47 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
48 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
49 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
50 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
51 
52 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
53 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
54 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
55 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
56 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
57 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
58 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
59 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
60 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
61 import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW;
62 
63 import static com.google.common.truth.Truth.assertThat;
64 
65 import static org.hamcrest.Matchers.is;
66 import static org.hamcrest.Matchers.not;
67 import static org.junit.Assert.assertEquals;
68 import static org.junit.Assert.assertFalse;
69 import static org.junit.Assert.assertNotEquals;
70 import static org.junit.Assert.assertNotNull;
71 import static org.junit.Assert.assertNull;
72 import static org.junit.Assert.assertThat;
73 import static org.junit.Assert.assertTrue;
74 import static org.junit.Assume.assumeTrue;
75 import static org.mockito.ArgumentMatchers.any;
76 import static org.mockito.ArgumentMatchers.anyBoolean;
77 import static org.mockito.ArgumentMatchers.anyInt;
78 import static org.mockito.ArgumentMatchers.anyLong;
79 import static org.mockito.ArgumentMatchers.anyString;
80 import static org.mockito.ArgumentMatchers.eq;
81 import static org.mockito.Mockito.atLeast;
82 import static org.mockito.Mockito.atMost;
83 import static org.mockito.Mockito.clearInvocations;
84 import static org.mockito.Mockito.doAnswer;
85 import static org.mockito.Mockito.reset;
86 import static org.mockito.Mockito.when;
87 
88 import android.content.ContentResolver;
89 import android.content.res.CompatibilityInfo;
90 import android.content.res.Configuration;
91 import android.graphics.Matrix;
92 import android.graphics.Point;
93 import android.graphics.Rect;
94 import android.graphics.Region;
95 import android.os.Build;
96 import android.os.IBinder;
97 import android.os.InputConfig;
98 import android.os.RemoteException;
99 import android.platform.test.annotations.DisableFlags;
100 import android.platform.test.annotations.EnableFlags;
101 import android.platform.test.annotations.Presubmit;
102 import android.platform.test.annotations.RequiresFlagsEnabled;
103 import android.provider.Settings;
104 import android.util.ArraySet;
105 import android.util.MergedConfiguration;
106 import android.view.Gravity;
107 import android.view.IWindow;
108 import android.view.InputWindowHandle;
109 import android.view.InsetsSource;
110 import android.view.InsetsSourceControl;
111 import android.view.InsetsState;
112 import android.view.SurfaceControl;
113 import android.view.View;
114 import android.view.WindowInsets;
115 import android.view.WindowManager;
116 import android.view.WindowRelayoutResult;
117 import android.view.inputmethod.ImeTracker;
118 import android.window.ClientWindowFrames;
119 import android.window.ITaskFragmentOrganizer;
120 import android.window.TaskFragmentOrganizer;
121 
122 import androidx.test.filters.SmallTest;
123 
124 import com.android.server.inputmethod.InputMethodManagerInternal;
125 import com.android.server.testutils.StubTransaction;
126 import com.android.server.wm.SensitiveContentPackages.PackageInfo;
127 import com.android.window.flags.Flags;
128 
129 import org.junit.After;
130 import org.junit.Test;
131 import org.junit.runner.RunWith;
132 
133 import java.util.ArrayList;
134 import java.util.Arrays;
135 import java.util.Collections;
136 import java.util.LinkedList;
137 import java.util.List;
138 
139 /**
140  * Tests for the {@link WindowState} class.
141  *
142  * <p> Build/Install/Run:
143  * atest WmTests:WindowStateTests
144  */
145 @SmallTest
146 @Presubmit
147 @RunWith(WindowTestRunner.class)
148 public class WindowStateTests extends WindowTestsBase {
149 
150     @After
tearDown()151     public void tearDown() {
152         mWm.mSensitiveContentPackages.clearBlockedApps();
153     }
154 
155     @Test
testIsParentWindowHidden()156     public void testIsParentWindowHidden() {
157         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
158         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
159         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
160 
161         // parentWindow is initially set to hidden.
162         assertTrue(parentWindow.mHidden);
163         assertFalse(parentWindow.isParentWindowHidden());
164         assertTrue(child1.isParentWindowHidden());
165         assertTrue(child2.isParentWindowHidden());
166 
167         parentWindow.mHidden = false;
168         assertFalse(parentWindow.isParentWindowHidden());
169         assertFalse(child1.isParentWindowHidden());
170         assertFalse(child2.isParentWindowHidden());
171     }
172 
173     @Test
testIsChildWindow()174     public void testIsChildWindow() {
175         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
176         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
177         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
178         final WindowState randomWindow = createWindow(null, TYPE_APPLICATION, "randomWindow");
179 
180         assertFalse(parentWindow.isChildWindow());
181         assertTrue(child1.isChildWindow());
182         assertTrue(child2.isChildWindow());
183         assertFalse(randomWindow.isChildWindow());
184     }
185 
186     @Test
testHasChild()187     public void testHasChild() {
188         final WindowState win1 = createWindow(null, TYPE_APPLICATION, "win1");
189         final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, "win11");
190         final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, "win12");
191         final WindowState win2 = createWindow(null, TYPE_APPLICATION, "win2");
192         final WindowState win21 = createWindow(win2, FIRST_SUB_WINDOW, "win21");
193         final WindowState randomWindow = createWindow(null, TYPE_APPLICATION, "randomWindow");
194 
195         assertTrue(win1.hasChild(win11));
196         assertTrue(win1.hasChild(win12));
197         assertTrue(win2.hasChild(win21));
198 
199         assertFalse(win1.hasChild(win21));
200         assertFalse(win1.hasChild(randomWindow));
201 
202         assertFalse(win2.hasChild(win11));
203         assertFalse(win2.hasChild(win12));
204         assertFalse(win2.hasChild(randomWindow));
205     }
206 
207     @Test
testGetParentWindow()208     public void testGetParentWindow() {
209         final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
210         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
211         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
212 
213         assertNull(parentWindow.getParentWindow());
214         assertEquals(parentWindow, child1.getParentWindow());
215         assertEquals(parentWindow, child2.getParentWindow());
216     }
217 
218     @Test
testOverlayWindowHiddenWhenSuspended()219     public void testOverlayWindowHiddenWhenSuspended() {
220         final WindowState overlayWindow = spy(createWindow(null, TYPE_APPLICATION_OVERLAY,
221                 "overlayWindow"));
222         overlayWindow.setHiddenWhileSuspended(true);
223         verify(overlayWindow).hide(true /* doAnimation */, true /* requestAnim */);
224         overlayWindow.setHiddenWhileSuspended(false);
225         verify(overlayWindow).show(true /* doAnimation */, true /* requestAnim */);
226     }
227 
228     @Test
testGetTopParentWindow()229     public void testGetTopParentWindow() {
230         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
231         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
232         final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
233 
234         assertEquals(root, root.getTopParentWindow());
235         assertEquals(root, child1.getTopParentWindow());
236         assertEquals(child1, child2.getParentWindow());
237         assertEquals(root, child2.getTopParentWindow());
238 
239         // Test case were child is detached from parent.
240         root.removeChild(child1);
241         assertEquals(child1, child1.getTopParentWindow());
242         assertEquals(child1, child2.getParentWindow());
243     }
244 
245     @Test
testIsOnScreen_hiddenByPolicy()246     public void testIsOnScreen_hiddenByPolicy() {
247         final WindowState window = createWindow(null, TYPE_APPLICATION, "window");
248         window.setHasSurface(true);
249         assertTrue(window.isOnScreen());
250         window.hide(false /* doAnimation */, false /* requestAnim */);
251         assertFalse(window.isOnScreen());
252 
253         // Verifies that a window without animation can be hidden even if its parent is animating.
254         window.show(false /* doAnimation */, false /* requestAnim */);
255         assertTrue(window.isVisibleByPolicy());
256         window.getParent().startAnimation(mTransaction, mock(AnimationAdapter.class),
257                 false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_TOKEN_TRANSFORM);
258         window.mAttrs.windowAnimations = 0;
259         window.hide(true /* doAnimation */, true /* requestAnim */);
260         assertFalse(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
261         assertFalse(window.isVisibleByPolicy());
262         assertFalse(window.isOnScreen());
263 
264         // Verifies that a window with animation can be hidden after the hide animation is finished.
265         window.show(false /* doAnimation */, false /* requestAnim */);
266         window.mAttrs.windowAnimations = android.R.style.Animation_Dialog;
267         window.hide(true /* doAnimation */, true /* requestAnim */);
268         assertTrue(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
269         assertTrue(window.isVisibleByPolicy());
270         window.cancelAnimation();
271         assertFalse(window.isVisibleByPolicy());
272     }
273 
274     @Test
testCanBeImeTarget()275     public void testCanBeImeTarget() {
276         final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
277         final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
278 
279         // Setting FLAG_NOT_FOCUSABLE prevents the window from being an IME target.
280         appWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
281         imeWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
282 
283         // Make windows visible
284         appWindow.setHasSurface(true);
285         imeWindow.setHasSurface(true);
286 
287         // Windows with FLAG_NOT_FOCUSABLE can't be IME targets
288         assertFalse(appWindow.canBeImeTarget());
289         assertFalse(imeWindow.canBeImeTarget());
290 
291         // Add IME target flags
292         appWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
293         imeWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
294 
295         // Visible app window with flags can be IME target while an IME window can never be an IME
296         // target regardless of its visibility or flags.
297         assertTrue(appWindow.canBeImeTarget());
298         assertFalse(imeWindow.canBeImeTarget());
299 
300         // Verify PINNED windows can't be IME target.
301         int initialMode = appWindow.mActivityRecord.getWindowingMode();
302         appWindow.mActivityRecord.setWindowingMode(WINDOWING_MODE_PINNED);
303         assertFalse(appWindow.canBeImeTarget());
304         appWindow.mActivityRecord.setWindowingMode(initialMode);
305 
306         // Verify that app window can still be IME target as long as it is visible (even if
307         // it is going to become invisible).
308         appWindow.mActivityRecord.setVisibleRequested(false);
309         assertTrue(appWindow.canBeImeTarget());
310 
311         // Make windows invisible
312         appWindow.hide(false /* doAnimation */, false /* requestAnim */);
313         imeWindow.hide(false /* doAnimation */, false /* requestAnim */);
314 
315         // Invisible window can't be IME targets even if they have the right flags.
316         assertFalse(appWindow.canBeImeTarget());
317         assertFalse(imeWindow.canBeImeTarget());
318 
319         // Simulate the window is in split screen root task.
320         final Task rootTask = createTask(mDisplayContent,
321                 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
322         rootTask.setFocusable(false);
323         appWindow.mActivityRecord.reparent(rootTask, 0 /* position */, "test");
324 
325         // Make sure canBeImeTarget is false;
326         assertFalse(appWindow.canBeImeTarget());
327     }
328 
329     @Test
testGetWindow()330     public void testGetWindow() {
331         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
332         final WindowState mediaChild = createWindow(root, TYPE_APPLICATION_MEDIA, "mediaChild");
333         final WindowState mediaOverlayChild = createWindow(root,
334                 TYPE_APPLICATION_MEDIA_OVERLAY, "mediaOverlayChild");
335         final WindowState attachedDialogChild = createWindow(root,
336                 TYPE_APPLICATION_ATTACHED_DIALOG, "attachedDialogChild");
337         final WindowState subPanelChild = createWindow(root,
338                 TYPE_APPLICATION_SUB_PANEL, "subPanelChild");
339         final WindowState aboveSubPanelChild = createWindow(root,
340                 TYPE_APPLICATION_ABOVE_SUB_PANEL, "aboveSubPanelChild");
341 
342         final LinkedList<WindowState> windows = new LinkedList<>();
343 
344         root.getWindow(w -> {
345             windows.addLast(w);
346             return false;
347         });
348 
349         // getWindow should have returned candidate windows in z-order.
350         assertEquals(aboveSubPanelChild, windows.pollFirst());
351         assertEquals(subPanelChild, windows.pollFirst());
352         assertEquals(attachedDialogChild, windows.pollFirst());
353         assertEquals(root, windows.pollFirst());
354         assertEquals(mediaOverlayChild, windows.pollFirst());
355         assertEquals(mediaChild, windows.pollFirst());
356         assertTrue(windows.isEmpty());
357     }
358 
359     @Test
testDestroySurface()360     public void testDestroySurface() {
361         final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
362         win.mHasSurface = win.mAnimatingExit = true;
363         win.mWinAnimator.mSurfaceControl = mock(SurfaceControl.class);
364         win.onExitAnimationDone();
365 
366         assertFalse("Case 1 destroySurface no-op",
367                 win.destroySurface(false /* cleanupOnResume */, false /* appStopped */));
368         assertTrue(win.mHasSurface);
369         assertTrue(win.mDestroying);
370 
371         assertFalse("Case 2 destroySurface no-op",
372                 win.destroySurface(true /* cleanupOnResume */, false /* appStopped */));
373         assertTrue(win.mHasSurface);
374         assertTrue(win.mDestroying);
375 
376         assertTrue("Case 3 destroySurface destroys surface",
377                 win.destroySurface(false /* cleanupOnResume */, true /* appStopped */));
378         assertFalse(win.mDestroying);
379         assertFalse(win.mHasSurface);
380     }
381 
382     @Test
testPrepareWindowToDisplayDuringRelayout()383     public void testPrepareWindowToDisplayDuringRelayout() {
384         // Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON before
385         // calling setCurrentLaunchCanTurnScreenOn for windows with flag in the same activity.
386         final ActivityRecord activity = createActivityRecord(mDisplayContent);
387         final WindowState first = createWindow(null, TYPE_APPLICATION, activity, "first");
388         final WindowState second = createWindow(null, TYPE_APPLICATION, activity, "second");
389 
390         testPrepareWindowToDisplayDuringRelayout(first, false /* expectedWakeupCalled */,
391                 true /* expectedCurrentLaunchCanTurnScreenOn */);
392         testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */,
393                 true /* expectedCurrentLaunchCanTurnScreenOn */);
394 
395         // Call prepareWindowToDisplayDuringRelayout for two windows from the same activity, one of
396         // which has FLAG_TURN_SCREEN_ON. The first processed one should trigger the wakeup.
397         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
398         testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */,
399                 false /* expectedCurrentLaunchCanTurnScreenOn */);
400         testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */,
401                 false /* expectedCurrentLaunchCanTurnScreenOn */);
402 
403         // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON
404         // from the same activity. Only one should trigger the wakeup.
405         activity.setCurrentLaunchCanTurnScreenOn(true);
406         first.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
407         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
408 
409         testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */,
410                 false /* expectedCurrentLaunchCanTurnScreenOn */);
411         testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */,
412                 false /* expectedCurrentLaunchCanTurnScreenOn */);
413 
414         // Without window flags, the state of ActivityRecord.canTurnScreenOn should still be able to
415         // turn on the screen.
416         activity.setCurrentLaunchCanTurnScreenOn(true);
417         first.mAttrs.flags &= ~WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
418         doReturn(true).when(activity).canTurnScreenOn();
419 
420         testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */,
421                 false /* expectedCurrentLaunchCanTurnScreenOn */);
422 
423         // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
424         // activity. Both windows have the FLAG_TURNS_SCREEN_ON so both should call wakeup
425         final WindowToken windowToken = createTestWindowToken(FIRST_SUB_WINDOW, mDisplayContent);
426         final WindowState firstWindow = createWindow(null, TYPE_APPLICATION, windowToken,
427                 "firstWindow");
428         final WindowState secondWindow = createWindow(null, TYPE_APPLICATION, windowToken,
429                 "secondWindow");
430         firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
431         secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
432 
433         final var powerManager = mWm.mPowerManager;
434         clearInvocations(powerManager);
435         firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
436         verify(powerManager).wakeUp(anyLong(), anyInt(), anyString(), anyInt());
437 
438         clearInvocations(powerManager);
439         secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
440         verify(powerManager).wakeUp(anyLong(), anyInt(), anyString(), anyInt());
441     }
442 
testPrepareWindowToDisplayDuringRelayout(WindowState appWindow, boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn)443     private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow,
444             boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) {
445         final var powerManager = mWm.mPowerManager;
446         clearInvocations(powerManager);
447         appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */);
448 
449         if (expectedWakeupCalled) {
450             verify(powerManager).wakeUp(anyLong(), anyInt(), anyString(), anyInt());
451         } else {
452             verify(powerManager, never()).wakeUp(anyLong(), anyInt(), anyString(), anyInt());
453         }
454         // If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false
455         // because the state will be consumed.
456         assertThat(appWindow.mActivityRecord.currentLaunchCanTurnScreenOn(),
457                 is(expectedCurrentLaunchCanTurnScreenOn));
458     }
459 
460     @Test
testCanAffectSystemUiFlags()461     public void testCanAffectSystemUiFlags() {
462         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
463         app.mActivityRecord.setVisible(true);
464         assertTrue(app.canAffectSystemUiFlags());
465         app.mActivityRecord.setVisible(false);
466         assertFalse(app.canAffectSystemUiFlags());
467         app.mActivityRecord.setVisible(true);
468         app.mAttrs.alpha = 0.0f;
469         assertFalse(app.canAffectSystemUiFlags());
470     }
471 
472     @Test
testCanAffectSystemUiFlags_starting()473     public void testCanAffectSystemUiFlags_starting() {
474         final WindowState app = createWindow(null, TYPE_APPLICATION_STARTING, "app");
475         app.mActivityRecord.setVisible(true);
476         app.mStartingData = new SnapshotStartingData(mWm, null, 0);
477         assertFalse(app.canAffectSystemUiFlags());
478         app.mStartingData = new SplashScreenStartingData(mWm, 0, 0);
479         assertTrue(app.canAffectSystemUiFlags());
480     }
481 
482     @Test
testCanAffectSystemUiFlags_disallow()483     public void testCanAffectSystemUiFlags_disallow() {
484         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
485         app.mActivityRecord.setVisible(true);
486         assertTrue(app.canAffectSystemUiFlags());
487         app.getTask().setCanAffectSystemUiFlags(false);
488         assertFalse(app.canAffectSystemUiFlags());
489     }
490 
491     @SetupWindows(addWindows = { W_ACTIVITY, W_STATUS_BAR })
492     @Test
testVisibleWithInsetsProvider()493     public void testVisibleWithInsetsProvider() {
494         final WindowState statusBar = mStatusBarWindow;
495         final WindowState app = mAppWindow;
496         statusBar.mHasSurface = true;
497         assertTrue(statusBar.isVisible());
498         final int statusBarId = InsetsSource.createId(null, 0, statusBars());
499         mDisplayContent.getInsetsStateController()
500                 .getOrCreateSourceProvider(statusBarId, statusBars())
501                 .setWindowContainer(statusBar, null /* frameProvider */,
502                         null /* imeFrameProvider */);
503         mDisplayContent.getInsetsStateController().onBarControlTargetChanged(
504                 app, null /* fakeTopControlling */, app, null /* fakeNavControlling */);
505         app.setRequestedVisibleTypes(0, statusBars());
506         mDisplayContent.getInsetsStateController()
507                 .getOrCreateSourceProvider(statusBarId, statusBars())
508                 .updateClientVisibility(app, null /* statsToken */);
509         waitUntilHandlersIdle();
510         assertFalse(statusBar.isVisible());
511     }
512 
513     /**
514      * Verifies that the InsetsSourceProvider frame cannot be updated by WindowState before
515      * relayout is called.
516      */
517     @SetupWindows(addWindows = { W_STATUS_BAR })
518     @Test
testUpdateSourceFrameBeforeRelayout()519     public void testUpdateSourceFrameBeforeRelayout() {
520         final WindowState statusBar = mStatusBarWindow;
521         statusBar.mHasSurface = true;
522         assertTrue(statusBar.isVisible());
523         final int statusBarId = InsetsSource.createId(null, 0, statusBars());
524         final var statusBarProvider = mDisplayContent.getInsetsStateController()
525                 .getOrCreateSourceProvider(statusBarId, statusBars());
526         statusBarProvider.setWindowContainer(statusBar, null /* frameProvider */,
527                         null /* imeFrameProvider */);
528 
529         statusBar.updateSourceFrame(new Rect(0, 0, 500, 200));
530         assertTrue("InsetsSourceProvider frame should not be updated before relayout",
531                 statusBarProvider.getSourceFrame().isEmpty());
532 
533         makeWindowVisible(statusBar);
534         statusBar.updateSourceFrame(new Rect(0, 0, 500, 100));
535         assertEquals("InsetsSourceProvider frame should be updated after relayout",
536                 new Rect(0, 0, 500, 100), statusBarProvider.getSourceFrame());
537     }
538 
539     @Test
testIsSelfOrAncestorWindowAnimating()540     public void testIsSelfOrAncestorWindowAnimating() {
541         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
542         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
543         final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
544         assertFalse(child2.isSelfOrAncestorWindowAnimatingExit());
545         child2.mAnimatingExit = true;
546         assertTrue(child2.isSelfOrAncestorWindowAnimatingExit());
547         child2.mAnimatingExit = false;
548         root.mAnimatingExit = true;
549         assertTrue(child2.isSelfOrAncestorWindowAnimatingExit());
550     }
551 
552     @Test
testDeferredRemovalByAnimating()553     public void testDeferredRemovalByAnimating() {
554         final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
555         makeWindowVisible(appWindow);
556         spyOn(appWindow.mWinAnimator);
557         doReturn(true).when(appWindow.mWinAnimator).getShown();
558         final AnimationAdapter animation = mock(AnimationAdapter.class);
559         final ActivityRecord activity = appWindow.mActivityRecord;
560         activity.startAnimation(appWindow.getPendingTransaction(),
561                 animation, false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION);
562 
563         appWindow.removeIfPossible();
564         assertTrue(appWindow.mAnimatingExit);
565         assertFalse(appWindow.mRemoved);
566 
567         activity.cancelAnimation();
568         assertFalse(appWindow.mAnimatingExit);
569         assertTrue(appWindow.mRemoved);
570     }
571 
572     @Test
testOnExitAnimationDone()573     public void testOnExitAnimationDone() {
574         final WindowState parent = createWindow(null, TYPE_APPLICATION, "parent");
575         final WindowState child = createWindow(parent, TYPE_APPLICATION_PANEL, "child");
576         final SurfaceControl.Transaction t = parent.getPendingTransaction();
577         child.startAnimation(t, mock(AnimationAdapter.class), false /* hidden */,
578                 SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
579         parent.mAnimatingExit = parent.mRemoveOnExit = parent.mWindowRemovalAllowed = true;
580         child.mAnimatingExit = child.mRemoveOnExit = child.mWindowRemovalAllowed = true;
581         final int[] numRemovals = new int[2];
582         parent.registerWindowContainerListener(new WindowContainerListener() {
583             @Override
584             public void onRemoved() {
585                 numRemovals[0]++;
586             }
587         });
588         child.registerWindowContainerListener(new WindowContainerListener() {
589             @Override
590             public void onRemoved() {
591                 numRemovals[1]++;
592             }
593         });
594         spyOn(parent);
595         // parent onExitAnimationDone
596         //   -> child onExitAnimationDone() -> no-op because isAnimating()
597         //   -> parent destroySurface()
598         //     -> parent removeImmediately() because mDestroying+mRemoveOnExit
599         //       -> child removeImmediately() -> cancelAnimation()
600         //       -> child onExitAnimationDone()
601         //         -> child destroySurface() because animation is canceled
602         //           -> child removeImmediately() -> no-op because mRemoved
603         parent.onExitAnimationDone();
604         // There must be no additional destroySurface() of parent from its child.
605         verify(parent, atMost(1)).destroySurface(anyBoolean(), anyBoolean());
606         assertEquals(1, numRemovals[0]);
607         assertEquals(1, numRemovals[1]);
608     }
609 
610     @Test
testLayoutSeqResetOnReparent()611     public void testLayoutSeqResetOnReparent() {
612         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
613         app.mLayoutSeq = 1;
614         mDisplayContent.mLayoutSeq = 1;
615 
616         DisplayContent newDisplay = createNewDisplay();
617 
618         app.onDisplayChanged(newDisplay);
619 
620         assertThat(app.mLayoutSeq, not(is(mDisplayContent.mLayoutSeq)));
621     }
622 
623     @Test
testDisplayIdUpdatedOnReparent()624     public void testDisplayIdUpdatedOnReparent() {
625         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
626         // fake a different display
627         app.mInputWindowHandle.setDisplayId(mDisplayContent.getDisplayId() + 1);
628         app.onDisplayChanged(mDisplayContent);
629 
630         assertThat(app.mInputWindowHandle.getDisplayId(), is(mDisplayContent.getDisplayId()));
631         assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
632     }
633 
634     @Test
testApplyWithNextDraw()635     public void testApplyWithNextDraw() {
636         final WindowState win = createWindow(null, TYPE_APPLICATION_OVERLAY, "app");
637         final SurfaceControl.Transaction[] handledT = { null };
638         // The normal case that the draw transaction is applied with finishing drawing.
639         win.applyWithNextDraw(t -> handledT[0] = t);
640         assertTrue(win.syncNextBuffer());
641         final SurfaceControl.Transaction drawT = new StubTransaction();
642         final SurfaceControl.Transaction currT = win.getSyncTransaction();
643         clearInvocations(currT);
644         win.mWinAnimator.mLastHidden = true;
645         assertTrue(win.finishDrawing(drawT, Integer.MAX_VALUE));
646         // The draw transaction should be merged to current transaction even if the state is hidden.
647         verify(currT).merge(eq(drawT));
648         assertEquals(drawT, handledT[0]);
649         assertFalse(win.syncNextBuffer());
650 
651         // If the window is gone before reporting drawn, the sync state should be cleared.
652         win.applyWithNextDraw(t -> handledT[0] = t);
653         win.destroySurfaceUnchecked();
654         assertFalse(win.syncNextBuffer());
655         assertNotEquals(drawT, handledT[0]);
656     }
657 
658     @Test
testSeamlesslyRotateWindow()659     public void testSeamlesslyRotateWindow() {
660         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
661         final SurfaceControl.Transaction t = spy(StubTransaction.class);
662 
663         makeWindowVisible(app);
664         app.mSurfaceControl = mock(SurfaceControl.class);
665         final Rect frame = app.getFrame();
666         frame.set(10, 20, 60, 80);
667         app.updateSurfacePosition(t);
668         assertTrue(app.mLastSurfacePosition.equals(frame.left, frame.top));
669         app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true /* requested */);
670         assertTrue(app.mSeamlesslyRotated);
671 
672         // Verify we un-rotate the window state surface.
673         final Matrix matrix = new Matrix();
674         // Un-rotate 90 deg.
675         matrix.setRotate(270);
676         // Translate it back to origin.
677         matrix.postTranslate(0, mDisplayInfo.logicalWidth);
678         verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class));
679 
680         // Verify we update the position as well.
681         final float[] curSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y};
682         matrix.mapPoints(curSurfacePos);
683         verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1]));
684 
685         app.finishSeamlessRotation(t);
686         assertFalse(app.mSeamlesslyRotated);
687         assertNull(app.mPendingSeamlessRotate);
688 
689         // Simulate the case with deferred layout and animation.
690         app.resetSurfacePositionForAnimationLeash(t);
691         clearInvocations(t);
692         mWm.mWindowPlacerLocked.deferLayout();
693         app.updateSurfacePosition(t);
694         // Because layout is deferred, the position should keep the reset value.
695         assertTrue(app.mLastSurfacePosition.equals(0, 0));
696 
697         app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_270, true /* requested */);
698         // The last position must be updated so the surface can be unrotated properly.
699         assertTrue(app.mLastSurfacePosition.equals(frame.left, frame.top));
700         matrix.setRotate(90);
701         matrix.postTranslate(mDisplayInfo.logicalHeight, 0);
702         curSurfacePos[0] = frame.left;
703         curSurfacePos[1] = frame.top;
704         matrix.mapPoints(curSurfacePos);
705         verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1]));
706     }
707 
708     @Test
testVisibilityChangeSwitchUser()709     public void testVisibilityChangeSwitchUser() {
710         final WindowState window = createWindow(null, TYPE_APPLICATION, "app");
711         window.mHasSurface = true;
712         spyOn(window);
713         doReturn(false).when(window).showForAllUsers();
714 
715         mWm.mCurrentUserId = 1;
716         window.switchUser(mWm.mCurrentUserId);
717         assertFalse(window.isVisible());
718         assertFalse(window.isVisibleByPolicy());
719 
720         mWm.mCurrentUserId = 0;
721         window.switchUser(mWm.mCurrentUserId);
722         assertTrue(window.isVisible());
723         assertTrue(window.isVisibleByPolicy());
724     }
725 
726     @Test
testCompatOverrideScale()727     public void testCompatOverrideScale() {
728         final float overrideScale = 2; // 0.5x on client side.
729         final CompatModePackages cmp = mWm.mAtmService.mCompatModePackages;
730         spyOn(cmp);
731         doReturn(overrideScale).when(cmp).getCompatScale(anyString(), anyInt());
732         final WindowState w = createWindow(null, TYPE_APPLICATION_OVERLAY, "win");
733         final WindowState child = createWindow(w, TYPE_APPLICATION_PANEL, "child");
734 
735         assertTrue(w.hasCompatScale());
736         assertTrue(child.hasCompatScale());
737 
738         makeWindowVisible(w, child);
739         w.setRequestedSize(100, 200);
740         child.setRequestedSize(50, 100);
741         child.mAttrs.width = child.mAttrs.height = 0;
742         w.mAttrs.x = w.mAttrs.y = 100;
743         w.mAttrs.width = w.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
744         w.mAttrs.gravity = Gravity.TOP | Gravity.LEFT;
745         child.mAttrs.gravity = Gravity.CENTER;
746         DisplayContentTests.performLayout(mDisplayContent);
747         final Rect parentFrame = w.getFrame();
748         final Rect childFrame = child.getFrame();
749 
750         // Frame on screen = 200x400 (200, 200 - 400, 600). Compat frame on client = 100x200.
751         final Rect unscaledCompatFrame = new Rect(w.getWindowFrames().mCompatFrame);
752         unscaledCompatFrame.scale(overrideScale);
753         assertEquals(parentFrame, unscaledCompatFrame);
754 
755         // Frame on screen = 100x200 (250, 300 - 350, 500). Compat frame on client = 50x100.
756         unscaledCompatFrame.set(child.getWindowFrames().mCompatFrame);
757         unscaledCompatFrame.scale(overrideScale);
758         assertEquals(childFrame, unscaledCompatFrame);
759 
760         // The position of child is relative to parent. So the local coordinates should be scaled.
761         final Point expectedChildPos = new Point(
762                 (int) ((childFrame.left - parentFrame.left) / overrideScale),
763                 (int) ((childFrame.top - parentFrame.top) / overrideScale));
764         final Point childPos = new Point();
765         child.transformFrameToSurfacePosition(childFrame.left, childFrame.top, childPos);
766         assertEquals(expectedChildPos, childPos);
767 
768         // Surface should apply the scale.
769         final SurfaceControl.Transaction t = w.getPendingTransaction();
770         w.prepareSurfaces();
771         verify(t).setMatrix(w.mSurfaceControl, overrideScale, 0, 0, overrideScale);
772         // Child surface inherits parent's scale, so it doesn't need to scale.
773         verify(t, never()).setMatrix(any(), anyInt(), anyInt(), anyInt(), anyInt());
774 
775         // According to "dp * density / 160 = px", density is scaled and the size in dp is the same.
776         final Configuration winConfig = w.getConfiguration();
777         final Configuration clientConfig = new Configuration(w.getConfiguration());
778         CompatibilityInfo.scaleConfiguration(w.mInvGlobalScale, clientConfig);
779 
780         assertEquals(winConfig.screenWidthDp, clientConfig.screenWidthDp);
781         assertEquals(winConfig.screenHeightDp, clientConfig.screenHeightDp);
782         assertEquals(winConfig.smallestScreenWidthDp, clientConfig.smallestScreenWidthDp);
783         assertEquals(winConfig.densityDpi, (int) (clientConfig.densityDpi * overrideScale));
784 
785         final Rect unscaledClientBounds = new Rect(clientConfig.windowConfiguration.getBounds());
786         unscaledClientBounds.scale(overrideScale);
787         assertEquals(w.getWindowConfiguration().getBounds(), unscaledClientBounds);
788 
789         // Child window without scale (e.g. different app) should apply inverse scale of parent.
790         doReturn(1f).when(cmp).getCompatScale(anyString(), anyInt());
791         final WindowState child2 = createWindow(w, TYPE_APPLICATION_SUB_PANEL, "child2");
792         makeWindowVisible(w, child2);
793         clearInvocations(t);
794         child2.prepareSurfaces();
795         verify(t).setMatrix(child2.mSurfaceControl, w.mInvGlobalScale, 0, 0, w.mInvGlobalScale);
796     }
797 
798     @SetupWindows(addWindows = { W_ABOVE_ACTIVITY, W_NOTIFICATION_SHADE })
799     @Test
testRequestDrawIfNeeded()800     public void testRequestDrawIfNeeded() {
801         final WindowState startingApp = createWindow(null /* parent */,
802                 TYPE_BASE_APPLICATION, "startingApp");
803         final WindowState startingWindow = createWindow(null /* parent */,
804                 TYPE_APPLICATION_STARTING, startingApp.mToken, "starting");
805         startingApp.mActivityRecord.mStartingWindow = startingWindow;
806         final WindowState keyguardHostWindow = mNotificationShadeWindow;
807         final WindowState allDrawnApp = mAppWindow;
808         allDrawnApp.mActivityRecord.allDrawn = true;
809 
810         // The waiting list is used to ensure the content is ready when turning on screen.
811         final List<WindowState> outWaitingForDrawn = mDisplayContent.mWaitingForDrawn;
812         final List<WindowState> visibleWindows = Arrays.asList(mChildAppWindowAbove,
813                 keyguardHostWindow, allDrawnApp, startingApp, startingWindow);
814         visibleWindows.forEach(w -> {
815             w.mHasSurface = true;
816             w.requestDrawIfNeeded(outWaitingForDrawn);
817         });
818 
819         // Keyguard host window should be always contained. The drawn app or app with starting
820         // window are unnecessary to draw.
821         assertEquals(Arrays.asList(keyguardHostWindow, startingWindow), outWaitingForDrawn);
822 
823         // No need to wait for a window of invisible activity even if the window has surface.
824         final WindowState invisibleApp = mAppWindow;
825         invisibleApp.mActivityRecord.setVisibleRequested(false);
826         invisibleApp.mActivityRecord.allDrawn = false;
827         outWaitingForDrawn.clear();
828         invisibleApp.requestDrawIfNeeded(outWaitingForDrawn);
829         assertTrue(outWaitingForDrawn.isEmpty());
830 
831         // Drawn state should not be changed for insets change if the window is not visible.
832         startingApp.mActivityRecord.setVisibleRequested(false);
833         makeWindowVisibleAndDrawn(startingApp);
834         startingApp.getConfiguration().orientation = 0; // Reset to be the same as last reported.
835         startingApp.getWindowFrames().setInsetsChanged(true);
836         startingApp.updateResizingWindowIfNeeded();
837         assertTrue(mWm.mResizingWindows.contains(startingApp));
838         assertTrue(startingApp.isDrawn());
839         assertFalse(startingApp.getOrientationChanging());
840 
841         // Even if the display is frozen, invisible requested window should not be affected.
842         mWm.startFreezingDisplay(0, 0, mDisplayContent);
843         startingApp.getWindowFrames().setInsetsChanged(true);
844         startingApp.updateResizingWindowIfNeeded();
845         assertTrue(startingApp.isDrawn());
846     }
847 
848     @SetupWindows(addWindows = W_ABOVE_ACTIVITY)
849     @Test
testReportResizedWithRemoteException()850     public void testReportResizedWithRemoteException() {
851         final WindowState win = mChildAppWindowAbove;
852         makeWindowVisible(win, win.getParentWindow());
853         win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
854         win.updateResizingWindowIfNeeded();
855 
856         assertThat(mWm.mResizingWindows).contains(win);
857         assertTrue(win.getOrientationChanging());
858 
859         mWm.mResizingWindows.remove(win);
860         spyOn(win.mClient);
861         try {
862             doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
863                     anyBoolean() /* reportDraw */, any() /* mergedConfig */,
864                     any() /* insetsState */, anyBoolean() /* forceLayout */,
865                     anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
866                     anyInt() /* seqId */, anyBoolean() /* dragResizing */,
867                     any() /* activityWindowInfo */);
868         } catch (RemoteException ignored) {
869         }
870         win.reportResized();
871         win.updateResizingWindowIfNeeded();
872 
873         // Even "resized" throws remote exception, it is still considered as reported. So the window
874         // shouldn't be resized again (which may block unfreeze in real case).
875         assertThat(mWm.mResizingWindows).doesNotContain(win);
876         assertFalse(win.getOrientationChanging());
877     }
878 
879     @Test
testRequestResizeForBlastSync()880     public void testRequestResizeForBlastSync() {
881         final WindowState win = createWindow(null, TYPE_APPLICATION, "window");
882         makeWindowVisible(win);
883         makeLastConfigReportedToClient(win, true /* visible */);
884         win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
885         win.reportResized();
886         win.updateResizingWindowIfNeeded();
887         assertThat(mWm.mResizingWindows).doesNotContain(win);
888 
889         // Check that the window is in resizing if using blast sync.
890         final BLASTSyncEngine.SyncGroup syncGroup = mock(BLASTSyncEngine.SyncGroup.class);
891         syncGroup.mSyncMethod = BLASTSyncEngine.METHOD_BLAST;
892         win.mSyncGroup = syncGroup;
893         win.reportResized();
894         win.prepareSync();
895         assertEquals(SYNC_STATE_WAITING_FOR_DRAW, win.mSyncState);
896         win.updateResizingWindowIfNeeded();
897         assertThat(mWm.mResizingWindows).contains(win);
898 
899         // Don't re-add the window again if it's been reported to the client and still waiting on
900         // the client draw for blast sync.
901         win.reportResized();
902         mWm.mResizingWindows.remove(win);
903         win.updateResizingWindowIfNeeded();
904         assertThat(mWm.mResizingWindows).doesNotContain(win);
905 
906         // Non blast sync doesn't require to force resizing, because it won't use syncSeqId.
907         // And if the window is already drawn, it can report sync finish immediately so that the
908         // sync group won't be blocked.
909         win.finishSync(mTransaction, syncGroup, false /* cancel */);
910         syncGroup.mSyncMethod = BLASTSyncEngine.METHOD_NONE;
911         win.mSyncGroup = syncGroup;
912         win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
913         win.prepareSync();
914         assertEquals(SYNC_STATE_WAITING_FOR_DRAW, win.mSyncState);
915         win.updateResizingWindowIfNeeded();
916         assertThat(mWm.mResizingWindows).doesNotContain(win);
917         assertTrue(win.isSyncFinished(syncGroup));
918         assertEquals(WindowContainer.SYNC_STATE_READY, win.mSyncState);
919     }
920 
921     @Test
testEmbeddedActivityResizing_clearAllDrawn()922     public void testEmbeddedActivityResizing_clearAllDrawn() {
923         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
924         registerTaskFragmentOrganizer(
925                 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
926         final Task task = createTask(mDisplayContent);
927         final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
928         final ActivityRecord embeddedActivity = embeddedTf.getTopMostActivity();
929         final WindowState win = createWindow(null /* parent */, TYPE_APPLICATION, embeddedActivity,
930                 "App window");
931         doReturn(true).when(embeddedActivity).isVisible();
932         embeddedActivity.setVisibleRequested(true);
933         makeWindowVisible(win);
934         win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
935         // Set the bounds twice:
936         // 1. To make sure there is no orientation change after #reportResized, which can also cause
937         // #clearAllDrawn.
938         // 2. Make #isLastConfigReportedToClient to be false after #reportResized, so it can process
939         // to check if we need redraw.
940         embeddedTf.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
941         embeddedTf.setBounds(0, 0, 1000, 2000);
942         win.reportResized();
943         embeddedTf.setBounds(500, 0, 1000, 2000);
944 
945         // Clear all drawn when the window config of embedded TaskFragment is changed.
946         win.updateResizingWindowIfNeeded();
947         verify(embeddedActivity).clearAllDrawn();
948     }
949 
950     @Test
testCantReceiveTouchWhenAppTokenHiddenRequested()951     public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
952         final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
953         win0.mActivityRecord.setVisibleRequested(false);
954         assertFalse(win0.canReceiveTouchInput());
955     }
956 
957     @Test
testCantReceiveTouchWhenNotFocusable()958     public void testCantReceiveTouchWhenNotFocusable() {
959         final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
960         final Task rootTask = win0.mActivityRecord.getRootTask();
961         spyOn(rootTask);
962         when(rootTask.shouldIgnoreInput()).thenReturn(true);
963         assertFalse(win0.canReceiveTouchInput());
964     }
965 
testFlag(int flags, int test)966     private boolean testFlag(int flags, int test) {
967         return (flags & test) == test;
968     }
969 
970     @Test
testUpdateInputWindowHandle()971     public void testUpdateInputWindowHandle() {
972         final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
973         win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
974         win.mAttrs.flags = FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH;
975         final InputWindowHandle handle = new InputWindowHandle(
976                 win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId());
977         final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle);
978         final IBinder inputChannelToken = mock(IBinder.class);
979         win.mInputChannelToken = inputChannelToken;
980 
981         mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
982 
983         assertTrue(handleWrapper.isChanged());
984         assertTrue(testFlag(handle.inputConfig, InputConfig.WATCH_OUTSIDE_TOUCH));
985         assertFalse(testFlag(handle.inputConfig, InputConfig.PREVENT_SPLITTING));
986         assertTrue(testFlag(handle.inputConfig, InputConfig.DISABLE_USER_ACTIVITY));
987         // The window of standard resizable task should not use surface crop as touchable region.
988         assertFalse(handle.replaceTouchableRegionWithCrop);
989         assertEquals(inputChannelToken, handle.token);
990         assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */),
991                 handle.inputApplicationHandle);
992 
993         final SurfaceControl sc = mock(SurfaceControl.class);
994         final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction;
995         InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
996 
997         // The fields of input window handle are changed, so it must set input window info
998         // successfully. And then the changed flag should be reset.
999         verify(transaction).setInputWindowInfo(eq(sc), eq(handle));
1000         assertFalse(handleWrapper.isChanged());
1001         // Populate the same states again, the handle should not detect change.
1002         mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
1003         assertFalse(handleWrapper.isChanged());
1004 
1005         // Apply the no change handle, the invocation of setInputWindowInfo should be skipped.
1006         clearInvocations(transaction);
1007         InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
1008         verify(transaction, never()).setInputWindowInfo(any(), any());
1009 
1010         // The rotated bounds have higher priority as the touchable region.
1011         final Rect rotatedBounds = new Rect(0, 0, 123, 456);
1012         doReturn(rotatedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
1013         mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
1014         assertEquals(rotatedBounds, handle.touchableRegion.getBounds());
1015 
1016         // Populate as an overlay to disable the input of window.
1017         InputMonitor.populateOverlayInputInfo(handleWrapper);
1018         // The overlay attributes should be set.
1019         assertTrue(handleWrapper.isChanged());
1020         assertFalse(handleWrapper.isFocusable());
1021         assertNull(handle.token);
1022         assertEquals(0L, handle.dispatchingTimeoutMillis);
1023         assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL));
1024     }
1025 
1026     @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
1027     @Test
testTouchRegionUsesLetterboxBoundsIfTransformedBoundsAndLetterboxScrolling()1028     public void testTouchRegionUsesLetterboxBoundsIfTransformedBoundsAndLetterboxScrolling() {
1029         final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
1030 
1031         // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
1032         final Rect transformedBounds = new Rect(0, 0, 300, 500);
1033         doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
1034 
1035         // Otherwise, touchable region should match letterbox inner bounds.
1036         final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
1037         doAnswer(invocation -> {
1038             Rect rect = invocation.getArgument(0);
1039             rect.set(letterboxInnerBounds);
1040             return null;
1041         }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
1042 
1043         Region outRegion = new Region();
1044         win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
1045 
1046         // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
1047         // touchable region should match letterboxInnerBounds always.
1048         assertEquals(letterboxInnerBounds, outRegion.getBounds());
1049     }
1050 
1051     @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
1052     @Test
testTouchRegionUsesLetterboxBoundsIfNullTransformedBoundsAndLetterboxScrolling()1053     public void testTouchRegionUsesLetterboxBoundsIfNullTransformedBoundsAndLetterboxScrolling() {
1054         final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
1055 
1056         // Fragment bounds used for size of touchable region if letterbox inner bounds are empty
1057         // and Transform bounds are null.
1058         doReturn(null).when(win.mToken).getFixedRotationTransformDisplayBounds();
1059         final Rect fragmentBounds = new Rect(0, 0, 300, 500);
1060         final TaskFragment taskFragment = win.mActivityRecord.getTaskFragment();
1061         doAnswer(invocation -> {
1062             Rect rect = invocation.getArgument(0);
1063             rect.set(fragmentBounds);
1064             return null;
1065         }).when(taskFragment).getDimBounds(any());
1066 
1067         // Otherwise, touchable region should match letterbox inner bounds.
1068         final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
1069         doAnswer(invocation -> {
1070             Rect rect = invocation.getArgument(0);
1071             rect.set(letterboxInnerBounds);
1072             return null;
1073         }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
1074 
1075         Region outRegion = new Region();
1076         win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
1077 
1078         // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
1079         // touchable region should match letterboxInnerBounds always.
1080         assertEquals(letterboxInnerBounds, outRegion.getBounds());
1081     }
1082 
1083     @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
1084     @Test
testTouchRegionUsesTransformedBoundsIfLetterboxScrolling()1085     public void testTouchRegionUsesTransformedBoundsIfLetterboxScrolling() {
1086         final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
1087 
1088         // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
1089         final Rect transformedBounds = new Rect(0, 0, 300, 500);
1090         doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
1091 
1092         // Otherwise, touchable region should match letterbox inner bounds.
1093         final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
1094         doAnswer(invocation -> {
1095             Rect rect = invocation.getArgument(0);
1096             rect.set(letterboxInnerBounds);
1097             return null;
1098         }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
1099 
1100         Region outRegion = new Region();
1101         win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
1102 
1103         // Because scrollingFromLetterbox flag is enabled and transformedBounds are non-null,
1104         // touchable region should match transformedBounds.
1105         assertEquals(transformedBounds, outRegion.getBounds());
1106     }
1107 
1108     @Test
testHasActiveVisibleWindow()1109     public void testHasActiveVisibleWindow() {
1110         final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
1111 
1112         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", uid);
1113         app.mActivityRecord.setVisible(false);
1114         app.mActivityRecord.setVisibility(false);
1115         assertFalse(mAtm.hasActiveVisibleWindow(uid));
1116 
1117         app.mActivityRecord.setVisibility(true);
1118         assertTrue(mAtm.hasActiveVisibleWindow(uid));
1119 
1120         // Make the activity invisible and add a visible toast. The uid should have no active
1121         // visible window because toast can be misused by legacy app to bypass background check.
1122         app.mActivityRecord.setVisibility(false);
1123         final WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay", uid);
1124         final WindowState toast = createWindow(null, TYPE_TOAST, app.mToken, "toast", uid);
1125         toast.onSurfaceShownChanged(true);
1126         assertFalse(mAtm.hasActiveVisibleWindow(uid));
1127 
1128         // Though starting window should belong to system. Make sure it is ignored to avoid being
1129         // allow-list unexpectedly, see b/129563343.
1130         final WindowState starting =
1131                 createWindow(null, TYPE_APPLICATION_STARTING, app.mToken, "starting", uid);
1132         starting.onSurfaceShownChanged(true);
1133         assertFalse(mAtm.hasActiveVisibleWindow(uid));
1134 
1135         // Make the application overlay window visible. It should be a valid active visible window.
1136         overlay.onSurfaceShownChanged(true);
1137         assertTrue(mAtm.hasActiveVisibleWindow(uid));
1138 
1139         // The number of windows should be independent of the existence of uid state.
1140         mAtm.mActiveUids.onUidInactive(uid);
1141         mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
1142         assertTrue(mAtm.mActiveUids.hasNonAppVisibleWindow(uid));
1143     }
1144 
1145     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
1146     @Test
testNeedsRelativeLayeringToIme_notAttached()1147     public void testNeedsRelativeLayeringToIme_notAttached() {
1148         WindowState sameTokenWindow = createWindow(null, TYPE_BASE_APPLICATION, mAppWindow.mToken,
1149                 "SameTokenWindow");
1150         mDisplayContent.setImeLayeringTarget(mAppWindow);
1151         makeWindowVisible(mImeWindow);
1152         sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1153         assertTrue(sameTokenWindow.needsRelativeLayeringToIme());
1154         sameTokenWindow.removeImmediately();
1155         assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
1156     }
1157 
1158     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
1159     @Test
testNeedsRelativeLayeringToIme_startingWindow()1160     public void testNeedsRelativeLayeringToIme_startingWindow() {
1161         WindowState sameTokenWindow = createWindow(null, TYPE_APPLICATION_STARTING,
1162                 mAppWindow.mToken, "SameTokenWindow");
1163         mDisplayContent.setImeLayeringTarget(mAppWindow);
1164         makeWindowVisible(mImeWindow);
1165         sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1166         assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
1167     }
1168 
1169     @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
1170     @Test
testNeedsRelativeLayeringToIme_systemDialog()1171     public void testNeedsRelativeLayeringToIme_systemDialog() {
1172         WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
1173                 mDisplayContent,
1174                 "SystemDialog", true);
1175         mDisplayContent.setImeLayeringTarget(mAppWindow);
1176         mAppWindow.getTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1177         makeWindowVisible(mImeWindow);
1178         systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
1179         assertTrue(systemDialogWindow.needsRelativeLayeringToIme());
1180     }
1181 
1182     @UseTestDisplay(addWindows = {W_INPUT_METHOD})
1183     @Test
testNeedsRelativeLayeringToIme_notificationShadeShouldNotHideSystemDialog()1184     public void testNeedsRelativeLayeringToIme_notificationShadeShouldNotHideSystemDialog() {
1185         WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
1186                 mDisplayContent,
1187                 "SystemDialog", true);
1188         mDisplayContent.setImeLayeringTarget(systemDialogWindow);
1189         makeWindowVisible(mImeWindow);
1190         WindowState notificationShade = createWindow(null, TYPE_NOTIFICATION_SHADE,
1191                 mDisplayContent, "NotificationShade", true);
1192         notificationShade.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
1193         assertFalse(notificationShade.needsRelativeLayeringToIme());
1194     }
1195 
1196     @Test
testSetFreezeInsetsState()1197     public void testSetFreezeInsetsState() {
1198         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
1199         spyOn(app);
1200         doReturn(true).when(app).isVisible();
1201 
1202         // Set freezing the insets state to make the window ignore to dispatch insets changed.
1203         final InsetsState expectedState = new InsetsState(app.getInsetsState(),
1204                 true /* copySources */);
1205         app.freezeInsetsState();
1206         assertEquals(expectedState, app.getFrozenInsetsState());
1207         assertFalse(app.isReadyToDispatchInsetsState());
1208         assertEquals(expectedState, app.getInsetsState());
1209         mDisplayContent.getInsetsStateController().notifyInsetsChanged();
1210         verify(app, never()).notifyInsetsChanged();
1211 
1212         // Unfreeze the insets state to make the window can dispatch insets changed.
1213         app.clearFrozenInsetsState();
1214         assertTrue(app.isReadyToDispatchInsetsState());
1215         mDisplayContent.getInsetsStateController().notifyInsetsChanged();
1216         verify(app).notifyInsetsChanged();
1217 
1218         // Verify that invisible non-activity window won't dispatch insets changed.
1219         final WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay");
1220         makeWindowVisible(overlay);
1221         assertTrue(overlay.isReadyToDispatchInsetsState());
1222         overlay.mHasSurface = false;
1223         assertFalse(overlay.isReadyToDispatchInsetsState());
1224         mDisplayContent.getInsetsStateController().notifyInsetsChanged();
1225         assertFalse(overlay.getWindowFrames().hasInsetsChanged());
1226     }
1227 
1228     @SetupWindows(addWindows = { W_INPUT_METHOD, W_ACTIVITY })
1229     @Test
testImeAlwaysReceivesVisibleNavigationBarInsets()1230     public void testImeAlwaysReceivesVisibleNavigationBarInsets() {
1231         final int navId = InsetsSource.createId(null, 0, navigationBars());
1232         final InsetsSource navSource = new InsetsSource(navId, navigationBars());
1233         mImeWindow.mAboveInsetsState.addSource(navSource);
1234         mAppWindow.mAboveInsetsState.addSource(navSource);
1235 
1236         navSource.setVisible(false);
1237         assertTrue(mImeWindow.getInsetsState().isSourceOrDefaultVisible(navId, navigationBars()));
1238         assertFalse(mAppWindow.getInsetsState().isSourceOrDefaultVisible(navId, navigationBars()));
1239 
1240         navSource.setVisible(true);
1241         assertTrue(mImeWindow.getInsetsState().isSourceOrDefaultVisible(navId, navigationBars()));
1242         assertTrue(mAppWindow.getInsetsState().isSourceOrDefaultVisible(navId, navigationBars()));
1243     }
1244 
1245     @Test
testAdjustImeInsetsVisibilityWhenSwitchingApps()1246     public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
1247         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
1248         final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
1249         final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
1250         spyOn(imeWindow);
1251         doReturn(true).when(imeWindow).isVisible();
1252         mDisplayContent.mInputMethodWindow = imeWindow;
1253 
1254         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
1255         controller.getImeSourceProvider().setWindowContainer(imeWindow, null, null);
1256 
1257         // Simulate app requests IME with updating all windows Insets State when IME is above app.
1258         mDisplayContent.setImeLayeringTarget(app);
1259         mDisplayContent.setImeInputTarget(app);
1260         app.setRequestedVisibleTypes(ime(), ime());
1261         assertTrue(mDisplayContent.shouldImeAttachedToApp());
1262         controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
1263         controller.getImeSourceProvider().getSource().setVisible(true);
1264         controller.updateAboveInsetsState(false);
1265 
1266         // Expect all app windows behind IME can receive IME insets visible.
1267         assertTrue(app.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1268         assertTrue(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1269 
1270         // Simulate app plays closing transition to app2.
1271         app.mActivityRecord.commitVisibility(false, false);
1272         assertTrue(app.mActivityRecord.mLastImeShown);
1273         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
1274 
1275         // Verify the IME insets is visible on app, but not for app2 during app task switching.
1276         assertTrue(app.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1277         assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1278     }
1279 
1280     @Test
testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode()1281     public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
1282         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
1283         final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
1284                 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
1285         final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
1286         spyOn(imeWindow);
1287         doReturn(true).when(imeWindow).isVisible();
1288         mDisplayContent.mInputMethodWindow = imeWindow;
1289 
1290         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
1291         controller.getImeSourceProvider().setWindowContainer(imeWindow, null, null);
1292 
1293         // Simulate app2 in multi-window mode is going to background to switch to the fullscreen
1294         // app which requests IME with updating all windows Insets State when IME is above app.
1295         app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
1296         mDisplayContent.setImeLayeringTarget(app);
1297         mDisplayContent.setImeInputTarget(app);
1298         app.setRequestedVisibleTypes(ime(), ime());
1299         assertTrue(mDisplayContent.shouldImeAttachedToApp());
1300         controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
1301         controller.getImeSourceProvider().getSource().setVisible(true);
1302         controller.updateAboveInsetsState(false);
1303 
1304         // Expect app windows behind IME can receive IME insets visible,
1305         // but not for app2 in background.
1306         assertTrue(app.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1307         assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1308 
1309         // Simulate app plays closing transition to app2.
1310         // And app2 is now IME layering target but not yet to be the IME input target.
1311         mDisplayContent.setImeLayeringTarget(app2);
1312         app.mActivityRecord.commitVisibility(false, false);
1313         assertTrue(app.mActivityRecord.mLastImeShown);
1314         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
1315 
1316         // Verify the IME insets is still visible on app, but not for app2 during task switching.
1317         assertTrue(app.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1318         assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
1319     }
1320 
1321     @SetupWindows(addWindows = W_ACTIVITY)
1322     @Test
testUpdateImeControlTargetWhenLeavingMultiWindow()1323     public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
1324         WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
1325                 mAppWindow.mToken, "app");
1326         mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
1327 
1328         spyOn(app);
1329         mDisplayContent.setImeInputTarget(mAppWindow);
1330         mDisplayContent.setImeLayeringTarget(mAppWindow);
1331 
1332         // Simulate entering multi-window mode and verify if the IME control target is remote.
1333         app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1334         assertEquals(WINDOWING_MODE_MULTI_WINDOW, app.getWindowingMode());
1335         assertEquals(mDisplayContent.mRemoteInsetsControlTarget,
1336                 mDisplayContent.computeImeControlTarget());
1337 
1338         // Simulate exiting multi-window mode and verify if the IME control target changed
1339         // to the app window.
1340         spyOn(app.getDisplayContent());
1341         app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
1342 
1343         // Expect updateImeParent will be invoked when the configuration of the IME control
1344         // target has changed.
1345         verify(app.getDisplayContent()).updateImeControlTarget(eq(true) /* updateImeParent */);
1346         assertEquals(mAppWindow, mDisplayContent.getImeTarget(IME_TARGET_CONTROL).getWindow());
1347     }
1348 
1349     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD, W_NOTIFICATION_SHADE })
1350     @Test
testNotificationShadeHasImeInsetsWhenMultiWindow()1351     public void testNotificationShadeHasImeInsetsWhenMultiWindow() {
1352         WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
1353                 mAppWindow.mToken, "app");
1354 
1355         // Simulate entering multi-window mode and windowing mode is multi-window.
1356         app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1357         assertEquals(WINDOWING_MODE_MULTI_WINDOW, app.getWindowingMode());
1358 
1359         // Simulate notificationShade is shown and being IME layering target.
1360         mNotificationShadeWindow.setHasSurface(true);
1361         mNotificationShadeWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
1362         assertTrue(mNotificationShadeWindow.canBeImeTarget());
1363         mDisplayContent.getInsetsStateController().getOrCreateSourceProvider(ID_IME, ime())
1364                 .setWindowContainer(mImeWindow, null, null);
1365 
1366         mDisplayContent.computeImeTarget(true);
1367         assertEquals(mNotificationShadeWindow, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
1368         mDisplayContent.getInsetsStateController().getRawInsetsState()
1369                 .setSourceVisible(ID_IME, true);
1370 
1371         // Verify notificationShade can still get IME insets even windowing mode is multi-window.
1372         InsetsState state = mNotificationShadeWindow.getInsetsState();
1373         assertNotNull(state.peekSource(ID_IME));
1374         assertTrue(state.isSourceOrDefaultVisible(ID_IME, ime()));
1375     }
1376 
1377     @Test
testRequestedVisibility()1378     public void testRequestedVisibility() {
1379         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
1380         app.mActivityRecord.setVisible(false);
1381         app.mActivityRecord.setVisibility(false);
1382         assertFalse(app.isVisibleRequested());
1383 
1384         // It doesn't have a surface yet, but should still be visible requested.
1385         app.setHasSurface(false);
1386         app.mActivityRecord.setVisibility(true);
1387 
1388         assertFalse(app.isVisible());
1389         assertTrue(app.isVisibleRequested());
1390     }
1391 
1392     @Test
testKeepClearAreas()1393     public void testKeepClearAreas() {
1394         final WindowState window = createWindow(null, TYPE_APPLICATION, "window");
1395         makeWindowVisible(window);
1396 
1397         final Rect keepClearArea1 = new Rect(0, 0, 10, 10);
1398         final Rect keepClearArea2 = new Rect(5, 10, 15, 20);
1399         final List<Rect> keepClearAreas = Arrays.asList(keepClearArea1, keepClearArea2);
1400         window.setKeepClearAreas(keepClearAreas, Collections.emptyList());
1401 
1402         // Test that the keep-clear rects are stored and returned
1403         final List<Rect> windowKeepClearAreas = new ArrayList();
1404         window.getKeepClearAreas(windowKeepClearAreas, new ArrayList());
1405         assertEquals(new ArraySet(keepClearAreas), new ArraySet(windowKeepClearAreas));
1406 
1407         // Test that keep-clear rects are overwritten
1408         window.setKeepClearAreas(Collections.emptyList(), Collections.emptyList());
1409         windowKeepClearAreas.clear();
1410         window.getKeepClearAreas(windowKeepClearAreas, new ArrayList());
1411         assertEquals(0, windowKeepClearAreas.size());
1412 
1413         // Move the window position
1414         final SurfaceControl.Transaction t = spy(StubTransaction.class);
1415         window.mSurfaceControl = mock(SurfaceControl.class);
1416         final Rect frame = window.getFrame();
1417         frame.set(10, 20, 60, 80);
1418         window.updateSurfacePosition(t);
1419         assertEquals(new Point(frame.left, frame.top), window.mLastSurfacePosition);
1420 
1421         // Test that the returned keep-clear rects are translated to display space
1422         window.setKeepClearAreas(keepClearAreas, Collections.emptyList());
1423         Rect expectedArea1 = new Rect(keepClearArea1);
1424         expectedArea1.offset(frame.left, frame.top);
1425         Rect expectedArea2 = new Rect(keepClearArea2);
1426         expectedArea2.offset(frame.left, frame.top);
1427 
1428         windowKeepClearAreas.clear();
1429         window.getKeepClearAreas(windowKeepClearAreas, new ArrayList());
1430         assertEquals(new ArraySet(Arrays.asList(expectedArea1, expectedArea2)),
1431                      new ArraySet(windowKeepClearAreas));
1432     }
1433 
1434     @Test
testUnrestrictedKeepClearAreas()1435     public void testUnrestrictedKeepClearAreas() {
1436         final WindowState window = createWindow(null, TYPE_APPLICATION, "window");
1437         makeWindowVisible(window);
1438 
1439         final Rect keepClearArea1 = new Rect(0, 0, 10, 10);
1440         final Rect keepClearArea2 = new Rect(5, 10, 15, 20);
1441         final List<Rect> keepClearAreas = Arrays.asList(keepClearArea1, keepClearArea2);
1442         window.setKeepClearAreas(Collections.emptyList(), keepClearAreas);
1443 
1444         // Test that the keep-clear rects are stored and returned
1445         final List<Rect> restrictedKeepClearAreas = new ArrayList();
1446         final List<Rect> unrestrictedKeepClearAreas = new ArrayList();
1447         window.getKeepClearAreas(restrictedKeepClearAreas, unrestrictedKeepClearAreas);
1448         assertEquals(Collections.emptySet(), new ArraySet(restrictedKeepClearAreas));
1449         assertEquals(new ArraySet(keepClearAreas), new ArraySet(unrestrictedKeepClearAreas));
1450 
1451         // Test that keep-clear rects are overwritten
1452         window.setKeepClearAreas(Collections.emptyList(), Collections.emptyList());
1453         unrestrictedKeepClearAreas.clear();
1454         window.getKeepClearAreas(unrestrictedKeepClearAreas, new ArrayList());
1455         assertEquals(0, unrestrictedKeepClearAreas.size());
1456 
1457         // Move the window position
1458         final SurfaceControl.Transaction t = spy(StubTransaction.class);
1459         window.mSurfaceControl = mock(SurfaceControl.class);
1460         final Rect frame = window.getFrame();
1461         frame.set(10, 20, 60, 80);
1462         window.updateSurfacePosition(t);
1463         assertEquals(new Point(frame.left, frame.top), window.mLastSurfacePosition);
1464 
1465         // Test that the returned keep-clear rects are translated to display space
1466         window.setKeepClearAreas(Collections.emptyList(), keepClearAreas);
1467         Rect expectedArea1 = new Rect(keepClearArea1);
1468         expectedArea1.offset(frame.left, frame.top);
1469         Rect expectedArea2 = new Rect(keepClearArea2);
1470         expectedArea2.offset(frame.left, frame.top);
1471 
1472         unrestrictedKeepClearAreas.clear();
1473         window.getKeepClearAreas(restrictedKeepClearAreas, unrestrictedKeepClearAreas);
1474         assertEquals(Collections.emptySet(), new ArraySet(restrictedKeepClearAreas));
1475         assertEquals(new ArraySet(Arrays.asList(expectedArea1, expectedArea2)),
1476                      new ArraySet(unrestrictedKeepClearAreas));
1477     }
1478 
1479     @Test
testImeTargetChangeListener_OnImeInputTargetVisibilityChanged()1480     public void testImeTargetChangeListener_OnImeInputTargetVisibilityChanged() {
1481         final InputMethodManagerInternal immi = InputMethodManagerInternal.get();
1482         spyOn(immi);
1483 
1484         final WindowState imeTarget = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
1485                 createActivityRecord(mDisplayContent), "imeTarget");
1486 
1487         imeTarget.mActivityRecord.setVisibleRequested(true);
1488         makeWindowVisible(imeTarget);
1489         mDisplayContent.setImeInputTarget(imeTarget);
1490         waitHandlerIdle(mWm.mH);
1491         verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(),
1492                 true /* visibleAndNotRemoved */, mDisplayContent.getDisplayId());
1493         reset(immi);
1494 
1495         imeTarget.mActivityRecord.setVisibleRequested(false);
1496         waitHandlerIdle(mWm.mH);
1497         verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(),
1498                 false /* visibleAndNotRemoved */, mDisplayContent.getDisplayId());
1499         reset(immi);
1500 
1501         imeTarget.removeImmediately();
1502         verify(immi).onImeInputTargetVisibilityChanged(imeTarget.mClient.asBinder(),
1503                 false /* visibleAndNotRemoved */, mDisplayContent.getDisplayId());
1504     }
1505 
1506     @SetupWindows(addWindows = {W_INPUT_METHOD})
1507     @Test
testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged()1508     public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged() {
1509         final InputMethodManagerInternal immi = InputMethodManagerInternal.get();
1510         spyOn(immi);
1511 
1512         // Scenario 1: test addWindow/relayoutWindow to add Ime layering overlay window as visible.
1513         final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
1514                 mDisplayContent);
1515         final IWindow client = new TestIWindow();
1516         final Session session = getTestSession();
1517         final ClientWindowFrames outFrames = new ClientWindowFrames();
1518         final MergedConfiguration outConfig = new MergedConfiguration();
1519         final SurfaceControl outSurfaceControl = new SurfaceControl();
1520         final InsetsState outInsetsState = new InsetsState();
1521         final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
1522         final WindowRelayoutResult outRelayoutResult = new WindowRelayoutResult(outFrames,
1523                 outConfig, outSurfaceControl, outInsetsState, outControls);
1524         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1525                 TYPE_APPLICATION_OVERLAY);
1526         params.setTitle("imeLayeringTargetOverlay");
1527         params.token = windowToken.token;
1528         params.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM;
1529 
1530         mWm.addWindow(session, client, params, View.VISIBLE, DEFAULT_DISPLAY,
1531                 0 /* userUd */, WindowInsets.Type.defaultVisible(), null, new InsetsState(),
1532                 new InsetsSourceControl.Array(), new Rect(), new float[1]);
1533         mWm.relayoutWindow(session, client, params, 100, 200, View.VISIBLE, 0, 0, 0,
1534                 outRelayoutResult);
1535         waitHandlerIdle(mWm.mH);
1536 
1537         final WindowState imeLayeringTargetOverlay = mDisplayContent.getWindow(
1538                 w -> w.mClient.asBinder() == client.asBinder());
1539         assertThat(imeLayeringTargetOverlay.isVisible()).isTrue();
1540         verify(immi, atLeast(1))
1541                 .setHasVisibleImeLayeringOverlay(true /* hasVisibleOverlay */,
1542                         mDisplayContent.getDisplayId());
1543         reset(immi);
1544 
1545         // Scenario 2: test relayoutWindow to let the Ime layering target overlay window invisible.
1546         mWm.relayoutWindow(session, client, params, 100, 200, View.GONE, 0, 0, 0,
1547                 outRelayoutResult);
1548         waitHandlerIdle(mWm.mH);
1549 
1550         assertThat(imeLayeringTargetOverlay.isVisible()).isFalse();
1551         verify(immi).setHasVisibleImeLayeringOverlay(false /* hasVisibleOverlay */,
1552                 mDisplayContent.getDisplayId());
1553         reset(immi);
1554 
1555         // Scenario 3: test removeWindow to remove the Ime layering target overlay window.
1556         mWm.removeClientToken(session, client.asBinder());
1557         waitHandlerIdle(mWm.mH);
1558 
1559         verify(immi).setHasVisibleImeLayeringOverlay(false /* hasVisibleOverlay */,
1560                 mDisplayContent.getDisplayId());
1561     }
1562 
1563     @Test
testIsSecureLocked_flagSecureSet()1564     public void testIsSecureLocked_flagSecureSet() {
1565         WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
1566                 1 /* ownerId */);
1567         window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
1568 
1569         assertTrue(window.isSecureLocked());
1570     }
1571 
1572     @Test
testIsSecureLocked_flagSecureNotSet()1573     public void testIsSecureLocked_flagSecureNotSet() {
1574         WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
1575                 1 /* ownerId */);
1576 
1577         assertFalse(window.isSecureLocked());
1578     }
1579 
1580     @Test
testIsSecureLocked_disableSecureWindows()1581     public void testIsSecureLocked_disableSecureWindows() {
1582         assumeTrue(Build.IS_DEBUGGABLE);
1583 
1584         WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
1585                 1 /* ownerId */);
1586         window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
1587         ContentResolver cr = useFakeSettingsProvider();
1588 
1589         // isSecureLocked should return false when DISABLE_SECURE_WINDOWS is set to 1
1590         Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
1591         mWm.mSettingsObserver.onChange(false /* selfChange */,
1592                 Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
1593         assertFalse(window.isSecureLocked());
1594 
1595         // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is set to 0.
1596         Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "0");
1597         mWm.mSettingsObserver.onChange(false /* selfChange */,
1598                 Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
1599         assertTrue(window.isSecureLocked());
1600 
1601         // Disable secure windows again.
1602         Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
1603         mWm.mSettingsObserver.onChange(false /* selfChange */,
1604                 Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
1605         assertFalse(window.isSecureLocked());
1606 
1607         // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is deleted.
1608         Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, null);
1609         mWm.mSettingsObserver.onChange(false /* selfChange */,
1610                 Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
1611         assertTrue(window.isSecureLocked());
1612     }
1613 
1614     @Test
1615     @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
testIsSecureLocked_sensitiveContentProtectionManagerEnabled()1616     public void testIsSecureLocked_sensitiveContentProtectionManagerEnabled() {
1617         String testPackage = "test";
1618         int ownerId1 = 20;
1619         int ownerId2 = 21;
1620         final WindowState window1 = createWindow(null, TYPE_APPLICATION, "window1", ownerId1);
1621         final WindowState window2 = createWindow(null, TYPE_APPLICATION, "window2", ownerId2);
1622 
1623         // Setting packagename for targeted feature
1624         window1.mAttrs.packageName = testPackage;
1625         window2.mAttrs.packageName = testPackage;
1626 
1627         PackageInfo blockedPackage = new PackageInfo(testPackage, ownerId1);
1628         ArraySet<PackageInfo> blockedPackages = new ArraySet();
1629         blockedPackages.add(blockedPackage);
1630         mWm.mSensitiveContentPackages.addBlockScreenCaptureForApps(blockedPackages);
1631 
1632         assertTrue(window1.isSecureLocked());
1633         assertFalse(window2.isSecureLocked());
1634     }
1635 
1636     @Test
1637     @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
testIsSecureLocked_sensitiveContentBlockOrClearScreenCaptureForApp()1638     public void testIsSecureLocked_sensitiveContentBlockOrClearScreenCaptureForApp() {
1639         String testPackage = "test";
1640         int ownerId = 20;
1641         final WindowState window = createWindow(null, TYPE_APPLICATION, "window", ownerId);
1642         window.mAttrs.packageName = testPackage;
1643         assertFalse(window.isSecureLocked());
1644 
1645         PackageInfo blockedPackage = new PackageInfo(testPackage, ownerId);
1646         ArraySet<PackageInfo> blockedPackages = new ArraySet();
1647         blockedPackages.add(blockedPackage);
1648         mWm.mSensitiveContentPackages.addBlockScreenCaptureForApps(blockedPackages);
1649         assertTrue(window.isSecureLocked());
1650 
1651         mWm.mSensitiveContentPackages.removeBlockScreenCaptureForApps(blockedPackages);
1652         assertFalse(window.isSecureLocked());
1653     }
1654 }
1655