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