• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view.inputmethod;
18 
19 import 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