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