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