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