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.view.Display.DEFAULT_DISPLAY; 20 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; 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_TOUCH_MODAL; 25 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS; 26 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 27 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 28 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 29 30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; 31 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; 32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; 33 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; 34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 35 36 import android.app.ActivityManager; 37 import android.graphics.Rect; 38 import android.os.Debug; 39 import android.os.IBinder; 40 import android.os.Looper; 41 import android.os.Process; 42 import android.os.RemoteException; 43 import android.os.UserHandle; 44 import android.util.ArrayMap; 45 import android.util.Log; 46 import android.util.Slog; 47 import android.view.InputChannel; 48 import android.view.InputEventReceiver; 49 import android.view.KeyEvent; 50 import android.view.WindowManager; 51 52 import com.android.server.input.InputApplicationHandle; 53 import com.android.server.input.InputManagerService; 54 import com.android.server.input.InputWindowHandle; 55 import com.android.server.policy.WindowManagerPolicy; 56 57 import java.io.PrintWriter; 58 import java.util.Arrays; 59 import java.util.Set; 60 import java.util.function.Consumer; 61 62 final class InputMonitor implements InputManagerService.WindowManagerCallbacks { 63 private final WindowManagerService mService; 64 65 // Current window with input focus for keys and other non-touch events. May be null. 66 private WindowState mInputFocus; 67 68 // When true, prevents input dispatch from proceeding until set to false again. 69 private boolean mInputDispatchFrozen; 70 71 // The reason the input is currently frozen or null if the input isn't frozen. 72 private String mInputFreezeReason = null; 73 74 // When true, input dispatch proceeds normally. Otherwise all events are dropped. 75 // Initially false, so that input does not get dispatched until boot is finished at 76 // which point the ActivityManager will enable dispatching. 77 private boolean mInputDispatchEnabled; 78 79 // When true, need to call updateInputWindowsLw(). 80 private boolean mUpdateInputWindowsNeeded = true; 81 82 // Array of window handles to provide to the input dispatcher. 83 private InputWindowHandle[] mInputWindowHandles; 84 private int mInputWindowHandleCount; 85 private InputWindowHandle mFocusedInputWindowHandle; 86 87 private boolean mAddInputConsumerHandle; 88 private boolean mAddPipInputConsumerHandle; 89 private boolean mAddWallpaperInputConsumerHandle; 90 private boolean mAddRecentsAnimationInputConsumerHandle; 91 private boolean mDisableWallpaperTouchEvents; 92 private final Rect mTmpRect = new Rect(); 93 private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer = 94 new UpdateInputForAllWindowsConsumer(); 95 96 // Set to true when the first input device configuration change notification 97 // is received to indicate that the input devices are ready. 98 private final Object mInputDevicesReadyMonitor = new Object(); 99 private boolean mInputDevicesReady; 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 private static final class EventReceiverInputConsumer extends InputConsumerImpl 108 implements WindowManagerPolicy.InputConsumer { 109 private InputMonitor mInputMonitor; 110 private final InputEventReceiver mInputEventReceiver; 111 EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor, Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory, int clientPid, UserHandle clientUser)112 EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor, 113 Looper looper, String name, 114 InputEventReceiver.Factory inputEventReceiverFactory, 115 int clientPid, UserHandle clientUser) { 116 super(service, null /* token */, name, null /* inputChannel */, clientPid, clientUser); 117 mInputMonitor = monitor; 118 mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver( 119 mClientChannel, looper); 120 } 121 122 @Override dismiss()123 public void dismiss() { 124 synchronized (mService.mWindowMap) { 125 if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) { 126 mInputEventReceiver.dispose(); 127 } 128 } 129 } 130 } 131 InputMonitor(WindowManagerService service)132 public InputMonitor(WindowManagerService service) { 133 mService = service; 134 } 135 addInputConsumer(String name, InputConsumerImpl consumer)136 private void addInputConsumer(String name, InputConsumerImpl consumer) { 137 mInputConsumers.put(name, consumer); 138 consumer.linkToDeathRecipient(); 139 updateInputWindowsLw(true /* force */); 140 } 141 destroyInputConsumer(String name)142 boolean destroyInputConsumer(String name) { 143 if (disposeInputConsumer(mInputConsumers.remove(name))) { 144 updateInputWindowsLw(true /* force */); 145 return true; 146 } 147 return false; 148 } 149 disposeInputConsumer(InputConsumerImpl consumer)150 private boolean disposeInputConsumer(InputConsumerImpl consumer) { 151 if (consumer != null) { 152 consumer.disposeChannelsLw(); 153 return true; 154 } 155 return false; 156 } 157 getInputConsumer(String name, int displayId)158 InputConsumerImpl getInputConsumer(String name, int displayId) { 159 // TODO(multi-display): Allow input consumers on non-default displays? 160 return (displayId == DEFAULT_DISPLAY) ? mInputConsumers.get(name) : null; 161 } 162 layoutInputConsumers(int dw, int dh)163 void layoutInputConsumers(int dw, int dh) { 164 for (int i = mInputConsumers.size() - 1; i >= 0; i--) { 165 mInputConsumers.valueAt(i).layout(dw, dh); 166 } 167 } 168 createInputConsumer(Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory)169 WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, 170 InputEventReceiver.Factory inputEventReceiverFactory) { 171 if (mInputConsumers.containsKey(name)) { 172 throw new IllegalStateException("Existing input consumer found with name: " + name); 173 } 174 175 final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService, 176 this, looper, name, inputEventReceiverFactory, Process.myPid(), 177 UserHandle.SYSTEM); 178 addInputConsumer(name, consumer); 179 return consumer; 180 } 181 createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid, UserHandle clientUser)182 void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid, 183 UserHandle clientUser) { 184 if (mInputConsumers.containsKey(name)) { 185 throw new IllegalStateException("Existing input consumer found with name: " + name); 186 } 187 188 final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name, 189 inputChannel, clientPid, clientUser); 190 switch (name) { 191 case INPUT_CONSUMER_WALLPAPER: 192 consumer.mWindowHandle.hasWallpaper = true; 193 break; 194 case INPUT_CONSUMER_PIP: 195 // The touchable region of the Pip input window is cropped to the bounds of the 196 // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through 197 consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL; 198 break; 199 } 200 addInputConsumer(name, consumer); 201 } 202 203 /* Notifies the window manager about a broken input channel. 204 * 205 * Called by the InputManager. 206 */ 207 @Override notifyInputChannelBroken(InputWindowHandle inputWindowHandle)208 public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { 209 if (inputWindowHandle == null) { 210 return; 211 } 212 213 synchronized (mService.mWindowMap) { 214 WindowState windowState = (WindowState) inputWindowHandle.windowState; 215 if (windowState != null) { 216 Slog.i(TAG_WM, "WINDOW DIED " + windowState); 217 windowState.removeIfPossible(); 218 } 219 } 220 } 221 222 /* Notifies the window manager about an application that is not responding. 223 * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. 224 * 225 * Called by the InputManager. 226 */ 227 @Override notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle, String reason)228 public long notifyANR(InputApplicationHandle inputApplicationHandle, 229 InputWindowHandle inputWindowHandle, String reason) { 230 AppWindowToken appWindowToken = null; 231 WindowState windowState = null; 232 boolean aboveSystem = false; 233 synchronized (mService.mWindowMap) { 234 if (inputWindowHandle != null) { 235 windowState = (WindowState) inputWindowHandle.windowState; 236 if (windowState != null) { 237 appWindowToken = windowState.mAppToken; 238 } 239 } 240 if (appWindowToken == null && inputApplicationHandle != null) { 241 appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken; 242 } 243 244 if (windowState != null) { 245 Slog.i(TAG_WM, "Input event dispatching timed out " 246 + "sending to " + windowState.mAttrs.getTitle() 247 + ". Reason: " + reason); 248 // Figure out whether this window is layered above system windows. 249 // We need to do this here to help the activity manager know how to 250 // layer its ANR dialog. 251 int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw( 252 TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow); 253 aboveSystem = windowState.mBaseLayer > systemAlertLayer; 254 } else if (appWindowToken != null) { 255 Slog.i(TAG_WM, "Input event dispatching timed out " 256 + "sending to application " + appWindowToken.stringName 257 + ". Reason: " + reason); 258 } else { 259 Slog.i(TAG_WM, "Input event dispatching timed out " 260 + ". Reason: " + reason); 261 } 262 263 mService.saveANRStateLocked(appWindowToken, windowState, reason); 264 } 265 266 // All the calls below need to happen without the WM lock held since they call into AM. 267 mService.mAmInternal.saveANRState(reason); 268 269 if (appWindowToken != null && appWindowToken.appToken != null) { 270 // Notify the activity manager about the timeout and let it decide whether 271 // to abort dispatching or keep waiting. 272 final AppWindowContainerController controller = appWindowToken.getController(); 273 final boolean abort = controller != null 274 && controller.keyDispatchingTimedOut(reason, 275 (windowState != null) ? windowState.mSession.mPid : -1); 276 if (!abort) { 277 // The activity manager declined to abort dispatching. 278 // Wait a bit longer and timeout again later. 279 return appWindowToken.mInputDispatchingTimeoutNanos; 280 } 281 } else if (windowState != null) { 282 try { 283 // Notify the activity manager about the timeout and let it decide whether 284 // to abort dispatching or keep waiting. 285 long timeout = ActivityManager.getService().inputDispatchingTimedOut( 286 windowState.mSession.mPid, aboveSystem, reason); 287 if (timeout >= 0) { 288 // The activity manager declined to abort dispatching. 289 // Wait a bit longer and timeout again later. 290 return timeout * 1000000L; // nanoseconds 291 } 292 } catch (RemoteException ex) { 293 } 294 } 295 return 0; // abort dispatching 296 } 297 addInputWindowHandle(final InputWindowHandle windowHandle)298 private void addInputWindowHandle(final InputWindowHandle windowHandle) { 299 if (mInputWindowHandles == null) { 300 mInputWindowHandles = new InputWindowHandle[16]; 301 } 302 if (mInputWindowHandleCount >= mInputWindowHandles.length) { 303 mInputWindowHandles = Arrays.copyOf(mInputWindowHandles, 304 mInputWindowHandleCount * 2); 305 } 306 mInputWindowHandles[mInputWindowHandleCount++] = windowHandle; 307 } 308 addInputWindowHandle(final InputWindowHandle inputWindowHandle, final WindowState child, int flags, final int type, final boolean isVisible, final boolean hasFocus, final boolean hasWallpaper)309 void addInputWindowHandle(final InputWindowHandle inputWindowHandle, 310 final WindowState child, int flags, final int type, final boolean isVisible, 311 final boolean hasFocus, final boolean hasWallpaper) { 312 // Add a window to our list of input windows. 313 inputWindowHandle.name = child.toString(); 314 flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags); 315 inputWindowHandle.layoutParamsFlags = flags; 316 inputWindowHandle.layoutParamsType = type; 317 inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos(); 318 inputWindowHandle.visible = isVisible; 319 inputWindowHandle.canReceiveKeys = child.canReceiveKeys(); 320 inputWindowHandle.hasFocus = hasFocus; 321 inputWindowHandle.hasWallpaper = hasWallpaper; 322 inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false; 323 inputWindowHandle.layer = child.mLayer; 324 inputWindowHandle.ownerPid = child.mSession.mPid; 325 inputWindowHandle.ownerUid = child.mSession.mUid; 326 inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures; 327 328 final Rect frame = child.mFrame; 329 inputWindowHandle.frameLeft = frame.left; 330 inputWindowHandle.frameTop = frame.top; 331 inputWindowHandle.frameRight = frame.right; 332 inputWindowHandle.frameBottom = frame.bottom; 333 334 if (child.mGlobalScale != 1) { 335 // If we are scaling the window, input coordinates need 336 // to be inversely scaled to map from what is on screen 337 // to what is actually being touched in the UI. 338 inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale; 339 } else { 340 inputWindowHandle.scaleFactor = 1; 341 } 342 343 if (DEBUG_INPUT) { 344 Slog.d(TAG_WM, "addInputWindowHandle: " 345 + child + ", " + inputWindowHandle); 346 } 347 addInputWindowHandle(inputWindowHandle); 348 if (hasFocus) { 349 mFocusedInputWindowHandle = inputWindowHandle; 350 } 351 } 352 clearInputWindowHandlesLw()353 private void clearInputWindowHandlesLw() { 354 while (mInputWindowHandleCount != 0) { 355 mInputWindowHandles[--mInputWindowHandleCount] = null; 356 } 357 mFocusedInputWindowHandle = null; 358 } 359 setUpdateInputWindowsNeededLw()360 void setUpdateInputWindowsNeededLw() { 361 mUpdateInputWindowsNeeded = true; 362 } 363 364 /* Updates the cached window information provided to the input dispatcher. */ updateInputWindowsLw(boolean force)365 void updateInputWindowsLw(boolean force) { 366 if (!force && !mUpdateInputWindowsNeeded) { 367 return; 368 } 369 mUpdateInputWindowsNeeded = false; 370 371 if (false) Slog.d(TAG_WM, ">>>>>> ENTERED updateInputWindowsLw"); 372 373 // Populate the input window list with information about all of the windows that 374 // could potentially receive input. 375 // As an optimization, we could try to prune the list of windows but this turns 376 // out to be difficult because only the native code knows for sure which window 377 // currently has touch focus. 378 379 // If there's a drag in flight, provide a pseudo-window to catch drag input 380 final boolean inDrag = mService.mDragDropController.dragDropActiveLocked(); 381 if (inDrag) { 382 if (DEBUG_DRAG) { 383 Log.d(TAG_WM, "Inserting drag window"); 384 } 385 final InputWindowHandle dragWindowHandle = 386 mService.mDragDropController.getInputWindowHandleLocked(); 387 if (dragWindowHandle != null) { 388 addInputWindowHandle(dragWindowHandle); 389 } else { 390 Slog.w(TAG_WM, "Drag is in progress but there is no " 391 + "drag window handle."); 392 } 393 } 394 395 final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked(); 396 if (inPositioning) { 397 if (DEBUG_TASK_POSITIONING) { 398 Log.d(TAG_WM, "Inserting window handle for repositioning"); 399 } 400 final InputWindowHandle dragWindowHandle = 401 mService.mTaskPositioningController.getDragWindowHandleLocked(); 402 if (dragWindowHandle != null) { 403 addInputWindowHandle(dragWindowHandle); 404 } else { 405 Slog.e(TAG_WM, 406 "Repositioning is in progress but there is no drag window handle."); 407 } 408 } 409 410 // Add all windows on the default display. 411 mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag); 412 413 if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw"); 414 } 415 416 /* Notifies that the input device configuration has changed. */ 417 @Override notifyConfigurationChanged()418 public void notifyConfigurationChanged() { 419 // TODO(multi-display): Notify proper displays that are associated with this input device. 420 mService.sendNewConfiguration(DEFAULT_DISPLAY); 421 422 synchronized (mInputDevicesReadyMonitor) { 423 if (!mInputDevicesReady) { 424 mInputDevicesReady = true; 425 mInputDevicesReadyMonitor.notifyAll(); 426 } 427 } 428 } 429 430 /* Waits until the built-in input devices have been configured. */ waitForInputDevicesReady(long timeoutMillis)431 public boolean waitForInputDevicesReady(long timeoutMillis) { 432 synchronized (mInputDevicesReadyMonitor) { 433 if (!mInputDevicesReady) { 434 try { 435 mInputDevicesReadyMonitor.wait(timeoutMillis); 436 } catch (InterruptedException ex) { 437 } 438 } 439 return mInputDevicesReady; 440 } 441 } 442 443 /* Notifies that the lid switch changed state. */ 444 @Override notifyLidSwitchChanged(long whenNanos, boolean lidOpen)445 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 446 mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); 447 } 448 449 /* Notifies that the camera lens cover state has changed. */ 450 @Override notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered)451 public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { 452 mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); 453 } 454 455 /* Provides an opportunity for the window manager policy to intercept early key 456 * processing as soon as the key has been read from the device. */ 457 @Override interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)458 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 459 return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); 460 } 461 462 /* Provides an opportunity for the window manager policy to intercept early motion event 463 * processing when the device is in a non-interactive state since these events are normally 464 * dropped. */ 465 @Override interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags)466 public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { 467 return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive( 468 whenNanos, policyFlags); 469 } 470 471 /* Provides an opportunity for the window manager policy to process a key before 472 * ordinary dispatch. */ 473 @Override interceptKeyBeforeDispatching( InputWindowHandle focus, KeyEvent event, int policyFlags)474 public long interceptKeyBeforeDispatching( 475 InputWindowHandle focus, KeyEvent event, int policyFlags) { 476 WindowState windowState = focus != null ? (WindowState) focus.windowState : null; 477 return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); 478 } 479 480 /* Provides an opportunity for the window manager policy to process a key that 481 * the application did not handle. */ 482 @Override dispatchUnhandledKey( InputWindowHandle focus, KeyEvent event, int policyFlags)483 public KeyEvent dispatchUnhandledKey( 484 InputWindowHandle focus, KeyEvent event, int policyFlags) { 485 WindowState windowState = focus != null ? (WindowState) focus.windowState : null; 486 return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); 487 } 488 489 /* Callback to get pointer layer. */ 490 @Override getPointerLayer()491 public int getPointerLayer() { 492 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER) 493 * WindowManagerService.TYPE_LAYER_MULTIPLIER 494 + WindowManagerService.TYPE_LAYER_OFFSET; 495 } 496 497 /* Called when the current input focus changes. 498 * Layer assignment is assumed to be complete by the time this is called. 499 */ setInputFocusLw(WindowState newWindow, boolean updateInputWindows)500 public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) { 501 if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) { 502 Slog.d(TAG_WM, "Input focus has changed to " + newWindow); 503 } 504 505 if (newWindow != mInputFocus) { 506 if (newWindow != null && newWindow.canReceiveKeys()) { 507 // Displaying a window implicitly causes dispatching to be unpaused. 508 // This is to protect against bugs if someone pauses dispatching but 509 // forgets to resume. 510 newWindow.mToken.paused = false; 511 } 512 513 mInputFocus = newWindow; 514 setUpdateInputWindowsNeededLw(); 515 516 if (updateInputWindows) { 517 updateInputWindowsLw(false /*force*/); 518 } 519 } 520 } 521 setFocusedAppLw(AppWindowToken newApp)522 public void setFocusedAppLw(AppWindowToken newApp) { 523 // Focused app has changed. 524 if (newApp == null) { 525 mService.mInputManager.setFocusedApplication(null); 526 } else { 527 final InputApplicationHandle handle = newApp.mInputApplicationHandle; 528 handle.name = newApp.toString(); 529 handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos; 530 531 mService.mInputManager.setFocusedApplication(handle); 532 } 533 } 534 pauseDispatchingLw(WindowToken window)535 public void pauseDispatchingLw(WindowToken window) { 536 if (! window.paused) { 537 if (DEBUG_INPUT) { 538 Slog.v(TAG_WM, "Pausing WindowToken " + window); 539 } 540 541 window.paused = true; 542 updateInputWindowsLw(true /*force*/); 543 } 544 } 545 resumeDispatchingLw(WindowToken window)546 public void resumeDispatchingLw(WindowToken window) { 547 if (window.paused) { 548 if (DEBUG_INPUT) { 549 Slog.v(TAG_WM, "Resuming WindowToken " + window); 550 } 551 552 window.paused = false; 553 updateInputWindowsLw(true /*force*/); 554 } 555 } 556 freezeInputDispatchingLw()557 public void freezeInputDispatchingLw() { 558 if (!mInputDispatchFrozen) { 559 if (DEBUG_INPUT) { 560 Slog.v(TAG_WM, "Freezing input dispatching"); 561 } 562 563 mInputDispatchFrozen = true; 564 565 if (DEBUG_INPUT || true) { 566 mInputFreezeReason = Debug.getCallers(6); 567 } 568 updateInputDispatchModeLw(); 569 } 570 } 571 thawInputDispatchingLw()572 public void thawInputDispatchingLw() { 573 if (mInputDispatchFrozen) { 574 if (DEBUG_INPUT) { 575 Slog.v(TAG_WM, "Thawing input dispatching"); 576 } 577 578 mInputDispatchFrozen = false; 579 mInputFreezeReason = null; 580 updateInputDispatchModeLw(); 581 } 582 } 583 setEventDispatchingLw(boolean enabled)584 public void setEventDispatchingLw(boolean enabled) { 585 if (mInputDispatchEnabled != enabled) { 586 if (DEBUG_INPUT) { 587 Slog.v(TAG_WM, "Setting event dispatching to " + enabled); 588 } 589 590 mInputDispatchEnabled = enabled; 591 updateInputDispatchModeLw(); 592 } 593 } 594 updateInputDispatchModeLw()595 private void updateInputDispatchModeLw() { 596 mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen); 597 } 598 dump(PrintWriter pw, String prefix)599 void dump(PrintWriter pw, String prefix) { 600 if (mInputFreezeReason != null) { 601 pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason); 602 } 603 final Set<String> inputConsumerKeys = mInputConsumers.keySet(); 604 if (!inputConsumerKeys.isEmpty()) { 605 pw.println(prefix + "InputConsumers:"); 606 for (String key : inputConsumerKeys) { 607 mInputConsumers.get(key).dump(pw, key, prefix); 608 } 609 } 610 } 611 612 private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> { 613 614 InputConsumerImpl navInputConsumer; 615 InputConsumerImpl pipInputConsumer; 616 InputConsumerImpl wallpaperInputConsumer; 617 InputConsumerImpl recentsAnimationInputConsumer; 618 boolean inDrag; 619 WallpaperController wallpaperController; 620 updateInputWindows(boolean inDrag)621 private void updateInputWindows(boolean inDrag) { 622 623 // TODO: multi-display 624 navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY); 625 pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY); 626 wallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER, DEFAULT_DISPLAY); 627 recentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION, 628 DEFAULT_DISPLAY); 629 mAddInputConsumerHandle = navInputConsumer != null; 630 mAddPipInputConsumerHandle = pipInputConsumer != null; 631 mAddWallpaperInputConsumerHandle = wallpaperInputConsumer != null; 632 mAddRecentsAnimationInputConsumerHandle = recentsAnimationInputConsumer != null; 633 mTmpRect.setEmpty(); 634 mDisableWallpaperTouchEvents = false; 635 this.inDrag = inDrag; 636 wallpaperController = mService.mRoot.mWallpaperController; 637 638 mService.mRoot.forAllWindows(this, true /* traverseTopToBottom */); 639 if (mAddWallpaperInputConsumerHandle) { 640 // No visible wallpaper found, add the wallpaper input consumer at the end. 641 addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); 642 } 643 644 // Send windows to native code. 645 mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle); 646 647 clearInputWindowHandlesLw(); 648 } 649 650 @Override accept(WindowState w)651 public void accept(WindowState w) { 652 final InputChannel inputChannel = w.mInputChannel; 653 final InputWindowHandle inputWindowHandle = w.mInputWindowHandle; 654 if (inputChannel == null || inputWindowHandle == null || w.mRemoved 655 || w.canReceiveTouchInput()) { 656 // Skip this window because it cannot possibly receive input. 657 return; 658 } 659 660 final int flags = w.mAttrs.flags; 661 final int privateFlags = w.mAttrs.privateFlags; 662 final int type = w.mAttrs.type; 663 final boolean hasFocus = w == mInputFocus; 664 final boolean isVisible = w.isVisibleLw(); 665 666 if (mAddRecentsAnimationInputConsumerHandle) { 667 final RecentsAnimationController recentsAnimationController = 668 mService.getRecentsAnimationController(); 669 if (recentsAnimationController != null 670 && recentsAnimationController.hasInputConsumerForApp(w.mAppToken)) { 671 if (recentsAnimationController.updateInputConsumerForApp( 672 recentsAnimationInputConsumer, hasFocus)) { 673 addInputWindowHandle(recentsAnimationInputConsumer.mWindowHandle); 674 mAddRecentsAnimationInputConsumerHandle = false; 675 } 676 // Skip adding the window below regardless of whether there is an input consumer 677 // to handle it 678 return; 679 } 680 } 681 682 if (w.inPinnedWindowingMode()) { 683 if (mAddPipInputConsumerHandle 684 && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) { 685 // Update the bounds of the Pip input consumer to match the window bounds. 686 w.getBounds(mTmpRect); 687 pipInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect); 688 addInputWindowHandle(pipInputConsumer.mWindowHandle); 689 mAddPipInputConsumerHandle = false; 690 } 691 // TODO: Fix w.canReceiveTouchInput() to handle this case 692 if (!hasFocus) { 693 // Skip this pinned stack window if it does not have focus 694 return; 695 } 696 } 697 698 if (mAddInputConsumerHandle 699 && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) { 700 addInputWindowHandle(navInputConsumer.mWindowHandle); 701 mAddInputConsumerHandle = false; 702 } 703 704 if (mAddWallpaperInputConsumerHandle) { 705 if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) { 706 // Add the wallpaper input consumer above the first visible wallpaper. 707 addInputWindowHandle(wallpaperInputConsumer.mWindowHandle); 708 mAddWallpaperInputConsumerHandle = false; 709 } 710 } 711 712 if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { 713 mDisableWallpaperTouchEvents = true; 714 } 715 final boolean hasWallpaper = wallpaperController.isWallpaperTarget(w) 716 && (privateFlags & PRIVATE_FLAG_KEYGUARD) == 0 717 && !mDisableWallpaperTouchEvents; 718 719 // If there's a drag in progress and 'child' is a potential drop target, 720 // make sure it's been told about the drag 721 if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) { 722 mService.mDragDropController.sendDragStartedIfNeededLocked(w); 723 } 724 725 addInputWindowHandle( 726 inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper); 727 } 728 } 729 } 730