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