1 /* 2 * Copyright (C) 2010 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.WINDOWING_MODE_FULLSCREEN; 20 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 21 import static android.view.Display.INVALID_DISPLAY; 22 import static android.view.WindowManager.INPUT_CONSUMER_PIP; 23 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; 24 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; 25 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 26 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 27 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 28 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; 29 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS; 30 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; 31 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 32 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 33 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; 34 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 35 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 36 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; 37 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 38 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; 39 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; 40 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 41 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 42 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; 43 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 44 45 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; 46 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; 47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 48 import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS; 49 50 import android.graphics.Rect; 51 import android.graphics.Region; 52 import android.os.Handler; 53 import android.os.IBinder; 54 import android.os.Looper; 55 import android.os.Trace; 56 import android.os.UserHandle; 57 import android.util.ArrayMap; 58 import android.util.EventLog; 59 import android.util.Slog; 60 import android.view.InputChannel; 61 import android.view.InputEventReceiver; 62 import android.view.InputWindowHandle; 63 import android.view.SurfaceControl; 64 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.internal.protolog.common.ProtoLog; 67 68 import java.io.PrintWriter; 69 import java.util.Set; 70 import java.util.function.Consumer; 71 72 final class InputMonitor { 73 private final WindowManagerService mService; 74 75 // Current input focus token for keys and other non-touch events. May be null. 76 private IBinder mInputFocus = null; 77 78 // When true, need to call updateInputWindowsLw(). 79 private boolean mUpdateInputWindowsNeeded = true; 80 private boolean mUpdateInputWindowsPending; 81 private boolean mUpdateInputWindowsImmediately; 82 83 private boolean mDisableWallpaperTouchEvents; 84 private final Region mTmpRegion = new Region(); 85 private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer; 86 87 private final int mDisplayId; 88 private final DisplayContent mDisplayContent; 89 private boolean mDisplayRemoved; 90 private int mDisplayWidth; 91 private int mDisplayHeight; 92 93 private final SurfaceControl.Transaction mInputTransaction; 94 private final Handler mHandler; 95 96 /** 97 * The set of input consumer added to the window manager by name, which consumes input events 98 * for the windows below it. 99 */ 100 private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap(); 101 102 /** 103 * Representation of a input consumer that the policy has added to the window manager to consume 104 * input events going to windows below it. 105 */ 106 static final class EventReceiverInputConsumer extends InputConsumerImpl { 107 private InputMonitor mInputMonitor; 108 private final InputEventReceiver mInputEventReceiver; 109 EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor, Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory, int clientPid, UserHandle clientUser, int displayId)110 EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor, 111 Looper looper, String name, 112 InputEventReceiver.Factory inputEventReceiverFactory, 113 int clientPid, UserHandle clientUser, int displayId) { 114 super(service, null /* token */, name, null /* inputChannel */, clientPid, clientUser, 115 displayId); 116 mInputMonitor = monitor; 117 mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver( 118 mClientChannel, looper); 119 } 120 121 /** Removes the input consumer from the window manager. */ dismiss()122 void dismiss() { 123 synchronized (mService.mGlobalLock) { 124 mInputMonitor.mInputConsumers.remove(mName); 125 hide(mInputMonitor.mInputTransaction); 126 mInputMonitor.updateInputWindowsLw(true /* force */); 127 } 128 } 129 130 /** Disposes the input consumer and input receiver from the associated thread. */ dispose()131 void dispose() { 132 synchronized (mService.mGlobalLock) { 133 disposeChannelsLw(mInputMonitor.mInputTransaction); 134 mInputEventReceiver.dispose(); 135 mInputMonitor.updateInputWindowsLw(true /* force */); 136 } 137 } 138 } 139 140 private class UpdateInputWindows implements Runnable { 141 @Override run()142 public void run() { 143 synchronized (mService.mGlobalLock) { 144 mUpdateInputWindowsPending = false; 145 mUpdateInputWindowsNeeded = false; 146 147 if (mDisplayRemoved) { 148 return; 149 } 150 151 // Populate the input window list with information about all of the windows that 152 // could potentially receive input. 153 // As an optimization, we could try to prune the list of windows but this turns 154 // out to be difficult because only the native code knows for sure which window 155 // currently has touch focus. 156 157 // If there's a drag in flight, provide a pseudo-window to catch drag input 158 final boolean inDrag = mService.mDragDropController.dragDropActiveLocked(); 159 160 // Add all windows on the default display. 161 mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag); 162 } 163 } 164 } 165 166 private final UpdateInputWindows mUpdateInputWindows = new UpdateInputWindows(); 167 InputMonitor(WindowManagerService service, DisplayContent displayContent)168 InputMonitor(WindowManagerService service, DisplayContent displayContent) { 169 mService = service; 170 mDisplayContent = displayContent; 171 mDisplayId = displayContent.getDisplayId(); 172 mInputTransaction = mService.mTransactionFactory.get(); 173 mHandler = mService.mAnimationHandler; 174 mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer(); 175 } 176 onDisplayRemoved()177 void onDisplayRemoved() { 178 mHandler.removeCallbacks(mUpdateInputWindows); 179 mHandler.post(() -> { 180 // Make sure any pending setInputWindowInfo transactions are completed. That prevents 181 // the timing of updating input info of removed display after cleanup. 182 mService.mTransactionFactory.get().syncInputWindows().apply(); 183 // It calls InputDispatcher::setInputWindows directly. 184 mService.mInputManager.onDisplayRemoved(mDisplayId); 185 }); 186 mDisplayRemoved = true; 187 } 188 addInputConsumer(String name, InputConsumerImpl consumer)189 private void addInputConsumer(String name, InputConsumerImpl consumer) { 190 mInputConsumers.put(name, consumer); 191 consumer.linkToDeathRecipient(); 192 consumer.layout(mInputTransaction, mDisplayWidth, mDisplayHeight); 193 updateInputWindowsLw(true /* force */); 194 } 195 destroyInputConsumer(String name)196 boolean destroyInputConsumer(String name) { 197 if (disposeInputConsumer(mInputConsumers.remove(name))) { 198 updateInputWindowsLw(true /* force */); 199 return true; 200 } 201 return false; 202 } 203 disposeInputConsumer(InputConsumerImpl consumer)204 private boolean disposeInputConsumer(InputConsumerImpl consumer) { 205 if (consumer != null) { 206 consumer.disposeChannelsLw(mInputTransaction); 207 return true; 208 } 209 return false; 210 } 211 getInputConsumer(String name)212 InputConsumerImpl getInputConsumer(String name) { 213 return mInputConsumers.get(name); 214 } 215 layoutInputConsumers(int dw, int dh)216 void layoutInputConsumers(int dw, int dh) { 217 if (mDisplayWidth == dw && mDisplayHeight == dh) { 218 return; 219 } 220 mDisplayWidth = dw; 221 mDisplayHeight = dh; 222 try { 223 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer"); 224 for (int i = mInputConsumers.size() - 1; i >= 0; i--) { 225 mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh); 226 } 227 } finally { 228 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 229 } 230 } 231 232 // The visibility of the input consumers is recomputed each time we 233 // update the input windows. We use a model where consumers begin invisible 234 // (set so by this function) and must meet some condition for visibility on each update. resetInputConsumers(SurfaceControl.Transaction t)235 void resetInputConsumers(SurfaceControl.Transaction t) { 236 for (int i = mInputConsumers.size() - 1; i >= 0; i--) { 237 mInputConsumers.valueAt(i).hide(t); 238 } 239 } 240 createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid, UserHandle clientUser)241 void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid, 242 UserHandle clientUser) { 243 if (mInputConsumers.containsKey(name)) { 244 throw new IllegalStateException("Existing input consumer found with name: " + name 245 + ", display: " + mDisplayId); 246 } 247 248 final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name, 249 inputChannel, clientPid, clientUser, mDisplayId); 250 switch (name) { 251 case INPUT_CONSUMER_WALLPAPER: 252 consumer.mWindowHandle.hasWallpaper = true; 253 break; 254 case INPUT_CONSUMER_PIP: 255 // The touchable region of the Pip input window is cropped to the bounds of the 256 // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through 257 consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL; 258 break; 259 case INPUT_CONSUMER_RECENTS_ANIMATION: 260 consumer.mWindowHandle.focusable = true; 261 break; 262 default: 263 throw new IllegalArgumentException("Illegal input consumer : " + name 264 + ", display: " + mDisplayId); 265 } 266 addInputConsumer(name, consumer); 267 } 268 269 @VisibleForTesting populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle, final WindowState w)270 void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle, 271 final WindowState w) { 272 // Add a window to our list of input windows. 273 inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null 274 ? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null); 275 inputWindowHandle.setToken(w.mInputChannelToken); 276 inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis()); 277 inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode()); 278 inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures); 279 inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused); 280 inputWindowHandle.setVisible(w.isVisible()); 281 282 final boolean focusable = w.canReceiveKeys() 283 && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop()); 284 inputWindowHandle.setFocusable(focusable); 285 286 final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w) 287 && !mService.mPolicy.isKeyguardShowing() 288 && !mDisableWallpaperTouchEvents; 289 inputWindowHandle.setHasWallpaper(hasWallpaper); 290 291 final Rect frame = w.getFrame(); 292 inputWindowHandle.setFrame(frame.left, frame.top, frame.right, frame.bottom); 293 294 // Surface insets are hardcoded to be the same in all directions 295 // and we could probably deprecate the "left/right/top/bottom" concept. 296 // we avoid reintroducing this concept by just choosing one of them here. 297 inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left); 298 299 // If we are scaling the window, input coordinates need to be inversely scaled to map from 300 // what is on screen to what is actually being touched in the UI. 301 inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f); 302 303 final int flags = w.getSurfaceTouchableRegion(mTmpRegion, w.mAttrs.flags); 304 inputWindowHandle.setTouchableRegion(mTmpRegion); 305 inputWindowHandle.setLayoutParamsFlags(flags); 306 307 boolean useSurfaceCrop = false; 308 final Task task = w.getTask(); 309 if (task != null) { 310 if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { 311 // If the window is in a TaskManaged by a TaskOrganizer then most cropping will 312 // be applied using the SurfaceControl hierarchy from the Organizer. This means 313 // we need to make sure that these changes in crop are reflected in the input 314 // windows, and so ensure this flag is set so that the input crop always reflects 315 // the surface hierarchy. 316 // TODO(b/168252846): we have some issues with modal-windows, so we need to cross 317 // that bridge now that we organize full-screen Tasks. 318 inputWindowHandle.setTouchableRegionCrop(null /* Use this surfaces crop */); 319 inputWindowHandle.setReplaceTouchableRegionWithCrop(true); 320 useSurfaceCrop = true; 321 } else if (task.cropWindowsToRootTaskBounds() && !w.inFreeformWindowingMode()) { 322 inputWindowHandle.setTouchableRegionCrop(task.getRootTask().getSurfaceControl()); 323 inputWindowHandle.setReplaceTouchableRegionWithCrop(false); 324 useSurfaceCrop = true; 325 } 326 } 327 if (!useSurfaceCrop) { 328 inputWindowHandle.setReplaceTouchableRegionWithCrop(false); 329 inputWindowHandle.setTouchableRegionCrop(null); 330 } 331 } 332 setUpdateInputWindowsNeededLw()333 void setUpdateInputWindowsNeededLw() { 334 mUpdateInputWindowsNeeded = true; 335 } 336 337 /* Updates the cached window information provided to the input dispatcher. */ updateInputWindowsLw(boolean force)338 void updateInputWindowsLw(boolean force) { 339 if (!force && !mUpdateInputWindowsNeeded) { 340 return; 341 } 342 scheduleUpdateInputWindows(); 343 } 344 scheduleUpdateInputWindows()345 private void scheduleUpdateInputWindows() { 346 if (mDisplayRemoved) { 347 return; 348 } 349 350 if (!mUpdateInputWindowsPending) { 351 mUpdateInputWindowsPending = true; 352 mHandler.post(mUpdateInputWindows); 353 } 354 } 355 356 /** 357 * Immediately update the input transaction and merge into the passing Transaction that could be 358 * collected and applied later. 359 */ updateInputWindowsImmediately(SurfaceControl.Transaction t)360 void updateInputWindowsImmediately(SurfaceControl.Transaction t) { 361 mHandler.removeCallbacks(mUpdateInputWindows); 362 mUpdateInputWindowsImmediately = true; 363 mUpdateInputWindows.run(); 364 mUpdateInputWindowsImmediately = false; 365 t.merge(mInputTransaction); 366 } 367 368 /** 369 * Called when the current input focus changes. Will apply it in next updateInputWindows. 370 * Layer assignment is assumed to be complete by the time this is called. 371 */ setInputFocusLw(WindowState newWindow, boolean updateInputWindows)372 void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) { 373 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d", 374 newWindow, mDisplayId); 375 final IBinder focus = newWindow != null ? newWindow.mInputChannelToken : null; 376 if (focus == mInputFocus) { 377 return; 378 } 379 380 if (newWindow != null && newWindow.canReceiveKeys()) { 381 // Displaying a window implicitly causes dispatching to be unpaused. 382 // This is to protect against bugs if someone pauses dispatching but 383 // forgets to resume. 384 newWindow.mToken.paused = false; 385 } 386 387 setUpdateInputWindowsNeededLw(); 388 389 if (updateInputWindows) { 390 updateInputWindowsLw(false /*force*/); 391 } 392 } 393 394 /** 395 * Called when the current input focus changes. 396 */ updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer)397 private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) { 398 final WindowState focus = mDisplayContent.mCurrentFocus; 399 // Request focus for the recents animation input consumer if an input consumer should 400 // be applied for the window. 401 if (recentsAnimationInputConsumer != null && focus != null) { 402 final RecentsAnimationController recentsAnimationController = 403 mService.getRecentsAnimationController(); 404 final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null 405 && recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord); 406 if (shouldApplyRecentsInputConsumer) { 407 requestFocus(recentsAnimationInputConsumer.mWindowHandle.token, 408 recentsAnimationInputConsumer.mName); 409 return; 410 } 411 } 412 413 final IBinder focusToken = focus != null ? focus.mInputChannelToken : null; 414 if (focusToken == null) { 415 mInputFocus = null; 416 return; 417 } 418 419 if (!focus.mWinAnimator.hasSurface() || !focus.mInputWindowHandle.isFocusable()) { 420 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus not requested for window=%s" 421 + " because it has no surface or is not focusable.", focus); 422 mInputFocus = null; 423 return; 424 } 425 426 requestFocus(focusToken, focus.getName()); 427 } 428 requestFocus(IBinder focusToken, String windowName)429 private void requestFocus(IBinder focusToken, String windowName) { 430 if (focusToken == mInputFocus) { 431 return; 432 } 433 434 mInputFocus = focusToken; 435 mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId); 436 EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName, 437 "reason=UpdateInputWindows"); 438 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName); 439 } 440 setFocusedAppLw(ActivityRecord newApp)441 void setFocusedAppLw(ActivityRecord newApp) { 442 // Focused app has changed. 443 mService.mInputManager.setFocusedApplication(mDisplayId, 444 newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null); 445 } 446 pauseDispatchingLw(WindowToken window)447 public void pauseDispatchingLw(WindowToken window) { 448 if (! window.paused) { 449 if (DEBUG_INPUT) { 450 Slog.v(TAG_WM, "Pausing WindowToken " + window); 451 } 452 453 window.paused = true; 454 updateInputWindowsLw(true /*force*/); 455 } 456 } 457 resumeDispatchingLw(WindowToken window)458 public void resumeDispatchingLw(WindowToken window) { 459 if (window.paused) { 460 if (DEBUG_INPUT) { 461 Slog.v(TAG_WM, "Resuming WindowToken " + window); 462 } 463 464 window.paused = false; 465 updateInputWindowsLw(true /*force*/); 466 } 467 } 468 dump(PrintWriter pw, String prefix)469 void dump(PrintWriter pw, String prefix) { 470 final Set<String> inputConsumerKeys = mInputConsumers.keySet(); 471 if (!inputConsumerKeys.isEmpty()) { 472 pw.println(prefix + "InputConsumers:"); 473 for (String key : inputConsumerKeys) { 474 mInputConsumers.get(key).dump(pw, key, prefix); 475 } 476 } 477 } 478 479 private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> { 480 InputConsumerImpl mPipInputConsumer; 481 InputConsumerImpl mWallpaperInputConsumer; 482 InputConsumerImpl mRecentsAnimationInputConsumer; 483 484 private boolean mAddPipInputConsumerHandle; 485 private boolean mAddWallpaperInputConsumerHandle; 486 private boolean mAddRecentsAnimationInputConsumerHandle; 487 488 boolean mInDrag; 489 updateInputWindows(boolean inDrag)490 private void updateInputWindows(boolean inDrag) { 491 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows"); 492 493 mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP); 494 mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER); 495 mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); 496 497 mAddPipInputConsumerHandle = mPipInputConsumer != null; 498 mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null; 499 mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null; 500 501 mDisableWallpaperTouchEvents = false; 502 mInDrag = inDrag; 503 504 resetInputConsumers(mInputTransaction); 505 mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */); 506 updateInputFocusRequest(mRecentsAnimationInputConsumer); 507 508 if (!mUpdateInputWindowsImmediately) { 509 mDisplayContent.getPendingTransaction().merge(mInputTransaction); 510 mDisplayContent.scheduleAnimation(); 511 } 512 513 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 514 } 515 516 @Override accept(WindowState w)517 public void accept(WindowState w) { 518 final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle; 519 final RecentsAnimationController recentsAnimationController = 520 mService.getRecentsAnimationController(); 521 final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null 522 && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord); 523 if (w.mInputChannelToken == null || w.mRemoved 524 || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) { 525 if (w.mWinAnimator.hasSurface()) { 526 // Make sure the input info can't receive input event. It may be omitted from 527 // occlusion detection depending on the type or if it's a trusted overlay. 528 populateOverlayInputInfo(inputWindowHandle, w); 529 setInputWindowInfoIfNeeded(mInputTransaction, 530 w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); 531 return; 532 } 533 // Skip this window because it cannot possibly receive input. 534 return; 535 } 536 537 final int privateFlags = w.mAttrs.privateFlags; 538 539 if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) { 540 if (recentsAnimationController.updateInputConsumerForApp( 541 mRecentsAnimationInputConsumer.mWindowHandle)) { 542 mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord); 543 mAddRecentsAnimationInputConsumerHandle = false; 544 } 545 } 546 547 if (w.inPinnedWindowingMode()) { 548 if (mAddPipInputConsumerHandle) { 549 final Task rootTask = w.getTask().getRootTask(); 550 mPipInputConsumer.mWindowHandle.replaceTouchableRegionWithCrop( 551 rootTask.getSurfaceControl()); 552 // We set the layer to z=MAX-1 so that it's always on top. 553 mPipInputConsumer.reparent(mInputTransaction, rootTask); 554 mPipInputConsumer.show(mInputTransaction, Integer.MAX_VALUE - 1); 555 mAddPipInputConsumerHandle = false; 556 } 557 } 558 559 if (mAddWallpaperInputConsumerHandle) { 560 if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) { 561 // Add the wallpaper input consumer above the first visible wallpaper. 562 mWallpaperInputConsumer.show(mInputTransaction, w); 563 mAddWallpaperInputConsumerHandle = false; 564 } 565 } 566 567 if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { 568 mDisableWallpaperTouchEvents = true; 569 } 570 571 // If there's a drag in progress and 'child' is a potential drop target, 572 // make sure it's been told about the drag 573 if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) { 574 mService.mDragDropController.sendDragStartedIfNeededLocked(w); 575 } 576 577 // register key interception info 578 mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken, 579 w.getKeyInterceptionInfo()); 580 581 if (w.mWinAnimator.hasSurface()) { 582 populateInputWindowHandle(inputWindowHandle, w); 583 setInputWindowInfoIfNeeded(mInputTransaction, 584 w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle); 585 } 586 } 587 } 588 589 @VisibleForTesting setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc, InputWindowHandleWrapper inputWindowHandle)590 static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc, 591 InputWindowHandleWrapper inputWindowHandle) { 592 if (DEBUG_INPUT) { 593 Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle); 594 } 595 if (inputWindowHandle.isChanged()) { 596 inputWindowHandle.applyChangesToSurface(t, sc); 597 } 598 } 599 populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, WindowState w)600 static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, 601 WindowState w) { 602 populateOverlayInputInfo(inputWindowHandle, w.isVisible()); 603 inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode()); 604 } 605 606 // This would reset InputWindowHandle fields to prevent it could be found by input event. 607 // We need to check if any new field of InputWindowHandle could impact the result. 608 @VisibleForTesting populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, boolean isVisible)609 static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, 610 boolean isVisible) { 611 inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input. 612 inputWindowHandle.setVisible(isVisible); 613 inputWindowHandle.setFocusable(false); 614 inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL); 615 // The input window handle without input channel must not have a token. 616 inputWindowHandle.setToken(null); 617 inputWindowHandle.setScaleFactor(1f); 618 inputWindowHandle.setLayoutParamsFlags( 619 FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE); 620 inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY); 621 inputWindowHandle.clearTouchableRegion(); 622 inputWindowHandle.setTouchableRegionCrop(null); 623 } 624 625 /** 626 * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input 627 * info will not have an input channel or be touchable, but is used to omit Surfaces 628 * from occlusion detection, so that System global overlays like the Watermark aren't 629 * counted by the InputDispatcher as occluding applications below. 630 */ setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t, int displayId, String name)631 static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t, 632 int displayId, String name) { 633 final InputWindowHandleWrapper inputWindowHandle = new InputWindowHandleWrapper( 634 new InputWindowHandle(null /* inputApplicationHandle */, displayId)); 635 inputWindowHandle.setName(name); 636 inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY); 637 inputWindowHandle.setTrustedOverlay(true); 638 populateOverlayInputInfo(inputWindowHandle, true /* isVisible */); 639 setInputWindowInfoIfNeeded(t, sc, inputWindowHandle); 640 } 641 isTrustedOverlay(int type)642 static boolean isTrustedOverlay(int type) { 643 return type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY 644 || type == TYPE_INPUT_METHOD || type == TYPE_INPUT_METHOD_DIALOG 645 || type == TYPE_MAGNIFICATION_OVERLAY || type == TYPE_STATUS_BAR 646 || type == TYPE_NOTIFICATION_SHADE 647 || type == TYPE_NAVIGATION_BAR 648 || type == TYPE_NAVIGATION_BAR_PANEL 649 || type == TYPE_SECURE_SYSTEM_OVERLAY 650 || type == TYPE_DOCK_DIVIDER 651 || type == TYPE_ACCESSIBILITY_OVERLAY 652 || type == TYPE_INPUT_CONSUMER 653 || type == TYPE_VOICE_INTERACTION; 654 } 655 } 656