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