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.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
21 import static android.view.Display.INVALID_DISPLAY;
22 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
23 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
24 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
25 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
26 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
27 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
28 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
29 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
30 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
31 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
32 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
33 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
34 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
35 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
36 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
37 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
38 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
39 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
40 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
41 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
42 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
43 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
44 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
45 
46 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
47 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
48 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
49 import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
50 
51 import static java.lang.Integer.MAX_VALUE;
52 
53 import android.annotation.Nullable;
54 import android.graphics.Region;
55 import android.os.Handler;
56 import android.os.IBinder;
57 import android.os.Looper;
58 import android.os.Trace;
59 import android.os.UserHandle;
60 import android.util.ArrayMap;
61 import android.util.EventLog;
62 import android.util.Slog;
63 import android.view.InputChannel;
64 import android.view.InputEventReceiver;
65 import android.view.InputWindowHandle;
66 import android.view.SurfaceControl;
67 
68 import com.android.internal.annotations.VisibleForTesting;
69 import com.android.internal.protolog.common.ProtoLog;
70 
71 import java.io.PrintWriter;
72 import java.lang.ref.WeakReference;
73 import java.util.Set;
74 import java.util.function.Consumer;
75 
76 final class InputMonitor {
77     private final WindowManagerService mService;
78 
79     // Current input focus token for keys and other non-touch events.  May be null.
80     private IBinder mInputFocus = null;
81 
82     // When true, need to call updateInputWindowsLw().
83     private boolean mUpdateInputWindowsNeeded = true;
84     private boolean mUpdateInputWindowsPending;
85     private boolean mUpdateInputWindowsImmediately;
86 
87     private boolean mDisableWallpaperTouchEvents;
88     private final Region mTmpRegion = new Region();
89     private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
90 
91     private final int mDisplayId;
92     private final DisplayContent mDisplayContent;
93     private boolean mDisplayRemoved;
94     private int mDisplayWidth;
95     private int mDisplayHeight;
96 
97     private final SurfaceControl.Transaction mInputTransaction;
98     private final Handler mHandler;
99 
100     /**
101      * The set of input consumer added to the window manager by name, which consumes input events
102      * for the windows below it.
103      */
104     private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
105 
106     /**
107      * Set when recents (overview) is active as part of a shell transition. While set, any focus
108      * going to the recents activity will be redirected to the Recents input consumer. Since we
109      * draw the live-tile above the recents activity, we also need to provide that activity as a
110      * z-layering reference so that we can place the recents input consumer above it.
111      */
112     private WeakReference<ActivityRecord> mActiveRecentsActivity = null;
113     private WeakReference<ActivityRecord> mActiveRecentsLayerRef = null;
114 
115     /**
116      * Representation of a input consumer that the policy has added to the window manager to consume
117      * input events going to windows below it.
118      */
119     static final class EventReceiverInputConsumer extends InputConsumerImpl {
120         private InputMonitor mInputMonitor;
121         private final InputEventReceiver mInputEventReceiver;
122 
EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor, Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory, int clientPid, UserHandle clientUser, int displayId)123         EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor,
124                                    Looper looper, String name,
125                                    InputEventReceiver.Factory inputEventReceiverFactory,
126                                    int clientPid, UserHandle clientUser, int displayId) {
127             super(service, null /* token */, name, null /* inputChannel */, clientPid, clientUser,
128                     displayId);
129             mInputMonitor = monitor;
130             mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
131                     mClientChannel, looper);
132         }
133 
134         /** Removes the input consumer from the window manager. */
dismiss()135         void dismiss() {
136             synchronized (mService.mGlobalLock) {
137                 mInputMonitor.mInputConsumers.remove(mName);
138                 hide(mInputMonitor.mInputTransaction);
139                 mInputMonitor.updateInputWindowsLw(true /* force */);
140             }
141         }
142 
143         /** Disposes the input consumer and input receiver from the associated thread. */
dispose()144         void dispose() {
145             synchronized (mService.mGlobalLock) {
146                 disposeChannelsLw(mInputMonitor.mInputTransaction);
147                 mInputEventReceiver.dispose();
148                 mInputMonitor.updateInputWindowsLw(true /* force */);
149             }
150         }
151     }
152 
153     private class UpdateInputWindows implements Runnable {
154         @Override
run()155         public void run() {
156             synchronized (mService.mGlobalLock) {
157                 mUpdateInputWindowsPending = false;
158                 mUpdateInputWindowsNeeded = false;
159 
160                 if (mDisplayRemoved) {
161                     return;
162                 }
163 
164                 // Populate the input window list with information about all of the windows that
165                 // could potentially receive input.
166                 // As an optimization, we could try to prune the list of windows but this turns
167                 // out to be difficult because only the native code knows for sure which window
168                 // currently has touch focus.
169 
170                 // If there's a drag in flight, provide a pseudo-window to catch drag input
171                 final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
172 
173                 // Add all windows on the default display.
174                 mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
175             }
176         }
177     }
178 
179     private final UpdateInputWindows mUpdateInputWindows = new UpdateInputWindows();
180 
InputMonitor(WindowManagerService service, DisplayContent displayContent)181     InputMonitor(WindowManagerService service, DisplayContent displayContent) {
182         mService = service;
183         mDisplayContent = displayContent;
184         mDisplayId = displayContent.getDisplayId();
185         mInputTransaction = mService.mTransactionFactory.get();
186         mHandler = mService.mAnimationHandler;
187         mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer();
188     }
189 
onDisplayRemoved()190     void onDisplayRemoved() {
191         mHandler.removeCallbacks(mUpdateInputWindows);
192         mHandler.post(() -> {
193             // Make sure any pending setInputWindowInfo transactions are completed. That prevents
194             // the timing of updating input info of removed display after cleanup.
195             mService.mTransactionFactory.get().syncInputWindows().apply();
196             // It calls InputDispatcher::setInputWindows directly.
197             mService.mInputManager.onDisplayRemoved(mDisplayId);
198         });
199         mDisplayRemoved = true;
200     }
201 
addInputConsumer(String name, InputConsumerImpl consumer)202     private void addInputConsumer(String name, InputConsumerImpl consumer) {
203         mInputConsumers.put(name, consumer);
204         consumer.linkToDeathRecipient();
205         consumer.layout(mInputTransaction, mDisplayWidth, mDisplayHeight);
206         updateInputWindowsLw(true /* force */);
207     }
208 
destroyInputConsumer(String name)209     boolean destroyInputConsumer(String name) {
210         if (disposeInputConsumer(mInputConsumers.remove(name))) {
211             updateInputWindowsLw(true /* force */);
212             return true;
213         }
214         return false;
215     }
216 
disposeInputConsumer(InputConsumerImpl consumer)217     private boolean disposeInputConsumer(InputConsumerImpl consumer) {
218         if (consumer != null) {
219             consumer.disposeChannelsLw(mInputTransaction);
220             return true;
221         }
222         return false;
223     }
224 
getInputConsumer(String name)225     InputConsumerImpl getInputConsumer(String name) {
226         return mInputConsumers.get(name);
227     }
228 
layoutInputConsumers(int dw, int dh)229     void layoutInputConsumers(int dw, int dh) {
230         if (mDisplayWidth == dw && mDisplayHeight == dh) {
231             return;
232         }
233         mDisplayWidth = dw;
234         mDisplayHeight = dh;
235         try {
236             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer");
237             for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
238                 mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
239             }
240         } finally {
241             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
242         }
243     }
244 
245     // The visibility of the input consumers is recomputed each time we
246     // update the input windows. We use a model where consumers begin invisible
247     // (set so by this function) and must meet some condition for visibility on each update.
resetInputConsumers(SurfaceControl.Transaction t)248     void resetInputConsumers(SurfaceControl.Transaction t) {
249         for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
250             mInputConsumers.valueAt(i).hide(t);
251         }
252     }
253 
createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid, UserHandle clientUser)254     void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
255             UserHandle clientUser) {
256         if (mInputConsumers.containsKey(name)) {
257             throw new IllegalStateException("Existing input consumer found with name: " + name
258                     + ", display: " + mDisplayId);
259         }
260 
261         final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
262                 inputChannel, clientPid, clientUser, mDisplayId);
263         switch (name) {
264             case INPUT_CONSUMER_WALLPAPER:
265                 consumer.mWindowHandle.hasWallpaper = true;
266                 break;
267             case INPUT_CONSUMER_PIP:
268                 // The touchable region of the Pip input window is cropped to the bounds of the
269                 // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
270                 consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL;
271                 break;
272             case INPUT_CONSUMER_RECENTS_ANIMATION:
273                 consumer.mWindowHandle.focusable = true;
274                 break;
275             default:
276                 throw new IllegalArgumentException("Illegal input consumer : " + name
277                         + ", display: " + mDisplayId);
278         }
279         addInputConsumer(name, consumer);
280     }
281 
282     @VisibleForTesting
populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle, final WindowState w)283     void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle,
284             final WindowState w) {
285         // Add a window to our list of input windows.
286         inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null
287                 ? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null);
288         inputWindowHandle.setToken(w.mInputChannelToken);
289         inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
290         inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
291         inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
292         inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
293         inputWindowHandle.setVisible(w.isVisible());
294         inputWindowHandle.setWindowToken(w.mClient);
295 
296         final boolean focusable = w.canReceiveKeys()
297                 && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
298         inputWindowHandle.setFocusable(focusable);
299 
300         final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
301                 && !mService.mPolicy.isKeyguardShowing()
302                 && !mDisableWallpaperTouchEvents;
303         inputWindowHandle.setHasWallpaper(hasWallpaper);
304 
305         // Surface insets are hardcoded to be the same in all directions
306         // and we could probably deprecate the "left/right/top/bottom" concept.
307         // we avoid reintroducing this concept by just choosing one of them here.
308         inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left);
309 
310         // If we are scaling the window, input coordinates need to be inversely scaled to map from
311         // what is on screen to what is actually being touched in the UI.
312         inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f);
313 
314         // Update layout params flags to force the window to be not touch modal. We do this to
315         // restrict the window's touchable region to the task even if it request touches outside its
316         // window bounds. An example is a dialog in primary split should get touches outside its
317         // window within the primary task but should not get any touches going to the secondary
318         // task.
319         int flags = w.mAttrs.flags;
320         if (w.mAttrs.isModal()) {
321             flags = flags | FLAG_NOT_TOUCH_MODAL;
322         }
323         inputWindowHandle.setLayoutParamsFlags(flags);
324 
325         boolean useSurfaceBoundsAsTouchRegion = false;
326         SurfaceControl touchableRegionCrop = null;
327         final Task task = w.getTask();
328         if (task != null) {
329             // TODO(b/165794636): Remove the special case for freeform window once drag resizing is
330             // handled by WM shell.
331             if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
332                         && !task.inFreeformWindowingMode()) {
333                 // If the window is in a TaskManaged by a TaskOrganizer then most cropping will
334                 // be applied using the SurfaceControl hierarchy from the Organizer. This means
335                 // we need to make sure that these changes in crop are reflected in the input
336                 // windows, and so ensure this flag is set so that the input crop always reflects
337                 // the surface hierarchy.
338                 useSurfaceBoundsAsTouchRegion = true;
339 
340                 if (w.mAttrs.isModal()) {
341                     TaskFragment parent = w.getTaskFragment();
342                     touchableRegionCrop = parent != null ? parent.getSurfaceControl() : null;
343                 }
344             } else if (task.cropWindowsToRootTaskBounds() && !w.inFreeformWindowingMode()) {
345                 touchableRegionCrop = task.getRootTask().getSurfaceControl();
346             }
347         }
348         inputWindowHandle.setReplaceTouchableRegionWithCrop(useSurfaceBoundsAsTouchRegion);
349         inputWindowHandle.setTouchableRegionCrop(touchableRegionCrop);
350 
351         if (!useSurfaceBoundsAsTouchRegion) {
352             w.getSurfaceTouchableRegion(mTmpRegion, w.mAttrs);
353             inputWindowHandle.setTouchableRegion(mTmpRegion);
354         }
355     }
356 
setUpdateInputWindowsNeededLw()357     void setUpdateInputWindowsNeededLw() {
358         mUpdateInputWindowsNeeded = true;
359     }
360 
361     /* Updates the cached window information provided to the input dispatcher. */
updateInputWindowsLw(boolean force)362     void updateInputWindowsLw(boolean force) {
363         if (!force && !mUpdateInputWindowsNeeded) {
364             return;
365         }
366         scheduleUpdateInputWindows();
367     }
368 
scheduleUpdateInputWindows()369     private void scheduleUpdateInputWindows() {
370         if (mDisplayRemoved) {
371             return;
372         }
373 
374         if (!mUpdateInputWindowsPending) {
375             mUpdateInputWindowsPending = true;
376             mHandler.post(mUpdateInputWindows);
377         }
378     }
379 
380     /**
381      * Immediately update the input transaction and merge into the passing Transaction that could be
382      * collected and applied later.
383      */
updateInputWindowsImmediately(SurfaceControl.Transaction t)384     void updateInputWindowsImmediately(SurfaceControl.Transaction t) {
385         mHandler.removeCallbacks(mUpdateInputWindows);
386         mUpdateInputWindowsImmediately = true;
387         mUpdateInputWindows.run();
388         mUpdateInputWindowsImmediately = false;
389         t.merge(mInputTransaction);
390     }
391 
392     /**
393      * Called when the current input focus changes. Will apply it in next updateInputWindows.
394      * Layer assignment is assumed to be complete by the time this is called.
395      */
setInputFocusLw(WindowState newWindow, boolean updateInputWindows)396     void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
397         ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s display=%d",
398                 newWindow, mDisplayId);
399         final IBinder focus = newWindow != null ? newWindow.mInputChannelToken : null;
400         if (focus == mInputFocus) {
401             return;
402         }
403 
404         if (newWindow != null && newWindow.canReceiveKeys()) {
405             // Displaying a window implicitly causes dispatching to be unpaused.
406             // This is to protect against bugs if someone pauses dispatching but
407             // forgets to resume.
408             newWindow.mToken.paused = false;
409         }
410 
411         setUpdateInputWindowsNeededLw();
412 
413         if (updateInputWindows) {
414             updateInputWindowsLw(false /*force*/);
415         }
416     }
417 
418     /**
419      * Inform InputMonitor when recents is active so it can enable the recents input consumer.
420      * @param activity The active recents activity. {@code null} means recents is not active.
421      * @param layer An activity whose Z-layer is used as a reference for how to sort the consumer.
422      */
setActiveRecents(@ullable ActivityRecord activity, @Nullable ActivityRecord layer)423     void setActiveRecents(@Nullable ActivityRecord activity, @Nullable ActivityRecord layer) {
424         final boolean clear = activity == null;
425         mActiveRecentsActivity = clear ? null : new WeakReference<>(activity);
426         mActiveRecentsLayerRef = clear ? null : new WeakReference<>(layer);
427     }
428 
getWeak(WeakReference<T> ref)429     private static <T> T getWeak(WeakReference<T> ref) {
430         return ref != null ? ref.get() : null;
431     }
432 
433     /**
434      * Called when the current input focus changes.
435      */
updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer)436     private void updateInputFocusRequest(InputConsumerImpl recentsAnimationInputConsumer) {
437         final WindowState focus = mDisplayContent.mCurrentFocus;
438         // Request focus for the recents animation input consumer if an input consumer should
439         // be applied for the window.
440         if (recentsAnimationInputConsumer != null && focus != null) {
441             final RecentsAnimationController recentsAnimationController =
442                     mService.getRecentsAnimationController();
443             final boolean shouldApplyRecentsInputConsumer = (recentsAnimationController != null
444                     && recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord))
445                     // Shell transitions doesn't use RecentsAnimationController
446                     || getWeak(mActiveRecentsActivity) != null;
447             if (shouldApplyRecentsInputConsumer) {
448                 requestFocus(recentsAnimationInputConsumer.mWindowHandle.token,
449                         recentsAnimationInputConsumer.mName);
450                 return;
451             }
452         }
453 
454         final IBinder focusToken = focus != null ? focus.mInputChannelToken : null;
455         if (focusToken == null) {
456             mInputFocus = null;
457             return;
458         }
459 
460         if (!focus.mWinAnimator.hasSurface() || !focus.mInputWindowHandle.isFocusable()) {
461             ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus not requested for window=%s"
462                     + " because it has no surface or is not focusable.", focus);
463             mInputFocus = null;
464             return;
465         }
466 
467         requestFocus(focusToken, focus.getName());
468     }
469 
requestFocus(IBinder focusToken, String windowName)470     private void requestFocus(IBinder focusToken, String windowName) {
471         if (focusToken == mInputFocus) {
472             return;
473         }
474 
475         mInputFocus = focusToken;
476         mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
477         EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
478                 "reason=UpdateInputWindows");
479         ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
480     }
481 
setFocusedAppLw(ActivityRecord newApp)482     void setFocusedAppLw(ActivityRecord newApp) {
483         // Focused app has changed.
484         mService.mInputManager.setFocusedApplication(mDisplayId,
485                 newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
486     }
487 
pauseDispatchingLw(WindowToken window)488     public void pauseDispatchingLw(WindowToken window) {
489         if (! window.paused) {
490             if (DEBUG_INPUT) {
491                 Slog.v(TAG_WM, "Pausing WindowToken " + window);
492             }
493 
494             window.paused = true;
495             updateInputWindowsLw(true /*force*/);
496         }
497     }
498 
resumeDispatchingLw(WindowToken window)499     public void resumeDispatchingLw(WindowToken window) {
500         if (window.paused) {
501             if (DEBUG_INPUT) {
502                 Slog.v(TAG_WM, "Resuming WindowToken " + window);
503             }
504 
505             window.paused = false;
506             updateInputWindowsLw(true /*force*/);
507         }
508     }
509 
dump(PrintWriter pw, String prefix)510     void dump(PrintWriter pw, String prefix) {
511         final Set<String> inputConsumerKeys = mInputConsumers.keySet();
512         if (!inputConsumerKeys.isEmpty()) {
513             pw.println(prefix + "InputConsumers:");
514             for (String key : inputConsumerKeys) {
515                 mInputConsumers.get(key).dump(pw, key, prefix);
516             }
517         }
518     }
519 
520     private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
521         InputConsumerImpl mPipInputConsumer;
522         InputConsumerImpl mWallpaperInputConsumer;
523         InputConsumerImpl mRecentsAnimationInputConsumer;
524 
525         private boolean mAddPipInputConsumerHandle;
526         private boolean mAddWallpaperInputConsumerHandle;
527         private boolean mAddRecentsAnimationInputConsumerHandle;
528 
529         boolean mInDrag;
530 
updateInputWindows(boolean inDrag)531         private void updateInputWindows(boolean inDrag) {
532             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
533 
534             mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
535             mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER);
536             mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
537 
538             mAddPipInputConsumerHandle = mPipInputConsumer != null;
539             mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
540             mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
541 
542             mDisableWallpaperTouchEvents = false;
543             mInDrag = inDrag;
544 
545             resetInputConsumers(mInputTransaction);
546             // Update recents input consumer layer if active
547             if (mAddRecentsAnimationInputConsumerHandle
548                     && getWeak(mActiveRecentsActivity) != null) {
549                 final WindowContainer layer = getWeak(mActiveRecentsLayerRef);
550                 mRecentsAnimationInputConsumer.show(mInputTransaction,
551                         layer != null ? layer : getWeak(mActiveRecentsActivity));
552                 mAddRecentsAnimationInputConsumerHandle = false;
553             }
554             mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
555             updateInputFocusRequest(mRecentsAnimationInputConsumer);
556 
557             if (!mUpdateInputWindowsImmediately) {
558                 mDisplayContent.getPendingTransaction().merge(mInputTransaction);
559                 mDisplayContent.scheduleAnimation();
560             }
561 
562             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
563         }
564 
565         @Override
accept(WindowState w)566         public void accept(WindowState w) {
567             final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
568             final RecentsAnimationController recentsAnimationController =
569                     mService.getRecentsAnimationController();
570             final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
571                     && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
572             if (w.mInputChannelToken == null || w.mRemoved
573                     || (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
574                 if (w.mWinAnimator.hasSurface()) {
575                     // Make sure the input info can't receive input event. It may be omitted from
576                     // occlusion detection depending on the type or if it's a trusted overlay.
577                     populateOverlayInputInfo(inputWindowHandle, w);
578                     setInputWindowInfoIfNeeded(mInputTransaction,
579                             w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
580                     return;
581                 }
582                 // Skip this window because it cannot possibly receive input.
583                 return;
584             }
585 
586             final int privateFlags = w.mAttrs.privateFlags;
587 
588             // This only works for legacy transitions.
589             if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
590                 if (recentsAnimationController.updateInputConsumerForApp(
591                         mRecentsAnimationInputConsumer.mWindowHandle)) {
592                     final DisplayArea targetDA =
593                             recentsAnimationController.getTargetAppDisplayArea();
594                     if (targetDA != null) {
595                         mRecentsAnimationInputConsumer.reparent(mInputTransaction, targetDA);
596                         mRecentsAnimationInputConsumer.show(mInputTransaction, MAX_VALUE - 1);
597                         mAddRecentsAnimationInputConsumerHandle = false;
598                     }
599                 }
600             }
601 
602             if (w.inPinnedWindowingMode()) {
603                 if (mAddPipInputConsumerHandle) {
604                     final Task rootTask = w.getTask().getRootTask();
605                     mPipInputConsumer.mWindowHandle.replaceTouchableRegionWithCrop(
606                             rootTask.getSurfaceControl());
607                     // We set the layer to z=MAX-1 so that it's always on top.
608                     mPipInputConsumer.reparent(mInputTransaction, rootTask);
609                     mPipInputConsumer.show(mInputTransaction, MAX_VALUE - 1);
610                     mAddPipInputConsumerHandle = false;
611                 }
612             }
613 
614             if (mAddWallpaperInputConsumerHandle) {
615                 if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) {
616                     // Add the wallpaper input consumer above the first visible wallpaper.
617                     mWallpaperInputConsumer.show(mInputTransaction, w);
618                     mAddWallpaperInputConsumerHandle = false;
619                 }
620             }
621 
622             if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
623                 mDisableWallpaperTouchEvents = true;
624             }
625 
626             // If there's a drag in progress and 'child' is a potential drop target,
627             // make sure it's been told about the drag
628             if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) {
629                 mService.mDragDropController.sendDragStartedIfNeededLocked(w);
630             }
631 
632             // register key interception info
633             mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken,
634                     w.getKeyInterceptionInfo());
635 
636             if (w.mWinAnimator.hasSurface()) {
637                 populateInputWindowHandle(inputWindowHandle, w);
638                 setInputWindowInfoIfNeeded(mInputTransaction,
639                         w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
640             }
641         }
642     }
643 
644     @VisibleForTesting
setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc, InputWindowHandleWrapper inputWindowHandle)645     static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
646             InputWindowHandleWrapper inputWindowHandle) {
647         if (DEBUG_INPUT) {
648             Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
649         }
650         if (inputWindowHandle.isChanged()) {
651             inputWindowHandle.applyChangesToSurface(t, sc);
652         }
653     }
654 
populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, WindowState w)655     static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
656             WindowState w) {
657         populateOverlayInputInfo(inputWindowHandle, w.isVisible());
658         inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
659     }
660 
661     // This would reset InputWindowHandle fields to prevent it could be found by input event.
662     // We need to check if any new field of InputWindowHandle could impact the result.
663     @VisibleForTesting
populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle, boolean isVisible)664     static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
665             boolean isVisible) {
666         inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input.
667         inputWindowHandle.setVisible(isVisible);
668         inputWindowHandle.setFocusable(false);
669         inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL);
670         // The input window handle without input channel must not have a token.
671         inputWindowHandle.setToken(null);
672         inputWindowHandle.setScaleFactor(1f);
673         inputWindowHandle.setLayoutParamsFlags(
674                 FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
675         inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY);
676         inputWindowHandle.clearTouchableRegion();
677         inputWindowHandle.setTouchableRegionCrop(null);
678     }
679 
680     /**
681      * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
682      * info will not have an input channel or be touchable, but is used to omit Surfaces
683      * from occlusion detection, so that System global overlays like the Watermark aren't
684      * counted by the InputDispatcher as occluding applications below.
685      */
setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t, int displayId, String name)686     static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
687             int displayId, String name) {
688         final InputWindowHandleWrapper inputWindowHandle = new InputWindowHandleWrapper(
689                 new InputWindowHandle(null /* inputApplicationHandle */, displayId));
690         inputWindowHandle.setName(name);
691         inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
692         inputWindowHandle.setTrustedOverlay(true);
693         populateOverlayInputInfo(inputWindowHandle, true /* isVisible */);
694         setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
695     }
696 
isTrustedOverlay(int type)697     static boolean isTrustedOverlay(int type) {
698         return type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
699                 || type == TYPE_INPUT_METHOD || type == TYPE_INPUT_METHOD_DIALOG
700                 || type == TYPE_MAGNIFICATION_OVERLAY || type == TYPE_STATUS_BAR
701                 || type == TYPE_NOTIFICATION_SHADE
702                 || type == TYPE_NAVIGATION_BAR
703                 || type == TYPE_NAVIGATION_BAR_PANEL
704                 || type == TYPE_SECURE_SYSTEM_OVERLAY
705                 || type == TYPE_DOCK_DIVIDER
706                 || type == TYPE_ACCESSIBILITY_OVERLAY
707                 || type == TYPE_INPUT_CONSUMER
708                 || type == TYPE_VOICE_INTERACTION
709                 || type == TYPE_STATUS_BAR_ADDITIONAL;
710     }
711 }
712