InputMonitor.java revision 768012e4c18dd8650bf1b067f7e0b37a3c5db462
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;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
30import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
31import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
32import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
33
34import android.app.ActivityManager;
35import android.graphics.Rect;
36import android.os.Debug;
37import android.os.Looper;
38import android.os.RemoteException;
39import android.util.ArrayMap;
40import android.util.Log;
41import android.util.Slog;
42import android.view.InputChannel;
43import android.view.InputEventReceiver;
44import android.view.KeyEvent;
45import android.view.WindowManager;
46
47import android.view.WindowManagerPolicy;
48
49import com.android.server.input.InputApplicationHandle;
50import com.android.server.input.InputManagerService;
51import com.android.server.input.InputWindowHandle;
52
53import java.io.PrintWriter;
54import java.util.Arrays;
55import java.util.Set;
56import java.util.function.Consumer;
57
58final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
59    private final WindowManagerService mService;
60
61    // Current window with input focus for keys and other non-touch events.  May be null.
62    private WindowState mInputFocus;
63
64    // When true, prevents input dispatch from proceeding until set to false again.
65    private boolean mInputDispatchFrozen;
66
67    // The reason the input is currently frozen or null if the input isn't frozen.
68    private String mInputFreezeReason = null;
69
70    // When true, input dispatch proceeds normally.  Otherwise all events are dropped.
71    // Initially false, so that input does not get dispatched until boot is finished at
72    // which point the ActivityManager will enable dispatching.
73    private boolean mInputDispatchEnabled;
74
75    // When true, need to call updateInputWindowsLw().
76    private boolean mUpdateInputWindowsNeeded = true;
77
78    // Array of window handles to provide to the input dispatcher.
79    private InputWindowHandle[] mInputWindowHandles;
80    private int mInputWindowHandleCount;
81    private InputWindowHandle mFocusedInputWindowHandle;
82
83    private boolean mAddInputConsumerHandle;
84    private boolean mAddPipInputConsumerHandle;
85    private boolean mAddWallpaperInputConsumerHandle;
86    private boolean mDisableWallpaperTouchEvents;
87    private final Rect mTmpRect = new Rect();
88    private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer =
89            new UpdateInputForAllWindowsConsumer();
90
91    // Set to true when the first input device configuration change notification
92    // is received to indicate that the input devices are ready.
93    private final Object mInputDevicesReadyMonitor = new Object();
94    private boolean mInputDevicesReady;
95
96    /**
97     * The set of input consumer added to the window manager by name, which consumes input events
98     * for the windows below it.
99     */
100    private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
101
102    private static final class EventReceiverInputConsumer extends InputConsumerImpl
103            implements WindowManagerPolicy.InputConsumer {
104        private InputMonitor mInputMonitor;
105        private final InputEventReceiver mInputEventReceiver;
106
107        EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor,
108                                   Looper looper, String name,
109                                   InputEventReceiver.Factory inputEventReceiverFactory) {
110            super(service, name, null);
111            mInputMonitor = monitor;
112            mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
113                    mClientChannel, looper);
114        }
115
116        @Override
117        public void dismiss() {
118            synchronized (mService.mWindowMap) {
119                if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) {
120                    mInputEventReceiver.dispose();
121                }
122            }
123        }
124    }
125
126    public InputMonitor(WindowManagerService service) {
127        mService = service;
128    }
129
130    private void addInputConsumer(String name, InputConsumerImpl consumer) {
131        mInputConsumers.put(name, consumer);
132        updateInputWindowsLw(true /* force */);
133    }
134
135    boolean destroyInputConsumer(String name) {
136        if (disposeInputConsumer(mInputConsumers.remove(name))) {
137            updateInputWindowsLw(true /* force */);
138            return true;
139        }
140        return false;
141    }
142
143    private boolean disposeInputConsumer(InputConsumerImpl consumer) {
144        if (consumer != null) {
145            consumer.disposeChannelsLw();
146            return true;
147        }
148        return false;
149    }
150
151    InputConsumerImpl getInputConsumer(String name, int displayId) {
152        // TODO(multi-display): Allow input consumers on non-default displays?
153        return (displayId == DEFAULT_DISPLAY) ? mInputConsumers.get(name) : null;
154    }
155
156    void layoutInputConsumers(int dw, int dh) {
157        for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
158            mInputConsumers.valueAt(i).layout(dw, dh);
159        }
160    }
161
162    WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
163            InputEventReceiver.Factory inputEventReceiverFactory) {
164        if (mInputConsumers.containsKey(name)) {
165            throw new IllegalStateException("Existing input consumer found with name: " + name);
166        }
167
168        final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService,
169                this, looper, name, inputEventReceiverFactory);
170        addInputConsumer(name, consumer);
171        return consumer;
172    }
173
174    void createInputConsumer(String name, InputChannel inputChannel) {
175        if (mInputConsumers.containsKey(name)) {
176            throw new IllegalStateException("Existing input consumer found with name: " + name);
177        }
178
179        final InputConsumerImpl consumer = new InputConsumerImpl(mService, name, inputChannel);
180        switch (name) {
181            case INPUT_CONSUMER_WALLPAPER:
182                consumer.mWindowHandle.hasWallpaper = true;
183                break;
184            case INPUT_CONSUMER_PIP:
185                // The touchable region of the Pip input window is cropped to the bounds of the
186                // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
187                consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL;
188                break;
189        }
190        addInputConsumer(name, consumer);
191    }
192
193    /* Notifies the window manager about a broken input channel.
194     *
195     * Called by the InputManager.
196     */
197    @Override
198    public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {
199        if (inputWindowHandle == null) {
200            return;
201        }
202
203        synchronized (mService.mWindowMap) {
204            WindowState windowState = (WindowState) inputWindowHandle.windowState;
205            if (windowState != null) {
206                Slog.i(TAG_WM, "WINDOW DIED " + windowState);
207                windowState.removeIfPossible();
208            }
209        }
210    }
211
212    /* Notifies the window manager about an application that is not responding.
213     * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
214     *
215     * Called by the InputManager.
216     */
217    @Override
218    public long notifyANR(InputApplicationHandle inputApplicationHandle,
219            InputWindowHandle inputWindowHandle, String reason) {
220        AppWindowToken appWindowToken = null;
221        WindowState windowState = null;
222        boolean aboveSystem = false;
223        synchronized (mService.mWindowMap) {
224            if (inputWindowHandle != null) {
225                windowState = (WindowState) inputWindowHandle.windowState;
226                if (windowState != null) {
227                    appWindowToken = windowState.mAppToken;
228                }
229            }
230            if (appWindowToken == null && inputApplicationHandle != null) {
231                appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken;
232            }
233
234            if (windowState != null) {
235                Slog.i(TAG_WM, "Input event dispatching timed out "
236                        + "sending to " + windowState.mAttrs.getTitle()
237                        + ".  Reason: " + reason);
238                // Figure out whether this window is layered above system windows.
239                // We need to do this here to help the activity manager know how to
240                // layer its ANR dialog.
241                int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw(
242                        TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow);
243                aboveSystem = windowState.mBaseLayer > systemAlertLayer;
244            } else if (appWindowToken != null) {
245                Slog.i(TAG_WM, "Input event dispatching timed out "
246                        + "sending to application " + appWindowToken.stringName
247                        + ".  Reason: " + reason);
248            } else {
249                Slog.i(TAG_WM, "Input event dispatching timed out "
250                        + ".  Reason: " + reason);
251            }
252
253            mService.saveANRStateLocked(appWindowToken, windowState, reason);
254        }
255
256        // All the calls below need to happen without the WM lock held since they call into AM.
257        mService.mAmInternal.saveANRState(reason);
258
259        if (appWindowToken != null && appWindowToken.appToken != null) {
260            // Notify the activity manager about the timeout and let it decide whether
261            // to abort dispatching or keep waiting.
262            final AppWindowContainerController controller = appWindowToken.getController();
263            final boolean abort = controller != null
264                    && controller.keyDispatchingTimedOut(reason,
265                            (windowState != null) ? windowState.mSession.mPid : -1);
266            if (!abort) {
267                // The activity manager declined to abort dispatching.
268                // Wait a bit longer and timeout again later.
269                return appWindowToken.mInputDispatchingTimeoutNanos;
270            }
271        } else if (windowState != null) {
272            try {
273                // Notify the activity manager about the timeout and let it decide whether
274                // to abort dispatching or keep waiting.
275                long timeout = ActivityManager.getService().inputDispatchingTimedOut(
276                        windowState.mSession.mPid, aboveSystem, reason);
277                if (timeout >= 0) {
278                    // The activity manager declined to abort dispatching.
279                    // Wait a bit longer and timeout again later.
280                    return timeout * 1000000L; // nanoseconds
281                }
282            } catch (RemoteException ex) {
283            }
284        }
285        return 0; // abort dispatching
286    }
287
288    private void addInputWindowHandle(final InputWindowHandle windowHandle) {
289        if (mInputWindowHandles == null) {
290            mInputWindowHandles = new InputWindowHandle[16];
291        }
292        if (mInputWindowHandleCount >= mInputWindowHandles.length) {
293            mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
294                    mInputWindowHandleCount * 2);
295        }
296        mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
297    }
298
299    void addInputWindowHandle(final InputWindowHandle inputWindowHandle,
300            final WindowState child, int flags, final int type, final boolean isVisible,
301            final boolean hasFocus, final boolean hasWallpaper) {
302        // Add a window to our list of input windows.
303        inputWindowHandle.name = child.toString();
304        flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags);
305        inputWindowHandle.layoutParamsFlags = flags;
306        inputWindowHandle.layoutParamsType = type;
307        inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
308        inputWindowHandle.visible = isVisible;
309        inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
310        inputWindowHandle.hasFocus = hasFocus;
311        inputWindowHandle.hasWallpaper = hasWallpaper;
312        inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
313        inputWindowHandle.layer = child.mLayer;
314        inputWindowHandle.ownerPid = child.mSession.mPid;
315        inputWindowHandle.ownerUid = child.mSession.mUid;
316        inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
317
318        final Rect frame = child.mFrame;
319        inputWindowHandle.frameLeft = frame.left;
320        inputWindowHandle.frameTop = frame.top;
321        inputWindowHandle.frameRight = frame.right;
322        inputWindowHandle.frameBottom = frame.bottom;
323
324        if (child.mGlobalScale != 1) {
325            // If we are scaling the window, input coordinates need
326            // to be inversely scaled to map from what is on screen
327            // to what is actually being touched in the UI.
328            inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
329        } else {
330            inputWindowHandle.scaleFactor = 1;
331        }
332
333        if (DEBUG_INPUT) {
334            Slog.d(TAG_WM, "addInputWindowHandle: "
335                    + child + ", " + inputWindowHandle);
336        }
337        addInputWindowHandle(inputWindowHandle);
338        if (hasFocus) {
339            mFocusedInputWindowHandle = inputWindowHandle;
340        }
341    }
342
343    private void clearInputWindowHandlesLw() {
344        while (mInputWindowHandleCount != 0) {
345            mInputWindowHandles[--mInputWindowHandleCount] = null;
346        }
347        mFocusedInputWindowHandle = null;
348    }
349
350    void setUpdateInputWindowsNeededLw() {
351        mUpdateInputWindowsNeeded = true;
352    }
353
354    /* Updates the cached window information provided to the input dispatcher. */
355    void updateInputWindowsLw(boolean force) {
356        if (!force && !mUpdateInputWindowsNeeded) {
357            return;
358        }
359        mUpdateInputWindowsNeeded = false;
360
361        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED updateInputWindowsLw");
362
363        // Populate the input window list with information about all of the windows that
364        // could potentially receive input.
365        // As an optimization, we could try to prune the list of windows but this turns
366        // out to be difficult because only the native code knows for sure which window
367        // currently has touch focus.
368
369        // If there's a drag in flight, provide a pseudo-window to catch drag input
370        final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
371        if (inDrag) {
372            if (DEBUG_DRAG) {
373                Log.d(TAG_WM, "Inserting drag window");
374            }
375            final InputWindowHandle dragWindowHandle =
376                    mService.mDragDropController.getInputWindowHandleLocked();
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.inPinnedWindowingMode()) {
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.mDragDropController.sendDragStartedIfNeededLocked(w);
694            }
695
696            addInputWindowHandle(
697                    inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper);
698        }
699    }
700}
701