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 * @param displayId display ID from which this request originates 201 * @param exceptionHandler an optional {@link RemoteException} handler 202 */ 203 @AnyThread 204 @RequiresPermission(allOf = { 205 Manifest.permission.INTERNAL_SYSTEM_WINDOW, 206 Manifest.permission.INTERACT_ACROSS_USERS_FULL}) removeImeSurface(int displayId, @Nullable Consumer<RemoteException> exceptionHandler)207 static void removeImeSurface(int displayId, 208 @Nullable Consumer<RemoteException> exceptionHandler) { 209 final IInputMethodManager service = getService(); 210 if (service == null) { 211 return; 212 } 213 try { 214 service.removeImeSurface(displayId); 215 } catch (RemoteException e) { 216 handleRemoteExceptionOrRethrow(e, exceptionHandler); 217 } 218 } 219 220 @AnyThread addClient(@onNull IInputMethodClient client, @NonNull IRemoteInputConnection fallbackInputConnection, int untrustedDisplayId)221 static void addClient(@NonNull IInputMethodClient client, 222 @NonNull IRemoteInputConnection fallbackInputConnection, int untrustedDisplayId) { 223 final IInputMethodManager service = getService(); 224 if (service == null) { 225 return; 226 } 227 try { 228 service.addClient(client, fallbackInputConnection, untrustedDisplayId); 229 } catch (RemoteException e) { 230 throw e.rethrowFromSystemServer(); 231 } 232 } 233 234 @AnyThread 235 @Nullable 236 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getCurrentInputMethodInfoAsUser(@serIdInt int userId)237 static InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId) { 238 final IInputMethodManager service = getService(); 239 if (service == null) { 240 return null; 241 } 242 try { 243 return service.getCurrentInputMethodInfoAsUser(userId); 244 } catch (RemoteException e) { 245 throw e.rethrowFromSystemServer(); 246 } 247 } 248 249 @AnyThread 250 @NonNull 251 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getInputMethodList(@serIdInt int userId, @DirectBootAwareness int directBootAwareness)252 static List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, 253 @DirectBootAwareness int directBootAwareness) { 254 final IInputMethodManager service = getService(); 255 if (service == null) { 256 return new ArrayList<>(); 257 } 258 try { 259 if (Flags.useInputMethodInfoSafeList()) { 260 return InputMethodInfoSafeList.extractFrom( 261 service.getInputMethodList(userId, directBootAwareness)); 262 } else { 263 return service.getInputMethodListLegacy(userId, directBootAwareness); 264 } 265 } catch (RemoteException e) { 266 throw e.rethrowFromSystemServer(); 267 } 268 } 269 270 @AnyThread 271 @NonNull 272 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getEnabledInputMethodList(@serIdInt int userId)273 static List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) { 274 final IInputMethodManager service = getService(); 275 if (service == null) { 276 return new ArrayList<>(); 277 } 278 try { 279 if (Flags.useInputMethodInfoSafeList()) { 280 return InputMethodInfoSafeList.extractFrom( 281 service.getEnabledInputMethodList(userId)); 282 } else { 283 return service.getEnabledInputMethodListLegacy(userId); 284 } 285 } catch (RemoteException e) { 286 throw e.rethrowFromSystemServer(); 287 } 288 } 289 290 @AnyThread 291 @NonNull 292 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getEnabledInputMethodSubtypeList(@ullable String imiId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId)293 static List<InputMethodSubtype> getEnabledInputMethodSubtypeList(@Nullable String imiId, 294 boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) { 295 final IInputMethodManager service = getService(); 296 if (service == null) { 297 return new ArrayList<>(); 298 } 299 try { 300 return service.getEnabledInputMethodSubtypeList(imiId, 301 allowsImplicitlyEnabledSubtypes, userId); 302 } catch (RemoteException e) { 303 throw e.rethrowFromSystemServer(); 304 } 305 } 306 307 @AnyThread 308 @Nullable 309 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getLastInputMethodSubtype(@serIdInt int userId)310 static InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId) { 311 final IInputMethodManager service = getService(); 312 if (service == null) { 313 return null; 314 } 315 try { 316 return service.getLastInputMethodSubtype(userId); 317 } catch (RemoteException e) { 318 throw e.rethrowFromSystemServer(); 319 } 320 } 321 322 @AnyThread showSoftInput(@onNull IInputMethodClient client, @Nullable IBinder windowToken, @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, int lastClickToolType, @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async)323 static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken, 324 @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, 325 int lastClickToolType, @Nullable ResultReceiver resultReceiver, 326 @SoftInputShowHideReason int reason, boolean async) { 327 final IInputMethodManager service = getService(); 328 if (service == null) { 329 return false; 330 } 331 try { 332 return service.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType, 333 resultReceiver, reason, async); 334 } catch (RemoteException e) { 335 throw e.rethrowFromSystemServer(); 336 } 337 } 338 339 @AnyThread hideSoftInput(@onNull IInputMethodClient client, @Nullable IBinder windowToken, @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async)340 static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken, 341 @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, 342 @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, 343 boolean async) { 344 final IInputMethodManager service = getService(); 345 if (service == null) { 346 return false; 347 } 348 try { 349 return service.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver, 350 reason, async); 351 } catch (RemoteException e) { 352 throw e.rethrowFromSystemServer(); 353 } 354 } 355 356 // TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled. 357 @AnyThread 358 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) hideSoftInputFromServerForTest()359 static void hideSoftInputFromServerForTest() { 360 final IInputMethodManager service = getService(); 361 if (service == null) { 362 return; 363 } 364 try { 365 service.hideSoftInputFromServerForTest(); 366 } catch (RemoteException e) { 367 throw e.rethrowFromSystemServer(); 368 } 369 } 370 371 @AnyThread 372 @NonNull 373 @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, boolean imeRequestedVisible)374 static InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason, 375 @NonNull IInputMethodClient client, @Nullable IBinder windowToken, 376 @StartInputFlags int startInputFlags, 377 @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, 378 @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, 379 @Nullable IRemoteInputConnection remoteInputConnection, 380 @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 381 int unverifiedTargetSdkVersion, @UserIdInt int userId, 382 @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible) { 383 final IInputMethodManager service = getService(); 384 if (service == null) { 385 return InputBindResult.NULL; 386 } 387 try { 388 return service.startInputOrWindowGainedFocus(startInputReason, client, windowToken, 389 startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, 390 remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, 391 imeDispatcher, imeRequestedVisible); 392 } catch (RemoteException e) { 393 throw e.rethrowFromSystemServer(); 394 } 395 } 396 397 /** 398 * Returns a sequence number for startInput. 399 */ 400 @AnyThread 401 @NonNull 402 @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, boolean imeRequestedVisible, boolean useAsyncShowHideMethod)403 static int startInputOrWindowGainedFocusAsync(@StartInputReason int startInputReason, 404 @NonNull IInputMethodClient client, @Nullable IBinder windowToken, 405 @StartInputFlags int startInputFlags, 406 @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, 407 @WindowManager.LayoutParams.Flags int windowFlags, @Nullable EditorInfo editorInfo, 408 @Nullable IRemoteInputConnection remoteInputConnection, 409 @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 410 int unverifiedTargetSdkVersion, @UserIdInt int userId, 411 @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean imeRequestedVisible, 412 boolean useAsyncShowHideMethod) { 413 final IInputMethodManager service = getService(); 414 if (service == null) { 415 return -1; 416 } 417 try { 418 service.startInputOrWindowGainedFocusAsync(startInputReason, client, windowToken, 419 startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection, 420 remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId, 421 imeDispatcher, imeRequestedVisible, advanceAngGetStartInputSequenceNumber(), 422 useAsyncShowHideMethod); 423 } catch (RemoteException e) { 424 throw e.rethrowFromSystemServer(); 425 } 426 return sCurStartInputSeq; 427 } 428 advanceAngGetStartInputSequenceNumber()429 private static int advanceAngGetStartInputSequenceNumber() { 430 return ++sCurStartInputSeq; 431 } 432 433 434 @AnyThread showInputMethodPickerFromClient(@onNull IInputMethodClient client, int auxiliarySubtypeMode)435 static void showInputMethodPickerFromClient(@NonNull IInputMethodClient client, 436 int auxiliarySubtypeMode) { 437 final IInputMethodManager service = getService(); 438 if (service == null) { 439 return; 440 } 441 try { 442 service.showInputMethodPickerFromClient(client, auxiliarySubtypeMode); 443 } catch (RemoteException e) { 444 throw e.rethrowFromSystemServer(); 445 } 446 } 447 448 @AnyThread 449 @RequiresPermission(allOf = { 450 Manifest.permission.WRITE_SECURE_SETTINGS, 451 Manifest.permission.INTERACT_ACROSS_USERS_FULL}) showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId)452 static void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { 453 final IInputMethodManager service = getService(); 454 if (service == null) { 455 return; 456 } 457 try { 458 service.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId); 459 } catch (RemoteException e) { 460 throw e.rethrowFromSystemServer(); 461 } 462 } 463 464 @AnyThread 465 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) isInputMethodPickerShownForTest()466 static boolean isInputMethodPickerShownForTest() { 467 final IInputMethodManager service = getService(); 468 if (service == null) { 469 return false; 470 } 471 try { 472 return service.isInputMethodPickerShownForTest(); 473 } catch (RemoteException e) { 474 throw e.rethrowFromSystemServer(); 475 } 476 } 477 478 @AnyThread 479 @RequiresPermission(allOf = { 480 Manifest.permission.WRITE_SECURE_SETTINGS, 481 Manifest.permission.INTERACT_ACROSS_USERS_FULL}) onImeSwitchButtonClickFromSystem(int displayId)482 static void onImeSwitchButtonClickFromSystem(int displayId) { 483 final IInputMethodManager service = getService(); 484 if (service == null) { 485 return; 486 } 487 try { 488 service.onImeSwitchButtonClickFromSystem(displayId); 489 } catch (RemoteException e) { 490 throw e.rethrowFromSystemServer(); 491 } 492 } 493 494 @AnyThread 495 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) shouldShowImeSwitcherButtonForTest()496 static boolean shouldShowImeSwitcherButtonForTest() { 497 final IInputMethodManager service = getService(); 498 if (service == null) { 499 return false; 500 } 501 try { 502 return service.shouldShowImeSwitcherButtonForTest(); 503 } catch (RemoteException e) { 504 throw e.rethrowFromSystemServer(); 505 } 506 } 507 508 @AnyThread 509 @Nullable 510 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) getCurrentInputMethodSubtype(@serIdInt int userId)511 static InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) { 512 final IInputMethodManager service = getService(); 513 if (service == null) { 514 return null; 515 } 516 try { 517 return service.getCurrentInputMethodSubtype(userId); 518 } catch (RemoteException e) { 519 throw e.rethrowFromSystemServer(); 520 } 521 } 522 523 @AnyThread 524 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) setAdditionalInputMethodSubtypes(@onNull String imeId, @NonNull InputMethodSubtype[] subtypes, @UserIdInt int userId)525 static void setAdditionalInputMethodSubtypes(@NonNull String imeId, 526 @NonNull InputMethodSubtype[] subtypes, @UserIdInt int userId) { 527 final IInputMethodManager service = getService(); 528 if (service == null) { 529 return; 530 } 531 try { 532 service.setAdditionalInputMethodSubtypes(imeId, subtypes, userId); 533 } catch (RemoteException e) { 534 throw e.rethrowFromSystemServer(); 535 } 536 } 537 538 @AnyThread 539 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) setExplicitlyEnabledInputMethodSubtypes(@onNull String imeId, @NonNull int[] subtypeHashCodes, @UserIdInt int userId)540 static void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imeId, 541 @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { 542 final IInputMethodManager service = getService(); 543 if (service == null) { 544 return; 545 } 546 try { 547 service.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); 548 } catch (RemoteException e) { 549 throw e.rethrowFromSystemServer(); 550 } 551 } 552 553 @AnyThread getInputMethodWindowVisibleHeight(@onNull IInputMethodClient client)554 static int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) { 555 final IInputMethodManager service = getService(); 556 if (service == null) { 557 return 0; 558 } 559 try { 560 return service.getInputMethodWindowVisibleHeight(client); 561 } catch (RemoteException e) { 562 throw e.rethrowFromSystemServer(); 563 } 564 } 565 566 @AnyThread reportPerceptibleAsync(@onNull IBinder windowToken, boolean perceptible)567 static void reportPerceptibleAsync(@NonNull IBinder windowToken, boolean perceptible) { 568 final IInputMethodManager service = getService(); 569 if (service == null) { 570 return; 571 } 572 try { 573 service.reportPerceptibleAsync(windowToken, perceptible); 574 } catch (RemoteException e) { 575 throw e.rethrowFromSystemServer(); 576 } 577 } 578 579 @AnyThread removeImeSurfaceFromWindowAsync(@onNull IBinder windowToken)580 static void removeImeSurfaceFromWindowAsync(@NonNull IBinder windowToken) { 581 final IInputMethodManager service = getService(); 582 if (service == null) { 583 return; 584 } 585 try { 586 service.removeImeSurfaceFromWindowAsync(windowToken); 587 } catch (RemoteException e) { 588 throw e.rethrowFromSystemServer(); 589 } 590 } 591 592 @AnyThread startStylusHandwriting(@onNull IInputMethodClient client)593 static void startStylusHandwriting(@NonNull IInputMethodClient client) { 594 final IInputMethodManager service = getService(); 595 if (service == null) { 596 return; 597 } 598 try { 599 service.startStylusHandwriting(client); 600 } catch (RemoteException e) { 601 throw e.rethrowFromSystemServer(); 602 } 603 } 604 605 @AnyThread startConnectionlessStylusHandwriting( @onNull IInputMethodClient client, @UserIdInt int userId, @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, @Nullable String delegatorPackageName, @NonNull IConnectionlessHandwritingCallback callback)606 static boolean startConnectionlessStylusHandwriting( 607 @NonNull IInputMethodClient client, 608 @UserIdInt int userId, 609 @Nullable CursorAnchorInfo cursorAnchorInfo, 610 @Nullable String delegatePackageName, 611 @Nullable String delegatorPackageName, 612 @NonNull IConnectionlessHandwritingCallback callback) { 613 final IInputMethodManager service = getService(); 614 if (service == null) { 615 return false; 616 } 617 try { 618 service.startConnectionlessStylusHandwriting(client, userId, cursorAnchorInfo, 619 delegatePackageName, delegatorPackageName, callback); 620 } catch (RemoteException e) { 621 throw e.rethrowFromSystemServer(); 622 } 623 return true; 624 } 625 626 @AnyThread prepareStylusHandwritingDelegation( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName)627 static void prepareStylusHandwritingDelegation( 628 @NonNull IInputMethodClient client, 629 @UserIdInt int userId, 630 @NonNull String delegatePackageName, 631 @NonNull String delegatorPackageName) { 632 final IInputMethodManager service = getService(); 633 if (service == null) { 634 return; 635 } 636 try { 637 service.prepareStylusHandwritingDelegation( 638 client, userId, delegatePackageName, delegatorPackageName); 639 } catch (RemoteException e) { 640 throw e.rethrowFromSystemServer(); 641 } 642 } 643 644 @AnyThread acceptStylusHandwritingDelegation( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, @InputMethodManager.HandwritingDelegateFlags int flags)645 static boolean acceptStylusHandwritingDelegation( 646 @NonNull IInputMethodClient client, 647 @UserIdInt int userId, 648 @NonNull String delegatePackageName, 649 @NonNull String delegatorPackageName, 650 @InputMethodManager.HandwritingDelegateFlags int flags) { 651 final IInputMethodManager service = getService(); 652 if (service == null) { 653 return false; 654 } 655 try { 656 return service.acceptStylusHandwritingDelegation( 657 client, userId, delegatePackageName, delegatorPackageName, flags); 658 } catch (RemoteException e) { 659 throw e.rethrowFromSystemServer(); 660 } 661 } 662 663 /** Returns {@code true} if method is invoked */ 664 @AnyThread acceptStylusHandwritingDelegationAsync( @onNull IInputMethodClient client, @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, @InputMethodManager.HandwritingDelegateFlags int flags, @NonNull IBooleanListener callback)665 static boolean acceptStylusHandwritingDelegationAsync( 666 @NonNull IInputMethodClient client, 667 @UserIdInt int userId, 668 @NonNull String delegatePackageName, 669 @NonNull String delegatorPackageName, 670 @InputMethodManager.HandwritingDelegateFlags int flags, 671 @NonNull IBooleanListener callback) { 672 final IInputMethodManager service = getService(); 673 if (service == null) { 674 return false; 675 } 676 try { 677 service.acceptStylusHandwritingDelegationAsync( 678 client, userId, delegatePackageName, delegatorPackageName, flags, callback); 679 } catch (RemoteException e) { 680 throw e.rethrowFromSystemServer(); 681 } 682 return true; 683 } 684 685 @AnyThread 686 @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true) isStylusHandwritingAvailableAsUser( @serIdInt int userId, boolean connectionless)687 static boolean isStylusHandwritingAvailableAsUser( 688 @UserIdInt int userId, boolean connectionless) { 689 final IInputMethodManager service = getService(); 690 if (service == null) { 691 return false; 692 } 693 try { 694 return service.isStylusHandwritingAvailableAsUser(userId, connectionless); 695 } catch (RemoteException e) { 696 throw e.rethrowFromSystemServer(); 697 } 698 } 699 700 @AnyThread 701 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) addVirtualStylusIdForTestSession(IInputMethodClient client)702 static void addVirtualStylusIdForTestSession(IInputMethodClient client) { 703 final IInputMethodManager service = getService(); 704 if (service == null) { 705 return; 706 } 707 try { 708 service.addVirtualStylusIdForTestSession(client); 709 } catch (RemoteException e) { 710 throw e.rethrowFromSystemServer(); 711 } 712 } 713 714 @AnyThread 715 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) setStylusWindowIdleTimeoutForTest( IInputMethodClient client, @DurationMillisLong long timeout)716 static void setStylusWindowIdleTimeoutForTest( 717 IInputMethodClient client, @DurationMillisLong long timeout) { 718 final IInputMethodManager service = getService(); 719 if (service == null) { 720 return; 721 } 722 try { 723 service.setStylusWindowIdleTimeoutForTest(client, timeout); 724 } catch (RemoteException e) { 725 throw e.rethrowFromSystemServer(); 726 } 727 } 728 729 /** @see com.android.server.inputmethod.ImeTrackerService#onStart */ 730 @AnyThread 731 @NonNull onStart(@onNull String tag, int uid, @ImeTracker.Type int type, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser)732 static ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type, 733 @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) { 734 final var service = getImeTrackerService(); 735 if (service == null) { 736 // Create token with "empty" binder if the service was not found. 737 return ImeTracker.Token.empty(tag); 738 } 739 try { 740 return service.onStart(tag, uid, type, origin, reason, fromUser); 741 } catch (RemoteException e) { 742 throw e.rethrowFromSystemServer(); 743 } 744 } 745 746 /** @see com.android.server.inputmethod.ImeTrackerService#onProgress */ 747 @AnyThread onProgress(@onNull IBinder binder, @ImeTracker.Phase int phase)748 static void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) { 749 final IImeTracker service = getImeTrackerService(); 750 if (service == null) { 751 return; 752 } 753 try { 754 service.onProgress(binder, phase); 755 } catch (RemoteException e) { 756 throw e.rethrowFromSystemServer(); 757 } 758 } 759 760 /** @see com.android.server.inputmethod.ImeTrackerService#onFailed */ 761 @AnyThread onFailed(@onNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase)762 static void onFailed(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) { 763 final IImeTracker service = getImeTrackerService(); 764 if (service == null) { 765 return; 766 } 767 try { 768 service.onFailed(statsToken, phase); 769 } catch (RemoteException e) { 770 throw e.rethrowFromSystemServer(); 771 } 772 } 773 774 /** @see com.android.server.inputmethod.ImeTrackerService#onCancelled */ 775 @AnyThread onCancelled(@onNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase)776 static void onCancelled(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) { 777 final IImeTracker service = getImeTrackerService(); 778 if (service == null) { 779 return; 780 } 781 try { 782 service.onCancelled(statsToken, phase); 783 } catch (RemoteException e) { 784 throw e.rethrowFromSystemServer(); 785 } 786 } 787 788 /** @see com.android.server.inputmethod.ImeTrackerService#onShown */ 789 @AnyThread onShown(@onNull ImeTracker.Token statsToken)790 static void onShown(@NonNull ImeTracker.Token statsToken) { 791 final IImeTracker service = getImeTrackerService(); 792 if (service == null) { 793 return; 794 } 795 try { 796 service.onShown(statsToken); 797 } catch (RemoteException e) { 798 throw e.rethrowFromSystemServer(); 799 } 800 } 801 802 /** @see com.android.server.inputmethod.ImeTrackerService#onHidden */ 803 @AnyThread onHidden(@onNull ImeTracker.Token statsToken)804 static void onHidden(@NonNull ImeTracker.Token statsToken) { 805 final IImeTracker service = getImeTrackerService(); 806 if (service == null) { 807 return; 808 } 809 try { 810 service.onHidden(statsToken); 811 } catch (RemoteException e) { 812 throw e.rethrowFromSystemServer(); 813 } 814 } 815 816 /** @see com.android.server.inputmethod.ImeTrackerService#onDispatched */ onDispatched(@onNull ImeTracker.Token statsToken)817 static void onDispatched(@NonNull ImeTracker.Token statsToken) { 818 final IImeTracker service = getImeTrackerService(); 819 if (service == null) { 820 return; 821 } 822 try { 823 service.onDispatched(statsToken); 824 } catch (RemoteException e) { 825 throw e.rethrowFromSystemServer(); 826 } 827 } 828 829 /** @see com.android.server.inputmethod.ImeTrackerService#hasPendingImeVisibilityRequests */ 830 @AnyThread 831 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) hasPendingImeVisibilityRequests()832 static boolean hasPendingImeVisibilityRequests() { 833 final var service = getImeTrackerService(); 834 if (service == null) { 835 return true; 836 } 837 try { 838 return service.hasPendingImeVisibilityRequests(); 839 } catch (RemoteException e) { 840 throw e.rethrowFromSystemServer(); 841 } 842 } 843 844 @AnyThread 845 @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) finishTrackingPendingImeVisibilityRequests()846 static void finishTrackingPendingImeVisibilityRequests() { 847 final var service = getImeTrackerService(); 848 if (service == null) { 849 return; 850 } 851 try { 852 final var completionSignal = new AndroidFuture<Void>(); 853 service.finishTrackingPendingImeVisibilityRequests(completionSignal); 854 completionSignal.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); 855 } catch (RemoteException e) { 856 throw e.rethrowFromSystemServer(); 857 } catch (Exception e) { 858 throw ExceptionUtils.propagate(e); 859 } 860 } 861 862 @AnyThread 863 @Nullable getImeTrackerService()864 private static IImeTracker getImeTrackerService() { 865 var trackerService = sTrackerServiceCache; 866 if (trackerService == null) { 867 final var service = getService(); 868 if (service == null) { 869 return null; 870 } 871 872 try { 873 trackerService = service.getImeTrackerService(); 874 if (trackerService == null) { 875 return null; 876 } 877 878 sTrackerServiceCache = trackerService; 879 } catch (RemoteException e) { 880 throw e.rethrowFromSystemServer(); 881 } 882 } 883 return trackerService; 884 } 885 } 886