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