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