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 android.Manifest; 20 import android.annotation.AnyThread; 21 import android.annotation.DurationMillisLong; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresNoPermission; 25 import android.annotation.RequiresPermission; 26 import android.annotation.UserIdInt; 27 import android.content.Context; 28 import android.os.IBinder; 29 import android.os.RemoteException; 30 import android.os.ResultReceiver; 31 import android.os.ServiceManager; 32 import android.util.ExceptionUtils; 33 import android.view.WindowManager; 34 import android.window.ImeOnBackInvokedDispatcher; 35 36 import com.android.internal.infra.AndroidFuture; 37 import com.android.internal.inputmethod.DirectBootAwareness; 38 import com.android.internal.inputmethod.IBooleanListener; 39 import com.android.internal.inputmethod.IConnectionlessHandwritingCallback; 40 import com.android.internal.inputmethod.IImeTracker; 41 import com.android.internal.inputmethod.IInputMethodClient; 42 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; 43 import com.android.internal.inputmethod.IRemoteInputConnection; 44 import com.android.internal.inputmethod.InputBindResult; 45 import com.android.internal.inputmethod.InputMethodInfoSafeList; 46 import com.android.internal.inputmethod.SoftInputShowHideReason; 47 import com.android.internal.inputmethod.StartInputFlags; 48 import com.android.internal.inputmethod.StartInputReason; 49 import com.android.internal.view.IInputMethodManager; 50 51 import java.util.ArrayList; 52 import java.util.List; 53 import java.util.concurrent.TimeUnit; 54 import java.util.function.Consumer; 55 56 /** 57 * A global wrapper to directly invoke {@link IInputMethodManager} IPCs. 58 * 59 * <p>All public static methods are guaranteed to be thread-safe.</p> 60 * 61 * <p>All public methods are guaranteed to do nothing when {@link IInputMethodManager} is 62 * unavailable.</p> 63 * 64 * <p>If you want to use any of this method outside of {@code android.view.inputmethod}, create 65 * a wrapper method in {@link InputMethodManagerGlobal} instead of making this class public.</p> 66 */ 67 final class IInputMethodManagerGlobalInvoker { 68 69 /** The threshold in milliseconds for an {@link AndroidFuture} completion signal. */ 70 private static final long TIMEOUT_MS = 10_000; 71 72 @Nullable 73 private static volatile IInputMethodManager sServiceCache = null; 74 75 @Nullable 76 private static volatile IImeTracker sTrackerServiceCache = null; 77 private static int sCurStartInputSeq = 0; 78 79 /** 80 * @return {@code true} if {@link IInputMethodManager} is available. 81 */ 82 @AnyThread isAvailable()83 static boolean isAvailable() { 84 return getService() != null; 85 } 86 87 @AnyThread 88 @Nullable getService()89 static IInputMethodManager getService() { 90 IInputMethodManager service = sServiceCache; 91 if (service == null) { 92 if (InputMethodManager.isInEditModeInternal()) { 93 return null; 94 } 95 service = IInputMethodManager.Stub.asInterface( 96 ServiceManager.getService(Context.INPUT_METHOD_SERVICE)); 97 if (service == null) { 98 return null; 99 } 100 sServiceCache = service; 101 } 102 return service; 103 } 104 105 @AnyThread handleRemoteExceptionOrRethrow(@onNull RemoteException e, @Nullable Consumer<RemoteException> exceptionHandler)106 private static void handleRemoteExceptionOrRethrow(@NonNull RemoteException e, 107 @Nullable Consumer<RemoteException> exceptionHandler) { 108 if (exceptionHandler != null) { 109 exceptionHandler.accept(e); 110 } else { 111 throw e.rethrowFromSystemServer(); 112 } 113 } 114 115 /** 116 * Invokes {@link IInputMethodManager#startProtoDump(byte[], int, String)}. 117 * 118 * @param protoDump client or service side information to be stored by the server 119 * @param source where the information is coming from, refer to 120 * {@link com.android.internal.inputmethod.ImeTracing#IME_TRACING_FROM_CLIENT} and 121 * {@link com.android.internal.inputmethod.ImeTracing#IME_TRACING_FROM_IMS} 122 * @param where where the information is coming from. 123 * @param exceptionHandler an optional {@link RemoteException} handler. 124 */ 125 @AnyThread 126 @RequiresNoPermission startProtoDump(byte[] protoDump, int source, String where, @Nullable Consumer<RemoteException> exceptionHandler)127 static void startProtoDump(byte[] protoDump, int source, String where, 128 @Nullable Consumer<RemoteException> exceptionHandler) { 129 final IInputMethodManager service = getService(); 130 if (service == null) { 131 return; 132 } 133 try { 134 service.startProtoDump(protoDump, source, where); 135 } catch (RemoteException e) { 136 handleRemoteExceptionOrRethrow(e, exceptionHandler); 137 } 138 } 139 140 /** 141 * Invokes {@link IInputMethodManager#startImeTrace()}. 142 * 143 * @param exceptionHandler an optional {@link RemoteException} handler. 144 */ 145 @AnyThread 146 @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING) startImeTrace(@ullable Consumer<RemoteException> exceptionHandler)147 static void startImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) { 148 final IInputMethodManager service = getService(); 149 if (service == null) { 150 return; 151 } 152 try { 153 service.startImeTrace(); 154 } catch (RemoteException e) { 155 handleRemoteExceptionOrRethrow(e, exceptionHandler); 156 } 157 } 158 159 /** 160 * Invokes {@link IInputMethodManager#stopImeTrace()}. 161 * 162 * @param exceptionHandler an optional {@link RemoteException} handler. 163 */ 164 @AnyThread 165 @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING) stopImeTrace(@ullable Consumer<RemoteException> exceptionHandler)166 static void stopImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) { 167 final IInputMethodManager service = getService(); 168 if (service == null) { 169 return; 170 } 171 try { 172 service.stopImeTrace(); 173 } catch (RemoteException e) { 174 handleRemoteExceptionOrRethrow(e, exceptionHandler); 175 } 176 } 177 178 /** 179 * Invokes {@link IInputMethodManager#isImeTraceEnabled()}. 180 * 181 * @return The return value of {@link IInputMethodManager#isImeTraceEnabled()}. 182 */ 183 @AnyThread 184 @RequiresNoPermission isImeTraceEnabled()185 static boolean isImeTraceEnabled() { 186 final IInputMethodManager service = getService(); 187 if (service == null) { 188 return false; 189 } 190 try { 191 return service.isImeTraceEnabled(); 192 } catch (RemoteException e) { 193 throw e.rethrowFromSystemServer(); 194 } 195 } 196 197 /** 198 * Invokes {@link IInputMethodManager#removeImeSurface()} 199 */ 200 @AnyThread 201 @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) removeImeSurface(@ullable Consumer<RemoteException> exceptionHandler)202 static void removeImeSurface(@Nullable Consumer<RemoteException> exceptionHandler) { 203 final IInputMethodManager service = getService(); 204 if (service == null) { 205 return; 206 } 207 try { 208 service.removeImeSurface(); 209 } catch (RemoteException e) { 210 handleRemoteExceptionOrRethrow(e, exceptionHandler); 211 } 212 } 213 214 @AnyThread addClient(@onNull IInputMethodClient client, @NonNull IRemoteInputConnection fallbackInputConnection, int untrustedDisplayId)215 static void addClient(@NonNull IInputMethodClient client, 216 @NonNull IRemoteInputConnection fallbackInputConnection, int untrustedDisplayId) { 217 final IInputMethodManager service = getService(); 218 if (service == null) { 219 return; 220 } 221 try { 222 service.addClient(client, fallbackInputConnection, untrustedDisplayId); 223 } catch (RemoteException e) { 224 throw e.rethrowFromSystemServer(); 225 } 226 } 227 228 @AnyThread 229 @Nullable 230 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getCurrentInputMethodInfoAsUser(@serIdInt int userId)231 static InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId) { 232 final IInputMethodManager service = getService(); 233 if (service == null) { 234 return null; 235 } 236 try { 237 return service.getCurrentInputMethodInfoAsUser(userId); 238 } catch (RemoteException e) { 239 throw e.rethrowFromSystemServer(); 240 } 241 } 242 243 @AnyThread 244 @NonNull 245 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getInputMethodList(@serIdInt int userId, @DirectBootAwareness int directBootAwareness)246 static List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, 247 @DirectBootAwareness int directBootAwareness) { 248 final IInputMethodManager service = getService(); 249 if (service == null) { 250 return new ArrayList<>(); 251 } 252 try { 253 if (Flags.useInputMethodInfoSafeList()) { 254 return InputMethodInfoSafeList.extractFrom( 255 service.getInputMethodList(userId, directBootAwareness)); 256 } else { 257 return service.getInputMethodListLegacy(userId, directBootAwareness); 258 } 259 } catch (RemoteException e) { 260 throw e.rethrowFromSystemServer(); 261 } 262 } 263 264 @AnyThread 265 @NonNull 266 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getEnabledInputMethodList(@serIdInt int userId)267 static List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) { 268 final IInputMethodManager service = getService(); 269 if (service == null) { 270 return new ArrayList<>(); 271 } 272 try { 273 if (Flags.useInputMethodInfoSafeList()) { 274 return InputMethodInfoSafeList.extractFrom( 275 service.getEnabledInputMethodList(userId)); 276 } else { 277 return service.getEnabledInputMethodListLegacy(userId); 278 } 279 } catch (RemoteException e) { 280 throw e.rethrowFromSystemServer(); 281 } 282 } 283 284 @AnyThread 285 @NonNull 286 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getEnabledInputMethodSubtypeList(@ullable String imiId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId)287 static List<InputMethodSubtype> getEnabledInputMethodSubtypeList(@Nullable String imiId, 288 boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) { 289 final IInputMethodManager service = getService(); 290 if (service == null) { 291 return new ArrayList<>(); 292 } 293 try { 294 return service.getEnabledInputMethodSubtypeList(imiId, 295 allowsImplicitlyEnabledSubtypes, userId); 296 } catch (RemoteException e) { 297 throw e.rethrowFromSystemServer(); 298 } 299 } 300 301 @AnyThread 302 @Nullable 303 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getLastInputMethodSubtype(@serIdInt int userId)304 static InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId) { 305 final IInputMethodManager service = getService(); 306 if (service == null) { 307 return null; 308 } 309 try { 310 return service.getLastInputMethodSubtype(userId); 311 } catch (RemoteException e) { 312 throw e.rethrowFromSystemServer(); 313 } 314 } 315 316 @AnyThread showSoftInput(@onNull IInputMethodClient client, @Nullable IBinder windowToken, @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, int lastClickToolType, @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)317 static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken, 318 @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, 319 int lastClickToolType, @Nullable ResultReceiver resultReceiver, 320 @SoftInputShowHideReason int reason) { 321 final IInputMethodManager service = getService(); 322 if (service == null) { 323 return false; 324 } 325 try { 326 return service.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType, 327 resultReceiver, reason); 328 } catch (RemoteException e) { 329 throw e.rethrowFromSystemServer(); 330 } 331 } 332 333 @AnyThread hideSoftInput(@onNull IInputMethodClient client, @Nullable IBinder windowToken, @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)334 static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken, 335 @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, 336 @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { 337 final IInputMethodManager service = getService(); 338 if (service == null) { 339 return false; 340 } 341 try { 342 return service.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver, 343 reason); 344 } catch (RemoteException e) { 345 throw e.rethrowFromSystemServer(); 346 } 347 } 348 349 // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled. 350 @AnyThread 351 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) hideSoftInputFromServerForTest()352 static void hideSoftInputFromServerForTest() { 353 final IInputMethodManager service = getService(); 354 if (service == null) { 355 return; 356 } 357 try { 358 service.hideSoftInputFromServerForTest(); 359 } catch (RemoteException e) { 360 throw e.rethrowFromSystemServer(); 361 } 362 } 363 364 @AnyThread 365 @NonNull 366 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) startInputOrWindowGainedFocus(@tartInputReason int startInputReason, @NonNull IInputMethodClient client, @Nullable IBinder windowToken, @StartInputFlags int startInputFlags, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, @Nullable IRemoteInputConnection remoteInputConnection, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, @NonNull ImeOnBackInvokedDispatcher imeDispatcher)367 static InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason, 368 @NonNull IInputMethodClient client, @Nullable IBinder windowToken, 369 @StartInputFlags int startInputFlags, 370 @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, 371 @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, 372 @Nullable IRemoteInputConnection remoteInputConnection, 373 @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 374 int unverifiedTargetSdkVersion, @UserIdInt int userId, 375 @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { 376 final IInputMethodManager service = getService(); 377 if (service == null) { 378 return InputBindResult.NULL; 379 } 380 try { 381 return service.startInputOrWindowGainedFocus(startInputReason, client, windowToken, 382 startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, 383 remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, 384 imeDispatcher); 385 } catch (RemoteException e) { 386 throw e.rethrowFromSystemServer(); 387 } 388 } 389 390 /** 391 * Returns a sequence number for startInput. 392 */ 393 @AnyThread 394 @NonNull 395 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) startInputOrWindowGainedFocusAsync(@tartInputReason int startInputReason, @NonNull IInputMethodClient client, @Nullable IBinder windowToken, @StartInputFlags int startInputFlags, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, @Nullable IRemoteInputConnection remoteInputConnection, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, @NonNull ImeOnBackInvokedDispatcher imeDispatcher)396 static int startInputOrWindowGainedFocusAsync(@StartInputReason int startInputReason, 397 @NonNull IInputMethodClient client, @Nullable IBinder windowToken, 398 @StartInputFlags int startInputFlags, 399 @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, 400 @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, 401 @Nullable IRemoteInputConnection remoteInputConnection, 402 @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 403 int unverifiedTargetSdkVersion, @UserIdInt int userId, 404 @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { 405 final IInputMethodManager service = getService(); 406 if (service == null) { 407 return -1; 408 } 409 try { 410 service.startInputOrWindowGainedFocusAsync(startInputReason, client, windowToken, 411 startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, 412 remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, 413 imeDispatcher, advanceAngGetStartInputSequenceNumber()); 414 } catch (RemoteException e) { 415 throw e.rethrowFromSystemServer(); 416 } 417 return sCurStartInputSeq; 418 } 419 advanceAngGetStartInputSequenceNumber()420 private static int advanceAngGetStartInputSequenceNumber() { 421 return ++sCurStartInputSeq; 422 } 423 424 425 @AnyThread showInputMethodPickerFromClient(@onNull IInputMethodClient client, int auxiliarySubtypeMode)426 static void showInputMethodPickerFromClient(@NonNull IInputMethodClient client, 427 int auxiliarySubtypeMode) { 428 final IInputMethodManager service = getService(); 429 if (service == null) { 430 return; 431 } 432 try { 433 service.showInputMethodPickerFromClient(client, auxiliarySubtypeMode); 434 } catch (RemoteException e) { 435 throw e.rethrowFromSystemServer(); 436 } 437 } 438 439 @AnyThread 440 @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId)441 static void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { 442 final IInputMethodManager service = getService(); 443 if (service == null) { 444 return; 445 } 446 try { 447 service.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId); 448 } catch (RemoteException e) { 449 throw e.rethrowFromSystemServer(); 450 } 451 } 452 453 @AnyThread 454 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) isInputMethodPickerShownForTest()455 static boolean isInputMethodPickerShownForTest() { 456 final IInputMethodManager service = getService(); 457 if (service == null) { 458 return false; 459 } 460 try { 461 return service.isInputMethodPickerShownForTest(); 462 } catch (RemoteException e) { 463 throw e.rethrowFromSystemServer(); 464 } 465 } 466 467 @AnyThread 468 @Nullable 469 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getCurrentInputMethodSubtype(@serIdInt int userId)470 static InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) { 471 final IInputMethodManager service = getService(); 472 if (service == null) { 473 return null; 474 } 475 try { 476 return service.getCurrentInputMethodSubtype(userId); 477 } catch (RemoteException e) { 478 throw e.rethrowFromSystemServer(); 479 } 480 } 481 482 @AnyThread 483 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) setAdditionalInputMethodSubtypes(@onNull String imeId, @NonNull InputMethodSubtype[] subtypes, @UserIdInt int userId)484 static void setAdditionalInputMethodSubtypes(@NonNull String imeId, 485 @NonNull InputMethodSubtype[] subtypes, @UserIdInt int userId) { 486 final IInputMethodManager service = getService(); 487 if (service == null) { 488 return; 489 } 490 try { 491 service.setAdditionalInputMethodSubtypes(imeId, subtypes, userId); 492 } catch (RemoteException e) { 493 throw e.rethrowFromSystemServer(); 494 } 495 } 496 497 @AnyThread 498 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) setExplicitlyEnabledInputMethodSubtypes(@onNull String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId)499 static void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imeId, 500 @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { 501 final IInputMethodManager service = getService(); 502 if (service == null) { 503 return; 504 } 505 try { 506 service.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); 507 } catch (RemoteException e) { 508 throw e.rethrowFromSystemServer(); 509 } 510 } 511 512 @AnyThread getInputMethodWindowVisibleHeight(@onNull IInputMethodClient client)513 static int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { 514 final IInputMethodManager service = getService(); 515 if (service == null) { 516 return 0; 517 } 518 try { 519 return service.getInputMethodWindowVisibleHeight(client); 520 } catch (RemoteException e) { 521 throw e.rethrowFromSystemServer(); 522 } 523 } 524 525 @AnyThread reportPerceptibleAsync(@onNull IBinder windowToken, boolean perceptible)526 static void reportPerceptibleAsync(@NonNull IBinder windowToken, boolean perceptible) { 527 final IInputMethodManager service = getService(); 528 if (service == null) { 529 return; 530 } 531 try { 532 service.reportPerceptibleAsync(windowToken, perceptible); 533 } catch (RemoteException e) { 534 throw e.rethrowFromSystemServer(); 535 } 536 } 537 538 @AnyThread removeImeSurfaceFromWindowAsync(@onNull IBinder windowToken)539 static void removeImeSurfaceFromWindowAsync(@NonNull IBinder windowToken) { 540 final IInputMethodManager service = getService(); 541 if (service == null) { 542 return; 543 } 544 try { 545 service.removeImeSurfaceFromWindowAsync(windowToken); 546 } catch (RemoteException e) { 547 throw e.rethrowFromSystemServer(); 548 } 549 } 550 551 @AnyThread startStylusHandwriting(@onNull IInputMethodClient client)552 static void startStylusHandwriting(@NonNull IInputMethodClient client) { 553 final IInputMethodManager service = getService(); 554 if (service == null) { 555 return; 556 } 557 try { 558 service.startStylusHandwriting(client); 559 } catch (RemoteException e) { 560 throw e.rethrowFromSystemServer(); 561 } 562 } 563 564 @AnyThread startConnectionlessStylusHandwriting( @onNull IInputMethodClient client, @UserIdInt int userId, @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, @Nullable String delegatorPackageName, @NonNull IConnectionlessHandwritingCallback callback)565 static boolean startConnectionlessStylusHandwriting( 566 @NonNull IInputMethodClient client, 567 @UserIdInt int userId, 568 @Nullable CursorAnchorInfo cursorAnchorInfo, 569 @Nullable String delegatePackageName, 570 @Nullable String delegatorPackageName, 571 @NonNull IConnectionlessHandwritingCallback callback) { 572 final IInputMethodManager service = getService(); 573 if (service == null) { 574 return false; 575 } 576 try { 577 service.startConnectionlessStylusHandwriting(client, userId, cursorAnchorInfo, 578 delegatePackageName, delegatorPackageName, callback); 579 } catch (RemoteException e) { 580 throw e.rethrowFromSystemServer(); 581 } 582 return true; 583 } 584 585 @AnyThread prepareStylusHandwritingDelegation( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName)586 static void prepareStylusHandwritingDelegation( 587 @NonNull IInputMethodClient client, 588 @UserIdInt int userId, 589 @NonNull String delegatePackageName, 590 @NonNull String delegatorPackageName) { 591 final IInputMethodManager service = getService(); 592 if (service == null) { 593 return; 594 } 595 try { 596 service.prepareStylusHandwritingDelegation( 597 client, userId, delegatePackageName, delegatorPackageName); 598 } catch (RemoteException e) { 599 throw e.rethrowFromSystemServer(); 600 } 601 } 602 603 @AnyThread acceptStylusHandwritingDelegation( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, @InputMethodManager.HandwritingDelegateFlags int flags)604 static boolean acceptStylusHandwritingDelegation( 605 @NonNull IInputMethodClient client, 606 @UserIdInt int userId, 607 @NonNull String delegatePackageName, 608 @NonNull String delegatorPackageName, 609 @InputMethodManager.HandwritingDelegateFlags int flags) { 610 final IInputMethodManager service = getService(); 611 if (service == null) { 612 return false; 613 } 614 try { 615 return service.acceptStylusHandwritingDelegation( 616 client, userId, delegatePackageName, delegatorPackageName, flags); 617 } catch (RemoteException e) { 618 throw e.rethrowFromSystemServer(); 619 } 620 } 621 622 /** Returns {@code true} if method is invoked */ 623 @AnyThread acceptStylusHandwritingDelegationAsync( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, @InputMethodManager.HandwritingDelegateFlags int flags, @NonNull IBooleanListener callback)624 static boolean acceptStylusHandwritingDelegationAsync( 625 @NonNull IInputMethodClient client, 626 @UserIdInt int userId, 627 @NonNull String delegatePackageName, 628 @NonNull String delegatorPackageName, 629 @InputMethodManager.HandwritingDelegateFlags int flags, 630 @NonNull IBooleanListener callback) { 631 final IInputMethodManager service = getService(); 632 if (service == null) { 633 return false; 634 } 635 try { 636 service.acceptStylusHandwritingDelegationAsync( 637 client, userId, delegatePackageName, delegatorPackageName, flags, callback); 638 } catch (RemoteException e) { 639 throw e.rethrowFromSystemServer(); 640 } 641 return true; 642 } 643 644 @AnyThread 645 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) isStylusHandwritingAvailableAsUser( @serIdInt int userId, boolean connectionless)646 static boolean isStylusHandwritingAvailableAsUser( 647 @UserIdInt int userId, boolean connectionless) { 648 final IInputMethodManager service = getService(); 649 if (service == null) { 650 return false; 651 } 652 try { 653 return service.isStylusHandwritingAvailableAsUser(userId, connectionless); 654 } catch (RemoteException e) { 655 throw e.rethrowFromSystemServer(); 656 } 657 } 658 659 @AnyThread 660 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) addVirtualStylusIdForTestSession(IInputMethodClient client)661 static void addVirtualStylusIdForTestSession(IInputMethodClient client) { 662 final IInputMethodManager service = getService(); 663 if (service == null) { 664 return; 665 } 666 try { 667 service.addVirtualStylusIdForTestSession(client); 668 } catch (RemoteException e) { 669 throw e.rethrowFromSystemServer(); 670 } 671 } 672 673 @AnyThread 674 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) setStylusWindowIdleTimeoutForTest( IInputMethodClient client, @DurationMillisLong long timeout)675 static void setStylusWindowIdleTimeoutForTest( 676 IInputMethodClient client, @DurationMillisLong long timeout) { 677 final IInputMethodManager service = getService(); 678 if (service == null) { 679 return; 680 } 681 try { 682 service.setStylusWindowIdleTimeoutForTest(client, timeout); 683 } catch (RemoteException e) { 684 throw e.rethrowFromSystemServer(); 685 } 686 } 687 688 /** @see com.android.server.inputmethod.ImeTrackerService#onStart */ 689 @AnyThread 690 @NonNull onStart(@onNull String tag, int uid, @ImeTracker.Type int type, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser)691 static ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type, 692 @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) { 693 final var service = getImeTrackerService(); 694 if (service == null) { 695 // Create token with "empty" binder if the service was not found. 696 return ImeTracker.Token.empty(tag); 697 } 698 try { 699 return service.onStart(tag, uid, type, origin, reason, fromUser); 700 } catch (RemoteException e) { 701 throw e.rethrowFromSystemServer(); 702 } 703 } 704 705 /** @see com.android.server.inputmethod.ImeTrackerService#onProgress */ 706 @AnyThread onProgress(@onNull IBinder binder, @ImeTracker.Phase int phase)707 static void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) { 708 final IImeTracker service = getImeTrackerService(); 709 if (service == null) { 710 return; 711 } 712 try { 713 service.onProgress(binder, phase); 714 } catch (RemoteException e) { 715 throw e.rethrowFromSystemServer(); 716 } 717 } 718 719 /** @see com.android.server.inputmethod.ImeTrackerService#onFailed */ 720 @AnyThread onFailed(@onNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase)721 static void onFailed(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) { 722 final IImeTracker service = getImeTrackerService(); 723 if (service == null) { 724 return; 725 } 726 try { 727 service.onFailed(statsToken, phase); 728 } catch (RemoteException e) { 729 throw e.rethrowFromSystemServer(); 730 } 731 } 732 733 /** @see com.android.server.inputmethod.ImeTrackerService#onCancelled */ 734 @AnyThread onCancelled(@onNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase)735 static void onCancelled(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) { 736 final IImeTracker service = getImeTrackerService(); 737 if (service == null) { 738 return; 739 } 740 try { 741 service.onCancelled(statsToken, phase); 742 } catch (RemoteException e) { 743 throw e.rethrowFromSystemServer(); 744 } 745 } 746 747 /** @see com.android.server.inputmethod.ImeTrackerService#onShown */ 748 @AnyThread onShown(@onNull ImeTracker.Token statsToken)749 static void onShown(@NonNull ImeTracker.Token statsToken) { 750 final IImeTracker service = getImeTrackerService(); 751 if (service == null) { 752 return; 753 } 754 try { 755 service.onShown(statsToken); 756 } catch (RemoteException e) { 757 throw e.rethrowFromSystemServer(); 758 } 759 } 760 761 /** @see com.android.server.inputmethod.ImeTrackerService#onHidden */ 762 @AnyThread onHidden(@onNull ImeTracker.Token statsToken)763 static void onHidden(@NonNull ImeTracker.Token statsToken) { 764 final IImeTracker service = getImeTrackerService(); 765 if (service == null) { 766 return; 767 } 768 try { 769 service.onHidden(statsToken); 770 } catch (RemoteException e) { 771 throw e.rethrowFromSystemServer(); 772 } 773 } 774 775 /** @see com.android.server.inputmethod.ImeTrackerService#onDispatched */ onDispatched(@onNull ImeTracker.Token statsToken)776 static void onDispatched(@NonNull ImeTracker.Token statsToken) { 777 final IImeTracker service = getImeTrackerService(); 778 if (service == null) { 779 return; 780 } 781 try { 782 service.onDispatched(statsToken); 783 } catch (RemoteException e) { 784 throw e.rethrowFromSystemServer(); 785 } 786 } 787 788 /** @see com.android.server.inputmethod.ImeTrackerService#hasPendingImeVisibilityRequests */ 789 @AnyThread 790 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) hasPendingImeVisibilityRequests()791 static boolean hasPendingImeVisibilityRequests() { 792 final var service = getImeTrackerService(); 793 if (service == null) { 794 return true; 795 } 796 try { 797 return service.hasPendingImeVisibilityRequests(); 798 } catch (RemoteException e) { 799 throw e.rethrowFromSystemServer(); 800 } 801 } 802 803 @AnyThread 804 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) finishTrackingPendingImeVisibilityRequests()805 static void finishTrackingPendingImeVisibilityRequests() { 806 final var service = getImeTrackerService(); 807 if (service == null) { 808 return; 809 } 810 try { 811 final var completionSignal = new AndroidFuture<Void>(); 812 service.finishTrackingPendingImeVisibilityRequests(completionSignal); 813 completionSignal.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); 814 } catch (RemoteException e) { 815 throw e.rethrowFromSystemServer(); 816 } catch (Exception e) { 817 throw ExceptionUtils.propagate(e); 818 } 819 } 820 821 @AnyThread 822 @Nullable getImeTrackerService()823 private static IImeTracker getImeTrackerService() { 824 var trackerService = sTrackerServiceCache; 825 if (trackerService == null) { 826 final var service = getService(); 827 if (service == null) { 828 return null; 829 } 830 831 try { 832 trackerService = service.getImeTrackerService(); 833 if (trackerService == null) { 834 return null; 835 } 836 837 sTrackerServiceCache = trackerService; 838 } catch (RemoteException e) { 839 throw e.rethrowFromSystemServer(); 840 } 841 } 842 return trackerService; 843 } 844 } 845