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_ASSISTANT;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
25 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
26 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
27 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
28 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
29 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
30 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
31 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
32 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
33 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
34 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
35 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
36 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
37 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
38 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
39 
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
43 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
44 import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER;
45 
46 import static com.google.common.truth.Truth.assertThat;
47 
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertNotNull;
50 import static org.junit.Assert.assertTrue;
51 import static org.mockito.Mockito.mock;
52 import static org.mockito.Mockito.when;
53 
54 import android.graphics.PixelFormat;
55 import android.graphics.Rect;
56 import android.os.Binder;
57 import android.platform.test.annotations.Presubmit;
58 import android.util.SparseBooleanArray;
59 import android.view.IRecentsAnimationRunner;
60 import android.view.SurfaceControl;
61 import android.view.SurfaceSession;
62 import android.window.ScreenCapture;
63 
64 import androidx.test.filters.SmallTest;
65 
66 import org.junit.After;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 
70 import java.util.ArrayList;
71 import java.util.HashMap;
72 import java.util.LinkedList;
73 import java.util.function.Function;
74 
75 /**
76  * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method.
77  *
78  * Build/Install/Run:
79  *  atest WmTests:ZOrderingTests
80  */
81 @SmallTest
82 @Presubmit
83 @WindowTestsBase.UseTestDisplay(addAllCommonWindows = true)
84 @RunWith(WindowTestRunner.class)
85 public class ZOrderingTests extends WindowTestsBase {
86 
87     private static class LayerRecordingTransaction extends SurfaceControl.Transaction {
88         // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
89         // such that we can keep track of the parents of Surfaces as they are constructed.
90         private final HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
91         HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
92         HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
93 
94         @Override
setLayer(SurfaceControl sc, int layer)95         public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
96             mRelativeLayersForControl.remove(sc);
97             mLayersForControl.put(sc, layer);
98             return this;
99         }
100 
101         @Override
setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int layer)102         public SurfaceControl.Transaction setRelativeLayer(SurfaceControl sc,
103                 SurfaceControl relativeTo,
104                 int layer) {
105             mRelativeLayersForControl.put(sc, relativeTo);
106             mLayersForControl.put(sc, layer);
107             return this;
108         }
109 
getLayer(SurfaceControl sc)110         private int getLayer(SurfaceControl sc) {
111             return mLayersForControl.getOrDefault(sc, 0);
112         }
113 
getRelativeLayer(SurfaceControl sc)114         private SurfaceControl getRelativeLayer(SurfaceControl sc) {
115             return mRelativeLayersForControl.get(sc);
116         }
117 
addParentFor(SurfaceControl child, SurfaceControl parent)118         void addParentFor(SurfaceControl child, SurfaceControl parent) {
119             mParentFor.put(child, parent);
120         }
121 
getParentFor(SurfaceControl child)122         SurfaceControl getParentFor(SurfaceControl child) {
123             return mParentFor.get(child);
124         }
125 
126         @Override
close()127         public void close() {
128 
129         }
130     }
131 
132     private static class HierarchyRecorder extends SurfaceControl.Builder {
133         private LayerRecordingTransaction mTransaction;
134         private SurfaceControl mPendingParent;
135 
HierarchyRecorder(SurfaceSession s, LayerRecordingTransaction transaction)136         HierarchyRecorder(SurfaceSession s, LayerRecordingTransaction transaction) {
137             super(s);
138             mTransaction = transaction;
139         }
140 
141         @Override
setParent(SurfaceControl sc)142         public SurfaceControl.Builder setParent(SurfaceControl sc) {
143             mPendingParent = sc;
144             return super.setParent(sc);
145         }
146 
147         @Override
build()148         public SurfaceControl build() {
149             final SurfaceControl sc = super.build();
150             mTransaction.addParentFor(sc, mPendingParent);
151             mPendingParent = null;
152             return sc;
153         }
154     }
155 
156     private static class HierarchyRecordingBuilderFactory implements Function<SurfaceSession,
157             SurfaceControl.Builder> {
158         private LayerRecordingTransaction mTransaction;
159 
HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction)160         HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) {
161             mTransaction = transaction;
162         }
163 
164         @Override
apply(SurfaceSession s)165         public SurfaceControl.Builder apply(SurfaceSession s) {
166             final LayerRecordingTransaction transaction = mTransaction;
167             return new HierarchyRecorder(s, transaction);
168         }
169     }
170 
171     private LayerRecordingTransaction mTransaction;
172 
173     @Override
beforeCreateTestDisplay()174     void beforeCreateTestDisplay() {
175         // We can't use @Before here because it may happen after WindowTestsBase @Before
176         // which is after construction of the DisplayContent, meaning the HierarchyRecorder
177         // would miss construction of the top-level layers.
178         mTransaction = new LayerRecordingTransaction();
179         mWm.mSurfaceControlFactory = new HierarchyRecordingBuilderFactory(mTransaction);
180         mWm.mTransactionFactory = () -> mTransaction;
181     }
182 
183     @After
tearDown()184     public void tearDown() {
185         mTransaction.close();
186     }
187 
getAncestors(LayerRecordingTransaction t, SurfaceControl sc)188     private static LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t,
189             SurfaceControl sc) {
190         LinkedList<SurfaceControl> p = new LinkedList<>();
191         SurfaceControl current = sc;
192         do {
193             p.addLast(current);
194 
195             SurfaceControl rs = t.getRelativeLayer(current);
196             if (rs != null) {
197                 current = rs;
198             } else {
199                 current = t.getParentFor(current);
200             }
201         } while (current != null);
202         return p;
203     }
204 
205 
assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left, SurfaceControl right)206     private static void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
207             SurfaceControl right) {
208         final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
209         final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
210 
211         SurfaceControl leftTop = leftParentChain.peekLast();
212         SurfaceControl rightTop = rightParentChain.peekLast();
213         while (leftTop != null && rightTop != null && leftTop == rightTop) {
214             leftParentChain.removeLast();
215             rightParentChain.removeLast();
216             leftTop = leftParentChain.peekLast();
217             rightTop = rightParentChain.peekLast();
218         }
219 
220         if (rightTop == null) { // right is the parent of left.
221             assertThat(t.getLayer(leftTop)).isGreaterThan(0);
222         } else if (leftTop == null) { // left is the parent of right.
223             assertThat(t.getLayer(rightTop)).isLessThan(0);
224         } else {
225             assertThat(t.getLayer(leftTop)).isGreaterThan(t.getLayer(rightTop));
226         }
227     }
228 
assertWindowHigher(WindowState left, WindowState right)229     void assertWindowHigher(WindowState left, WindowState right) {
230         assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
231     }
232 
createWindow(String name)233     WindowState createWindow(String name) {
234         return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
235     }
236 
237     @Test
testAssignWindowLayers_ForImeWithNoTarget()238     public void testAssignWindowLayers_ForImeWithNoTarget() {
239         mDisplayContent.setImeLayeringTarget(null);
240         mDisplayContent.assignChildLayers(mTransaction);
241 
242         // The Ime has an higher base layer than app windows and lower base layer than system
243         // windows, so it should be above app windows and below system windows if there isn't an IME
244         // target.
245         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
246         assertWindowHigher(mImeWindow, mAppWindow);
247         assertWindowHigher(mNavBarWindow, mImeWindow);
248         assertWindowHigher(mStatusBarWindow, mImeWindow);
249 
250         // And, IME dialogs should always have an higher layer than the IME.
251         assertWindowHigher(mImeDialogWindow, mImeWindow);
252     }
253 
254     @Test
testAssignWindowLayers_ForImeWithAppTarget()255     public void testAssignWindowLayers_ForImeWithAppTarget() {
256         final WindowState imeAppTarget = createWindow("imeAppTarget");
257         mDisplayContent.setImeLayeringTarget(imeAppTarget);
258 
259         mDisplayContent.assignChildLayers(mTransaction);
260 
261         // Ime should be above all app windows and below system windows if it is targeting an app
262         // window.
263         assertWindowHigher(mImeWindow, imeAppTarget);
264         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
265         assertWindowHigher(mImeWindow, mAppWindow);
266         assertWindowHigher(mNavBarWindow, mImeWindow);
267         assertWindowHigher(mStatusBarWindow, mImeWindow);
268 
269         // And, IME dialogs should always have an higher layer than the IME.
270         assertWindowHigher(mImeDialogWindow, mImeWindow);
271     }
272 
273     @Test
testAssignWindowLayers_ForImeWithAppTargetWithChildWindows()274     public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
275         final WindowState imeAppTarget = createWindow("imeAppTarget");
276         final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
277                 TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
278                 "imeAppTargetChildAboveWindow");
279         final WindowState imeAppTargetChildBelowWindow = createWindow(imeAppTarget,
280                 TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
281                 "imeAppTargetChildBelowWindow");
282 
283         mDisplayContent.setImeLayeringTarget(imeAppTarget);
284         makeWindowVisible(mImeWindow);
285         mDisplayContent.assignChildLayers(mTransaction);
286 
287         // Ime should be above all app windows except for child windows that are z-ordered above it
288         // and below system windows if it is targeting an app window.
289         assertWindowHigher(mImeWindow, imeAppTarget);
290         assertWindowHigher(imeAppTargetChildAboveWindow, mImeWindow);
291         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
292         assertWindowHigher(mImeWindow, mAppWindow);
293         assertWindowHigher(mNavBarWindow, mImeWindow);
294         assertWindowHigher(mStatusBarWindow, mImeWindow);
295 
296         // And, IME dialogs should always have an higher layer than the IME.
297         assertWindowHigher(mImeDialogWindow, mImeWindow);
298     }
299 
300     @Test
testAssignWindowLayers_ForImeWithAppTargetAndAppAbove()301     public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
302         final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
303         final WindowState imeAppTarget = createWindow("imeAppTarget");
304         final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
305 
306         mDisplayContent.setImeLayeringTarget(imeAppTarget);
307         mDisplayContent.setImeControlTarget(imeAppTarget);
308         mDisplayContent.assignChildLayers(mTransaction);
309 
310         // Ime should be above all app windows except for non-fullscreen app window above it and
311         // below system windows if it is targeting an app window.
312         assertWindowHigher(mImeWindow, imeAppTarget);
313         assertWindowHigher(mImeWindow, appBelowImeTarget);
314         assertWindowHigher(appAboveImeTarget, mImeWindow);
315         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
316         assertWindowHigher(mImeWindow, mAppWindow);
317         assertWindowHigher(mNavBarWindow, mImeWindow);
318         assertWindowHigher(mStatusBarWindow, mImeWindow);
319 
320         // And, IME dialogs should always have an higher layer than the IME.
321         assertWindowHigher(mImeDialogWindow, mImeWindow);
322     }
323 
324     @Test
testAssignWindowLayers_ForImeNonAppImeTarget()325     public void testAssignWindowLayers_ForImeNonAppImeTarget() {
326         final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
327                 mDisplayContent, "imeSystemOverlayTarget",
328                 true /* ownerCanAddInternalSystemWindow */);
329 
330         mDisplayContent.setImeLayeringTarget(imeSystemOverlayTarget);
331         mDisplayContent.assignChildLayers(mTransaction);
332 
333         // The IME target base layer is higher than all window except for the nav bar window, so the
334         // IME should be above all windows except for the nav bar.
335         assertWindowHigher(mImeWindow, imeSystemOverlayTarget);
336         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
337         assertWindowHigher(mImeWindow, mAppWindow);
338 
339         // The IME has a higher base layer than the status bar so we may expect it to go
340         // above the status bar once they are both in the Non-App layer, as past versions of this
341         // test enforced. However this seems like the wrong behavior unless the status bar is the
342         // IME target.
343         assertWindowHigher(mNavBarWindow, mImeWindow);
344         assertWindowHigher(mStatusBarWindow, mImeWindow);
345 
346         // And, IME dialogs should always have an higher layer than the IME.
347         assertWindowHigher(mImeDialogWindow, mImeWindow);
348     }
349 
350     @Test
testAssignWindowLayers_ForStatusBarImeTarget()351     public void testAssignWindowLayers_ForStatusBarImeTarget() {
352         mDisplayContent.setImeLayeringTarget(mStatusBarWindow);
353         mDisplayContent.setImeControlTarget(mStatusBarWindow);
354         mDisplayContent.assignChildLayers(mTransaction);
355 
356         assertWindowHigher(mImeWindow, mChildAppWindowAbove);
357         assertWindowHigher(mImeWindow, mAppWindow);
358         assertWindowHigher(mImeWindow, mStatusBarWindow);
359 
360         // And, IME dialogs should always have an higher layer than the IME.
361         assertWindowHigher(mImeDialogWindow, mImeWindow);
362     }
363 
364     @Test
testStackLayers()365     public void testStackLayers() {
366         final WindowState anyWindow1 = createWindow("anyWindow");
367         final WindowState pinnedStackWindow = createWindow(null, WINDOWING_MODE_PINNED,
368                 ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
369                 "pinnedStackWindow");
370         final WindowState dockedStackWindow = createWindow(null,
371                 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
372                 mDisplayContent, "dockedStackWindow");
373         final WindowState assistantStackWindow = createWindow(null,
374                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
375                 mDisplayContent, "assistantStackWindow");
376         final WindowState homeActivityWindow = createWindow(null, WINDOWING_MODE_FULLSCREEN,
377                 ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION,
378                 mDisplayContent, "homeActivityWindow");
379         final WindowState anyWindow2 = createWindow("anyWindow2");
380 
381         mDisplayContent.assignChildLayers(mTransaction);
382 
383         assertWindowHigher(dockedStackWindow, homeActivityWindow);
384         assertWindowHigher(assistantStackWindow, homeActivityWindow);
385         assertWindowHigher(pinnedStackWindow, homeActivityWindow);
386         assertWindowHigher(anyWindow1, homeActivityWindow);
387         assertWindowHigher(anyWindow2, homeActivityWindow);
388         assertWindowHigher(pinnedStackWindow, anyWindow1);
389         assertWindowHigher(pinnedStackWindow, anyWindow2);
390         assertWindowHigher(pinnedStackWindow, dockedStackWindow);
391         assertWindowHigher(pinnedStackWindow, assistantStackWindow);
392     }
393 
394     @Test
testAssignWindowLayers_ForSysUiPanels()395     public void testAssignWindowLayers_ForSysUiPanels() {
396         final WindowState navBarPanel =
397                 createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
398         final WindowState statusBarPanel =
399                 createWindow(null, TYPE_STATUS_BAR_ADDITIONAL, mDisplayContent,
400                         "StatusBarAdditional");
401         final WindowState statusBarSubPanel =
402                 createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, mDisplayContent, "StatusBarSubPanel");
403         mDisplayContent.assignChildLayers(mTransaction);
404 
405         // Ime should be above all app windows and below system windows if it is targeting an app
406         // window.
407         assertWindowHigher(navBarPanel, mNavBarWindow);
408         assertWindowHigher(statusBarPanel, mStatusBarWindow);
409         assertWindowHigher(statusBarSubPanel, statusBarPanel);
410     }
411 
412     @Test
testAssignWindowLayers_ForImeOnAppWithRecentsAnimating()413     public void testAssignWindowLayers_ForImeOnAppWithRecentsAnimating() {
414         final WindowState imeAppTarget = createWindow(null, TYPE_APPLICATION,
415                 mAppWindow.mActivityRecord, "imeAppTarget");
416         mDisplayContent.setImeInputTarget(imeAppTarget);
417         mDisplayContent.setImeLayeringTarget(imeAppTarget);
418         mDisplayContent.setImeControlTarget(imeAppTarget);
419         mDisplayContent.updateImeParent();
420 
421         // Simulate the ime layering target task is animating with recents animation.
422         final Task imeAppTargetTask = imeAppTarget.getTask();
423         final SurfaceAnimator imeTargetTaskAnimator = imeAppTargetTask.mSurfaceAnimator;
424         spyOn(imeTargetTaskAnimator);
425         doReturn(ANIMATION_TYPE_RECENTS).when(imeTargetTaskAnimator).getAnimationType();
426         doReturn(true).when(imeTargetTaskAnimator).isAnimating();
427 
428         mDisplayContent.assignChildLayers(mTransaction);
429 
430         // Ime should on top of the application window when in recents animation and keep
431         // attached on app.
432         assertTrue(mDisplayContent.shouldImeAttachedToApp());
433         assertWindowHigher(mImeWindow, imeAppTarget);
434     }
435 
436     @Test
testAssignWindowLayers_ForImeOnPopupImeLayeringTarget()437     public void testAssignWindowLayers_ForImeOnPopupImeLayeringTarget() {
438         final WindowState imeAppTarget = createWindow(null, TYPE_APPLICATION,
439                 mAppWindow.mActivityRecord, "imeAppTarget");
440         mDisplayContent.setImeInputTarget(imeAppTarget);
441         mDisplayContent.setImeLayeringTarget(imeAppTarget);
442         mDisplayContent.setImeControlTarget(imeAppTarget);
443 
444         // Set a popup IME layering target and keeps the original IME control target behinds it.
445         final WindowState popupImeTargetWin = createWindow(imeAppTarget,
446                 TYPE_APPLICATION_SUB_PANEL, mAppWindow.mActivityRecord, "popupImeTargetWin");
447         mDisplayContent.setImeLayeringTarget(popupImeTargetWin);
448         mDisplayContent.updateImeParent();
449 
450         // Ime should on top of the popup IME layering target window.
451         mDisplayContent.assignChildLayers(mTransaction);
452         assertWindowHigher(mImeWindow, popupImeTargetWin);
453     }
454 
455 
456     @Test
testAssignWindowLayers_ForNegativelyZOrderedSubtype()457     public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() {
458         // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
459         // then we can drop all negative layering on the windowing side.
460 
461         final WindowState anyWindow = createWindow("anyWindow");
462         final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
463                 "TypeApplicationMediaChild");
464         final WindowState mediaOverlayChild = createWindow(anyWindow,
465                 TYPE_APPLICATION_MEDIA_OVERLAY,
466                 mDisplayContent, "TypeApplicationMediaOverlayChild");
467 
468         mDisplayContent.assignChildLayers(mTransaction);
469 
470         assertWindowHigher(anyWindow, mediaOverlayChild);
471         assertWindowHigher(mediaOverlayChild, child);
472     }
473 
474     @Test
testAssignWindowLayers_ForPostivelyZOrderedSubtype()475     public void testAssignWindowLayers_ForPostivelyZOrderedSubtype() {
476         final WindowState anyWindow = createWindow("anyWindow");
477         final ArrayList<WindowState> childList = new ArrayList<>();
478         childList.add(createWindow(anyWindow, TYPE_APPLICATION_PANEL, mDisplayContent,
479                 "TypeApplicationPanelChild"));
480         childList.add(createWindow(anyWindow, TYPE_APPLICATION_SUB_PANEL, mDisplayContent,
481                 "TypeApplicationSubPanelChild"));
482         childList.add(createWindow(anyWindow, TYPE_APPLICATION_ATTACHED_DIALOG, mDisplayContent,
483                 "TypeApplicationAttachedDialogChild"));
484         childList.add(createWindow(anyWindow, TYPE_APPLICATION_ABOVE_SUB_PANEL, mDisplayContent,
485                 "TypeApplicationAboveSubPanelPanelChild"));
486 
487         final LayerRecordingTransaction t = mTransaction;
488         mDisplayContent.assignChildLayers(t);
489 
490         for (int i = childList.size() - 1; i >= 0; i--) {
491             assertThat(t.getLayer(childList.get(i).getSurfaceControl()))
492                     .isGreaterThan(PRESERVED_SURFACE_LAYER);
493         }
494     }
495 
496     @Test
testAttachNavBarWhenEnteringRecents_expectNavBarHigherThanIme()497     public void testAttachNavBarWhenEnteringRecents_expectNavBarHigherThanIme() {
498         // create RecentsAnimationController
499         IRecentsAnimationRunner mockRunner = mock(IRecentsAnimationRunner.class);
500         when(mockRunner.asBinder()).thenReturn(new Binder());
501         final int displayId = mDisplayContent.getDisplayId();
502         RecentsAnimationController controller = new RecentsAnimationController(
503                 mWm, mockRunner, null, displayId);
504         spyOn(controller);
505         doReturn(mNavBarWindow).when(controller).getNavigationBarWindow();
506         mWm.setRecentsAnimationController(controller);
507 
508         // set ime visible
509         spyOn(mDisplayContent.mInputMethodWindow);
510         doReturn(true).when(mDisplayContent.mInputMethodWindow).isVisible();
511 
512         DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
513         spyOn(policy);
514         doReturn(true).when(policy).shouldAttachNavBarToAppDuringTransition();
515 
516         // create home activity
517         Task rootHomeTask = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask();
518         final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
519                 .setParentTask(rootHomeTask)
520                 .setCreateTask(true)
521                 .build();
522         homeActivity.setVisibility(true);
523 
524         // start recent animation
525         controller.initialize(homeActivity.getActivityType(), new SparseBooleanArray(),
526                 homeActivity);
527 
528         mDisplayContent.assignChildLayers(mTransaction);
529         assertZOrderGreaterThan(mTransaction, mNavBarWindow.mToken.getSurfaceControl(),
530                 mDisplayContent.getImeContainer().getSurfaceControl());
531     }
532 
533     @Test
testPopupWindowAndParentIsImeTarget_expectHigherThanIme_inMultiWindow()534     public void testPopupWindowAndParentIsImeTarget_expectHigherThanIme_inMultiWindow() {
535         // Simulate the app window is in multi windowing mode and being IME target
536         mAppWindow.getConfiguration().windowConfiguration.setWindowingMode(
537                 WINDOWING_MODE_MULTI_WINDOW);
538         mDisplayContent.setImeLayeringTarget(mAppWindow);
539         mDisplayContent.setImeInputTarget(mAppWindow);
540         makeWindowVisible(mImeWindow);
541 
542         // Create a popupWindow
543         assertWindowHigher(mImeWindow, mAppWindow);
544         final WindowState popupWindow = createWindow(mAppWindow, TYPE_APPLICATION_PANEL,
545                 mDisplayContent, "PopupWindow");
546         spyOn(popupWindow);
547 
548         mDisplayContent.assignChildLayers(mTransaction);
549 
550         // Verify the surface layer of the popupWindow should higher than IME
551         verify(popupWindow).needsRelativeLayeringToIme();
552         assertThat(popupWindow.needsRelativeLayeringToIme()).isTrue();
553         assertZOrderGreaterThan(mTransaction, popupWindow.getSurfaceControl(),
554                 mDisplayContent.getImeContainer().getSurfaceControl());
555     }
556 
557     @Test
testSystemDialogWindow_expectHigherThanIme_inMultiWindow()558     public void testSystemDialogWindow_expectHigherThanIme_inMultiWindow() {
559         // Simulate the app window is in multi windowing mode and being IME target
560         mAppWindow.getConfiguration().windowConfiguration.setWindowingMode(
561                 WINDOWING_MODE_MULTI_WINDOW);
562         mDisplayContent.setImeLayeringTarget(mAppWindow);
563         mDisplayContent.setImeInputTarget(mAppWindow);
564         makeWindowVisible(mImeWindow);
565 
566         // Create a popupWindow
567         final WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
568                 mDisplayContent, "SystemDialog", true);
569         systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
570         spyOn(systemDialogWindow);
571 
572         mDisplayContent.assignChildLayers(mTransaction);
573 
574         // Verify the surface layer of the popupWindow should higher than IME
575         verify(systemDialogWindow).needsRelativeLayeringToIme();
576         assertThat(systemDialogWindow.needsRelativeLayeringToIme()).isTrue();
577         assertZOrderGreaterThan(mTransaction, systemDialogWindow.getSurfaceControl(),
578                 mDisplayContent.getImeContainer().getSurfaceControl());
579     }
580 
581     @Test
testImeScreenshotLayer()582     public void testImeScreenshotLayer() {
583         final Task task = createTask(mDisplayContent);
584         final WindowState imeAppTarget = createAppWindow(task, TYPE_APPLICATION, "imeAppTarget");
585         final Rect bounds = mImeWindow.getParentFrame();
586         final ScreenCapture.ScreenshotHardwareBuffer imeBuffer =
587                 ScreenCapture.captureLayersExcluding(mImeWindow.getSurfaceControl(),
588                 bounds, 1.0f, PixelFormat.RGB_565, null);
589 
590         spyOn(mDisplayContent.mWmService.mTaskSnapshotController);
591         doReturn(imeBuffer).when(mDisplayContent.mWmService.mTaskSnapshotController)
592                 .snapshotImeFromAttachedTask(task);
593 
594         mDisplayContent.showImeScreenshot(imeAppTarget);
595 
596         assertEquals(imeAppTarget, mDisplayContent.mImeScreenshot.getImeTarget());
597         assertNotNull(mDisplayContent.mImeScreenshot);
598         assertZOrderGreaterThan(mTransaction,
599                 mDisplayContent.mImeScreenshot.getImeScreenshotSurface(),
600                 imeAppTarget.mSurfaceControl);
601     }
602 }
603