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