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