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.app.ActivityManager.StackId.PINNED_STACK_ID;
20import static android.view.Display.DEFAULT_DISPLAY;
21import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
22import static android.view.WindowManager.INPUT_CONSUMER_PIP;
23import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
24import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
25import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
26import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
27import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
28import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
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.Looper;
39import android.os.RemoteException;
40import android.util.ArrayMap;
41import android.util.Log;
42import android.util.Slog;
43import android.view.InputChannel;
44import android.view.InputEventReceiver;
45import android.view.KeyEvent;
46import android.view.WindowManager;
47
48import android.view.WindowManagerPolicy;
49
50import com.android.server.input.InputApplicationHandle;
51import com.android.server.input.InputManagerService;
52import com.android.server.input.InputWindowHandle;
53
54import java.io.PrintWriter;
55import java.util.Arrays;
56import java.util.Set;
57import java.util.function.Consumer;
58
59final 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
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
118        public void dismiss() {
119            synchronized (mService.mWindowMap) {
120                if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) {
121                    mInputEventReceiver.dispose();
122                }
123            }
124        }
125    }
126
127    public InputMonitor(WindowManagerService service) {
128        mService = service;
129    }
130
131    private void addInputConsumer(String name, InputConsumerImpl consumer) {
132        mInputConsumers.put(name, consumer);
133        updateInputWindowsLw(true /* force */);
134    }
135
136    boolean destroyInputConsumer(String name) {
137        if (disposeInputConsumer(mInputConsumers.remove(name))) {
138            updateInputWindowsLw(true /* force */);
139            return true;
140        }
141        return false;
142    }
143
144    private boolean disposeInputConsumer(InputConsumerImpl consumer) {
145        if (consumer != null) {
146            consumer.disposeChannelsLw();
147            return true;
148        }
149        return false;
150    }
151
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
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
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
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
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
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
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
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
344    private void clearInputWindowHandlesLw() {
345        while (mInputWindowHandleCount != 0) {
346            mInputWindowHandles[--mInputWindowHandleCount] = null;
347        }
348        mFocusedInputWindowHandle = null;
349    }
350
351    void setUpdateInputWindowsNeededLw() {
352        mUpdateInputWindowsNeeded = true;
353    }
354
355    /* Updates the cached window information provided to the input dispatcher. */
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
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. */
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
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
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
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
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
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
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
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     */
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
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
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
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
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
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
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
584    private void updateInputDispatchModeLw() {
585        mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
586    }
587
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
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
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