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