• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.Manifest.permission.ALWAYS_UPDATE_WALLPAPER;
20 import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
21 import static android.Manifest.permission.HIDE_OVERLAY_WINDOWS;
22 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
23 import static android.Manifest.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION;
24 import static android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS;
25 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
26 import static android.Manifest.permission.STATUS_BAR_SERVICE;
27 import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY;
28 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
29 import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
30 import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
31 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
32 import static android.content.Intent.EXTRA_PACKAGE_NAME;
33 import static android.content.Intent.EXTRA_SHORTCUT_ID;
34 import static android.content.Intent.EXTRA_TASK_ID;
35 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
36 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
37 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
38 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
39 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
40 
41 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_IME;
42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
43 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
44 
45 import android.annotation.NonNull;
46 import android.annotation.Nullable;
47 import android.app.PendingIntent;
48 import android.content.ClipData;
49 import android.content.ClipDescription;
50 import android.content.Intent;
51 import android.content.pm.ActivityInfo;
52 import android.content.pm.ShortcutServiceInternal;
53 import android.graphics.Rect;
54 import android.graphics.Region;
55 import android.os.Binder;
56 import android.os.Bundle;
57 import android.os.IBinder;
58 import android.os.Parcel;
59 import android.os.Process;
60 import android.os.RemoteCallback;
61 import android.os.RemoteException;
62 import android.os.Trace;
63 import android.os.UserHandle;
64 import android.text.TextUtils;
65 import android.util.ArraySet;
66 import android.util.Slog;
67 import android.view.IWindow;
68 import android.view.IWindowId;
69 import android.view.IWindowSession;
70 import android.view.IWindowSessionCallback;
71 import android.view.InputChannel;
72 import android.view.InsetsSourceControl;
73 import android.view.InsetsState;
74 import android.view.SurfaceControl;
75 import android.view.View;
76 import android.view.View.FocusDirection;
77 import android.view.WindowInsets;
78 import android.view.WindowInsets.Type.InsetsType;
79 import android.view.WindowManager;
80 import android.view.WindowRelayoutResult;
81 import android.view.inputmethod.ImeTracker;
82 import android.window.InputTransferToken;
83 import android.window.OnBackInvokedCallbackInfo;
84 
85 import com.android.internal.annotations.VisibleForTesting;
86 import com.android.internal.os.logging.MetricsLoggerWrapper;
87 import com.android.internal.protolog.ProtoLog;
88 import com.android.server.LocalServices;
89 import com.android.server.wm.WindowManagerService.H;
90 import com.android.window.flags.Flags;
91 
92 import java.io.PrintWriter;
93 import java.util.ArrayList;
94 import java.util.Collections;
95 import java.util.List;
96 import java.util.function.BiConsumer;
97 
98 /**
99  * This class represents an active client session.  There is generally one
100  * Session object per process that is interacting with the window manager.
101  */
102 class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
103     final WindowManagerService mService;
104     final IWindowSessionCallback mCallback;
105     final int mUid;
106     final int mPid;
107     @NonNull
108     final WindowProcessController mProcess;
109     private final String mStringName;
110     private final ArrayList<WindowState> mAddedWindows = new ArrayList<>();
111     /** Set of visible alert/app-overlay windows connected to this session. */
112     private final ArraySet<WindowState> mAlertWindows = new ArraySet<>();
113     private final DragDropController mDragDropController;
114     final boolean mCanAddInternalSystemWindow;
115     boolean mCanForceShowingInsets;
116     private final boolean mCanStartTasksFromRecents;
117 
118     final boolean mCanCreateSystemApplicationOverlay;
119     final boolean mCanHideNonSystemOverlayWindows;
120     final boolean mCanSetUnrestrictedGestureExclusion;
121     final boolean mCanAlwaysUpdateWallpaper;
122     private AlertWindowNotification mAlertWindowNotification;
123     private boolean mShowingAlertWindowNotificationAllowed;
124     private boolean mClientDead = false;
125     private float mLastReportedAnimatorScale;
126     protected String mPackageName;
127     private String mRelayoutTag;
128     private final InsetsSourceControl.Array mDummyControls =  new InsetsSourceControl.Array();
129     final boolean mSetsUnrestrictedKeepClearAreas;
130 
Session(WindowManagerService service, IWindowSessionCallback callback)131     public Session(WindowManagerService service, IWindowSessionCallback callback) {
132         this(service, callback, Binder.getCallingPid(), Binder.getCallingUid());
133     }
134 
135     @VisibleForTesting
Session(WindowManagerService service, IWindowSessionCallback callback, int callingPid, int callingUid)136     Session(WindowManagerService service, IWindowSessionCallback callback,
137             int callingPid, int callingUid) {
138         mService = service;
139         mCallback = callback;
140         mPid = callingPid;
141         mUid = callingUid;
142         synchronized (service.mGlobalLock) {
143             mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
144             mProcess = service.mAtmService.mProcessMap.getProcess(mPid);
145         }
146         if (mProcess == null) {
147             throw new IllegalStateException("Unknown pid=" + mPid + " uid=" + mUid);
148         }
149         mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
150                 INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
151         mCanForceShowingInsets = service.mAtmService.isCallerRecents(mUid)
152                 || service.mContext.checkCallingOrSelfPermission(STATUS_BAR_SERVICE)
153                 == PERMISSION_GRANTED;
154         mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
155                 HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED
156                 || service.mContext.checkCallingOrSelfPermission(HIDE_OVERLAY_WINDOWS)
157                 == PERMISSION_GRANTED;
158         mCanCreateSystemApplicationOverlay =
159                 service.mContext.checkCallingOrSelfPermission(SYSTEM_APPLICATION_OVERLAY)
160                         == PERMISSION_GRANTED;
161         mCanStartTasksFromRecents = service.mContext.checkCallingOrSelfPermission(
162                 START_TASKS_FROM_RECENTS) == PERMISSION_GRANTED;
163         mSetsUnrestrictedKeepClearAreas =
164                 service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_KEEP_CLEAR_AREAS)
165                         == PERMISSION_GRANTED;
166         mCanSetUnrestrictedGestureExclusion =
167                 service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_GESTURE_EXCLUSION)
168                         == PERMISSION_GRANTED;
169         mCanAlwaysUpdateWallpaper = Flags.alwaysUpdateWallpaperPermission()
170                 && service.mContext.checkCallingOrSelfPermission(ALWAYS_UPDATE_WALLPAPER)
171                         == PERMISSION_GRANTED;
172         mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
173         mDragDropController = mService.mDragDropController;
174         StringBuilder sb = new StringBuilder();
175         sb.append("Session{");
176         sb.append(Integer.toHexString(System.identityHashCode(this)));
177         sb.append(" ");
178         sb.append(mPid);
179         if (mUid < Process.FIRST_APPLICATION_UID) {
180             sb.append(":");
181             sb.append(mUid);
182         } else {
183             sb.append(":u");
184             sb.append(UserHandle.getUserId(mUid));
185             sb.append('a');
186             sb.append(UserHandle.getAppId(mUid));
187         }
188         sb.append("}");
189         mStringName = sb.toString();
190 
191         try {
192             mCallback.asBinder().linkToDeath(this, 0);
193         } catch (RemoteException e) {
194             mClientDead = true;
195         }
196     }
197 
198     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)199     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
200             throws RemoteException {
201         try {
202             return super.onTransact(code, data, reply, flags);
203         } catch (RuntimeException e) {
204             // Log all 'real' exceptions thrown to the caller
205             if (!(e instanceof SecurityException)) {
206                 Slog.wtf(TAG_WM, "Window Session Crash", e);
207             }
208             throw e;
209         }
210     }
211 
isClientDead()212     boolean isClientDead() {
213         return mClientDead;
214     }
215 
216     @Override
binderDied()217     public void binderDied() {
218         synchronized (mService.mGlobalLock) {
219             mCallback.asBinder().unlinkToDeath(this, 0);
220             mClientDead = true;
221             try {
222                 for (int i = mAddedWindows.size() - 1; i >= 0; i--) {
223                     final WindowState w = mAddedWindows.get(i);
224                     Slog.i(TAG_WM, "WIN DEATH: " + w);
225                     if (w.mActivityRecord != null && w.mActivityRecord.findMainWindow() == w) {
226                         mService.mSnapshotController.onAppDied(w.mActivityRecord);
227                     }
228                     w.removeIfPossible();
229                 }
230             } finally {
231                 killSessionLocked();
232             }
233         }
234     }
235 
236     @Override
addToDisplay(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale)237     public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
238             int viewVisibility, int displayId, @InsetsType int requestedVisibleTypes,
239             InputChannel outInputChannel, InsetsState outInsetsState,
240             InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
241             float[] outSizeCompatScale) {
242         return mService.addWindow(this, window, attrs, viewVisibility, displayId,
243                 UserHandle.getUserId(mUid), requestedVisibleTypes, outInputChannel, outInsetsState,
244                 outActiveControls, outAttachedFrame, outSizeCompatScale);
245     }
246 
247     @Override
addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale)248     public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
249             int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
250             InputChannel outInputChannel, InsetsState outInsetsState,
251             InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
252             float[] outSizeCompatScale) {
253         return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
254                 requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls,
255                 outAttachedFrame, outSizeCompatScale);
256     }
257 
258     @Override
addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame, float[] outSizeCompatScale)259     public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
260             int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame,
261             float[] outSizeCompatScale) {
262         return mService.addWindow(this, window, attrs, viewVisibility, displayId,
263                 UserHandle.getUserId(mUid), WindowInsets.Type.defaultVisible(),
264                 null /* outInputChannel */, outInsetsState, mDummyControls, outAttachedFrame,
265                 outSizeCompatScale);
266     }
267 
268     @Override
remove(IBinder clientToken)269     public void remove(IBinder clientToken) {
270         mService.removeClientToken(this, clientToken);
271     }
272 
273     @Override
cancelDraw(IWindow window)274     public boolean cancelDraw(IWindow window) {
275         return mService.cancelDraw(this, window);
276     }
277 
278     @Override
relayout(IWindow window, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, int lastSyncSeqId, WindowRelayoutResult outRelayoutResult)279     public int relayout(IWindow window, WindowManager.LayoutParams attrs,
280             int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
281             int lastSyncSeqId, WindowRelayoutResult outRelayoutResult) {
282         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
283         int res = mService.relayoutWindow(this, window, attrs, requestedWidth,
284                 requestedHeight, viewFlags, flags, seq, lastSyncSeqId, outRelayoutResult);
285         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
286         return res;
287     }
288 
289     @Override
relayoutAsync(IWindow window, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq, int lastSyncSeqId)290     public void relayoutAsync(IWindow window, WindowManager.LayoutParams attrs,
291             int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
292             int lastSyncSeqId) {
293         relayout(window, attrs, requestedWidth, requestedHeight, viewFlags, flags, seq,
294                 lastSyncSeqId, null /* outRelayoutResult */);
295     }
296 
297     @Override
outOfMemory(IWindow window)298     public boolean outOfMemory(IWindow window) {
299         return mService.outOfMemoryWindow(this, window);
300     }
301 
302     @Override
setInsets(IWindow window, int touchableInsets, Rect contentInsets, Rect visibleInsets, Region touchableArea)303     public void setInsets(IWindow window, int touchableInsets,
304             Rect contentInsets, Rect visibleInsets, Region touchableArea) {
305         mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
306                 visibleInsets, touchableArea);
307     }
308 
309     @Override
clearTouchableRegion(IWindow window)310     public void clearTouchableRegion(IWindow window) {
311         mService.clearTouchableRegion(this, window);
312     }
313 
314     @Override
finishDrawing(IWindow window, @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId)315     public void finishDrawing(IWindow window,
316             @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
317         if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
318         if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
319             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishDrawing: " + mPackageName);
320         }
321         mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
322         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
323     }
324 
325     /* Drag/drop */
326 
327     @Override
performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data)328     public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
329             int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
330             float thumbCenterY, ClipData data) {
331         final int callingUid = Binder.getCallingUid();
332         final int callingPid = Binder.getCallingPid();
333         // Validate and resolve ClipDescription data before clearing the calling identity
334         validateAndResolveDragMimeTypeExtras(data, callingUid, callingPid, mPackageName);
335         validateDragFlags(flags, callingUid);
336         final long ident = Binder.clearCallingIdentity();
337         try {
338             return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
339                     touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY,
340                     data);
341         } finally {
342             Binder.restoreCallingIdentity(ident);
343         }
344     }
345 
346 
347     @Override
dropForAccessibility(IWindow window, int x, int y)348     public boolean dropForAccessibility(IWindow window, int x, int y) {
349         final long ident = Binder.clearCallingIdentity();
350         try {
351             return mDragDropController.dropForAccessibility(window, x, y);
352         } finally {
353             Binder.restoreCallingIdentity(ident);
354         }
355     }
356 
357     /**
358      * Validates the given drag flags.
359      */
360     @VisibleForTesting
validateDragFlags(int flags, int callingUid)361     void validateDragFlags(int flags, int callingUid) {
362         if ((flags & View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION) != 0) {
363             if (!mCanStartTasksFromRecents) {
364                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
365             }
366         }
367         if ((flags & View.DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START) != 0) {
368             if (!SafeActivityOptions.isAssistant(mService.mAtmService, callingUid)) {
369                 throw new SecurityException("Caller is not the assistant");
370             }
371         }
372     }
373 
374     /**
375      * Validates the given drag data.
376      */
377     @VisibleForTesting
validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid, String callingPackage)378     void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
379             String callingPackage) {
380         final ClipDescription desc = data != null ? data.getDescription() : null;
381         if (desc == null) {
382             return;
383         }
384         // Ensure that only one of the app mime types are set
385         final boolean hasActivity = desc.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY);
386         final boolean hasShortcut = desc.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
387         final boolean hasTask = desc.hasMimeType(MIMETYPE_APPLICATION_TASK);
388         int appMimeTypeCount = (hasActivity ? 1 : 0)
389                 + (hasShortcut ? 1 : 0)
390                 + (hasTask ? 1 : 0);
391         if (appMimeTypeCount == 0) {
392             return;
393         } else if (appMimeTypeCount > 1) {
394             throw new IllegalArgumentException("Can not specify more than one of activity, "
395                     + "shortcut, or task mime types");
396         }
397         // Ensure that data is provided and that they are intents
398         if (data.getItemCount() == 0) {
399             throw new IllegalArgumentException("Unexpected number of items (none)");
400         }
401         for (int i = 0; i < data.getItemCount(); i++) {
402             if (data.getItemAt(i).getIntent() == null) {
403                 throw new IllegalArgumentException("Unexpected item, expected an intent");
404             }
405         }
406 
407         if (hasActivity) {
408             long origId = Binder.clearCallingIdentity();
409             try {
410                 // Resolve the activity info for each intent
411                 for (int i = 0; i < data.getItemCount(); i++) {
412                     final ClipData.Item item = data.getItemAt(i);
413                     final Intent intent = item.getIntent();
414                     final PendingIntent pi = intent.getParcelableExtra(
415                             ClipDescription.EXTRA_PENDING_INTENT);
416                     final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
417                     if (pi == null || user == null) {
418                         throw new IllegalArgumentException("Clip data must include the pending "
419                                 + "intent to launch and its associated user to launch for.");
420                     }
421                     final Intent launchIntent = mService.mAmInternal.getIntentForIntentSender(
422                             pi.getIntentSender().getTarget());
423                     final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
424                             launchIntent, null /* resolvedType */, user.getIdentifier(),
425                             callingUid, callingPid);
426                     item.setActivityInfo(info);
427                 }
428             } finally {
429                 Binder.restoreCallingIdentity(origId);
430             }
431         } else if (hasShortcut) {
432             // Restrict who can start a shortcut drag since it will start the shortcut as the
433             // target shortcut package
434             if (!mCanStartTasksFromRecents) {
435                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
436             }
437             for (int i = 0; i < data.getItemCount(); i++) {
438                 final ClipData.Item item = data.getItemAt(i);
439                 final Intent intent = item.getIntent();
440                 final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID);
441                 final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
442                 final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
443                 if (TextUtils.isEmpty(shortcutId)
444                         || TextUtils.isEmpty(packageName)
445                         || user == null) {
446                     throw new IllegalArgumentException("Clip item must include the package name, "
447                             + "shortcut id, and the user to launch for.");
448                 }
449                 final ShortcutServiceInternal shortcutService =
450                         LocalServices.getService(ShortcutServiceInternal.class);
451                 final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
452                         UserHandle.getUserId(callingUid), callingPackage, packageName, shortcutId,
453                         user.getIdentifier(), callingPid, callingUid);
454                 if (shortcutIntents == null || shortcutIntents.length == 0) {
455                     throw new IllegalArgumentException("Invalid shortcut id");
456                 }
457                 final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
458                         shortcutIntents[0], null /* resolvedType */, user.getIdentifier(),
459                         callingUid, callingPid);
460                 item.setActivityInfo(info);
461             }
462         } else if (hasTask) {
463             // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
464             if (!mCanStartTasksFromRecents) {
465                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
466             }
467             for (int i = 0; i < data.getItemCount(); i++) {
468                 final ClipData.Item item = data.getItemAt(i);
469                 final Intent intent = item.getIntent();
470                 final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
471                 if (taskId == INVALID_TASK_ID) {
472                     throw new IllegalArgumentException("Clip item must include the task id.");
473                 }
474                 final Task task = mService.mRoot.anyTaskForId(taskId);
475                 if (task == null) {
476                     throw new IllegalArgumentException("Invalid task id.");
477                 }
478                 if (task.getRootActivity() != null) {
479                     item.setActivityInfo(task.getRootActivity().info);
480                 } else {
481                     // Resolve the activity info manually if the task was restored after reboot
482                     final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
483                             task.intent, null /* resolvedType */, task.mUserId, callingUid,
484                             callingPid);
485                     item.setActivityInfo(info);
486                 }
487             }
488         }
489     }
490 
491     @Override
reportDropResult(IWindow window, boolean consumed)492     public void reportDropResult(IWindow window, boolean consumed) {
493         final long ident = Binder.clearCallingIdentity();
494         try {
495             mDragDropController.reportDropResult(window, consumed);
496         } finally {
497             Binder.restoreCallingIdentity(ident);
498         }
499     }
500 
501     @Override
cancelDragAndDrop(IBinder dragToken, boolean skipAnimation)502     public void cancelDragAndDrop(IBinder dragToken, boolean skipAnimation) {
503         final long ident = Binder.clearCallingIdentity();
504         try {
505             mDragDropController.cancelDragAndDrop(dragToken, skipAnimation);
506         } finally {
507             Binder.restoreCallingIdentity(ident);
508         }
509     }
510 
511     @Override
dragRecipientEntered(IWindow window)512     public void dragRecipientEntered(IWindow window) {
513         mDragDropController.dragRecipientEntered(window);
514     }
515 
516     @Override
dragRecipientExited(IWindow window)517     public void dragRecipientExited(IWindow window) {
518         mDragDropController.dragRecipientExited(window);
519     }
520 
521     @Override
startMovingTask(IWindow window, float startX, float startY)522     public boolean startMovingTask(IWindow window, float startX, float startY) {
523         return false;
524     }
525 
526     @Override
finishMovingTask(IWindow window)527     public void finishMovingTask(IWindow window) {
528     }
529 
530     @Override
reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects)531     public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
532         final long ident = Binder.clearCallingIdentity();
533         try {
534             mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
535         } finally {
536             Binder.restoreCallingIdentity(ident);
537         }
538     }
539 
540     @Override
reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted)541     public void reportDecorViewGestureInterceptionChanged(IWindow window, boolean intercepted) {
542         final long ident = Binder.clearCallingIdentity();
543         try {
544             mService.reportDecorViewGestureChanged(this, window, intercepted);
545         } finally {
546             Binder.restoreCallingIdentity(ident);
547         }
548     }
549 
550     @Override
reportKeepClearAreasChanged(IWindow window, List<Rect> restricted, List<Rect> unrestricted)551     public void reportKeepClearAreasChanged(IWindow window, List<Rect> restricted,
552             List<Rect> unrestricted) {
553         if (!mSetsUnrestrictedKeepClearAreas && !unrestricted.isEmpty()) {
554             unrestricted = Collections.emptyList();
555         }
556 
557         final long ident = Binder.clearCallingIdentity();
558         try {
559             mService.reportKeepClearAreasChanged(this, window, restricted, unrestricted);
560         } finally {
561             Binder.restoreCallingIdentity(ident);
562         }
563     }
564 
actionOnWallpaper(IBinder window, BiConsumer<WallpaperController, WindowState> action)565     private void actionOnWallpaper(IBinder window,
566             BiConsumer<WallpaperController, WindowState> action) {
567         final WindowState windowState = mService.windowForClientLocked(this, window, true);
568         action.accept(windowState.getDisplayContent().mWallpaperController, windowState);
569     }
570 
571     @Override
setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep)572     public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
573         synchronized (mService.mGlobalLock) {
574             final long ident = Binder.clearCallingIdentity();
575             try {
576                 actionOnWallpaper(window, (wpController, windowState) ->
577                         wpController.setWindowWallpaperPosition(windowState, x, y, xStep, yStep));
578             } finally {
579                 Binder.restoreCallingIdentity(ident);
580             }
581         }
582     }
583 
584     @Override
setWallpaperZoomOut(IBinder window, float zoom)585     public void setWallpaperZoomOut(IBinder window, float zoom) {
586         if (Float.compare(0f, zoom) > 0 || Float.compare(1f, zoom) < 0 || Float.isNaN(zoom)) {
587             throw new IllegalArgumentException("Zoom must be a valid float between 0 and 1: "
588                     + zoom);
589         }
590         synchronized (mService.mGlobalLock) {
591             final long ident = Binder.clearCallingIdentity();
592             try {
593                 actionOnWallpaper(window, (wpController, windowState) ->
594                         wpController.setWallpaperZoomOut(windowState, zoom));
595             } finally {
596                 Binder.restoreCallingIdentity(ident);
597             }
598         }
599     }
600 
601     @Override
setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom)602     public void setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom) {
603         synchronized (mService.mGlobalLock) {
604             actionOnWallpaper(window, (wpController, windowState) ->
605                     wpController.setShouldZoomOutWallpaper(windowState, shouldZoom));
606         }
607     }
608 
609     @Override
wallpaperOffsetsComplete(IBinder window)610     public void wallpaperOffsetsComplete(IBinder window) {
611         synchronized (mService.mGlobalLock) {
612             actionOnWallpaper(window, (wpController, windowState) ->
613                     wpController.wallpaperOffsetsComplete(window));
614         }
615     }
616 
617     @Override
setWallpaperDisplayOffset(IBinder window, int x, int y)618     public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
619         synchronized (mService.mGlobalLock) {
620             final long ident = Binder.clearCallingIdentity();
621             try {
622                 actionOnWallpaper(window, (wpController, windowState) ->
623                         wpController.setWindowWallpaperDisplayOffset(windowState, x, y));
624             } finally {
625                 Binder.restoreCallingIdentity(ident);
626             }
627         }
628     }
629 
630     @Override
sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync)631     public void sendWallpaperCommand(IBinder window, String action, int x, int y,
632             int z, Bundle extras, boolean sync) {
633         synchronized (mService.mGlobalLock) {
634             final long ident = Binder.clearCallingIdentity();
635             try {
636                 final WindowState windowState = mService.windowForClientLocked(this, window, true);
637                 WallpaperController wallpaperController =
638                         windowState.getDisplayContent().mWallpaperController;
639                 if (mCanAlwaysUpdateWallpaper
640                         || windowState == wallpaperController.getWallpaperTarget()
641                         || windowState == wallpaperController.getPrevWallpaperTarget()) {
642                     wallpaperController.sendWindowWallpaperCommandUnchecked(
643                             windowState, action, x, y, z, extras, sync);
644                 }
645             } finally {
646                 Binder.restoreCallingIdentity(ident);
647             }
648         }
649     }
650 
651     @Override
wallpaperCommandComplete(IBinder window, Bundle result)652     public void wallpaperCommandComplete(IBinder window, Bundle result) {
653         synchronized (mService.mGlobalLock) {
654             actionOnWallpaper(window, (wpController, windowState) ->
655                     wpController.wallpaperCommandComplete(window));
656         }
657     }
658 
659     @Override
onRectangleOnScreenRequested(IBinder token, Rect rectangle)660     public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
661         synchronized (mService.mGlobalLock) {
662             final long identity = Binder.clearCallingIdentity();
663             try {
664                 mService.onRectangleOnScreenRequested(token, rectangle);
665             } finally {
666                 Binder.restoreCallingIdentity(identity);
667             }
668         }
669     }
670 
671     @Override
getWindowId(IBinder window)672     public IWindowId getWindowId(IBinder window) {
673         return mService.getWindowId(window);
674     }
675 
676     @Override
pokeDrawLock(IBinder window)677     public void pokeDrawLock(IBinder window) {
678         final long identity = Binder.clearCallingIdentity();
679         try {
680             mService.pokeDrawLock(this, window);
681         } finally {
682             Binder.restoreCallingIdentity(identity);
683         }
684     }
685 
686     @Override
updateTapExcludeRegion(IWindow window, Region region)687     public void updateTapExcludeRegion(IWindow window, Region region) {
688         final long identity = Binder.clearCallingIdentity();
689         try {
690             mService.updateTapExcludeRegion(window, region);
691         } finally {
692             Binder.restoreCallingIdentity(identity);
693         }
694     }
695 
696     @Override
updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken)697     public void updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes,
698             @Nullable ImeTracker.Token imeStatsToken) {
699         synchronized (mService.mGlobalLock) {
700             final WindowState win = mService.windowForClientLocked(this, window,
701                     false /* throwOnError */);
702             if (win != null) {
703                 if (android.view.inputmethod.Flags.refactorInsetsController()) {
704                     ImeTracker.forLogging().onProgress(imeStatsToken,
705                             ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
706                 }
707                 final @InsetsType int changedTypes =
708                         win.setRequestedVisibleTypes(requestedVisibleTypes);
709                 win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
710                         changedTypes, imeStatsToken);
711                 final Task task = win.getTask();
712                 if (task != null) {
713                     task.dispatchTaskInfoChangedIfNeeded(/* forced= */ true);
714                 }
715             } else {
716                 EmbeddedWindowController.EmbeddedWindow embeddedWindow = null;
717                 if (android.view.inputmethod.Flags.refactorInsetsController()) {
718                     embeddedWindow = mService.mEmbeddedWindowController.getByWindowToken(
719                             window.asBinder());
720                 }
721                 if (embeddedWindow != null) {
722                     // If there is no WindowState for the IWindow, it could be still an
723                     // EmbeddedWindow. Therefore, check the EmbeddedWindowController as well
724                     // TODO(b/353463205) Use different phase here
725                     ImeTracker.forLogging().onProgress(imeStatsToken,
726                             ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
727                     final @InsetsType int changedTypes = embeddedWindow.setRequestedVisibleTypes(
728                             requestedVisibleTypes & WindowInsets.Type.ime());
729                     embeddedWindow.getDisplayContent().getInsetsPolicy()
730                             .onRequestedVisibleTypesChanged(
731                                     embeddedWindow, changedTypes, imeStatsToken);
732                 } else {
733                     ImeTracker.forLogging().onFailed(imeStatsToken,
734                             ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
735                 }
736             }
737         }
738     }
739 
740     @Override
updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes, @Nullable ImeTracker.Token statsToken)741     public void updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes,
742             @Nullable ImeTracker.Token statsToken) {
743         synchronized (mService.mGlobalLock) {
744             final WindowState win = mService.windowForClientLocked(this, window,
745                     false /* throwOnError */);
746             if (win != null) {
747                 ImeTracker.forLogging().onProgress(statsToken,
748                         ImeTracker.PHASE_WM_UPDATE_ANIMATING_TYPES);
749                 win.setAnimatingTypes(animatingTypes, statsToken);
750             } else {
751                 ImeTracker.forLogging().onFailed(statsToken,
752                         ImeTracker.PHASE_WM_UPDATE_ANIMATING_TYPES);
753             }
754         }
755     }
756 
onWindowAdded(WindowState w)757     void onWindowAdded(WindowState w) {
758         if (mPackageName == null) {
759             mPackageName = mProcess.mInfo.packageName;
760             mRelayoutTag = "relayoutWindow: " + mPackageName;
761         }
762         if (mProcess.mWindowSession == null) {
763             if (DEBUG) {
764                 Slog.v(TAG_WM, "First window added to " + mProcess);
765             }
766             mService.mSessions.add(this);
767             if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
768                 mService.dispatchNewAnimatorScaleLocked(this);
769             }
770             mProcess.mWindowSession = this;
771         }
772         mAddedWindows.add(w);
773     }
774 
onWindowRemoved(WindowState w)775     void onWindowRemoved(WindowState w) {
776         mAddedWindows.remove(w);
777         if (mAddedWindows.isEmpty()) {
778             killSessionLocked();
779         }
780     }
781 
hasWindow()782     boolean hasWindow() {
783         return !mAddedWindows.isEmpty();
784     }
785 
onWindowSurfaceVisibilityChanged(WindowState window, boolean visible)786     void onWindowSurfaceVisibilityChanged(WindowState window, boolean visible) {
787         final int type = window.mAttrs.type;
788         if (!isSystemAlertWindowType(type) && type != TYPE_SYSTEM_DIALOG) {
789             return;
790         }
791 
792         boolean changed;
793         // Track non-system apps adding overlay/alert windows, so a notification can post for the
794         // user to control their visibility.
795         final boolean noSystemOverlayPermission =
796                 !mCanAddInternalSystemWindow && !mCanCreateSystemApplicationOverlay;
797         if (visible) {
798             changed = mAlertWindows.add(window);
799             if (type == TYPE_APPLICATION_OVERLAY) {
800                 MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type,
801                         false /* set false to only log for TYPE_APPLICATION_OVERLAY */);
802             } else if (noSystemOverlayPermission) {
803                 MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, changed, type,
804                         true /* only log for non-TYPE_APPLICATION_OVERLAY */);
805             }
806         } else {
807             changed = mAlertWindows.remove(window);
808             if (type == TYPE_APPLICATION_OVERLAY) {
809                 MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type,
810                         false /* set false to only log for TYPE_APPLICATION_OVERLAY */);
811             } else if (noSystemOverlayPermission) {
812                 MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, changed, type,
813                         true /* only log for non-TYPE_APPLICATION_OVERLAY */);
814             }
815         }
816 
817         if (changed && noSystemOverlayPermission) {
818             if (mAlertWindows.isEmpty()) {
819                 cancelAlertWindowNotification();
820             } else if (mAlertWindowNotification == null && !isSatellitePointingUiPackage()) {
821                 mAlertWindowNotification = new AlertWindowNotification(mService, mPackageName);
822                 if (mShowingAlertWindowNotificationAllowed) {
823                     mAlertWindowNotification.post();
824                 }
825             }
826         }
827 
828         if (changed && mPid != WindowManagerService.MY_PID) {
829             // Notify activity manager that the process contains overlay/alert windows, so it can
830             // adjust the importance score for the process.
831             setHasOverlayUi(!mAlertWindows.isEmpty());
832         }
833     }
834 
835     // TODO b/349195999 - short term solution to not show the satellite pointing ui notification.
isSatellitePointingUiPackage()836     private boolean isSatellitePointingUiPackage() {
837         if (mPackageName == null || !mPackageName.equals(mService.mContext.getString(
838             com.android.internal.R.string.config_pointing_ui_package))) {
839             return false;
840         }
841         return ActivityTaskManagerService.checkPermission(
842             android.Manifest.permission.SATELLITE_COMMUNICATION, mPid, mUid) == PERMISSION_GRANTED;
843     }
844 
setShowingAlertWindowNotificationAllowed(boolean allowed)845     void setShowingAlertWindowNotificationAllowed(boolean allowed) {
846         mShowingAlertWindowNotificationAllowed = allowed;
847         if (mAlertWindowNotification != null) {
848             if (allowed) {
849                 mAlertWindowNotification.post();
850             } else {
851                 mAlertWindowNotification.cancel(false /* deleteChannel */);
852             }
853         }
854     }
855 
killSessionLocked()856     private void killSessionLocked() {
857         if (!mClientDead) {
858             return;
859         }
860 
861         mService.mSessions.remove(this);
862         if (mProcess.mWindowSession == null) {
863             return;
864         }
865 
866         mProcess.mWindowSession = null;
867         mAddedWindows.clear();
868         mAlertWindows.clear();
869         setHasOverlayUi(false);
870         cancelAlertWindowNotification();
871     }
872 
873     @VisibleForTesting
setHasOverlayUi(boolean hasOverlayUi)874     void setHasOverlayUi(boolean hasOverlayUi) {
875         mService.mH.obtainMessage(H.SET_HAS_OVERLAY_UI, mPid, hasOverlayUi ? 1 : 0).sendToTarget();
876     }
877 
cancelAlertWindowNotification()878     private void cancelAlertWindowNotification() {
879         if (mAlertWindowNotification == null) {
880             return;
881         }
882         mAlertWindowNotification.cancel(true /* deleteChannel */);
883         mAlertWindowNotification = null;
884     }
885 
dump(PrintWriter pw, String prefix)886     void dump(PrintWriter pw, String prefix) {
887         pw.print(prefix); pw.print("numWindow="); pw.print(mAddedWindows.size());
888                 pw.print(" mCanAddInternalSystemWindow="); pw.print(mCanAddInternalSystemWindow);
889                 pw.print(" mAlertWindows="); pw.print(mAlertWindows);
890                 pw.print(" mClientDead="); pw.print(mClientDead);
891         pw.print(prefix); pw.print("mPackageName="); pw.println(mPackageName);
892         if (isSatellitePointingUiPackage()) {
893             pw.print(prefix); pw.println("mIsSatellitePointingUiPackage=true");
894         }
895     }
896 
897     @Override
toString()898     public String toString() {
899         return mStringName;
900     }
901 
902     /** @return {@code true} if there is an alert window surface on the given display. */
hasAlertWindowSurfaces(DisplayContent displayContent)903     boolean hasAlertWindowSurfaces(DisplayContent displayContent) {
904         for (int i = mAlertWindows.size() - 1; i >= 0; i--) {
905             final WindowState window = mAlertWindows.valueAt(i);
906             if (window.mDisplayContent == displayContent) {
907                 return true;
908             }
909         }
910         return false;
911     }
912 
913     @Override
grantInputChannel(int displayId, SurfaceControl surface, IBinder clientToken, @Nullable InputTransferToken hostInputTransferToken, int flags, int privateFlags, int inputFeatures, int type, IBinder windowToken, InputTransferToken inputTransferToken, String inputHandleName, InputChannel outInputChannel)914     public void grantInputChannel(int displayId, SurfaceControl surface,
915             IBinder clientToken, @Nullable InputTransferToken hostInputTransferToken, int flags,
916             int privateFlags, int inputFeatures, int type, IBinder windowToken,
917             InputTransferToken inputTransferToken, String inputHandleName,
918             InputChannel outInputChannel) {
919         if (hostInputTransferToken == null && !mCanAddInternalSystemWindow) {
920             // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
921             // embedded windows without providing a host window input token
922             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
923         }
924 
925         final long identity = Binder.clearCallingIdentity();
926         try {
927             mService.grantInputChannel(this, mUid, mPid, displayId, surface, clientToken,
928                     hostInputTransferToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0,
929                     inputFeatures, type, windowToken, inputTransferToken, inputHandleName,
930                     outInputChannel);
931         } finally {
932             Binder.restoreCallingIdentity(identity);
933         }
934     }
935 
936     @Override
updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, int flags, int privateFlags, int inputFeatures, Region region)937     public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
938             int flags, int privateFlags, int inputFeatures, Region region) {
939         final long identity = Binder.clearCallingIdentity();
940         try {
941             mService.updateInputChannel(channelToken, displayId, surface, flags,
942                     mCanAddInternalSystemWindow ? privateFlags : 0, inputFeatures, region);
943         } finally {
944             Binder.restoreCallingIdentity(identity);
945         }
946     }
947 
948     @Override
grantEmbeddedWindowFocus(IWindow callingWindow, InputTransferToken targetInputToken, boolean grantFocus)949     public void grantEmbeddedWindowFocus(IWindow callingWindow, InputTransferToken targetInputToken,
950                                          boolean grantFocus) {
951         final long identity = Binder.clearCallingIdentity();
952         try {
953             if (callingWindow == null) {
954                 if (!mCanAddInternalSystemWindow) {
955                     // Callers without INTERNAL_SYSTEM_WINDOW permission cannot request focus on
956                     // embedded windows without providing the calling window
957                     throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
958                 }
959                 mService.grantEmbeddedWindowFocus(this, targetInputToken, grantFocus);
960             } else {
961                 mService.grantEmbeddedWindowFocus(this, callingWindow, targetInputToken,
962                         grantFocus);
963             }
964         } finally {
965             Binder.restoreCallingIdentity(identity);
966         }
967     }
968 
969     @Override
moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction)970     public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) {
971         final long identity = Binder.clearCallingIdentity();
972         try {
973             synchronized (mService.mGlobalLock) {
974                 final WindowState win =
975                         mService.windowForClientLocked(this, fromWindow, false /* throwOnError */);
976                 if (win == null) {
977                     return false;
978                 }
979                 return mService.moveFocusToAdjacentWindow(win, direction);
980             }
981         } finally {
982             Binder.restoreCallingIdentity(identity);
983         }
984     }
985 
986     @Override
generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback)987     public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
988             RemoteCallback callback) {
989         final long origId = Binder.clearCallingIdentity();
990         try {
991             mService.generateDisplayHash(this, window, boundsInWindow, hashAlgorithm, callback);
992         } finally {
993             Binder.restoreCallingIdentity(origId);
994         }
995     }
996 
997     @Override
setOnBackInvokedCallbackInfo( IWindow window, OnBackInvokedCallbackInfo callbackInfo)998     public void setOnBackInvokedCallbackInfo(
999             IWindow window,
1000             OnBackInvokedCallbackInfo callbackInfo) {
1001         synchronized (mService.mGlobalLock) {
1002             WindowState windowState = mService.windowForClientLocked(this, window, false);
1003             if (windowState == null) {
1004                 Slog.i(TAG_WM,
1005                         "setOnBackInvokedCallback(): No window state for package:" + mPackageName);
1006             } else {
1007                 windowState.setOnBackInvokedCallbackInfo(callbackInfo);
1008             }
1009         }
1010     }
1011 
1012     @Override
notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible, @NonNull ImeTracker.Token statsToken)1013     public void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
1014             @NonNull ImeTracker.Token statsToken) {
1015         synchronized (mService.mGlobalLock) {
1016             // TODO(b/353463205) check if we can use mService.getDefaultDisplayContentLocked()
1017             //  instead of window
1018             final WindowState win = mService.windowForClientLocked(this, window,
1019                     false /* throwOnError */);
1020             if (win != null) {
1021                 final InsetsStateController insetsStateController =
1022                         win.getDisplayContent().getInsetsStateController();
1023                 ProtoLog.d(WM_DEBUG_IME, "notifyImeWindowVisibilityChangedFromClient: %s",
1024                         insetsStateController.getImeSourceProvider());
1025                 ImeTracker.forLogging().onProgress(statsToken,
1026                         ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT);
1027                 insetsStateController.getImeSourceProvider().receiveImeStatsToken(visible,
1028                         statsToken);
1029             } else {
1030                 ImeTracker.forLogging().onFailed(statsToken,
1031                         ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT);
1032             }
1033         }
1034     }
1035 }
1036