1 /* 2 * Copyright (C) 2020 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.Manifest.permission.ADD_TRUSTED_DISPLAY; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 24 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; 25 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; 26 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; 27 import static android.view.Display.DEFAULT_DISPLAY; 28 import static android.view.Display.FLAG_OWN_FOCUS; 29 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 30 import static android.view.WindowManager.LayoutParams.FLAG_SECURE; 31 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY; 32 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; 33 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; 34 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 35 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 36 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 37 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 38 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 39 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 40 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; 41 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 46 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND; 47 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; 48 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR; 49 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; 50 51 import static com.google.common.truth.Truth.assertThat; 52 53 import static org.junit.Assert.assertEquals; 54 import static org.junit.Assert.assertFalse; 55 import static org.junit.Assert.assertNotNull; 56 import static org.junit.Assert.assertNull; 57 import static org.junit.Assert.assertThrows; 58 import static org.junit.Assert.assertTrue; 59 import static org.mockito.ArgumentMatchers.any; 60 import static org.mockito.ArgumentMatchers.anyBoolean; 61 import static org.mockito.ArgumentMatchers.anyInt; 62 import static org.mockito.ArgumentMatchers.anyString; 63 import static org.mockito.ArgumentMatchers.argThat; 64 import static org.mockito.ArgumentMatchers.eq; 65 import static org.mockito.Mockito.mock; 66 import static org.mockito.Mockito.times; 67 import static org.mockito.Mockito.verify; 68 import static org.mockito.Mockito.when; 69 70 import android.content.pm.ActivityInfo; 71 import android.graphics.Point; 72 import android.graphics.Rect; 73 import android.hardware.display.VirtualDisplay; 74 import android.os.Binder; 75 import android.os.Bundle; 76 import android.os.IBinder; 77 import android.os.InputConfig; 78 import android.os.Process; 79 import android.os.RemoteException; 80 import android.os.UserHandle; 81 import android.platform.test.annotations.Presubmit; 82 import android.util.DisplayMetrics; 83 import android.util.MergedConfiguration; 84 import android.view.ContentRecordingSession; 85 import android.view.IWindow; 86 import android.view.IWindowSessionCallback; 87 import android.view.InputChannel; 88 import android.view.InsetsSourceControl; 89 import android.view.InsetsState; 90 import android.view.Surface; 91 import android.view.SurfaceControl; 92 import android.view.View; 93 import android.view.WindowInsets; 94 import android.view.WindowManager; 95 import android.view.WindowManager.LayoutParams; 96 import android.window.ClientWindowFrames; 97 import android.window.ScreenCapture; 98 import android.window.WindowContainerToken; 99 100 import androidx.test.filters.SmallTest; 101 import androidx.test.platform.app.InstrumentationRegistry; 102 103 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 104 import com.android.internal.os.IResultReceiver; 105 import com.android.server.LocalServices; 106 107 import org.junit.Rule; 108 import org.junit.Test; 109 import org.junit.runner.RunWith; 110 import org.mockito.ArgumentCaptor; 111 112 /** 113 * Build/Install/Run: 114 * atest WmTests:WindowManagerServiceTests 115 */ 116 @SmallTest 117 @Presubmit 118 @RunWith(WindowTestRunner.class) 119 public class WindowManagerServiceTests extends WindowTestsBase { 120 121 @Rule 122 public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( 123 InstrumentationRegistry.getInstrumentation().getUiAutomation(), 124 ADD_TRUSTED_DISPLAY); 125 126 @Test testIsRequestedOrientationMapped()127 public void testIsRequestedOrientationMapped() { 128 mWm.setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled*/ true, 129 /* fromOrientations */ new int[]{1}, /* toOrientations */ new int[]{2}); 130 assertThat(mWm.mapOrientationRequest(1)).isEqualTo(2); 131 assertThat(mWm.mapOrientationRequest(3)).isEqualTo(3); 132 133 // Mapping disabled 134 mWm.setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled*/ false, 135 /* fromOrientations */ null, /* toOrientations */ null); 136 assertThat(mWm.mapOrientationRequest(1)).isEqualTo(1); 137 assertThat(mWm.mapOrientationRequest(3)).isEqualTo(3); 138 } 139 140 @Test testAddWindowToken()141 public void testAddWindowToken() { 142 IBinder token = mock(IBinder.class); 143 mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId(), null /* options */); 144 145 WindowToken windowToken = mWm.mRoot.getWindowToken(token); 146 assertFalse(windowToken.mRoundedCornerOverlay); 147 assertFalse(windowToken.isFromClient()); 148 } 149 150 @Test testTaskFocusChange_rootTaskNotHomeType_focusChanges()151 public void testTaskFocusChange_rootTaskNotHomeType_focusChanges() throws RemoteException { 152 DisplayContent display = createNewDisplay(); 153 // Current focused window 154 Task focusedRootTask = createTask( 155 display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 156 Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */); 157 WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); 158 mDisplayContent.mCurrentFocus = focusedWindow; 159 // Tapped task 160 Task tappedRootTask = createTask( 161 display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 162 Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); 163 spyOn(mWm.mAtmService); 164 165 mWm.handleTaskFocusChange(tappedTask, null /* window */); 166 167 verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null); 168 } 169 170 @Test testTaskFocusChange_rootTaskHomeTypeWithSameTaskDisplayArea_focusDoesNotChange()171 public void testTaskFocusChange_rootTaskHomeTypeWithSameTaskDisplayArea_focusDoesNotChange() 172 throws RemoteException { 173 DisplayContent display = createNewDisplay(); 174 // Current focused window 175 Task focusedRootTask = createTask( 176 display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 177 Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */); 178 WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); 179 mDisplayContent.mCurrentFocus = focusedWindow; 180 // Tapped home task 181 Task tappedRootTask = createTask( 182 display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); 183 Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); 184 spyOn(mWm.mAtmService); 185 186 mWm.handleTaskFocusChange(tappedTask, null /* window */); 187 188 verify(mWm.mAtmService, never()).setFocusedTask(tappedTask.mTaskId, null); 189 } 190 191 @Test testTaskFocusChange_rootTaskHomeTypeWithDifferentTaskDisplayArea_focusChanges()192 public void testTaskFocusChange_rootTaskHomeTypeWithDifferentTaskDisplayArea_focusChanges() 193 throws RemoteException { 194 final DisplayContent display = createNewDisplay(); 195 final TaskDisplayArea secondTda = createTaskDisplayArea( 196 display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST); 197 // Current focused window 198 Task focusedRootTask = createTask( 199 display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 200 Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */); 201 WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window"); 202 mDisplayContent.mCurrentFocus = focusedWindow; 203 // Tapped home task on another task display area 204 Task tappedRootTask = createTask(secondTda, WINDOWING_MODE_FULLSCREEN, 205 ACTIVITY_TYPE_STANDARD); 206 Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */); 207 spyOn(mWm.mAtmService); 208 209 mWm.handleTaskFocusChange(tappedTask, null /* window */); 210 211 verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null); 212 } 213 214 @Test testDismissKeyguardCanWakeUp()215 public void testDismissKeyguardCanWakeUp() { 216 doReturn(true).when(mWm).checkCallingPermission(anyString(), anyString()); 217 doReturn(true).when(mWm.mAtmService.mKeyguardController).isShowingDream(); 218 doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); 219 mWm.dismissKeyguard(null, "test-dismiss-keyguard"); 220 verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); 221 } 222 223 @Test testRelayoutExitingWindow()224 public void testRelayoutExitingWindow() { 225 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); 226 final WindowSurfaceController surfaceController = mock(WindowSurfaceController.class); 227 win.mWinAnimator.mSurfaceController = surfaceController; 228 win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; 229 doReturn(true).when(surfaceController).hasSurface(); 230 spyOn(win.mTransitionController); 231 doReturn(true).when(win.mTransitionController).isShellTransitionsEnabled(); 232 doReturn(true).when(win.mTransitionController).inTransition( 233 eq(win.mActivityRecord)); 234 win.mViewVisibility = View.VISIBLE; 235 win.mHasSurface = true; 236 win.mActivityRecord.mAppStopped = true; 237 mWm.mWindowMap.put(win.mClient.asBinder(), win); 238 spyOn(mWm.mWindowPlacerLocked); 239 // Skip unnecessary operations of relayout. 240 doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean()); 241 final int w = 100; 242 final int h = 200; 243 final ClientWindowFrames outFrames = new ClientWindowFrames(); 244 final MergedConfiguration outConfig = new MergedConfiguration(); 245 final SurfaceControl outSurfaceControl = new SurfaceControl(); 246 final InsetsState outInsetsState = new InsetsState(); 247 final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); 248 final Bundle outBundle = new Bundle(); 249 mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, 250 outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); 251 // The window is in transition, so its destruction is deferred. 252 assertTrue(win.mAnimatingExit); 253 assertFalse(win.mDestroying); 254 assertTrue(win.mTransitionController.mAnimatingExitWindows.contains(win)); 255 256 win.mAnimatingExit = false; 257 win.mViewVisibility = View.VISIBLE; 258 win.mActivityRecord.setVisibleRequested(false); 259 win.mActivityRecord.setVisible(false); 260 mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0, 261 outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); 262 // Because the window is already invisible, it doesn't need to apply exiting animation 263 // and WMS#tryStartExitingAnimation() will destroy the surface directly. 264 assertFalse(win.mAnimatingExit); 265 assertFalse(win.mHasSurface); 266 assertNull(win.mWinAnimator.mSurfaceController); 267 268 doReturn(mSystemServicesTestRule.mTransaction).when(SurfaceControl::getGlobalTransaction); 269 // Invisible requested activity should not get the last config even if its view is visible. 270 mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0, 271 outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); 272 assertEquals(0, outConfig.getMergedConfiguration().densityDpi); 273 // Non activity window can still get the last config. 274 win.mActivityRecord = null; 275 win.fillClientWindowFramesAndConfiguration(outFrames, outConfig, 276 false /* useLatestConfig */, true /* relayoutVisible */); 277 assertEquals(win.getConfiguration().densityDpi, 278 outConfig.getMergedConfiguration().densityDpi); 279 } 280 281 @Test testRelayout_firstLayout_dwpcHelperCalledWithCorrectFlags()282 public void testRelayout_firstLayout_dwpcHelperCalledWithCorrectFlags() { 283 // When doing the first layout, the initial flags should be reported as changed to 284 // keepActivityOnWindowFlagsChanged. 285 testRelayoutFlagChanges( 286 /*firstRelayout=*/ true, 287 /*startFlags=*/ FLAG_SECURE, 288 /*startPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 289 /*newFlags=*/ FLAG_SECURE, 290 /*newPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 291 /*expectedChangedFlags=*/ FLAG_SECURE, 292 /*expectedChangedPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 293 /*expectedFlagsValue=*/ FLAG_SECURE, 294 /*expectedPrivateFlagsValue=*/ PRIVATE_FLAG_TRUSTED_OVERLAY); 295 } 296 297 @Test testRelayout_secondLayoutFlagAdded_dwpcHelperCalledWithCorrectFlags()298 public void testRelayout_secondLayoutFlagAdded_dwpcHelperCalledWithCorrectFlags() { 299 testRelayoutFlagChanges( 300 /*firstRelayout=*/ false, 301 /*startFlags=*/ 0, 302 /*startPrivateFlags=*/ 0, 303 /*newFlags=*/ FLAG_SECURE, 304 /*newPrivateFlags=*/ 0, 305 /*expectedChangedFlags=*/ FLAG_SECURE, 306 /*expectedChangedPrivateFlags=*/ 0, 307 /*expectedFlagsValue=*/ FLAG_SECURE, 308 /*expectedPrivateFlagsValue=*/ 0); 309 } 310 311 @Test testRelayout_secondLayoutMultipleFlagsAddOne_dwpcHelperCalledWithCorrectFlags()312 public void testRelayout_secondLayoutMultipleFlagsAddOne_dwpcHelperCalledWithCorrectFlags() { 313 testRelayoutFlagChanges( 314 /*firstRelayout=*/ false, 315 /*startFlags=*/ FLAG_NOT_FOCUSABLE, 316 /*startPrivateFlags=*/ 0, 317 /*newFlags=*/ FLAG_SECURE | FLAG_NOT_FOCUSABLE, 318 /*newPrivateFlags=*/ 0, 319 /*expectedChangedFlags=*/ FLAG_SECURE, 320 /*expectedChangedPrivateFlags=*/ 0, 321 /*expectedFlagsValue=*/ FLAG_SECURE | FLAG_NOT_FOCUSABLE, 322 /*expectedPrivateFlagsValue=*/ 0); 323 } 324 325 @Test testRelayout_secondLayoutPrivateFlagAdded_dwpcHelperCalledWithCorrectFlags()326 public void testRelayout_secondLayoutPrivateFlagAdded_dwpcHelperCalledWithCorrectFlags() { 327 testRelayoutFlagChanges( 328 /*firstRelayout=*/ false, 329 /*startFlags=*/ 0, 330 /*startPrivateFlags=*/ 0, 331 /*newFlags=*/ 0, 332 /*newPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 333 /*expectedChangedFlags=*/ 0, 334 /*expectedChangedPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 335 /*expectedFlagsValue=*/ 0, 336 /*expectedPrivateFlagsValue=*/ PRIVATE_FLAG_TRUSTED_OVERLAY); 337 } 338 339 @Test testRelayout_secondLayoutFlagsRemoved_dwpcHelperCalledWithCorrectFlags()340 public void testRelayout_secondLayoutFlagsRemoved_dwpcHelperCalledWithCorrectFlags() { 341 testRelayoutFlagChanges( 342 /*firstRelayout=*/ false, 343 /*startFlags=*/ FLAG_SECURE, 344 /*startPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 345 /*newFlags=*/ 0, 346 /*newPrivateFlags=*/ 0, 347 /*expectedChangedFlags=*/ FLAG_SECURE, 348 /*expectedChangedPrivateFlags=*/ PRIVATE_FLAG_TRUSTED_OVERLAY, 349 /*expectedFlagsValue=*/ 0, 350 /*expectedPrivateFlagsValue=*/ 0); 351 } 352 353 // Helper method to test relayout of a window, either for the initial layout, or a subsequent 354 // one, and makes sure that the flags and private flags changes and final values are properly 355 // reported to mDwpcHelper.keepActivityOnWindowFlagsChanged. testRelayoutFlagChanges(boolean firstRelayout, int startFlags, int startPrivateFlags, int newFlags, int newPrivateFlags, int expectedChangedFlags, int expectedChangedPrivateFlags, int expectedFlagsValue, int expectedPrivateFlagsValue)356 private void testRelayoutFlagChanges(boolean firstRelayout, int startFlags, 357 int startPrivateFlags, int newFlags, int newPrivateFlags, int expectedChangedFlags, 358 int expectedChangedPrivateFlags, int expectedFlagsValue, 359 int expectedPrivateFlagsValue) { 360 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "appWin"); 361 win.mRelayoutCalled = !firstRelayout; 362 mWm.mWindowMap.put(win.mClient.asBinder(), win); 363 spyOn(mDisplayContent.mDwpcHelper); 364 when(mDisplayContent.mDwpcHelper.hasController()).thenReturn(true); 365 366 win.mAttrs.flags = startFlags; 367 win.mAttrs.privateFlags = startPrivateFlags; 368 369 LayoutParams newParams = new LayoutParams(); 370 newParams.copyFrom(win.mAttrs); 371 newParams.flags = newFlags; 372 newParams.privateFlags = newPrivateFlags; 373 374 int seq = 1; 375 if (!firstRelayout) { 376 win.mRelayoutSeq = 1; 377 seq = 2; 378 } 379 mWm.relayoutWindow(win.mSession, win.mClient, newParams, 100, 200, View.VISIBLE, 0, seq, 380 0, new ClientWindowFrames(), new MergedConfiguration(), 381 new SurfaceControl(), new InsetsState(), new InsetsSourceControl.Array(), 382 new Bundle()); 383 384 ArgumentCaptor<Integer> changedFlags = ArgumentCaptor.forClass(Integer.class); 385 ArgumentCaptor<Integer> changedPrivateFlags = ArgumentCaptor.forClass(Integer.class); 386 ArgumentCaptor<Integer> flagsValue = ArgumentCaptor.forClass(Integer.class); 387 ArgumentCaptor<Integer> privateFlagsValue = ArgumentCaptor.forClass(Integer.class); 388 389 verify(mDisplayContent.mDwpcHelper).keepActivityOnWindowFlagsChanged( 390 any(ActivityInfo.class), changedFlags.capture(), changedPrivateFlags.capture(), 391 flagsValue.capture(), privateFlagsValue.capture()); 392 393 assertThat(changedFlags.getValue()).isEqualTo(expectedChangedFlags); 394 assertThat(changedPrivateFlags.getValue()).isEqualTo(expectedChangedPrivateFlags); 395 assertThat(flagsValue.getValue()).isEqualTo(expectedFlagsValue); 396 assertThat(privateFlagsValue.getValue()).isEqualTo(expectedPrivateFlagsValue); 397 } 398 399 @Test testMoveWindowTokenToDisplay_NullToken_DoNothing()400 public void testMoveWindowTokenToDisplay_NullToken_DoNothing() { 401 mWm.moveWindowTokenToDisplay(null, mDisplayContent.getDisplayId()); 402 403 verify(mDisplayContent, never()).reParentWindowToken(any()); 404 } 405 406 @Test testMoveWindowTokenToDisplay_SameDisplay_DoNothing()407 public void testMoveWindowTokenToDisplay_SameDisplay_DoNothing() { 408 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD_DIALOG, 409 mDisplayContent); 410 411 mWm.moveWindowTokenToDisplay(windowToken.token, mDisplayContent.getDisplayId()); 412 413 verify(mDisplayContent, never()).reParentWindowToken(any()); 414 } 415 416 @Test testMoveWindowTokenToDisplay_DifferentDisplay_DoMoveDisplay()417 public void testMoveWindowTokenToDisplay_DifferentDisplay_DoMoveDisplay() { 418 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD_DIALOG, 419 mDisplayContent); 420 421 mWm.moveWindowTokenToDisplay(windowToken.token, DEFAULT_DISPLAY); 422 423 assertThat(windowToken.getDisplayContent()).isEqualTo(mDefaultDisplay); 424 } 425 426 @Test testAttachWindowContextToWindowToken_InvalidToken_EarlyReturn()427 public void testAttachWindowContextToWindowToken_InvalidToken_EarlyReturn() { 428 spyOn(mWm.mWindowContextListenerController); 429 430 mWm.attachWindowContextToWindowToken(new Binder(), new Binder()); 431 432 verify(mWm.mWindowContextListenerController, never()).getWindowType(any()); 433 } 434 435 @Test(expected = IllegalArgumentException.class) testAttachWindowContextToWindowToken_InvalidWindowType_ThrowException()436 public void testAttachWindowContextToWindowToken_InvalidWindowType_ThrowException() { 437 spyOn(mWm.mWindowContextListenerController); 438 439 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); 440 doReturn(INVALID_WINDOW_TYPE).when(mWm.mWindowContextListenerController) 441 .getWindowType(any()); 442 443 mWm.attachWindowContextToWindowToken(new Binder(), windowToken.token); 444 } 445 446 @Test(expected = IllegalArgumentException.class) testAttachWindowContextToWindowToken_DifferentWindowType_ThrowException()447 public void testAttachWindowContextToWindowToken_DifferentWindowType_ThrowException() { 448 spyOn(mWm.mWindowContextListenerController); 449 450 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); 451 doReturn(TYPE_APPLICATION).when(mWm.mWindowContextListenerController) 452 .getWindowType(any()); 453 454 mWm.attachWindowContextToWindowToken(new Binder(), windowToken.token); 455 } 456 457 @Test testAttachWindowContextToWindowToken_CallerNotValid_EarlyReturn()458 public void testAttachWindowContextToWindowToken_CallerNotValid_EarlyReturn() { 459 spyOn(mWm.mWindowContextListenerController); 460 461 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); 462 doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController) 463 .getWindowType(any()); 464 doReturn(false).when(mWm.mWindowContextListenerController) 465 .assertCallerCanModifyListener(any(), anyBoolean(), anyInt()); 466 467 mWm.attachWindowContextToWindowToken(new Binder(), windowToken.token); 468 469 verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener( 470 any(), any(), anyInt(), anyInt(), any()); 471 } 472 473 @Test testAttachWindowContextToWindowToken_CallerValid_DoRegister()474 public void testAttachWindowContextToWindowToken_CallerValid_DoRegister() { 475 spyOn(mWm.mWindowContextListenerController); 476 477 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); 478 doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController) 479 .getWindowType(any()); 480 doReturn(true).when(mWm.mWindowContextListenerController) 481 .assertCallerCanModifyListener(any(), anyBoolean(), anyInt()); 482 483 final IBinder clientToken = new Binder(); 484 mWm.attachWindowContextToWindowToken(clientToken, windowToken.token); 485 486 verify(mWm.mWindowContextListenerController).registerWindowContainerListener( 487 eq(clientToken), eq(windowToken), anyInt(), eq(TYPE_INPUT_METHOD), 488 eq(windowToken.mOptions)); 489 } 490 491 @Test testAddWindowWithSubWindowTypeByWindowContext()492 public void testAddWindowWithSubWindowTypeByWindowContext() { 493 spyOn(mWm.mWindowContextListenerController); 494 495 final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay); 496 final Session session = new Session(mWm, new IWindowSessionCallback.Stub() { 497 @Override 498 public void onAnimatorScaleChanged(float v) throws RemoteException { 499 } 500 }); 501 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 502 TYPE_APPLICATION_ATTACHED_DIALOG); 503 params.token = windowToken.token; 504 final IBinder windowContextToken = new Binder(); 505 params.setWindowContextToken(windowContextToken); 506 doReturn(true).when(mWm.mWindowContextListenerController) 507 .hasListener(eq(windowContextToken)); 508 doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController) 509 .getWindowType(eq(windowContextToken)); 510 511 mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY, 512 UserHandle.USER_SYSTEM, WindowInsets.Type.defaultVisible(), null, new InsetsState(), 513 new InsetsSourceControl.Array(), new Rect(), new float[1]); 514 515 verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(), 516 any(), anyInt(), anyInt(), any()); 517 } 518 519 @Test testSetInTouchMode_instrumentedProcessGetPermissionToSwitchTouchMode()520 public void testSetInTouchMode_instrumentedProcessGetPermissionToSwitchTouchMode() { 521 // Enable global touch mode 522 mWm.mPerDisplayFocusEnabled = true; 523 524 // Get current touch mode state and setup WMS to run setInTouchMode 525 boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); 526 int callingPid = Binder.getCallingPid(); 527 int callingUid = Binder.getCallingUid(); 528 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 529 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 530 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); 531 532 mWm.setInTouchMode(!currentTouchMode, DEFAULT_DISPLAY); 533 534 verify(mWm.mInputManager).setInTouchMode( 535 !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true, 536 DEFAULT_DISPLAY); 537 } 538 539 @Test testSetInTouchMode_nonInstrumentedProcessDontGetPermissionToSwitchTouchMode()540 public void testSetInTouchMode_nonInstrumentedProcessDontGetPermissionToSwitchTouchMode() { 541 // Enable global touch mode 542 mWm.mPerDisplayFocusEnabled = true; 543 544 // Get current touch mode state and setup WMS to run setInTouchMode 545 boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); 546 int callingPid = Binder.getCallingPid(); 547 int callingUid = Binder.getCallingUid(); 548 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 549 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 550 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(false); 551 552 mWm.setInTouchMode(!currentTouchMode, DEFAULT_DISPLAY); 553 554 verify(mWm.mInputManager).setInTouchMode( 555 !currentTouchMode, callingPid, callingUid, /* hasPermission= */ false, 556 DEFAULT_DISPLAY); 557 } 558 559 @Test testSetInTouchMode_multiDisplay_globalTouchModeUpdate()560 public void testSetInTouchMode_multiDisplay_globalTouchModeUpdate() { 561 // Disable global touch mode 562 mWm.mPerDisplayFocusEnabled = false; 563 564 // Create one extra display 565 final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); 566 final VirtualDisplay virtualDisplayOwnTouchMode = 567 createVirtualDisplay(/* ownFocus= */ true); 568 final int numberOfDisplays = mWm.mRoot.mChildren.size(); 569 assertThat(numberOfDisplays).isAtLeast(3); 570 final int numberOfGlobalTouchModeDisplays = (int) mWm.mRoot.mChildren.stream() 571 .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0) 572 .count(); 573 assertThat(numberOfGlobalTouchModeDisplays).isAtLeast(2); 574 575 // Get current touch mode state and setup WMS to run setInTouchMode 576 boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); 577 int callingPid = Binder.getCallingPid(); 578 int callingUid = Binder.getCallingUid(); 579 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 580 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 581 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); 582 583 mWm.setInTouchMode(!currentTouchMode, DEFAULT_DISPLAY); 584 585 verify(mWm.mInputManager, times(numberOfGlobalTouchModeDisplays)).setInTouchMode( 586 eq(!currentTouchMode), eq(callingPid), eq(callingUid), 587 /* hasPermission= */ eq(true), /* displayId= */ anyInt()); 588 } 589 590 @Test testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate()591 public void testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate() { 592 // Enable global touch mode 593 mWm.mPerDisplayFocusEnabled = true; 594 595 // Create one extra display 596 final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); 597 final int numberOfDisplays = mWm.mRoot.mChildren.size(); 598 assertThat(numberOfDisplays).isAtLeast(2); 599 600 // Get current touch mode state and setup WMS to run setInTouchMode 601 boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); 602 int callingPid = Binder.getCallingPid(); 603 int callingUid = Binder.getCallingUid(); 604 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 605 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 606 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); 607 608 mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId()); 609 610 // Ensure that new display touch mode state has changed. 611 verify(mWm.mInputManager).setInTouchMode( 612 !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true, 613 virtualDisplay.getDisplay().getDisplayId()); 614 } 615 616 @Test testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate()617 public void testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate() { 618 // Disable global touch mode 619 mWm.mPerDisplayFocusEnabled = false; 620 621 // Create one extra display 622 final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ true); 623 final int numberOfDisplays = mWm.mRoot.mChildren.size(); 624 assertThat(numberOfDisplays).isAtLeast(2); 625 626 // Get current touch mode state and setup WMS to run setInTouchMode 627 boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); 628 int callingPid = Binder.getCallingPid(); 629 int callingUid = Binder.getCallingUid(); 630 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 631 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 632 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); 633 634 mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId()); 635 636 // Ensure that new display touch mode state has changed. 637 verify(mWm.mInputManager).setInTouchMode( 638 !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true, 639 virtualDisplay.getDisplay().getDisplayId()); 640 } 641 642 @Test testSetInTouchModeOnAllDisplays_perDisplayFocusDisabled()643 public void testSetInTouchModeOnAllDisplays_perDisplayFocusDisabled() { 644 testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ false); 645 } 646 647 @Test testSetInTouchModeOnAllDisplays_perDisplayFocusEnabled()648 public void testSetInTouchModeOnAllDisplays_perDisplayFocusEnabled() { 649 testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ true); 650 } 651 testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled)652 private void testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled) { 653 // Set global touch mode with the value passed as argument. 654 mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled; 655 656 // Create a couple of extra displays. 657 // setInTouchModeOnAllDisplays should ignore the ownFocus setting. 658 final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); 659 final VirtualDisplay virtualDisplayOwnFocus = createVirtualDisplay(/* ownFocus= */ true); 660 661 int callingPid = Binder.getCallingPid(); 662 int callingUid = Binder.getCallingUid(); 663 doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); 664 when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, 665 android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); 666 667 for (boolean inTouchMode : new boolean[]{true, false}) { 668 mWm.setInTouchModeOnAllDisplays(inTouchMode); 669 for (int i = 0; i < mWm.mRoot.mChildren.size(); ++i) { 670 DisplayContent dc = mWm.mRoot.mChildren.get(i); 671 // All displays that are not already in the desired touch mode are requested to 672 // change their touch mode. 673 if (dc.isInTouchMode() != inTouchMode) { 674 verify(mWm.mInputManager).setInTouchMode( 675 true, callingPid, callingUid, /* hasPermission= */ true, 676 dc.getDisplay().getDisplayId()); 677 } 678 } 679 } 680 } 681 createVirtualDisplay(boolean ownFocus)682 private VirtualDisplay createVirtualDisplay(boolean ownFocus) { 683 // Create virtual display 684 Point surfaceSize = new Point( 685 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(), 686 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height()); 687 int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC; 688 if (ownFocus) { 689 flags |= VIRTUAL_DISPLAY_FLAG_OWN_FOCUS | VIRTUAL_DISPLAY_FLAG_TRUSTED; 690 } 691 VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", 692 surfaceSize.x, surfaceSize.y, DisplayMetrics.DENSITY_140, new Surface(), flags); 693 final int displayId = virtualDisplay.getDisplay().getDisplayId(); 694 mWm.mRoot.onDisplayAdded(displayId); 695 696 // Ensure that virtual display was properly created and stored in WRC 697 assertThat(mWm.mRoot.getDisplayContent( 698 virtualDisplay.getDisplay().getDisplayId())).isNotNull(); 699 700 return virtualDisplay; 701 } 702 703 @Test testGetTaskWindowContainerTokenForLaunchCookie_nullCookie()704 public void testGetTaskWindowContainerTokenForLaunchCookie_nullCookie() { 705 WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(null); 706 assertThat(wct).isNull(); 707 } 708 709 @Test testGetTaskWindowContainerTokenForLaunchCookie_invalidCookie()710 public void testGetTaskWindowContainerTokenForLaunchCookie_invalidCookie() { 711 Binder cookie = new Binder("test cookie"); 712 WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie); 713 assertThat(wct).isNull(); 714 715 final ActivityRecord testActivity = new ActivityBuilder(mAtm) 716 .setCreateTask(true) 717 .build(); 718 719 wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie); 720 assertThat(wct).isNull(); 721 } 722 723 @Test testGetTaskWindowContainerTokenForLaunchCookie_validCookie()724 public void testGetTaskWindowContainerTokenForLaunchCookie_validCookie() { 725 final Binder cookie = new Binder("ginger cookie"); 726 final WindowContainerToken launchRootTask = mock(WindowContainerToken.class); 727 setupActivityWithLaunchCookie(cookie, launchRootTask); 728 729 WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie); 730 assertThat(wct).isEqualTo(launchRootTask); 731 } 732 733 @Test testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies()734 public void testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies() { 735 final Binder cookie1 = new Binder("ginger cookie"); 736 final WindowContainerToken launchRootTask1 = mock(WindowContainerToken.class); 737 setupActivityWithLaunchCookie(cookie1, launchRootTask1); 738 739 setupActivityWithLaunchCookie(new Binder("choc chip cookie"), 740 mock(WindowContainerToken.class)); 741 742 setupActivityWithLaunchCookie(new Binder("peanut butter cookie"), 743 mock(WindowContainerToken.class)); 744 745 WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie1); 746 assertThat(wct).isEqualTo(launchRootTask1); 747 } 748 749 @Test testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies_noneValid()750 public void testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies_noneValid() { 751 setupActivityWithLaunchCookie(new Binder("ginger cookie"), 752 mock(WindowContainerToken.class)); 753 754 setupActivityWithLaunchCookie(new Binder("choc chip cookie"), 755 mock(WindowContainerToken.class)); 756 757 setupActivityWithLaunchCookie(new Binder("peanut butter cookie"), 758 mock(WindowContainerToken.class)); 759 760 WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie( 761 new Binder("some other cookie")); 762 assertThat(wct).isNull(); 763 } 764 765 @Test setContentRecordingSession_sessionNull_returnsTrue()766 public void setContentRecordingSession_sessionNull_returnsTrue() { 767 WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class); 768 769 boolean result = wmInternal.setContentRecordingSession(/* incomingSession= */ null); 770 771 assertThat(result).isTrue(); 772 } 773 774 @Test setContentRecordingSession_sessionContentDisplay_returnsTrue()775 public void setContentRecordingSession_sessionContentDisplay_returnsTrue() { 776 WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class); 777 ContentRecordingSession session = ContentRecordingSession.createDisplaySession( 778 DEFAULT_DISPLAY); 779 780 boolean result = wmInternal.setContentRecordingSession(session); 781 782 assertThat(result).isTrue(); 783 } 784 785 @Test setContentRecordingSession_sessionContentTask_noMatchingTask_returnsFalse()786 public void setContentRecordingSession_sessionContentTask_noMatchingTask_returnsFalse() { 787 WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class); 788 IBinder launchCookie = new Binder(); 789 ContentRecordingSession session = ContentRecordingSession.createTaskSession(launchCookie); 790 791 boolean result = wmInternal.setContentRecordingSession(session); 792 793 assertThat(result).isFalse(); 794 } 795 796 @Test setContentRecordingSession_sessionContentTask_matchingTask_returnsTrue()797 public void setContentRecordingSession_sessionContentTask_matchingTask_returnsTrue() { 798 WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class); 799 ActivityRecord activityRecord = createActivityRecord(createTask(mDefaultDisplay)); 800 ContentRecordingSession session = ContentRecordingSession.createTaskSession( 801 activityRecord.mLaunchCookie); 802 803 boolean result = wmInternal.setContentRecordingSession(session); 804 805 assertThat(result).isTrue(); 806 } 807 808 @Test setContentRecordingSession_matchingTask_mutatesSessionWithWindowContainerToken()809 public void setContentRecordingSession_matchingTask_mutatesSessionWithWindowContainerToken() { 810 WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class); 811 Task task = createTask(mDefaultDisplay); 812 ActivityRecord activityRecord = createActivityRecord(task); 813 ContentRecordingSession session = ContentRecordingSession.createTaskSession( 814 activityRecord.mLaunchCookie); 815 816 wmInternal.setContentRecordingSession(session); 817 818 assertThat(session.getTokenToRecord()).isEqualTo( 819 task.mRemoteToken.toWindowContainerToken().asBinder()); 820 } 821 822 @Test testisLetterboxBackgroundMultiColored()823 public void testisLetterboxBackgroundMultiColored() { 824 assertThat(setupLetterboxConfigurationWithBackgroundType( 825 LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING)).isTrue(); 826 assertThat(setupLetterboxConfigurationWithBackgroundType( 827 LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND)).isTrue(); 828 assertThat(setupLetterboxConfigurationWithBackgroundType( 829 LETTERBOX_BACKGROUND_WALLPAPER)).isTrue(); 830 assertThat(setupLetterboxConfigurationWithBackgroundType( 831 LETTERBOX_BACKGROUND_SOLID_COLOR)).isFalse(); 832 } 833 834 @Test testCaptureDisplay()835 public void testCaptureDisplay() { 836 Rect displayBounds = new Rect(0, 0, 100, 200); 837 spyOn(mDisplayContent); 838 when(mDisplayContent.getBounds()).thenReturn(displayBounds); 839 840 // Null captureArgs 841 ScreenCapture.LayerCaptureArgs resultingArgs = 842 mWm.getCaptureArgs(DEFAULT_DISPLAY, null /* captureArgs */); 843 assertEquals(displayBounds, resultingArgs.mSourceCrop); 844 845 // Non null captureArgs, didn't set rect 846 ScreenCapture.CaptureArgs captureArgs = new ScreenCapture.CaptureArgs.Builder<>().build(); 847 resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs); 848 assertEquals(displayBounds, resultingArgs.mSourceCrop); 849 850 // Non null captureArgs, invalid rect 851 captureArgs = new ScreenCapture.CaptureArgs.Builder<>() 852 .setSourceCrop(new Rect(0, 0, -1, -1)) 853 .build(); 854 resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs); 855 assertEquals(displayBounds, resultingArgs.mSourceCrop); 856 857 // Non null captureArgs, null rect 858 captureArgs = new ScreenCapture.CaptureArgs.Builder<>() 859 .setSourceCrop(null) 860 .build(); 861 resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs); 862 assertEquals(displayBounds, resultingArgs.mSourceCrop); 863 864 // Non null captureArgs, valid rect 865 Rect validRect = new Rect(0, 0, 10, 50); 866 captureArgs = new ScreenCapture.CaptureArgs.Builder<>() 867 .setSourceCrop(validRect) 868 .build(); 869 resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs); 870 assertEquals(validRect, resultingArgs.mSourceCrop); 871 } 872 873 @Test testGrantInputChannel_sanitizeSpyWindowForApplications()874 public void testGrantInputChannel_sanitizeSpyWindowForApplications() { 875 final Session session = mock(Session.class); 876 final int callingUid = Process.FIRST_APPLICATION_UID; 877 final int callingPid = 1234; 878 final SurfaceControl surfaceControl = mock(SurfaceControl.class); 879 final IWindow window = mock(IWindow.class); 880 final IBinder windowToken = mock(IBinder.class); 881 when(window.asBinder()).thenReturn(windowToken); 882 final IBinder focusGrantToken = mock(IBinder.class); 883 884 final InputChannel inputChannel = new InputChannel(); 885 assertThrows(IllegalArgumentException.class, () -> 886 mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, 887 surfaceControl, window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, 888 PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, TYPE_APPLICATION, 889 null /* windowToken */, focusGrantToken, "TestInputChannel", 890 inputChannel)); 891 } 892 893 @Test testGrantInputChannel_allowSpyWindowForInputMonitorPermission()894 public void testGrantInputChannel_allowSpyWindowForInputMonitorPermission() { 895 final Session session = mock(Session.class); 896 final int callingUid = Process.SYSTEM_UID; 897 final int callingPid = 1234; 898 final SurfaceControl surfaceControl = mock(SurfaceControl.class); 899 final IWindow window = mock(IWindow.class); 900 final IBinder windowToken = mock(IBinder.class); 901 when(window.asBinder()).thenReturn(windowToken); 902 final IBinder focusGrantToken = mock(IBinder.class); 903 904 final InputChannel inputChannel = new InputChannel(); 905 mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, 906 window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, 907 INPUT_FEATURE_SPY, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, 908 "TestInputChannel", inputChannel); 909 910 verify(mTransaction).setInputWindowInfo( 911 eq(surfaceControl), 912 argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY)); 913 } 914 915 @Test testUpdateInputChannel_sanitizeSpyWindowForApplications()916 public void testUpdateInputChannel_sanitizeSpyWindowForApplications() { 917 final Session session = mock(Session.class); 918 final int callingUid = Process.FIRST_APPLICATION_UID; 919 final int callingPid = 1234; 920 final SurfaceControl surfaceControl = mock(SurfaceControl.class); 921 final IWindow window = mock(IWindow.class); 922 final IBinder windowToken = mock(IBinder.class); 923 when(window.asBinder()).thenReturn(windowToken); 924 final IBinder focusGrantToken = mock(IBinder.class); 925 926 final InputChannel inputChannel = new InputChannel(); 927 mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, 928 window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, 929 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, 930 "TestInputChannel", inputChannel); 931 verify(mTransaction).setInputWindowInfo( 932 eq(surfaceControl), 933 argThat(h -> (h.inputConfig & InputConfig.SPY) == 0)); 934 935 assertThrows(IllegalArgumentException.class, () -> 936 mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl, 937 FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, 938 null /* region */)); 939 } 940 941 @Test testUpdateInputChannel_allowSpyWindowForInputMonitorPermission()942 public void testUpdateInputChannel_allowSpyWindowForInputMonitorPermission() { 943 final Session session = mock(Session.class); 944 final int callingUid = Process.SYSTEM_UID; 945 final int callingPid = 1234; 946 final SurfaceControl surfaceControl = mock(SurfaceControl.class); 947 final IWindow window = mock(IWindow.class); 948 final IBinder windowToken = mock(IBinder.class); 949 when(window.asBinder()).thenReturn(windowToken); 950 final IBinder focusGrantToken = mock(IBinder.class); 951 952 final InputChannel inputChannel = new InputChannel(); 953 mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl, 954 window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, 955 0 /* inputFeatures */, TYPE_APPLICATION, null /* windowToken */, focusGrantToken, 956 "TestInputChannel", inputChannel); 957 verify(mTransaction).setInputWindowInfo( 958 eq(surfaceControl), 959 argThat(h -> (h.inputConfig & InputConfig.SPY) == 0)); 960 961 mWm.updateInputChannel(inputChannel.getToken(), DEFAULT_DISPLAY, surfaceControl, 962 FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, INPUT_FEATURE_SPY, 963 null /* region */); 964 verify(mTransaction).setInputWindowInfo( 965 eq(surfaceControl), 966 argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY)); 967 } 968 969 @Test testRequestKeyboardShortcuts_noWindow()970 public void testRequestKeyboardShortcuts_noWindow() { 971 doNothing().when(mWm.mContext).enforceCallingOrSelfPermission(anyString(), anyString()); 972 doReturn(null).when(mWm).getFocusedWindowLocked(); 973 doReturn(null).when(mWm.mRoot).getCurrentInputMethodWindow(); 974 975 TestResultReceiver receiver = new TestResultReceiver(); 976 mWm.requestAppKeyboardShortcuts(receiver, 0); 977 assertNotNull(receiver.resultData); 978 assertTrue(receiver.resultData.isEmpty()); 979 980 receiver = new TestResultReceiver(); 981 mWm.requestImeKeyboardShortcuts(receiver, 0); 982 assertNotNull(receiver.resultData); 983 assertTrue(receiver.resultData.isEmpty()); 984 } 985 986 @Test testRequestKeyboardShortcuts()987 public void testRequestKeyboardShortcuts() throws RemoteException { 988 final IWindow window = mock(IWindow.class); 989 final IBinder binder = mock(IBinder.class); 990 doReturn(binder).when(window).asBinder(); 991 final WindowState windowState = 992 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "appWin", window); 993 doNothing().when(mWm.mContext).enforceCallingOrSelfPermission(anyString(), anyString()); 994 doReturn(windowState).when(mWm).getFocusedWindowLocked(); 995 doReturn(windowState).when(mWm.mRoot).getCurrentInputMethodWindow(); 996 997 TestResultReceiver receiver = new TestResultReceiver(); 998 mWm.requestAppKeyboardShortcuts(receiver, 0); 999 mWm.requestImeKeyboardShortcuts(receiver, 0); 1000 verify(window, times(2)).requestAppKeyboardShortcuts(receiver, 0); 1001 } 1002 1003 class TestResultReceiver implements IResultReceiver { 1004 public android.os.Bundle resultData; 1005 private final IBinder mBinder = mock(IBinder.class); 1006 1007 @Override send(int resultCode, android.os.Bundle resultData)1008 public void send(int resultCode, android.os.Bundle resultData) 1009 throws android.os.RemoteException { 1010 this.resultData = resultData; 1011 } 1012 1013 @Override asBinder()1014 public android.os.IBinder asBinder() { 1015 return mBinder; 1016 } 1017 } 1018 setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct)1019 private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) { 1020 final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class); 1021 when(remoteToken.toWindowContainerToken()).thenReturn(wct); 1022 final ActivityRecord testActivity = new ActivityBuilder(mAtm) 1023 .setCreateTask(true) 1024 .build(); 1025 testActivity.mLaunchCookie = launchCookie; 1026 testActivity.getTask().mRemoteToken = remoteToken; 1027 } 1028 setupLetterboxConfigurationWithBackgroundType( @etterboxConfiguration.LetterboxBackgroundType int letterboxBackgroundType)1029 private boolean setupLetterboxConfigurationWithBackgroundType( 1030 @LetterboxConfiguration.LetterboxBackgroundType int letterboxBackgroundType) { 1031 mWm.mLetterboxConfiguration.setLetterboxBackgroundTypeOverride(letterboxBackgroundType); 1032 return mWm.isLetterboxBackgroundMultiColored(); 1033 } 1034 } 1035