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