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