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