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