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