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