• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 android.view.inputmethod;
18 
19 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
20 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
21 
22 import static com.android.internal.inputmethod.InputMethodDebug.softInputDisplayReasonToString;
23 import static com.android.internal.jank.Cuj.CUJ_IME_INSETS_HIDE_ANIMATION;
24 import static com.android.internal.jank.Cuj.CUJ_IME_INSETS_SHOW_ANIMATION;
25 import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_HIDDEN;
26 import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_SHOWN;
27 
28 import android.annotation.IntDef;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.content.Context;
32 import android.os.Binder;
33 import android.os.IBinder;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 import android.os.Process;
37 import android.os.SystemProperties;
38 import android.util.Log;
39 import android.view.InsetsController.AnimationType;
40 import android.view.SurfaceControl;
41 import android.view.View;
42 
43 import com.android.internal.annotations.VisibleForTesting;
44 import com.android.internal.annotations.VisibleForTesting.Visibility;
45 import com.android.internal.inputmethod.InputMethodDebug;
46 import com.android.internal.inputmethod.SoftInputShowHideReason;
47 import com.android.internal.jank.InteractionJankMonitor;
48 import com.android.internal.jank.InteractionJankMonitor.Configuration;
49 import com.android.internal.util.LatencyTracker;
50 
51 import java.lang.annotation.Retention;
52 import java.lang.annotation.RetentionPolicy;
53 import java.lang.reflect.Field;
54 import java.util.Arrays;
55 import java.util.Locale;
56 import java.util.Map;
57 import java.util.concurrent.ThreadLocalRandom;
58 import java.util.stream.Collectors;
59 
60 /** @hide */
61 public interface ImeTracker {
62 
63     String TAG = "ImeTracker";
64 
65     /** The debug flag for IME visibility event log. */
66     boolean DEBUG_IME_VISIBILITY = SystemProperties.getBoolean("persist.debug.imf_event", false);
67 
68     /** The message to indicate if there is no valid {@link Token}. */
69     String TOKEN_NONE = "TOKEN_NONE";
70 
71     /** The type of the IME request. */
72     @IntDef(prefix = { "TYPE_" }, value = {
73             TYPE_SHOW,
74             TYPE_HIDE,
75             TYPE_USER,
76     })
77     @Retention(RetentionPolicy.SOURCE)
78     @interface Type {}
79 
80     /**
81      * IME show request type.
82      *
83      * @see android.view.InsetsController#ANIMATION_TYPE_SHOW
84      */
85     int TYPE_SHOW = ImeProtoEnums.TYPE_SHOW;
86 
87     /**
88      * IME hide request type.
89      *
90      * @see android.view.InsetsController#ANIMATION_TYPE_HIDE
91      */
92     int TYPE_HIDE = ImeProtoEnums.TYPE_HIDE;
93 
94     /**
95      * IME user-controlled animation request type.
96      *
97      * @see android.view.InsetsController#ANIMATION_TYPE_USER
98      */
99     int TYPE_USER = ImeProtoEnums.TYPE_USER;
100 
101     /** The status of the IME request. */
102     @IntDef(prefix = { "STATUS_" }, value = {
103             STATUS_RUN,
104             STATUS_CANCEL,
105             STATUS_FAIL,
106             STATUS_SUCCESS,
107             STATUS_TIMEOUT,
108     })
109     @Retention(RetentionPolicy.SOURCE)
110     @interface Status {}
111 
112     /** IME request running. */
113     int STATUS_RUN = ImeProtoEnums.STATUS_RUN;
114 
115     /** IME request cancelled. */
116     int STATUS_CANCEL = ImeProtoEnums.STATUS_CANCEL;
117 
118     /** IME request failed. */
119     int STATUS_FAIL = ImeProtoEnums.STATUS_FAIL;
120 
121     /** IME request succeeded. */
122     int STATUS_SUCCESS = ImeProtoEnums.STATUS_SUCCESS;
123 
124     /** IME request timed out. */
125     int STATUS_TIMEOUT = ImeProtoEnums.STATUS_TIMEOUT;
126 
127     /**
128      * The origin of the IME request
129      *
130      * <p> The name follows the format {@code ORIGIN_x_...} where {@code x} denotes
131      * where the origin is (i.e. {@code ORIGIN_SERVER} occurs in the server).
132      */
133     @IntDef(prefix = { "ORIGIN_" }, value = {
134             ORIGIN_CLIENT,
135             ORIGIN_SERVER,
136             ORIGIN_IME,
137             ORIGIN_WM_SHELL,
138     })
139     @Retention(RetentionPolicy.SOURCE)
140     @interface Origin {}
141 
142     /** The IME request originated in the client. */
143     int ORIGIN_CLIENT = ImeProtoEnums.ORIGIN_CLIENT;
144 
145     /** The IME request originated in the server. */
146     int ORIGIN_SERVER = ImeProtoEnums.ORIGIN_SERVER;
147 
148     /** The IME request originated in the IME. */
149     int ORIGIN_IME = ImeProtoEnums.ORIGIN_IME;
150     /** The IME request originated in the WindowManager Shell. */
151     int ORIGIN_WM_SHELL = ImeProtoEnums.ORIGIN_WM_SHELL;
152 
153     /**
154      * The current phase of the IME request.
155      *
156      * <p> The name follows the format {@code PHASE_x_...} where {@code x} denotes
157      * where the phase is (i.e. {@code PHASE_SERVER_...} occurs in the server).
158      */
159     @IntDef(prefix = { "PHASE_" }, value = {
160             PHASE_NOT_SET,
161             PHASE_CLIENT_VIEW_SERVED,
162             PHASE_SERVER_CLIENT_KNOWN,
163             PHASE_SERVER_CLIENT_FOCUSED,
164             PHASE_SERVER_ACCESSIBILITY,
165             PHASE_SERVER_SYSTEM_READY,
166             PHASE_SERVER_HIDE_IMPLICIT,
167             PHASE_SERVER_HIDE_NOT_ALWAYS,
168             PHASE_SERVER_WAIT_IME,
169             PHASE_SERVER_HAS_IME,
170             PHASE_SERVER_SHOULD_HIDE,
171             PHASE_IME_WRAPPER,
172             PHASE_IME_WRAPPER_DISPATCH,
173             PHASE_IME_SHOW_SOFT_INPUT,
174             PHASE_IME_HIDE_SOFT_INPUT,
175             PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE,
176             PHASE_SERVER_APPLY_IME_VISIBILITY,
177             PHASE_WM_SHOW_IME_RUNNER,
178             PHASE_WM_SHOW_IME_READY,
179             PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET,
180             PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS,
181             PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS,
182             PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS,
183             PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS,
184             PHASE_WM_REMOTE_INSETS_CONTROLLER,
185             PHASE_WM_ANIMATION_CREATE,
186             PHASE_WM_ANIMATION_RUNNING,
187             PHASE_CLIENT_SHOW_INSETS,
188             PHASE_CLIENT_HIDE_INSETS,
189             PHASE_CLIENT_HANDLE_SHOW_INSETS,
190             PHASE_CLIENT_HANDLE_HIDE_INSETS,
191             PHASE_CLIENT_APPLY_ANIMATION,
192             PHASE_CLIENT_CONTROL_ANIMATION,
193             PHASE_CLIENT_COLLECT_SOURCE_CONTROLS,
194             PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW,
195             PHASE_CLIENT_REQUEST_IME_SHOW,
196             PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN,
197             PHASE_CLIENT_ANIMATION_RUNNING,
198             PHASE_CLIENT_ANIMATION_CANCEL,
199             PHASE_CLIENT_ANIMATION_FINISHED_SHOW,
200             PHASE_CLIENT_ANIMATION_FINISHED_HIDE,
201             PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT,
202             PHASE_IME_SHOW_WINDOW,
203             PHASE_IME_HIDE_WINDOW,
204             PHASE_IME_PRIVILEGED_OPERATIONS,
205             PHASE_SERVER_CURRENT_ACTIVE_IME,
206             PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES,
207             PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY,
208             PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED,
209             PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED,
210             PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED,
211             PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES,
212             PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY,
213             PHASE_WM_GET_CONTROL_WITH_LEASH,
214             PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES,
215             PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW,
216             PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY,
217             PHASE_CLIENT_SET_IME_VISIBILITY,
218             PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED,
219             PHASE_CLIENT_NO_ONGOING_USER_ANIMATION,
220             PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT,
221             PHASE_WM_POSTING_CHANGED_IME_VISIBILITY,
222             PHASE_WM_INVOKING_IME_REQUESTED_LISTENER,
223             PHASE_CLIENT_ALREADY_HIDDEN,
224             PHASE_CLIENT_VIEW_HANDLER_AVAILABLE,
225             PHASE_SERVER_UPDATE_CLIENT_VISIBILITY,
226             PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE,
227             PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES,
228             PHASE_WM_REQUESTED_VISIBLE_TYPES_NOT_CHANGED,
229             PHASE_CLIENT_UPDATE_ANIMATING_TYPES,
230             PHASE_WM_UPDATE_ANIMATING_TYPES,
231             PHASE_WM_WINDOW_ANIMATING_TYPES_CHANGED,
232             PHASE_WM_NOTIFY_HIDE_ANIMATION_FINISHED,
233             PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES,
234             PHASE_CLIENT_ON_CONTROLS_CHANGED,
235             PHASE_SERVER_IME_INVOKER,
236             PHASE_SERVER_CLIENT_INVOKER,
237     })
238     @Retention(RetentionPolicy.SOURCE)
239     @interface Phase {}
240 
241     int PHASE_NOT_SET = ImeProtoEnums.PHASE_NOT_SET;
242 
243     /** The view that requested the IME has been served by the IMM. */
244     int PHASE_CLIENT_VIEW_SERVED = ImeProtoEnums.PHASE_CLIENT_VIEW_SERVED;
245 
246     /** The IME client that requested the IME has window manager focus. */
247     int PHASE_SERVER_CLIENT_KNOWN = ImeProtoEnums.PHASE_SERVER_CLIENT_KNOWN;
248 
249     /** The IME client that requested the IME has IME focus. */
250     int PHASE_SERVER_CLIENT_FOCUSED = ImeProtoEnums.PHASE_SERVER_CLIENT_FOCUSED;
251 
252     /** The IME request complies with the current accessibility settings. */
253     int PHASE_SERVER_ACCESSIBILITY = ImeProtoEnums.PHASE_SERVER_ACCESSIBILITY;
254 
255     /** The server is ready to run third party code. */
256     int PHASE_SERVER_SYSTEM_READY = ImeProtoEnums.PHASE_SERVER_SYSTEM_READY;
257 
258     /** Checked the implicit hide request against any explicit show requests. */
259     int PHASE_SERVER_HIDE_IMPLICIT = ImeProtoEnums.PHASE_SERVER_HIDE_IMPLICIT;
260 
261     /** Checked the not-always hide request against any forced show requests. */
262     int PHASE_SERVER_HIDE_NOT_ALWAYS = ImeProtoEnums.PHASE_SERVER_HIDE_NOT_ALWAYS;
263 
264     /** The server is waiting for a connection to the IME. */
265     int PHASE_SERVER_WAIT_IME = ImeProtoEnums.PHASE_SERVER_WAIT_IME;
266 
267     /** The server has a connection to the IME. */
268     int PHASE_SERVER_HAS_IME = ImeProtoEnums.PHASE_SERVER_HAS_IME;
269 
270     /** The server decided the IME should be hidden. */
271     int PHASE_SERVER_SHOULD_HIDE = ImeProtoEnums.PHASE_SERVER_SHOULD_HIDE;
272 
273     /** Reached the IME wrapper. */
274     int PHASE_IME_WRAPPER = ImeProtoEnums.PHASE_IME_WRAPPER;
275 
276     /** Dispatched from the IME wrapper to the IME. */
277     int PHASE_IME_WRAPPER_DISPATCH = ImeProtoEnums.PHASE_IME_WRAPPER_DISPATCH;
278 
279     /** Reached the IME's showSoftInput method. */
280     int PHASE_IME_SHOW_SOFT_INPUT = ImeProtoEnums.PHASE_IME_SHOW_SOFT_INPUT;
281 
282     /** Reached the IME's hideSoftInput method. */
283     int PHASE_IME_HIDE_SOFT_INPUT = ImeProtoEnums.PHASE_IME_HIDE_SOFT_INPUT;
284 
285     /** The server decided the IME should be shown. */
286     int PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE = ImeProtoEnums.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE;
287 
288     /** Applied the IME visibility. */
289     int PHASE_SERVER_APPLY_IME_VISIBILITY = ImeProtoEnums.PHASE_SERVER_APPLY_IME_VISIBILITY;
290 
291     /** Started the show IME runner. */
292     int PHASE_WM_SHOW_IME_RUNNER = ImeProtoEnums.PHASE_WM_SHOW_IME_RUNNER;
293 
294     /** Ready to show IME. */
295     int PHASE_WM_SHOW_IME_READY = ImeProtoEnums.PHASE_WM_SHOW_IME_READY;
296 
297     /** The Window Manager has a connection to the IME insets control target. */
298     int PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET =
299             ImeProtoEnums.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET;
300 
301     /** Reached the window insets control target's show insets method. */
302     int PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS =
303             ImeProtoEnums.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS;
304 
305     /** Reached the window insets control target's hide insets method. */
306     int PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS =
307             ImeProtoEnums.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS;
308 
309     /** Reached the remote insets control target's show insets method. */
310     int PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS =
311             ImeProtoEnums.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS;
312 
313     /** Reached the remote insets control target's hide insets method. */
314     int PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS =
315             ImeProtoEnums.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS;
316 
317     /** Reached the remote insets controller. */
318     int PHASE_WM_REMOTE_INSETS_CONTROLLER = ImeProtoEnums.PHASE_WM_REMOTE_INSETS_CONTROLLER;
319 
320     /** Created the IME window insets show animation. */
321     int PHASE_WM_ANIMATION_CREATE = ImeProtoEnums.PHASE_WM_ANIMATION_CREATE;
322 
323     /** Started the IME window insets show animation. */
324     int PHASE_WM_ANIMATION_RUNNING = ImeProtoEnums.PHASE_WM_ANIMATION_RUNNING;
325 
326     /** Reached the client's show insets method. */
327     int PHASE_CLIENT_SHOW_INSETS = ImeProtoEnums.PHASE_CLIENT_SHOW_INSETS;
328 
329     /** Reached the client's hide insets method. */
330     int PHASE_CLIENT_HIDE_INSETS = ImeProtoEnums.PHASE_CLIENT_HIDE_INSETS;
331 
332     /** Handling the IME window insets show request. */
333     int PHASE_CLIENT_HANDLE_SHOW_INSETS = ImeProtoEnums.PHASE_CLIENT_HANDLE_SHOW_INSETS;
334 
335     /** Handling the IME window insets hide request. */
336     int PHASE_CLIENT_HANDLE_HIDE_INSETS = ImeProtoEnums.PHASE_CLIENT_HANDLE_HIDE_INSETS;
337 
338     /** Applied the IME window insets show animation. */
339     int PHASE_CLIENT_APPLY_ANIMATION = ImeProtoEnums.PHASE_CLIENT_APPLY_ANIMATION;
340 
341     /** Started the IME window insets show animation. */
342     int PHASE_CLIENT_CONTROL_ANIMATION = ImeProtoEnums.PHASE_CLIENT_CONTROL_ANIMATION;
343 
344     /** Collecting insets source controls. */
345     int PHASE_CLIENT_COLLECT_SOURCE_CONTROLS = ImeProtoEnums.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS;
346 
347     /** Reached the insets source consumer's show request method. */
348     int PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW =
349             ImeProtoEnums.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW;
350 
351     /** Reached input method manager's request IME show method. */
352     int PHASE_CLIENT_REQUEST_IME_SHOW = ImeProtoEnums.PHASE_CLIENT_REQUEST_IME_SHOW;
353 
354     /** Reached the insets source consumer's notify hidden method. */
355     int PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN =
356             ImeProtoEnums.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN;
357 
358     /** Queued the IME window insets show animation. */
359     int PHASE_CLIENT_ANIMATION_RUNNING = ImeProtoEnums.PHASE_CLIENT_ANIMATION_RUNNING;
360 
361     /** Cancelled the IME window insets show animation. */
362     int PHASE_CLIENT_ANIMATION_CANCEL = ImeProtoEnums.PHASE_CLIENT_ANIMATION_CANCEL;
363 
364     /** Finished the IME window insets show animation. */
365     int PHASE_CLIENT_ANIMATION_FINISHED_SHOW = ImeProtoEnums.PHASE_CLIENT_ANIMATION_FINISHED_SHOW;
366 
367     /** Finished the IME window insets hide animation. */
368     int PHASE_CLIENT_ANIMATION_FINISHED_HIDE = ImeProtoEnums.PHASE_CLIENT_ANIMATION_FINISHED_HIDE;
369 
370     /** Aborted the request to show the IME post layout. */
371     int PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT =
372             ImeProtoEnums.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT;
373 
374     /** Reached the IME's showWindow method. */
375     int PHASE_IME_SHOW_WINDOW = ImeProtoEnums.PHASE_IME_SHOW_WINDOW;
376 
377     /** Reached the IME's hideWindow method. */
378     int PHASE_IME_HIDE_WINDOW = ImeProtoEnums.PHASE_IME_HIDE_WINDOW;
379 
380     /** Reached the InputMethodPrivilegedOperations handler. */
381     int PHASE_IME_PRIVILEGED_OPERATIONS = ImeProtoEnums.PHASE_IME_PRIVILEGED_OPERATIONS;
382 
383     /** Checked that the calling IME is the currently active IME. */
384     int PHASE_SERVER_CURRENT_ACTIVE_IME = ImeProtoEnums.PHASE_SERVER_CURRENT_ACTIVE_IME;
385 
386     /** Reporting the new requested visible types. */
387     int PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES =
388             ImeProtoEnums.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES;
389     /** Setting the IME visibility for the RemoteInsetsControlTarget. */
390     int PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY =
391             ImeProtoEnums.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY;
392     /** IME has no insets pending and is server visible. Notify about changed controls. */
393     int PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED =
394             ImeProtoEnums.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED;
395     /** Handling the dispatch of the IME visibility change. */
396     int PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED =
397             ImeProtoEnums.PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED;
398     /** Dispatching the IME visibility change. */
399     int PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED =
400             ImeProtoEnums.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED;
401     /** Updating the requested visible types. */
402     int PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES =
403             ImeProtoEnums.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES;
404     /** Reached the remote insets control target's setImeInputTargetRequestedVisibility method. */
405     int PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY =
406             ImeProtoEnums.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY;
407     /** Received a new insets source control with a leash. */
408     int PHASE_WM_GET_CONTROL_WITH_LEASH =
409             ImeProtoEnums.PHASE_WM_GET_CONTROL_WITH_LEASH;
410     /**
411      * Updating the requested visible types in the WindowState and sending them to state
412      * controller.
413      */
414     int PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES =
415             ImeProtoEnums.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES;
416     /** Setting the requested IME visibility of a window. */
417     int PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW =
418             ImeProtoEnums.PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW;
419     /** Reached the redirect of InputMethodManager to InsetsController show/hide. */
420     int PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY =
421             ImeProtoEnums.PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY;
422     /** Reached the InputMethodManager Handler call to send the visibility. */
423     int PHASE_CLIENT_SET_IME_VISIBILITY = ImeProtoEnums.PHASE_CLIENT_SET_IME_VISIBILITY;
424     /** Calling into the listener to show/hide the IME from the ImeInsetsSourceProvider. */
425     int PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED =
426             ImeProtoEnums.PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED;
427     /** An ongoing user animation will not be interrupted by a IMM#showSoftInput. */
428     int PHASE_CLIENT_NO_ONGOING_USER_ANIMATION =
429             ImeProtoEnums.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION;
430     /** Dispatching the token to the ImeInsetsSourceProvider. */
431     int PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT =
432             ImeProtoEnums.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT;
433     /** Now posting the IME visibility to the WMS handler. */
434     int PHASE_WM_POSTING_CHANGED_IME_VISIBILITY =
435             ImeProtoEnums.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY;
436     /** Inside the WMS handler calling into the listener that calls into IMMS show/hide. */
437     int PHASE_WM_INVOKING_IME_REQUESTED_LISTENER =
438             ImeProtoEnums.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER;
439     /** IME is requested to be hidden, but already hidden. Don't hide to avoid another animation. */
440     int PHASE_CLIENT_ALREADY_HIDDEN = ImeProtoEnums.PHASE_CLIENT_ALREADY_HIDDEN;
441     /**
442      * The view's handler is needed to check if we're running on a different thread. We can't
443      * continue without.
444      */
445     int PHASE_CLIENT_VIEW_HANDLER_AVAILABLE = ImeProtoEnums.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE;
446     /**
447      * ImeInsetsSourceProvider sets the reported visibility of the caller/client window (either the
448      * app or the RemoteInsetsControlTarget).
449      */
450     int PHASE_SERVER_UPDATE_CLIENT_VISIBILITY = ImeProtoEnums.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY;
451     /** DisplayImeController received the requested visibility for the IME and stored it. */
452     int PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE =
453             ImeProtoEnums.PHASE_WM_DISPLAY_IME_CONTROLLER_SET_IME_REQUESTED_VISIBLE;
454     /** The control target reported its requestedVisibleTypes back to WindowManagerService. */
455     int PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES =
456             ImeProtoEnums.PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES;
457     /** The requestedVisibleTypes have not been changed, so this request is not continued. */
458     int PHASE_WM_REQUESTED_VISIBLE_TYPES_NOT_CHANGED =
459             ImeProtoEnums.PHASE_WM_REQUESTED_VISIBLE_TYPES_NOT_CHANGED;
460     /** Updating the currently animating types on the client side. */
461     int PHASE_CLIENT_UPDATE_ANIMATING_TYPES =
462             ImeProtoEnums.PHASE_CLIENT_UPDATE_ANIMATING_TYPES;
463     /** Updating the animating types in the WindowState on the WindowManager side. */
464     int PHASE_WM_UPDATE_ANIMATING_TYPES =
465             ImeProtoEnums.PHASE_WM_UPDATE_ANIMATING_TYPES;
466     /** Animating types of the WindowState have changed, now sending them to state controller. */
467     int PHASE_WM_WINDOW_ANIMATING_TYPES_CHANGED =
468             ImeProtoEnums.PHASE_WM_WINDOW_ANIMATING_TYPES_CHANGED;
469     /** ImeInsetsSourceProvider got notified that the hide animation is finished. */
470     int PHASE_WM_NOTIFY_HIDE_ANIMATION_FINISHED =
471             ImeProtoEnums.PHASE_WM_NOTIFY_HIDE_ANIMATION_FINISHED;
472     /** The control target reported its animatingTypes back to WindowManagerService. */
473     int PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES =
474             ImeProtoEnums.PHASE_WM_UPDATE_DISPLAY_WINDOW_ANIMATING_TYPES;
475     /** InsetsController received a control for the IME. */
476     int PHASE_CLIENT_ON_CONTROLS_CHANGED =
477             ImeProtoEnums.PHASE_CLIENT_ON_CONTROLS_CHANGED;
478     /** Reached the IME invoker on the server. */
479     int PHASE_SERVER_IME_INVOKER = ImeProtoEnums.PHASE_SERVER_IME_INVOKER;
480     /** Reached the IME client invoker on the server. */
481     int PHASE_SERVER_CLIENT_INVOKER = ImeProtoEnums.PHASE_SERVER_CLIENT_INVOKER;
482 
483     /**
484      * Called when an IME request is started.
485      *
486      * @param component the name of the component that started the request.
487      * @param uid the uid of the client that started the request.
488      * @param type the type of the request.
489      * @param origin the origin of the request.
490      * @param reason the reason for starting the request.
491      * @param fromUser whether this request was created directly from user interaction.
492      *
493      * @return An IME request tracking token.
494      */
495     @NonNull
onStart(@onNull String component, int uid, @Type int type, @Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser)496     Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
497             @SoftInputShowHideReason int reason, boolean fromUser);
498 
499     /**
500      * Called when an IME request is started for the current process.
501      *
502      * @param type the type of the request.
503      * @param origin the origin of the request.
504      * @param reason the reason for starting the request.
505      * @param fromUser whether this request was created directly from user interaction.
506      *
507      * @return An IME request tracking token.
508      */
509     @NonNull
onStart(@ype int type, @Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser)510     default Token onStart(@Type int type, @Origin int origin, @SoftInputShowHideReason int reason,
511             boolean fromUser) {
512         return onStart(Process.myProcessName(), Process.myUid(), type, origin, reason, fromUser);
513     }
514 
515     /**
516      * Called when an IME request progresses to a further phase.
517      *
518      * @param token the token tracking the current IME request or {@code null} otherwise.
519      * @param phase the new phase the IME request reached.
520      */
onProgress(@ullable Token token, @Phase int phase)521     void onProgress(@Nullable Token token, @Phase int phase);
522 
523     /**
524      * Called when an IME request fails.
525      *
526      * @param token the token tracking the current IME request or {@code null} otherwise.
527      * @param phase the phase the IME request failed at.
528      */
onFailed(@ullable Token token, @Phase int phase)529     void onFailed(@Nullable Token token, @Phase int phase);
530 
531     /**
532      * Called when an IME request reached a flow that is not yet implemented.
533      *
534      * @param token the token tracking the current IME request or {@code null} otherwise.
535      * @param phase the phase the IME request was currently at.
536      */
onTodo(@ullable Token token, @Phase int phase)537     void onTodo(@Nullable Token token, @Phase int phase);
538 
539     /**
540      * Called when an IME request is cancelled.
541      *
542      * @param token the token tracking the current IME request or {@code null} otherwise.
543      * @param phase the phase the IME request was cancelled at.
544      */
onCancelled(@ullable Token token, @Phase int phase)545     void onCancelled(@Nullable Token token, @Phase int phase);
546 
547     /**
548      * Called when the show IME request is successful.
549      *
550      * @param token the token tracking the current IME request or {@code null} otherwise.
551      */
onShown(@ullable Token token)552     void onShown(@Nullable Token token);
553 
554     /**
555      * Called when the hide IME request is successful.
556      *
557      * @param token the token tracking the current IME request or {@code null} otherwise.
558      */
onHidden(@ullable Token token)559     void onHidden(@Nullable Token token);
560 
561     /**
562      * Called when the user-controlled IME request was dispatched to the requesting app. The
563      * user animation can take an undetermined amount of time, so it shouldn't be tracked.
564      *
565      * @param token the token tracking the current IME request or {@code null} otherwise.
566      */
onDispatched(@ullable Token token)567     void onDispatched(@Nullable Token token);
568 
569     /**
570      * Called when the animation of the user-controlled IME request finished.
571      *
572      * @param token the token tracking the current IME request or {@code null} otherwise.
573      * @param shown whether the end state of the animation was shown or hidden.
574      */
onUserFinished(@ullable Token token, boolean shown)575     void onUserFinished(@Nullable Token token, boolean shown);
576 
577     /**
578      * Returns whether the current IME request was created due to a user interaction. This can
579      * only be {@code true} when running on the view's UI thread.
580      *
581      * @param view the view for which the IME was requested.
582      * @return {@code true} if this request is coming from a user interaction,
583      * {@code false} otherwise.
584      */
isFromUser(@ullable View view)585     static boolean isFromUser(@Nullable View view) {
586         if (view == null) {
587             return false;
588         }
589         final var handler = view.getHandler();
590         // Early return if not on the UI thread, to ensure safe access to getViewRootImpl() below.
591         if (handler == null || handler.getLooper() == null
592                 || !handler.getLooper().isCurrentThread()) {
593             return false;
594         }
595         final var viewRootImpl = view.getViewRootImpl();
596         return viewRootImpl != null && viewRootImpl.isHandlingPointerEvent();
597     }
598 
599     /**
600      * Get the singleton request tracker instance.
601      *
602      * @return the singleton request tracker instance
603      */
604     @NonNull
forLogging()605     static ImeTracker forLogging() {
606         return LOGGER;
607     }
608 
609     /**
610      * Get the singleton jank tracker instance.
611      *
612      * @return the singleton jank tracker instance
613      */
614     @NonNull
forJank()615     static ImeJankTracker forJank() {
616         return JANK_TRACKER;
617     }
618 
619     /**
620      * Get the singleton latency tracker instance.
621      *
622      * @return the singleton latency tracker instance
623      */
624     @NonNull
forLatency()625     static ImeLatencyTracker forLatency() {
626         return LATENCY_TRACKER;
627     }
628 
629     /** The singleton IME tracker instance. */
630     @NonNull
631     ImeTracker LOGGER = new ImeTracker() {
632 
633         {
634             // Read initial system properties.
635             reloadSystemProperties();
636             // Update when system properties change.
637             SystemProperties.addChangeCallback(this::reloadSystemProperties);
638         }
639 
640         /** Whether {@link #onProgress} calls should be logged. */
641         private boolean mLogProgress;
642 
643         /** Whether the stack trace at the request call site should be logged. */
644         private boolean mLogStackTrace;
645 
646         @NonNull
647         @Override
648         public Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
649                 @SoftInputShowHideReason int reason, boolean fromUser) {
650             final var tag = Token.createTag(component);
651             final var token = IInputMethodManagerGlobalInvoker.onStart(tag, uid, type,
652                     origin, reason, fromUser);
653 
654             Log.i(TAG, token.mTag + ": " + getOnStartPrefix(type)
655                     + " at " + Debug.originToString(origin)
656                     + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
657                     + " fromUser " + fromUser,
658                     mLogStackTrace ? new Throwable() : null);
659             return token;
660         }
661 
662         @Override
663         public void onProgress(@Nullable Token token, @Phase int phase) {
664             if (token == null) return;
665             IInputMethodManagerGlobalInvoker.onProgress(token.mBinder, phase);
666 
667             if (mLogProgress) {
668                 Log.i(TAG, token.mTag + ": onProgress at " + Debug.phaseToString(phase));
669             }
670         }
671 
672         @Override
673         public void onFailed(@Nullable Token token, @Phase int phase) {
674             if (token == null) return;
675             IInputMethodManagerGlobalInvoker.onFailed(token, phase);
676 
677             Log.i(TAG, token.mTag + ": onFailed at " + Debug.phaseToString(phase));
678         }
679 
680         @Override
681         public void onTodo(@Nullable Token token, @Phase int phase) {
682             if (token == null) return;
683             Log.i(TAG, token.mTag + ": onTodo at " + Debug.phaseToString(phase));
684         }
685 
686         @Override
687         public void onCancelled(@Nullable Token token, @Phase int phase) {
688             if (token == null) return;
689             IInputMethodManagerGlobalInvoker.onCancelled(token, phase);
690 
691             Log.i(TAG, token.mTag + ": onCancelled at " + Debug.phaseToString(phase));
692         }
693 
694         @Override
695         public void onShown(@Nullable Token token) {
696             if (token == null) return;
697             IInputMethodManagerGlobalInvoker.onShown(token);
698 
699             Log.i(TAG, token.mTag + ": onShown");
700         }
701 
702         @Override
703         public void onHidden(@Nullable Token token) {
704             if (token == null) return;
705             IInputMethodManagerGlobalInvoker.onHidden(token);
706 
707             Log.i(TAG, token.mTag + ": onHidden");
708         }
709 
710         @Override
711         public void onDispatched(@Nullable Token token) {
712             if (token == null) return;
713             IInputMethodManagerGlobalInvoker.onDispatched(token);
714 
715             Log.i(TAG, token.mTag + ": onDispatched");
716         }
717 
718         @Override
719         public void onUserFinished(@Nullable Token token, boolean shown) {
720             if (token == null) return;
721             // This is already sent to ImeTrackerService to mark it finished during onDispatched.
722 
723             Log.i(TAG, token.mTag + ": onUserFinished " + (shown ? "shown" : "hidden"));
724         }
725 
726         /**
727          * Gets the prefix string for {@link #onStart} based on the given request type.
728          *
729          * @param type request type for which to create the prefix string with.
730          */
731         @NonNull
732         private static String getOnStartPrefix(@Type int type) {
733             return switch (type) {
734                 case TYPE_SHOW -> "onRequestShow";
735                 case TYPE_HIDE -> "onRequestHide";
736                 case TYPE_USER -> "onRequestUser";
737                 default -> "onRequestUnknown";
738             };
739         }
740 
741         /** Reloads the system properties related to this class. */
742         private void reloadSystemProperties() {
743             mLogProgress = SystemProperties.getBoolean(
744                     "persist.debug.imetracker", false);
745             mLogStackTrace = SystemProperties.getBoolean(
746                     "persist.debug.imerequest.logstacktrace", false);
747         }
748     };
749 
750     /** The singleton IME tracker instance for instrumenting jank metrics. */
751     ImeJankTracker JANK_TRACKER = new ImeJankTracker();
752 
753     /** The singleton IME tracker instance for instrumenting latency metrics. */
754     ImeLatencyTracker LATENCY_TRACKER = new ImeLatencyTracker();
755 
756     /** A token that tracks the progress of an IME request. */
757     final class Token implements Parcelable {
758 
759         /** Empty binder, lazily initialized, used for empty token instantiation. */
760         @Nullable
761         private static IBinder sEmptyBinder;
762 
763         /** The binder used to identify this token. */
764         @NonNull
765         private final IBinder mBinder;
766 
767         /** Logging tag, of the shape "component:random_hexadecimal". */
768         @NonNull
769         private final String mTag;
770 
Token(@onNull IBinder binder, @NonNull String tag)771         public Token(@NonNull IBinder binder, @NonNull String tag) {
772             mBinder = binder;
773             mTag = tag;
774         }
775 
Token(@onNull Parcel in)776         private Token(@NonNull Parcel in) {
777             mBinder = in.readStrongBinder();
778             mTag = in.readString8();
779         }
780 
781         /** Returns the binder used to identify this token. */
782         @NonNull
getBinder()783         public IBinder getBinder() {
784             return mBinder;
785         }
786 
787         /** Returns the logging tag of this token. */
788         @NonNull
getTag()789         public String getTag() {
790             return mTag;
791         }
792 
793         /**
794          * Creates a logging tag.
795          *
796          * @param component the name of the component that created the IME request.
797          */
798         @NonNull
createTag(@onNull String component)799         private static String createTag(@NonNull String component) {
800             return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
801         }
802 
803         /** Returns a new token with an empty binder. */
804         @NonNull
805         @VisibleForTesting(visibility = Visibility.PACKAGE)
empty()806         public static Token empty() {
807             final var tag = createTag(Process.myProcessName());
808             return empty(tag);
809         }
810 
811         /** Returns a new token with an empty binder and the given logging tag. */
812         @NonNull
empty(@onNull String tag)813         static Token empty(@NonNull String tag) {
814             return new Token(getEmptyBinder(), tag);
815         }
816 
817         /** Returns the empty binder instance for empty token creation, lazily initializing it. */
818         @NonNull
getEmptyBinder()819         private static IBinder getEmptyBinder() {
820             if (sEmptyBinder == null) {
821                 sEmptyBinder = new Binder();
822             }
823             return sEmptyBinder;
824         }
825 
826         @Override
toString()827         public String toString() {
828             return super.toString() + "(tag: " + mTag + ")";
829         }
830 
831         /** For Parcelable, no special marshalled objects. */
832         @Override
describeContents()833         public int describeContents() {
834             return 0;
835         }
836 
837         @Override
writeToParcel(@onNull Parcel dest, int flags)838         public void writeToParcel(@NonNull Parcel dest, int flags) {
839             dest.writeStrongBinder(mBinder);
840             dest.writeString8(mTag);
841         }
842 
843         @NonNull
844         public static final Creator<Token> CREATOR = new Creator<>() {
845             @NonNull
846             @Override
847             public Token createFromParcel(@NonNull Parcel in) {
848                 return new Token(in);
849             }
850 
851             @NonNull
852             @Override
853             public Token[] newArray(int size) {
854                 return new Token[size];
855             }
856         };
857     }
858 
859     /**
860      * Utilities for mapping IntDef values to their names.
861      *
862      * Note: This is held in a separate class so that it only gets initialized when actually needed.
863      */
864     final class Debug {
865 
866         @NonNull
867         private static final Map<Integer, String> sTypes =
868                 getFieldMapping(ImeTracker.class, "TYPE_");
869         @NonNull
870         private static final Map<Integer, String> sStatus =
871                 getFieldMapping(ImeTracker.class, "STATUS_");
872         @NonNull
873         private static final Map<Integer, String> sOrigins =
874                 getFieldMapping(ImeTracker.class, "ORIGIN_");
875         @NonNull
876         private static final Map<Integer, String> sPhases =
877                 getFieldMapping(ImeTracker.class, "PHASE_");
878 
879         @NonNull
typeToString(@ype int type)880         public static String typeToString(@Type int type) {
881             return sTypes.getOrDefault(type, "TYPE_" + type);
882         }
883 
884         @NonNull
statusToString(@tatus int status)885         public static String statusToString(@Status int status) {
886             return sStatus.getOrDefault(status, "STATUS_" + status);
887         }
888 
889         @NonNull
originToString(@rigin int origin)890         public static String originToString(@Origin int origin) {
891             return sOrigins.getOrDefault(origin, "ORIGIN_" + origin);
892         }
893 
894         @NonNull
phaseToString(@hase int phase)895         public static String phaseToString(@Phase int phase) {
896             return sPhases.getOrDefault(phase, "PHASE_" + phase);
897         }
898 
899         @NonNull
getFieldMapping(Class<?> cls, @NonNull String fieldPrefix)900         private static Map<Integer, String> getFieldMapping(Class<?> cls,
901                 @NonNull String fieldPrefix) {
902             return Arrays.stream(cls.getDeclaredFields())
903                     .filter(field -> field.getName().startsWith(fieldPrefix))
904                     .collect(Collectors.toMap(Debug::getFieldValue, Field::getName));
905         }
906 
getFieldValue(@onNull Field field)907         private static int getFieldValue(@NonNull Field field) {
908             try {
909                 return field.getInt(null);
910             } catch (IllegalAccessException e) {
911                 throw new RuntimeException(e);
912             }
913         }
914     }
915 
916     /**
917      * Context related to {@link InteractionJankMonitor}.
918      */
919     interface InputMethodJankContext {
920         /**
921          * @return a context associated with a display
922          */
getDisplayContext()923         Context getDisplayContext();
924 
925         /**
926          * @return a SurfaceControl that is going to be monitored
927          */
getTargetSurfaceControl()928         SurfaceControl getTargetSurfaceControl();
929 
930         /**
931          * @return the package name of the host
932          */
getHostPackageName()933         String getHostPackageName();
934     }
935 
936     /**
937      * Context related to {@link LatencyTracker}.
938      */
939     interface InputMethodLatencyContext {
940         /**
941          * @return a context associated with current application
942          */
getAppContext()943         Context getAppContext();
944     }
945 
946     /**
947      * A tracker instance which is in charge of communicating with {@link InteractionJankMonitor}.
948      * This class disallows instantiating from outside, use {@link #forJank()} to get the singleton.
949      */
950     final class ImeJankTracker {
951 
952         /**
953          * This class disallows instantiating from outside.
954          */
ImeJankTracker()955         private ImeJankTracker() {
956         }
957 
958         /**
959          * Called when the animation, which is going to be monitored, starts.
960          *
961          * @param jankContext context which is needed by {@link InteractionJankMonitor}.
962          * @param animType the animation type.
963          * @param useSeparatedThread {@code true} if the animation is handled by the app,
964          *                           {@code false} if the animation will be scheduled on the
965          *                           {@link android.view.InsetsAnimationThread}.
966          */
onRequestAnimation(@onNull InputMethodJankContext jankContext, @AnimationType int animType, boolean useSeparatedThread)967         public void onRequestAnimation(@NonNull InputMethodJankContext jankContext,
968                 @AnimationType int animType, boolean useSeparatedThread) {
969             final int cujType = getImeInsetsCujFromAnimation(animType);
970             if (jankContext.getDisplayContext() == null
971                     || jankContext.getTargetSurfaceControl() == null
972                     || cujType == -1) {
973                 return;
974             }
975             final Configuration.Builder builder = Configuration.Builder.withSurface(
976                             cujType,
977                             jankContext.getDisplayContext(),
978                             jankContext.getTargetSurfaceControl(),
979                             jankContext.getDisplayContext().getMainThreadHandler())
980                     .setTag(String.format(Locale.US, "%d@%d@%s", animType,
981                             useSeparatedThread ? 0 : 1, jankContext.getHostPackageName()));
982             InteractionJankMonitor.getInstance().begin(builder);
983         }
984 
985         /**
986          * Called when the animation, which is going to be monitored, cancels.
987          *
988          * @param animType the animation type.
989          */
onCancelAnimation(@nimationType int animType)990         public void onCancelAnimation(@AnimationType int animType) {
991             final int cujType = getImeInsetsCujFromAnimation(animType);
992             if (cujType != -1) {
993                 InteractionJankMonitor.getInstance().cancel(cujType);
994             }
995         }
996 
997         /**
998          * Called when the animation, which is going to be monitored, ends.
999          *
1000          * @param animType the animation type.
1001          */
onFinishAnimation(@nimationType int animType)1002         public void onFinishAnimation(@AnimationType int animType) {
1003             final int cujType = getImeInsetsCujFromAnimation(animType);
1004             if (cujType != -1) {
1005                 InteractionJankMonitor.getInstance().end(cujType);
1006             }
1007         }
1008 
1009         /**
1010          * A helper method to translate animation type to CUJ type for IME animations.
1011          *
1012          * @param animType the animation type.
1013          * @return the integer in {@link com.android.internal.jank.Cuj.CujType},
1014          * or {@code -1} if the animation type is not supported for tracking yet.
1015          */
getImeInsetsCujFromAnimation(@nimationType int animType)1016         private static int getImeInsetsCujFromAnimation(@AnimationType int animType) {
1017             switch (animType) {
1018                 case ANIMATION_TYPE_SHOW:
1019                     return CUJ_IME_INSETS_SHOW_ANIMATION;
1020                 case ANIMATION_TYPE_HIDE:
1021                     return CUJ_IME_INSETS_HIDE_ANIMATION;
1022                 default:
1023                     return -1;
1024             }
1025         }
1026     }
1027 
1028     /**
1029      * A tracker instance which is in charge of communicating with {@link LatencyTracker}.
1030      * This class disallows instantiating from outside, use {@link #forLatency()}
1031      * to get the singleton.
1032      */
1033     final class ImeLatencyTracker {
1034 
1035         /**
1036          * This class disallows instantiating from outside.
1037          */
ImeLatencyTracker()1038         private ImeLatencyTracker() {
1039         }
1040 
shouldMonitorLatency(@oftInputShowHideReason int reason)1041         private boolean shouldMonitorLatency(@SoftInputShowHideReason int reason) {
1042             return reason == SoftInputShowHideReason.SHOW_SOFT_INPUT
1043                     || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT
1044                     || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW
1045                     || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API
1046                     || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API
1047                     || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME
1048                     || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME;
1049         }
1050 
onRequestShow(@ullable Token token, @Origin int origin, @SoftInputShowHideReason int reason, @NonNull InputMethodLatencyContext latencyContext)1051         public void onRequestShow(@Nullable Token token, @Origin int origin,
1052                 @SoftInputShowHideReason int reason,
1053                 @NonNull InputMethodLatencyContext latencyContext) {
1054             if (!shouldMonitorLatency(reason)) return;
1055             LatencyTracker.getInstance(latencyContext.getAppContext())
1056                     .onActionStart(
1057                             ACTION_REQUEST_IME_SHOWN,
1058                             softInputDisplayReasonToString(reason));
1059         }
1060 
onRequestHide(@ullable Token token, @Origin int origin, @SoftInputShowHideReason int reason, @NonNull InputMethodLatencyContext latencyContext)1061         public void onRequestHide(@Nullable Token token, @Origin int origin,
1062                 @SoftInputShowHideReason int reason,
1063                 @NonNull InputMethodLatencyContext latencyContext) {
1064             if (!shouldMonitorLatency(reason)) return;
1065             LatencyTracker.getInstance(latencyContext.getAppContext())
1066                     .onActionStart(
1067                             ACTION_REQUEST_IME_HIDDEN,
1068                             softInputDisplayReasonToString(reason));
1069         }
1070 
onShowFailed(@ullable Token token, @Phase int phase, @NonNull InputMethodLatencyContext latencyContext)1071         public void onShowFailed(@Nullable Token token, @Phase int phase,
1072                 @NonNull InputMethodLatencyContext latencyContext) {
1073             onShowCancelled(token, phase, latencyContext);
1074         }
1075 
onHideFailed(@ullable Token token, @Phase int phase, @NonNull InputMethodLatencyContext latencyContext)1076         public void onHideFailed(@Nullable Token token, @Phase int phase,
1077                 @NonNull InputMethodLatencyContext latencyContext) {
1078             onHideCancelled(token, phase, latencyContext);
1079         }
1080 
onShowCancelled(@ullable Token token, @Phase int phase, @NonNull InputMethodLatencyContext latencyContext)1081         public void onShowCancelled(@Nullable Token token, @Phase int phase,
1082                 @NonNull InputMethodLatencyContext latencyContext) {
1083             LatencyTracker.getInstance(latencyContext.getAppContext())
1084                     .onActionCancel(ACTION_REQUEST_IME_SHOWN);
1085         }
1086 
onHideCancelled(@ullable Token token, @Phase int phase, @NonNull InputMethodLatencyContext latencyContext)1087         public void onHideCancelled(@Nullable Token token, @Phase int phase,
1088                 @NonNull InputMethodLatencyContext latencyContext) {
1089             LatencyTracker.getInstance(latencyContext.getAppContext())
1090                     .onActionCancel(ACTION_REQUEST_IME_HIDDEN);
1091         }
1092 
onShown(@ullable Token token, @NonNull InputMethodLatencyContext latencyContext)1093         public void onShown(@Nullable Token token,
1094                 @NonNull InputMethodLatencyContext latencyContext) {
1095             LatencyTracker.getInstance(latencyContext.getAppContext())
1096                     .onActionEnd(ACTION_REQUEST_IME_SHOWN);
1097         }
1098 
onHidden(@ullable Token token, @NonNull InputMethodLatencyContext latencyContext)1099         public void onHidden(@Nullable Token token,
1100                 @NonNull InputMethodLatencyContext latencyContext) {
1101             LatencyTracker.getInstance(latencyContext.getAppContext())
1102                     .onActionEnd(ACTION_REQUEST_IME_HIDDEN);
1103         }
1104     }
1105 }
1106