InputMonitor.java revision 61ecc1bb39c475e790a6d23afa16204e294432a9
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.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        if (appWindowToken != null && appWindowToken.appToken != null) {
257            // Notify the activity manager about the timeout and let it decide whether
258            // to abort dispatching or keep waiting.
259            final AppWindowContainerController controller = appWindowToken.getController();
260            final boolean abort = controller != null && controller.keyDispatchingTimedOut(reason);
261            if (!abort) {
262                // The activity manager declined to abort dispatching.
263                // Wait a bit longer and timeout again later.
264                return appWindowToken.mInputDispatchingTimeoutNanos;
265            }
266        } else if (windowState != null) {
267            try {
268                // Notify the activity manager about the timeout and let it decide whether
269                // to abort dispatching or keep waiting.
270                long timeout = ActivityManager.getService().inputDispatchingTimedOut(
271                        windowState.mSession.mPid, aboveSystem, reason);
272                if (timeout >= 0) {
273                    // The activity manager declined to abort dispatching.
274                    // Wait a bit longer and timeout again later.
275                    return timeout * 1000000L; // nanoseconds
276                }
277            } catch (RemoteException ex) {
278            }
279        }
280        return 0; // abort dispatching
281    }
282
283    void addInputWindowHandle(final InputWindowHandle windowHandle) {
284        if (mInputWindowHandles == null) {
285            mInputWindowHandles = new InputWindowHandle[16];
286        }
287        if (mInputWindowHandleCount >= mInputWindowHandles.length) {
288            mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
289                    mInputWindowHandleCount * 2);
290        }
291        mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
292    }
293
294    void addInputWindowHandle(final InputWindowHandle inputWindowHandle,
295            final WindowState child, int flags, final int type, final boolean isVisible,
296            final boolean hasFocus, final boolean hasWallpaper) {
297        // Add a window to our list of input windows.
298        inputWindowHandle.name = child.toString();
299        flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags);
300        inputWindowHandle.layoutParamsFlags = flags;
301        inputWindowHandle.layoutParamsType = type;
302        inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
303        inputWindowHandle.visible = isVisible;
304        inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
305        inputWindowHandle.hasFocus = hasFocus;
306        inputWindowHandle.hasWallpaper = hasWallpaper;
307        inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
308        inputWindowHandle.layer = child.mLayer;
309        inputWindowHandle.ownerPid = child.mSession.mPid;
310        inputWindowHandle.ownerUid = child.mSession.mUid;
311        inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
312
313        final Rect frame = child.mFrame;
314        inputWindowHandle.frameLeft = frame.left;
315        inputWindowHandle.frameTop = frame.top;
316        inputWindowHandle.frameRight = frame.right;
317        inputWindowHandle.frameBottom = frame.bottom;
318
319        if (child.mGlobalScale != 1) {
320            // If we are scaling the window, input coordinates need
321            // to be inversely scaled to map from what is on screen
322            // to what is actually being touched in the UI.
323            inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
324        } else {
325            inputWindowHandle.scaleFactor = 1;
326        }
327
328        if (DEBUG_INPUT) {
329            Slog.d(TAG_WM, "addInputWindowHandle: "
330                    + child + ", " + inputWindowHandle);
331        }
332        addInputWindowHandle(inputWindowHandle);
333        if (hasFocus) {
334            mFocusedInputWindowHandle = inputWindowHandle;
335        }
336    }
337
338    private void clearInputWindowHandlesLw() {
339        while (mInputWindowHandleCount != 0) {
340            mInputWindowHandles[--mInputWindowHandleCount] = null;
341        }
342        mFocusedInputWindowHandle = null;
343    }
344
345    void setUpdateInputWindowsNeededLw() {
346        mUpdateInputWindowsNeeded = true;
347    }
348
349    /* Updates the cached window information provided to the input dispatcher. */
350    void updateInputWindowsLw(boolean force) {
351        if (!force && !mUpdateInputWindowsNeeded) {
352            return;
353        }
354        mUpdateInputWindowsNeeded = false;
355
356        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED updateInputWindowsLw");
357
358        // Populate the input window list with information about all of the windows that
359        // could potentially receive input.
360        // As an optimization, we could try to prune the list of windows but this turns
361        // out to be difficult because only the native code knows for sure which window
362        // currently has touch focus.
363
364        // If there's a drag in flight, provide a pseudo-window to catch drag input
365        final boolean inDrag = (mService.mDragState != null);
366        if (inDrag) {
367            if (DEBUG_DRAG) {
368                Log.d(TAG_WM, "Inserting drag window");
369            }
370            final InputWindowHandle dragWindowHandle = mService.mDragState.getInputWindowHandle();
371            if (dragWindowHandle != null) {
372                addInputWindowHandle(dragWindowHandle);
373            } else {
374                Slog.w(TAG_WM, "Drag is in progress but there is no "
375                        + "drag window handle.");
376            }
377        }
378
379        final boolean inPositioning = (mService.mTaskPositioner != null);
380        if (inPositioning) {
381            if (DEBUG_TASK_POSITIONING) {
382                Log.d(TAG_WM, "Inserting window handle for repositioning");
383            }
384            final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
385            if (dragWindowHandle != null) {
386                addInputWindowHandle(dragWindowHandle);
387            } else {
388                Slog.e(TAG_WM,
389                        "Repositioning is in progress but there is no drag window handle.");
390            }
391        }
392
393        // Add all windows on the default display.
394        mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
395
396        if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw");
397    }
398
399    /* Notifies that the input device configuration has changed. */
400    @Override
401    public void notifyConfigurationChanged() {
402        // TODO(multi-display): Notify proper displays that are associated with this input device.
403        mService.sendNewConfiguration(DEFAULT_DISPLAY);
404
405        synchronized (mInputDevicesReadyMonitor) {
406            if (!mInputDevicesReady) {
407                mInputDevicesReady = true;
408                mInputDevicesReadyMonitor.notifyAll();
409            }
410        }
411    }
412
413    /* Waits until the built-in input devices have been configured. */
414    public boolean waitForInputDevicesReady(long timeoutMillis) {
415        synchronized (mInputDevicesReadyMonitor) {
416            if (!mInputDevicesReady) {
417                try {
418                    mInputDevicesReadyMonitor.wait(timeoutMillis);
419                } catch (InterruptedException ex) {
420                }
421            }
422            return mInputDevicesReady;
423        }
424    }
425
426    /* Notifies that the lid switch changed state. */
427    @Override
428    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
429        mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
430    }
431
432    /* Notifies that the camera lens cover state has changed. */
433    @Override
434    public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
435        mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
436    }
437
438    /* Provides an opportunity for the window manager policy to intercept early key
439     * processing as soon as the key has been read from the device. */
440    @Override
441    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
442        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
443    }
444
445    /* Provides an opportunity for the window manager policy to intercept early motion event
446     * processing when the device is in a non-interactive state since these events are normally
447     * dropped. */
448    @Override
449    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
450        return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive(
451                whenNanos, policyFlags);
452    }
453
454    /* Provides an opportunity for the window manager policy to process a key before
455     * ordinary dispatch. */
456    @Override
457    public long interceptKeyBeforeDispatching(
458            InputWindowHandle focus, KeyEvent event, int policyFlags) {
459        WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
460        return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
461    }
462
463    /* Provides an opportunity for the window manager policy to process a key that
464     * the application did not handle. */
465    @Override
466    public KeyEvent dispatchUnhandledKey(
467            InputWindowHandle focus, KeyEvent event, int policyFlags) {
468        WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
469        return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
470    }
471
472    /* Callback to get pointer layer. */
473    @Override
474    public int getPointerLayer() {
475        return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER)
476                * WindowManagerService.TYPE_LAYER_MULTIPLIER
477                + WindowManagerService.TYPE_LAYER_OFFSET;
478    }
479
480    /* Called when the current input focus changes.
481     * Layer assignment is assumed to be complete by the time this is called.
482     */
483    public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
484        if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) {
485            Slog.d(TAG_WM, "Input focus has changed to " + newWindow);
486        }
487
488        if (newWindow != mInputFocus) {
489            if (newWindow != null && newWindow.canReceiveKeys()) {
490                // Displaying a window implicitly causes dispatching to be unpaused.
491                // This is to protect against bugs if someone pauses dispatching but
492                // forgets to resume.
493                newWindow.mToken.paused = false;
494            }
495
496            mInputFocus = newWindow;
497            setUpdateInputWindowsNeededLw();
498
499            if (updateInputWindows) {
500                updateInputWindowsLw(false /*force*/);
501            }
502        }
503    }
504
505    public void setFocusedAppLw(AppWindowToken newApp) {
506        // Focused app has changed.
507        if (newApp == null) {
508            mService.mInputManager.setFocusedApplication(null);
509        } else {
510            final InputApplicationHandle handle = newApp.mInputApplicationHandle;
511            handle.name = newApp.toString();
512            handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
513
514            mService.mInputManager.setFocusedApplication(handle);
515        }
516    }
517
518    public void pauseDispatchingLw(WindowToken window) {
519        if (! window.paused) {
520            if (DEBUG_INPUT) {
521                Slog.v(TAG_WM, "Pausing WindowToken " + window);
522            }
523
524            window.paused = true;
525            updateInputWindowsLw(true /*force*/);
526        }
527    }
528
529    public void resumeDispatchingLw(WindowToken window) {
530        if (window.paused) {
531            if (DEBUG_INPUT) {
532                Slog.v(TAG_WM, "Resuming WindowToken " + window);
533            }
534
535            window.paused = false;
536            updateInputWindowsLw(true /*force*/);
537        }
538    }
539
540    public void freezeInputDispatchingLw() {
541        if (!mInputDispatchFrozen) {
542            if (DEBUG_INPUT) {
543                Slog.v(TAG_WM, "Freezing input dispatching");
544            }
545
546            mInputDispatchFrozen = true;
547
548            if (DEBUG_INPUT || true) {
549                mInputFreezeReason = Debug.getCallers(6);
550            }
551            updateInputDispatchModeLw();
552        }
553    }
554
555    public void thawInputDispatchingLw() {
556        if (mInputDispatchFrozen) {
557            if (DEBUG_INPUT) {
558                Slog.v(TAG_WM, "Thawing input dispatching");
559            }
560
561            mInputDispatchFrozen = false;
562            mInputFreezeReason = null;
563            updateInputDispatchModeLw();
564        }
565    }
566
567    public void setEventDispatchingLw(boolean enabled) {
568        if (mInputDispatchEnabled != enabled) {
569            if (DEBUG_INPUT) {
570                Slog.v(TAG_WM, "Setting event dispatching to " + enabled);
571            }
572
573            mInputDispatchEnabled = enabled;
574            updateInputDispatchModeLw();
575        }
576    }
577
578    private void updateInputDispatchModeLw() {
579        mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
580    }
581
582    void dump(PrintWriter pw, String prefix) {
583        if (mInputFreezeReason != null) {
584            pw.println(prefix + "mInputFreezeReason=" + mInputFreezeReason);
585        }
586    }
587
588    private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
589
590        InputConsumerImpl navInputConsumer;
591        InputConsumerImpl pipInputConsumer;
592        InputConsumerImpl wallpaperInputConsumer;
593        Rect pipTouchableBounds;
594        boolean inDrag;
595        WallpaperController wallpaperController;
596
597        private void updateInputWindows(boolean inDrag) {
598
599            // TODO: multi-display
600            navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
601            pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
602            wallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER, DEFAULT_DISPLAY);
603            mAddInputConsumerHandle = navInputConsumer != null;
604            mAddPipInputConsumerHandle = pipInputConsumer != null;
605            mAddWallpaperInputConsumerHandle = wallpaperInputConsumer != null;
606            mTmpRect.setEmpty();
607            pipTouchableBounds = mAddPipInputConsumerHandle ? mTmpRect : null;
608            mDisableWallpaperTouchEvents = false;
609            this.inDrag = inDrag;
610            wallpaperController = mService.mRoot.mWallpaperController;
611
612            mService.mRoot.forAllWindows(this, true /* traverseTopToBottom */);
613            if (mAddWallpaperInputConsumerHandle) {
614                // No visible wallpaper found, add the wallpaper input consumer at the end.
615                addInputWindowHandle(wallpaperInputConsumer.mWindowHandle);
616            }
617
618            // Send windows to native code.
619            mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
620
621            clearInputWindowHandlesLw();
622        }
623
624        @Override
625        public void accept(WindowState w) {
626            final InputChannel inputChannel = w.mInputChannel;
627            final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
628            if (inputChannel == null || inputWindowHandle == null || w.mRemoved
629                    || w.canReceiveTouchInput()) {
630                // Skip this window because it cannot possibly receive input.
631                return;
632            }
633
634            final int flags = w.mAttrs.flags;
635            final int privateFlags = w.mAttrs.privateFlags;
636            final int type = w.mAttrs.type;
637            final boolean hasFocus = w == mInputFocus;
638            final boolean isVisible = w.isVisibleLw();
639
640            if (w.getStackId() == PINNED_STACK_ID) {
641                if (mAddPipInputConsumerHandle
642                        && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) {
643                    // Update the bounds of the Pip input consumer to match the Pinned stack
644                    w.getStack().getBounds(pipTouchableBounds);
645                    pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds);
646                    addInputWindowHandle(pipInputConsumer.mWindowHandle);
647                    mAddPipInputConsumerHandle = false;
648                }
649                // TODO: Fix w.canReceiveTouchInput() to handle this case
650                if (!hasFocus) {
651                    // Skip this pinned stack window if it does not have focus
652                    return;
653                }
654            }
655
656            if (mAddInputConsumerHandle
657                    && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) {
658                addInputWindowHandle(navInputConsumer.mWindowHandle);
659                mAddInputConsumerHandle = false;
660            }
661
662            if (mAddWallpaperInputConsumerHandle) {
663                if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) {
664                    // Add the wallpaper input consumer above the first visible wallpaper.
665                    addInputWindowHandle(wallpaperInputConsumer.mWindowHandle);
666                    mAddWallpaperInputConsumerHandle = false;
667                }
668            }
669
670            if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
671                mDisableWallpaperTouchEvents = true;
672            }
673            final boolean hasWallpaper = wallpaperController.isWallpaperTarget(w)
674                    && (privateFlags & PRIVATE_FLAG_KEYGUARD) == 0
675                    && !mDisableWallpaperTouchEvents;
676
677            // If there's a drag in progress and 'child' is a potential drop target,
678            // make sure it's been told about the drag
679            if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
680                mService.mDragState.sendDragStartedIfNeededLw(w);
681            }
682
683            addInputWindowHandle(
684                    inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper);
685        }
686    }
687}
688