• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 com.android.cts.mockime;
18 
19 import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
20 
21 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
22 
23 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
24 
25 import android.app.UiAutomation;
26 import android.app.compat.CompatChanges;
27 import android.content.BroadcastReceiver;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.os.Build;
34 import android.os.Bundle;
35 import android.os.Handler;
36 import android.os.HandlerThread;
37 import android.os.ParcelFileDescriptor;
38 import android.os.SystemClock;
39 import android.os.UserHandle;
40 import android.provider.Settings;
41 import android.text.TextUtils;
42 import android.view.KeyEvent;
43 import android.view.inputmethod.CompletionInfo;
44 import android.view.inputmethod.CorrectionInfo;
45 import android.view.inputmethod.ExtractedTextRequest;
46 import android.view.inputmethod.InputConnection;
47 import android.view.inputmethod.InputContentInfo;
48 import android.view.inputmethod.InputMethodManager;
49 import android.view.inputmethod.InputMethodSubtype;
50 import android.view.inputmethod.TextAttribute;
51 
52 import androidx.annotation.AnyThread;
53 import androidx.annotation.GuardedBy;
54 import androidx.annotation.IntRange;
55 import androidx.annotation.NonNull;
56 import androidx.annotation.Nullable;
57 import androidx.annotation.RequiresPermission;
58 
59 import com.android.compatibility.common.util.PollingCheck;
60 
61 import org.junit.AssumptionViolatedException;
62 
63 import java.io.IOException;
64 import java.util.ArrayList;
65 import java.util.List;
66 import java.util.concurrent.TimeUnit;
67 import java.util.concurrent.atomic.AtomicBoolean;
68 
69 /**
70  * Represents an active Mock IME session, which provides basic primitives to write end-to-end tests
71  * for IME APIs.
72  *
73  * <p>To use {@link MockIme} via {@link MockImeSession}, you need to </p>
74  * <p>Public methods are not thread-safe.</p>
75  */
76 public class MockImeSession implements AutoCloseable {
77     private final String mImeEventActionName =
78             "com.android.cts.mockime.action.IME_EVENT." + SystemClock.elapsedRealtimeNanos();
79 
80     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10);
81 
82     @NonNull
83     private final Context mContext;
84     @NonNull
85     private final UiAutomation mUiAutomation;
86 
87     @NonNull
88     private final AtomicBoolean mActive = new AtomicBoolean(true);
89 
90     private final HandlerThread mHandlerThread = new HandlerThread("EventReceiver");
91 
92     private final List<Intent> mStickyBroadcasts = new ArrayList<>();
93 
94     private static final class EventStore {
95         private static final int INITIAL_ARRAY_SIZE = 32;
96 
97         @NonNull
98         public final ImeEvent[] mArray;
99         public int mLength;
100 
EventStore()101         EventStore() {
102             mArray = new ImeEvent[INITIAL_ARRAY_SIZE];
103             mLength = 0;
104         }
105 
EventStore(EventStore src, int newLength)106         EventStore(EventStore src, int newLength) {
107             mArray = new ImeEvent[newLength];
108             mLength = src.mLength;
109             System.arraycopy(src.mArray, 0, mArray, 0, src.mLength);
110         }
111 
add(ImeEvent event)112         public EventStore add(ImeEvent event) {
113             if (mLength + 1 <= mArray.length) {
114                 mArray[mLength] = event;
115                 ++mLength;
116                 return this;
117             } else {
118                 return new EventStore(this, mLength * 2).add(event);
119             }
120         }
121 
takeSnapshot()122         public ImeEventStream.ImeEventArray takeSnapshot() {
123             return new ImeEventStream.ImeEventArray(mArray, mLength);
124         }
125     }
126 
127     private static final class MockImeEventReceiver extends BroadcastReceiver {
128         private final Object mLock = new Object();
129 
130         @GuardedBy("mLock")
131         @NonNull
132         private EventStore mCurrentEventStore = new EventStore();
133 
134         @NonNull
135         private final String mActionName;
136 
MockImeEventReceiver(@onNull String actionName)137         MockImeEventReceiver(@NonNull String actionName) {
138             mActionName = actionName;
139         }
140 
141         @Override
onReceive(Context context, Intent intent)142         public void onReceive(Context context, Intent intent) {
143             if (TextUtils.equals(mActionName, intent.getAction())) {
144                 synchronized (mLock) {
145                     mCurrentEventStore =
146                             mCurrentEventStore.add(ImeEvent.fromBundle(intent.getExtras()));
147                 }
148             }
149         }
150 
takeEventSnapshot()151         public ImeEventStream.ImeEventArray takeEventSnapshot() {
152             synchronized (mLock) {
153                 return mCurrentEventStore.takeSnapshot();
154             }
155         }
156     }
157     private final MockImeEventReceiver mEventReceiver =
158             new MockImeEventReceiver(mImeEventActionName);
159 
160     private final ImeEventStream mEventStream =
161             new ImeEventStream(mEventReceiver::takeEventSnapshot);
162 
executeShellCommand( @onNull UiAutomation uiAutomation, @NonNull String command)163     private static String executeShellCommand(
164             @NonNull UiAutomation uiAutomation, @NonNull String command) throws IOException {
165         try (ParcelFileDescriptor.AutoCloseInputStream in =
166                      new ParcelFileDescriptor.AutoCloseInputStream(
167                              uiAutomation.executeShellCommand(command))) {
168             final StringBuilder sb = new StringBuilder();
169             final byte[] buffer = new byte[4096];
170             while (true) {
171                 final int numRead = in.read(buffer);
172                 if (numRead <= 0) {
173                     break;
174                 }
175                 sb.append(new String(buffer, 0, numRead));
176             }
177             return sb.toString();
178         }
179     }
180 
181     @Nullable
getCurrentInputMethodId()182     private String getCurrentInputMethodId() {
183         // TODO: Replace this with IMM#getCurrentInputMethodIdForTesting()
184         return Settings.Secure.getString(mContext.getContentResolver(),
185                 Settings.Secure.DEFAULT_INPUT_METHOD);
186     }
187 
188     @Nullable
writeMockImeSettings(@onNull Context context, @NonNull String imeEventActionName, @Nullable ImeSettings.Builder imeSettings)189     private static void writeMockImeSettings(@NonNull Context context,
190             @NonNull String imeEventActionName,
191             @Nullable ImeSettings.Builder imeSettings) throws Exception {
192         final Bundle bundle = ImeSettings.serializeToBundle(imeEventActionName, imeSettings);
193         context.getContentResolver().call(SettingsProvider.AUTHORITY, "write", null, bundle);
194     }
195 
getMockImeComponentName()196     private ComponentName getMockImeComponentName() {
197         return MockIme.getComponentName();
198     }
199 
getMockImeId()200     private String getMockImeId() {
201         return MockIme.getImeId();
202     }
203 
MockImeSession(@onNull Context context, @NonNull UiAutomation uiAutomation)204     private MockImeSession(@NonNull Context context, @NonNull UiAutomation uiAutomation) {
205         mContext = context;
206         mUiAutomation = uiAutomation;
207     }
208 
initialize(@ullable ImeSettings.Builder imeSettings)209     private void initialize(@Nullable ImeSettings.Builder imeSettings) throws Exception {
210         // Make sure that MockIME is not selected.
211         if (mContext.getSystemService(InputMethodManager.class)
212                 .getInputMethodList()
213                 .stream()
214                 .anyMatch(info -> getMockImeComponentName().equals(info.getComponent()))) {
215             executeShellCommand(mUiAutomation, "ime reset");
216         }
217         if (mContext.getSystemService(InputMethodManager.class)
218                 .getEnabledInputMethodList()
219                 .stream()
220                 .anyMatch(info -> getMockImeComponentName().equals(info.getComponent()))) {
221             throw new IllegalStateException();
222         }
223 
224         writeMockImeSettings(mContext, mImeEventActionName, imeSettings);
225 
226         mHandlerThread.start();
227         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
228             mContext.registerReceiver(mEventReceiver,
229                     new IntentFilter(mImeEventActionName), null /* broadcastPermission */,
230                     new Handler(mHandlerThread.getLooper()), Context.RECEIVER_EXPORTED);
231         } else {
232             mContext.registerReceiver(mEventReceiver,
233                     new IntentFilter(mImeEventActionName), null /* broadcastPermission */,
234                     new Handler(mHandlerThread.getLooper()));
235         }
236 
237         executeShellCommand(mUiAutomation, "ime enable " + getMockImeId());
238         executeShellCommand(mUiAutomation, "ime set " + getMockImeId());
239 
240         PollingCheck.check("Make sure that MockIME becomes available", TIMEOUT,
241                 () -> getMockImeId().equals(getCurrentInputMethodId()));
242     }
243 
244     /** @see #create(Context, UiAutomation, ImeSettings.Builder) */
245     @NonNull
create(@onNull Context context)246     public static MockImeSession create(@NonNull Context context) throws Exception {
247         return create(context, getInstrumentation().getUiAutomation(), new ImeSettings.Builder());
248     }
249 
250     /**
251      * Creates a new Mock IME session. During this session, you can receive various events from
252      * {@link MockIme}.
253      *
254      * @param context {@link Context} to be used to receive inter-process events from the
255      *                {@link MockIme} (e.g. via {@link BroadcastReceiver}
256      * @param uiAutomation {@link UiAutomation} object to change the device state that are typically
257      *                     guarded by permissions.
258      * @param imeSettings Key-value pairs to be passed to the {@link MockIme}.
259      * @return A session object, with which you can retrieve event logs from the {@link MockIme} and
260      *         can clean up the session.
261      */
262     @NonNull
create( @onNull Context context, @NonNull UiAutomation uiAutomation, @Nullable ImeSettings.Builder imeSettings)263     public static MockImeSession create(
264             @NonNull Context context,
265             @NonNull UiAutomation uiAutomation,
266             @Nullable ImeSettings.Builder imeSettings) throws Exception {
267         final String unavailabilityReason = getUnavailabilityReason(context);
268         if (unavailabilityReason != null) {
269             throw new AssumptionViolatedException(unavailabilityReason);
270         }
271 
272         final MockImeSession client = new MockImeSession(context, uiAutomation);
273         client.initialize(imeSettings);
274         return client;
275     }
276 
277     /**
278      * Checks if the {@link MockIme} can be used in this device.
279      *
280      * @return {@code null} if it can be used, or message describing why if it cannot.
281      */
282     @Nullable
getUnavailabilityReason(@onNull Context context)283     public static String getUnavailabilityReason(@NonNull Context context) {
284         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
285             return "Device must support installable IMEs that implement InputMethodService API";
286         }
287         return null;
288     }
289 
290     /**
291      * Whether {@link MockIme} enabled a compatibility flag to finish input without fallback
292      * input connection when device interactive state changed. See detailed description in
293      * {@link MockImeSession#setEnabledFinishInputNoFallbackConnection}.
294      *
295      * @return {@code true} if the compatibility flag is enabled.
296      */
isFinishInputNoFallbackConnectionEnabled()297     public static boolean isFinishInputNoFallbackConnectionEnabled() {
298         AtomicBoolean result = new AtomicBoolean();
299         runWithShellPermissionIdentity(() ->
300                 result.set(CompatChanges.isChangeEnabled(FINISH_INPUT_NO_FALLBACK_CONNECTION,
301                         MockIme.getComponentName().getPackageName(), UserHandle.CURRENT)));
302         return result.get();
303     }
304 
305     /**
306      * @return {@link ImeEventStream} object that stores events sent from {@link MockIme} since the
307      *         session is created.
308      */
openEventStream()309     public ImeEventStream openEventStream() {
310         return mEventStream.copy();
311     }
312 
313     /**
314      * @return {@code true} until {@link #close()} gets called.
315      */
316     @AnyThread
isActive()317     public boolean isActive() {
318         return mActive.get();
319     }
320 
321     /**
322      * Closes the active session and de-selects {@link MockIme}. Currently which IME will be
323      * selected next is up to the system.
324      */
close()325     public void close() throws Exception {
326         mActive.set(false);
327 
328         mStickyBroadcasts.forEach(mContext::removeStickyBroadcast);
329         mStickyBroadcasts.clear();
330 
331         executeShellCommand(mUiAutomation, "ime reset");
332 
333         PollingCheck.check("Make sure that MockIME becomes unavailable", TIMEOUT, () ->
334                 mContext.getSystemService(InputMethodManager.class)
335                         .getEnabledInputMethodList()
336                         .stream()
337                         .noneMatch(info -> getMockImeComponentName().equals(info.getComponent())));
338         mContext.unregisterReceiver(mEventReceiver);
339         mHandlerThread.quitSafely();
340         mContext.getContentResolver().call(SettingsProvider.AUTHORITY, "delete", null, null);
341     }
342 
343     /**
344      * Common logic to send a special command to {@link MockIme}.
345      *
346      * @param commandName command to be passed to {@link MockIme}
347      * @param params {@link Bundle} to be passed to {@link MockIme} as a parameter set of
348      *               {@code commandName}
349      * @return {@link ImeCommand} that is sent to {@link MockIme}.  It can be passed to
350      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
351      *         wait until this event is handled by {@link MockIme}.
352      */
353     @NonNull
callCommandInternal(@onNull String commandName, @NonNull Bundle params)354     private ImeCommand callCommandInternal(@NonNull String commandName, @NonNull Bundle params) {
355         final ImeCommand command = new ImeCommand(
356                 commandName, SystemClock.elapsedRealtimeNanos(), true, params);
357         final Intent intent = createCommandIntent(command);
358         mContext.sendBroadcast(intent);
359         return command;
360     }
361 
362     /**
363      * A variant of {@link #callCommandInternal} that uses
364      * {@link Context#sendStickyBroadcast(android.content.Intent) sendStickyBroadcast} to ensure
365      * that the command is received even if the IME is not running at the time of sending
366      * (e.g. when {@code config_preventImeStartupUnlessTextEditor} is set).
367      * <p>
368      * The caller requires the {@link android.Manifest.permission#BROADCAST_STICKY BROADCAST_STICKY}
369      * permission.
370      */
371     @NonNull
372     @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
callCommandInternalSticky( @onNull String commandName, @NonNull Bundle params)373     private ImeCommand callCommandInternalSticky(
374             @NonNull String commandName,
375             @NonNull Bundle params) {
376         final ImeCommand command = new ImeCommand(
377                 commandName, SystemClock.elapsedRealtimeNanos(), true, params);
378         final Intent intent = createCommandIntent(command);
379         mStickyBroadcasts.add(intent);
380         mContext.sendStickyBroadcast(intent);
381         return command;
382     }
383 
384     @NonNull
createCommandIntent(@onNull ImeCommand command)385     private Intent createCommandIntent(@NonNull ImeCommand command) {
386         final Intent intent = new Intent();
387         intent.setPackage(MockIme.getComponentName().getPackageName());
388         intent.setAction(MockIme.getCommandActionName(mImeEventActionName));
389         intent.putExtras(command.toBundle());
390         return intent;
391     }
392 
393 
394     /**
395      * Lets {@link MockIme} suspend {@link MockIme.AbstractInputMethodImpl#createSession(
396      * android.view.inputmethod.InputMethod.SessionCallback)} until {@link #resumeCreateSession()}.
397      *
398      * <p>This is useful to test a tricky timing issue that the IME client initiated the
399      * IME session but {@link android.view.inputmethod.InputMethodSession} is not available
400      * yet.</p>
401      *
402      * <p>For simplicity and stability, {@link #suspendCreateSession()} must be called before
403      * {@link MockIme.AbstractInputMethodImpl#createSession(
404      * android.view.inputmethod.InputMethod.SessionCallback)} gets called again.</p>
405      *
406      * @return {@link ImeCommand} object that can be passed to
407      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
408      *         wait until this event is handled by {@link MockIme}.
409      */
410     @NonNull
suspendCreateSession()411     public ImeCommand suspendCreateSession() {
412         return callCommandInternal("suspendCreateSession", new Bundle());
413     }
414 
415     /**
416      * Lets {@link MockIme} resume suspended {@link MockIme.AbstractInputMethodImpl#createSession(
417      * android.view.inputmethod.InputMethod.SessionCallback)}.
418      *
419      * <p>Does nothing if {@link #suspendCreateSession()} was not called.</p>
420      *
421      * @return {@link ImeCommand} object that can be passed to
422      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
423      *         wait until this event is handled by {@link MockIme}.
424      */
425     @NonNull
resumeCreateSession()426     public ImeCommand resumeCreateSession() {
427         return callCommandInternal("resumeCreateSession", new Bundle());
428     }
429 
430 
431     /**
432      * Lets {@link MockIme} to call
433      * {@link android.inputmethodservice.InputMethodService#getCurrentInputConnection()} and
434      * memorize  it for later {@link InputConnection}-related operations.
435      *
436      * <p>Only the last one will be memorized if this method gets called multiple times.</p>
437      *
438      * @return {@link ImeCommand} object that can be passed to
439      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
440      *         wait until this event is handled by {@link MockIme}.
441      * @see #unmemorizeCurrentInputConnection()
442      */
443     @NonNull
memorizeCurrentInputConnection()444     public ImeCommand memorizeCurrentInputConnection() {
445         final Bundle params = new Bundle();
446         return callCommandInternal("memorizeCurrentInputConnection", params);
447     }
448 
449     /**
450      * Lets {@link MockIme} to forget memorized {@link InputConnection} if any. Does nothing
451      * otherwise.
452      *
453      * @return {@link ImeCommand} object that can be passed to
454      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
455      *         wait until this event is handled by {@link MockIme}.
456      * @see #memorizeCurrentInputConnection()
457      */
458     @NonNull
unmemorizeCurrentInputConnection()459     public ImeCommand unmemorizeCurrentInputConnection() {
460         final Bundle params = new Bundle();
461         return callCommandInternal("unmemorizeCurrentInputConnection", params);
462     }
463 
464     /**
465      * Lets {@link MockIme} to call {@link InputConnection#getTextBeforeCursor(int, int)} with the
466      * given parameters.
467      *
468      * <p>This triggers {@code getCurrentInputConnection().getTextBeforeCursor(n, flag)}.</p>
469      *
470      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
471      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
472      * value returned from the API.</p>
473      *
474      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
475      *
476      * @param n to be passed as the {@code n} parameter.
477      * @param flag to be passed as the {@code flag} parameter.
478      * @return {@link ImeCommand} object that can be passed to
479      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
480      *         wait until this event is handled by {@link MockIme}.
481      */
482     @NonNull
callGetTextBeforeCursor(int n, int flag)483     public ImeCommand callGetTextBeforeCursor(int n, int flag) {
484         final Bundle params = new Bundle();
485         params.putInt("n", n);
486         params.putInt("flag", flag);
487         return callCommandInternal("getTextBeforeCursor", params);
488     }
489 
490     /**
491      * Lets {@link MockIme} to call {@link InputConnection#getTextAfterCursor(int, int)} with the
492      * given parameters.
493      *
494      * <p>This triggers {@code getCurrentInputConnection().getTextAfterCursor(n, flag)}.</p>
495      *
496      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
497      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
498      * value returned from the API.</p>
499      *
500      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
501      *
502      * @param n to be passed as the {@code n} parameter.
503      * @param flag to be passed as the {@code flag} parameter.
504      * @return {@link ImeCommand} object that can be passed to
505      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
506      *         wait until this event is handled by {@link MockIme}.
507      */
508     @NonNull
callGetTextAfterCursor(int n, int flag)509     public ImeCommand callGetTextAfterCursor(int n, int flag) {
510         final Bundle params = new Bundle();
511         params.putInt("n", n);
512         params.putInt("flag", flag);
513         return callCommandInternal("getTextAfterCursor", params);
514     }
515 
516     /**
517      * Lets {@link MockIme} to call {@link InputConnection#getSelectedText(int)} with the
518      * given parameters.
519      *
520      * <p>This triggers {@code getCurrentInputConnection().getSelectedText(flag)}.</p>
521      *
522      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
523      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
524      * value returned from the API.</p>
525      *
526      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
527      *
528      * @param flag to be passed as the {@code flag} parameter.
529      * @return {@link ImeCommand} object that can be passed to
530      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
531      *         wait until this event is handled by {@link MockIme}.
532      */
533     @NonNull
callGetSelectedText(int flag)534     public ImeCommand callGetSelectedText(int flag) {
535         final Bundle params = new Bundle();
536         params.putInt("flag", flag);
537         return callCommandInternal("getSelectedText", params);
538     }
539 
540     /**
541      * Lets {@link MockIme} to call {@link InputConnection#getSurroundingText(int, int, int)} with
542      * the given parameters.
543      *
544      * <p>This triggers {@code getCurrentInputConnection().getSurroundingText(int, int, int)}.</p>
545      *
546      * <p>Use {@link ImeEvent#getReturnParcelableValue()} for {@link ImeEvent} returned from
547      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
548      * value returned from the API.</p>
549      *
550      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
551      *
552      * @param beforeLength The expected length of the text before the cursor.
553      * @param afterLength The expected length of the text after the cursor.
554      * @param flags Supplies additional options controlling how the text is returned. May be either
555      *              {@code 0} or {@link InputConnection#GET_TEXT_WITH_STYLES}.
556      * @return {@link ImeCommand} object that can be passed to
557      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
558      *         wait until this event is handled by {@link MockIme}.
559      */
560     @NonNull
callGetSurroundingText(@ntRangefrom = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags)561     public ImeCommand callGetSurroundingText(@IntRange(from = 0) int beforeLength,
562             @IntRange(from = 0) int afterLength, int flags) {
563         final Bundle params = new Bundle();
564         params.putInt("beforeLength", beforeLength);
565         params.putInt("afterLength", afterLength);
566         params.putInt("flags", flags);
567         return callCommandInternal("getSurroundingText", params);
568     }
569 
570     /**
571      * Lets {@link MockIme} to call {@link InputConnection#getCursorCapsMode(int)} with the given
572      * parameters.
573      *
574      * <p>This triggers {@code getCurrentInputConnection().getCursorCapsMode(reqModes)}.</p>
575      *
576      * <p>Use {@link ImeEvent#getReturnIntegerValue()} for {@link ImeEvent} returned from
577      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
578      * value returned from the API.</p>
579      *
580      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
581      *
582      * @param reqModes to be passed as the {@code reqModes} parameter.
583      * @return {@link ImeCommand} object that can be passed to
584      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
585      *         wait until this event is handled by {@link MockIme}.
586      */
587     @NonNull
callGetCursorCapsMode(int reqModes)588     public ImeCommand callGetCursorCapsMode(int reqModes) {
589         final Bundle params = new Bundle();
590         params.putInt("reqModes", reqModes);
591         return callCommandInternal("getCursorCapsMode", params);
592     }
593 
594     /**
595      * Lets {@link MockIme} to call
596      * {@link InputConnection#getExtractedText(ExtractedTextRequest, int)} with the given
597      * parameters.
598      *
599      * <p>This triggers {@code getCurrentInputConnection().getExtractedText(request, flags)}.</p>
600      *
601      * <p>Use {@link ImeEvent#getReturnParcelableValue()} for {@link ImeEvent} returned from
602      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
603      * value returned from the API.</p>
604      *
605      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
606      *
607      * @param request to be passed as the {@code request} parameter
608      * @param flags to be passed as the {@code flags} parameter
609      * @return {@link ImeCommand} object that can be passed to
610      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
611      *         wait until this event is handled by {@link MockIme}.
612      */
613     @NonNull
callGetExtractedText(@ullable ExtractedTextRequest request, int flags)614     public ImeCommand callGetExtractedText(@Nullable ExtractedTextRequest request, int flags) {
615         final Bundle params = new Bundle();
616         params.putParcelable("request", request);
617         params.putInt("flags", flags);
618         return callCommandInternal("getExtractedText", params);
619     }
620 
621     /**
622      * Lets {@link MockIme} to call {@link InputConnection#deleteSurroundingText(int, int)} with the
623      * given parameters.
624      *
625      * <p>This triggers
626      * {@code getCurrentInputConnection().deleteSurroundingText(beforeLength, afterLength)}.</p>
627      *
628      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
629      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
630      * value returned from the API.</p>
631      *
632      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
633      *
634      * @param beforeLength to be passed as the {@code beforeLength} parameter
635      * @param afterLength to be passed as the {@code afterLength} parameter
636      * @return {@link ImeCommand} object that can be passed to
637      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
638      *         wait until this event is handled by {@link MockIme}.
639      */
640     @NonNull
callDeleteSurroundingText(int beforeLength, int afterLength)641     public ImeCommand callDeleteSurroundingText(int beforeLength, int afterLength) {
642         final Bundle params = new Bundle();
643         params.putInt("beforeLength", beforeLength);
644         params.putInt("afterLength", afterLength);
645         return callCommandInternal("deleteSurroundingText", params);
646     }
647 
648     /**
649      * Lets {@link MockIme} to call
650      * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)} with the given
651      * parameters.
652      *
653      * <p>This triggers {@code getCurrentInputConnection().deleteSurroundingTextInCodePoints(
654      * beforeLength, afterLength)}.</p>
655      *
656      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
657      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
658      * value returned from the API.</p>
659      *
660      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
661      *
662      * @param beforeLength to be passed as the {@code beforeLength} parameter
663      * @param afterLength to be passed as the {@code afterLength} parameter
664      * @return {@link ImeCommand} object that can be passed to
665      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
666      *         wait until this event is handled by {@link MockIme}.
667      */
668     @NonNull
callDeleteSurroundingTextInCodePoints(int beforeLength, int afterLength)669     public ImeCommand callDeleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
670         final Bundle params = new Bundle();
671         params.putInt("beforeLength", beforeLength);
672         params.putInt("afterLength", afterLength);
673         return callCommandInternal("deleteSurroundingTextInCodePoints", params);
674     }
675 
676     /**
677      * Lets {@link MockIme} to call {@link InputConnection#setComposingText(CharSequence, int)} with
678      * the given parameters.
679      *
680      * <p>This triggers
681      * {@code getCurrentInputConnection().setComposingText(text, newCursorPosition)}.</p>
682      *
683      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
684      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
685      * value returned from the API.</p>
686      *
687      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
688      *
689      * @param text to be passed as the {@code text} parameter
690      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
691      * @return {@link ImeCommand} object that can be passed to
692      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
693      *         wait until this event is handled by {@link MockIme}.
694      */
695     @NonNull
callSetComposingText(@ullable CharSequence text, int newCursorPosition)696     public ImeCommand callSetComposingText(@Nullable CharSequence text, int newCursorPosition) {
697         final Bundle params = new Bundle();
698         params.putCharSequence("text", text);
699         params.putInt("newCursorPosition", newCursorPosition);
700         return callCommandInternal("setComposingText(CharSequence,int)", params);
701     }
702 
703     /**
704      * Lets {@link MockIme} to call
705      * {@link InputConnection#setComposingText(CharSequence, int, TextAttribute)} with the given
706      * parameters.
707      *
708      * <p>This triggers
709      * {@code getCurrentInputConnection().setComposingText(text, newCursorPosition, textAttribute)}.
710      * </p>
711      *
712      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
713      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
714      * value returned from the API.</p>
715      *
716      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
717      *
718      * @param text to be passed as the {@code text} parameter
719      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
720      * @param textAttribute to be passed as the {@code textAttribute} parameter
721      * @return {@link ImeCommand} object that can be passed to
722      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
723      *         wait until this event is handled by {@link MockIme}
724      */
725     @NonNull
callSetComposingText(@ullable CharSequence text, int newCursorPosition, @Nullable TextAttribute textAttribute)726     public ImeCommand callSetComposingText(@Nullable CharSequence text, int newCursorPosition,
727             @Nullable TextAttribute textAttribute) {
728         final Bundle params = new Bundle();
729         params.putCharSequence("text", text);
730         params.putInt("newCursorPosition", newCursorPosition);
731         params.putParcelable("textAttribute", textAttribute);
732         return callCommandInternal("setComposingText(CharSequence,int,TextAttribute)", params);
733     }
734 
735     /**
736      * Lets {@link MockIme} to call {@link InputConnection#setComposingRegion(int, int)} with the
737      * given parameters.
738      *
739      * <p>This triggers {@code getCurrentInputConnection().setComposingRegion(start, end)}.</p>
740      *
741      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
742      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
743      * value returned from the API.</p>
744      *
745      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
746      *
747      * @param start to be passed as the {@code start} parameter
748      * @param end to be passed as the {@code end} parameter
749      * @return {@link ImeCommand} object that can be passed to
750      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
751      *         wait until this event is handled by {@link MockIme}.
752      */
753     @NonNull
callSetComposingRegion(int start, int end)754     public ImeCommand callSetComposingRegion(int start, int end) {
755         final Bundle params = new Bundle();
756         params.putInt("start", start);
757         params.putInt("end", end);
758         return callCommandInternal("setComposingRegion(int,int)", params);
759     }
760 
761     /**
762      * Lets {@link MockIme} to call
763      * {@link InputConnection#setComposingRegion(int, int, TextAttribute)} with the given
764      * parameters.
765      *
766      * <p>This triggers
767      * {@code getCurrentInputConnection().setComposingRegion(start, end, TextAttribute)}.</p>
768      *
769      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
770      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
771      * value returned from the API.</p>
772      *
773      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
774      *
775      * @param start to be passed as the {@code start} parameter
776      * @param end to be passed as the {@code end} parameter
777      * @return {@link ImeCommand} object that can be passed to
778      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
779      *         wait until this event is handled by {@link MockIme}.
780      */
781     @NonNull
callSetComposingRegion(int start, int end, @Nullable TextAttribute textAttribute)782     public ImeCommand callSetComposingRegion(int start, int end,
783             @Nullable TextAttribute textAttribute) {
784         final Bundle params = new Bundle();
785         params.putInt("start", start);
786         params.putInt("end", end);
787         params.putParcelable("textAttribute", textAttribute);
788         return callCommandInternal("setComposingRegion(int,int,TextAttribute)", params);
789     }
790 
791     /**
792      * Lets {@link MockIme} to call {@link InputConnection#finishComposingText()} with the given
793      * parameters.
794      *
795      * <p>This triggers {@code getCurrentInputConnection().finishComposingText()}.</p>
796      *
797      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
798      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
799      * value returned from the API.</p>
800      *
801      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
802      *
803      * @return {@link ImeCommand} object that can be passed to
804      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
805      *         wait until this event is handled by {@link MockIme}.
806      */
807     @NonNull
callFinishComposingText()808     public ImeCommand callFinishComposingText() {
809         final Bundle params = new Bundle();
810         return callCommandInternal("finishComposingText", params);
811     }
812 
813     /**
814      * Lets {@link MockIme} to call {@link InputConnection#commitText(CharSequence, int)} with the
815      * given parameters.
816      *
817      * <p>This triggers {@code getCurrentInputConnection().commitText(text, newCursorPosition)}.</p>
818      *
819      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
820      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
821      * value returned from the API.</p>
822      *
823      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
824      *
825      * @param text to be passed as the {@code text} parameter
826      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
827      * @return {@link ImeCommand} object that can be passed to
828      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
829      *         wait until this event is handled by {@link MockIme}
830      */
831     @NonNull
callCommitText(@ullable CharSequence text, int newCursorPosition)832     public ImeCommand callCommitText(@Nullable CharSequence text, int newCursorPosition) {
833         final Bundle params = new Bundle();
834         params.putCharSequence("text", text);
835         params.putInt("newCursorPosition", newCursorPosition);
836         return callCommandInternal("commitText(CharSequence,int)", params);
837     }
838 
839     /**
840      * Lets {@link MockIme} to call
841      * {@link InputConnection#commitText(CharSequence, int, TextAttribute)} with the given
842      * parameters.
843      *
844      * <p>This triggers
845      * {@code getCurrentInputConnection().commitText(text, newCursorPosition, TextAttribute)}.</p>
846      *
847      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
848      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
849      * value returned from the API.</p>
850      *
851      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
852      *
853      * @param text to be passed as the {@code text} parameter
854      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
855      * @return {@link ImeCommand} object that can be passed to
856      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
857      *         wait until this event is handled by {@link MockIme}
858      */
859     @NonNull
callCommitText(@ullable CharSequence text, int newCursorPosition, @Nullable TextAttribute textAttribute)860     public ImeCommand callCommitText(@Nullable CharSequence text, int newCursorPosition,
861             @Nullable TextAttribute textAttribute) {
862         final Bundle params = new Bundle();
863         params.putCharSequence("text", text);
864         params.putInt("newCursorPosition", newCursorPosition);
865         params.putParcelable("textAttribute", textAttribute);
866         return callCommandInternal("commitText(CharSequence,int,TextAttribute)", params);
867     }
868 
869     /**
870      * Lets {@link MockIme} to call {@link InputConnection#commitCompletion(CompletionInfo)} with
871      * the given parameters.
872      *
873      * <p>This triggers {@code getCurrentInputConnection().commitCompletion(text)}.</p>
874      *
875      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
876      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
877      * value returned from the API.</p>
878      *
879      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
880      *
881      * @param text to be passed as the {@code text} parameter
882      * @return {@link ImeCommand} object that can be passed to
883      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
884      *         wait until this event is handled by {@link MockIme}
885      */
886     @NonNull
callCommitCompletion(@ullable CompletionInfo text)887     public ImeCommand callCommitCompletion(@Nullable CompletionInfo text) {
888         final Bundle params = new Bundle();
889         params.putParcelable("text", text);
890         return callCommandInternal("commitCompletion", params);
891     }
892 
893     /**
894      * Lets {@link MockIme} to call {@link InputConnection#commitCorrection(CorrectionInfo)} with
895      * the given parameters.
896      *
897      * <p>This triggers {@code getCurrentInputConnection().commitCorrection(correctionInfo)}.</p>
898      *
899      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
900      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
901      * value returned from the API.</p>
902      *
903      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
904      *
905      * @param correctionInfo to be passed as the {@code correctionInfo} parameter
906      * @return {@link ImeCommand} object that can be passed to
907      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
908      *         wait until this event is handled by {@link MockIme}
909      */
910     @NonNull
callCommitCorrection(@ullable CorrectionInfo correctionInfo)911     public ImeCommand callCommitCorrection(@Nullable CorrectionInfo correctionInfo) {
912         final Bundle params = new Bundle();
913         params.putParcelable("correctionInfo", correctionInfo);
914         return callCommandInternal("commitCorrection", params);
915     }
916 
917     /**
918      * Lets {@link MockIme} to call {@link InputConnection#setSelection(int, int)} with the given
919      * parameters.
920      *
921      * <p>This triggers {@code getCurrentInputConnection().setSelection(start, end)}.</p>
922      *
923      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
924      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
925      * value returned from the API.</p>
926      *
927      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
928      *
929      * @param start to be passed as the {@code start} parameter
930      * @param end to be passed as the {@code end} parameter
931      * @return {@link ImeCommand} object that can be passed to
932      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
933      *         wait until this event is handled by {@link MockIme}
934      */
935     @NonNull
callSetSelection(int start, int end)936     public ImeCommand callSetSelection(int start, int end) {
937         final Bundle params = new Bundle();
938         params.putInt("start", start);
939         params.putInt("end", end);
940         return callCommandInternal("setSelection", params);
941     }
942 
943     /**
944      * Lets {@link MockIme} to call {@link InputConnection#performEditorAction(int)} with the given
945      * parameters.
946      *
947      * <p>This triggers {@code getCurrentInputConnection().performEditorAction(editorAction)}.</p>
948      *
949      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
950      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
951      * value returned from the API.</p>
952      *
953      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
954      *
955      * @param editorAction to be passed as the {@code editorAction} parameter
956      * @return {@link ImeCommand} object that can be passed to
957      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
958      *         wait until this event is handled by {@link MockIme}
959      */
960     @NonNull
callPerformEditorAction(int editorAction)961     public ImeCommand callPerformEditorAction(int editorAction) {
962         final Bundle params = new Bundle();
963         params.putInt("editorAction", editorAction);
964         return callCommandInternal("performEditorAction", params);
965     }
966 
967     /**
968      * Lets {@link MockIme} to call {@link InputConnection#performContextMenuAction(int)} with the
969      * given parameters.
970      *
971      * <p>This triggers {@code getCurrentInputConnection().performContextMenuAction(id)}.</p>
972      *
973      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
974      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
975      * value returned from the API.</p>
976      *
977      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
978      *
979      * @param id to be passed as the {@code id} parameter
980      * @return {@link ImeCommand} object that can be passed to
981      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
982      *         wait until this event is handled by {@link MockIme}
983      */
984     @NonNull
callPerformContextMenuAction(int id)985     public ImeCommand callPerformContextMenuAction(int id) {
986         final Bundle params = new Bundle();
987         params.putInt("id", id);
988         return callCommandInternal("performContextMenuAction", params);
989     }
990 
991     /**
992      * Lets {@link MockIme} to call {@link InputConnection#beginBatchEdit()} with the given
993      * parameters.
994      *
995      * <p>This triggers {@code getCurrentInputConnection().beginBatchEdit()}.</p>
996      *
997      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
998      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
999      * value returned from the API.</p>
1000      *
1001      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1002      *
1003      * @return {@link ImeCommand} object that can be passed to
1004      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1005      *         wait until this event is handled by {@link MockIme}
1006      */
1007     @NonNull
callBeginBatchEdit()1008     public ImeCommand callBeginBatchEdit() {
1009         final Bundle params = new Bundle();
1010         return callCommandInternal("beginBatchEdit", params);
1011     }
1012 
1013     /**
1014      * Lets {@link MockIme} to call {@link InputConnection#endBatchEdit()} with the given
1015      * parameters.
1016      *
1017      * <p>This triggers {@code getCurrentInputConnection().endBatchEdit()}.</p>
1018      *
1019      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1020      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1021      * value returned from the API.</p>
1022      *
1023      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1024      *
1025      * @return {@link ImeCommand} object that can be passed to
1026      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1027      *         wait until this event is handled by {@link MockIme}
1028      */
1029     @NonNull
callEndBatchEdit()1030     public ImeCommand callEndBatchEdit() {
1031         final Bundle params = new Bundle();
1032         return callCommandInternal("endBatchEdit", params);
1033     }
1034 
1035     /**
1036      * Lets {@link MockIme} to call {@link InputConnection#sendKeyEvent(KeyEvent)} with the given
1037      * parameters.
1038      *
1039      * <p>This triggers {@code getCurrentInputConnection().sendKeyEvent(event)}.</p>
1040      *
1041      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1042      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1043      * value returned from the API.</p>
1044      *
1045      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1046      *
1047      * @param event to be passed as the {@code event} parameter
1048      * @return {@link ImeCommand} object that can be passed to
1049      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1050      *         wait until this event is handled by {@link MockIme}
1051      */
1052     @NonNull
callSendKeyEvent(@ullable KeyEvent event)1053     public ImeCommand callSendKeyEvent(@Nullable KeyEvent event) {
1054         final Bundle params = new Bundle();
1055         params.putParcelable("event", event);
1056         return callCommandInternal("sendKeyEvent", params);
1057     }
1058 
1059     /**
1060      * Lets {@link MockIme} to call {@link InputConnection#performSpellCheck()}.
1061      *
1062      * <p>This triggers {@code getCurrentInputConnection().performSpellCheck()}.</p>
1063      *
1064      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1065 
1066      * @return {@link ImeCommand} object that can be passed to
1067      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1068      *         wait until this event is handled by {@link MockIme}
1069      */
1070     @NonNull
callPerformSpellCheck()1071     public ImeCommand callPerformSpellCheck() {
1072         return callCommandInternal("performSpellCheck", new Bundle());
1073     }
1074 
1075     /**
1076      * Lets {@link MockIme} to call {@link InputConnection#takeSnapshot()}.
1077      *
1078      * <p>This triggers {@code getCurrentInputConnection().takeSnapshot()}.</p>
1079      *
1080      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1081 
1082      * @return {@link ImeCommand} object that can be passed to
1083      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1084      *         wait until this event is handled by {@link MockIme}
1085      */
1086     @NonNull
callTakeSnapshot()1087     public ImeCommand callTakeSnapshot() {
1088         return callCommandInternal("takeSnapshot", new Bundle());
1089     }
1090 
1091     /**
1092      * Lets {@link MockIme} to call {@link InputConnection#clearMetaKeyStates(int)} with the given
1093      * parameters.
1094      *
1095      * <p>This triggers {@code getCurrentInputConnection().sendKeyEvent(event)}.</p>
1096      *
1097      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1098      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1099      * value returned from the API.</p>
1100      *
1101      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1102      *
1103      * @param states to be passed as the {@code states} parameter
1104      * @return {@link ImeCommand} object that can be passed to
1105      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1106      *         wait until this event is handled by {@link MockIme}
1107      */
1108     @NonNull
callClearMetaKeyStates(int states)1109     public ImeCommand callClearMetaKeyStates(int states) {
1110         final Bundle params = new Bundle();
1111         params.putInt("states", states);
1112         return callCommandInternal("clearMetaKeyStates", params);
1113     }
1114 
1115     /**
1116      * Lets {@link MockIme} to call {@link InputConnection#reportFullscreenMode(boolean)} with the
1117      * given parameters.
1118      *
1119      * <p>This triggers {@code getCurrentInputConnection().reportFullscreenMode(enabled)}.</p>
1120      *
1121      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1122      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1123      * value returned from the API.</p>
1124      *
1125      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1126      *
1127      * @param enabled to be passed as the {@code enabled} parameter
1128      * @return {@link ImeCommand} object that can be passed to
1129      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1130      *         wait until this event is handled by {@link MockIme}
1131      */
1132     @NonNull
callReportFullscreenMode(boolean enabled)1133     public ImeCommand callReportFullscreenMode(boolean enabled) {
1134         final Bundle params = new Bundle();
1135         params.putBoolean("enabled", enabled);
1136         return callCommandInternal("reportFullscreenMode", params);
1137     }
1138 
1139     /**
1140      * Lets {@link MockIme} to call {@link InputConnection#performPrivateCommand(String, Bundle)}
1141      * with the given parameters.
1142      *
1143      * <p>This triggers {@code getCurrentInputConnection().performPrivateCommand(action, data)}.</p>
1144      *
1145      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1146      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1147      * value returned from the API.</p>
1148      *
1149      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1150      *
1151      * @param action to be passed as the {@code action} parameter
1152      * @param data to be passed as the {@code data} parameter
1153      * @return {@link ImeCommand} object that can be passed to
1154      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1155      *         wait until this event is handled by {@link MockIme}
1156      */
1157     @NonNull
callPerformPrivateCommand(@ullable String action, Bundle data)1158     public ImeCommand callPerformPrivateCommand(@Nullable String action, Bundle data) {
1159         final Bundle params = new Bundle();
1160         params.putString("action", action);
1161         params.putBundle("data", data);
1162         return callCommandInternal("performPrivateCommand", params);
1163     }
1164 
1165     /**
1166      * Lets {@link MockIme} to call {@link InputConnection#requestCursorUpdates(int)} with the given
1167      * parameters.
1168      *
1169      * <p>This triggers {@code getCurrentInputConnection().requestCursorUpdates(cursorUpdateMode)}.
1170      * </p>
1171      *
1172      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1173      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1174      * value returned from the API.</p>
1175      *
1176      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1177      *
1178      * @param cursorUpdateMode to be passed as the {@code cursorUpdateMode} parameter
1179      * @return {@link ImeCommand} object that can be passed to
1180      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1181      *         wait until this event is handled by {@link MockIme}
1182      */
1183     @NonNull
callRequestCursorUpdates(int cursorUpdateMode)1184     public ImeCommand callRequestCursorUpdates(int cursorUpdateMode) {
1185         final Bundle params = new Bundle();
1186         params.putInt("cursorUpdateMode", cursorUpdateMode);
1187         return callCommandInternal("requestCursorUpdates", params);
1188     }
1189 
1190     /**
1191      * Lets {@link MockIme} to call {@link InputConnection#requestCursorUpdates(int, int)} with the
1192      * given parameters.
1193      *
1194      * <p>This triggers {@code getCurrentInputConnection().requestCursorUpdates(
1195      * cursorUpdateMode, cursorUpdateFilter)}.
1196      * </p>
1197      *
1198      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1199      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1200      * value returned from the API.</p>
1201      *
1202      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1203      *
1204      * @param cursorUpdateMode to be passed as the {@code cursorUpdateMode} parameter
1205      * @param cursorUpdateFilter to be passed as the {@code cursorUpdateFilter} parameter
1206      * @return {@link ImeCommand} object that can be passed to
1207      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1208      *         wait until this event is handled by {@link MockIme}
1209      */
1210     @NonNull
callRequestCursorUpdates(int cursorUpdateMode, int cursorUpdateFilter)1211     public ImeCommand callRequestCursorUpdates(int cursorUpdateMode, int cursorUpdateFilter) {
1212         final Bundle params = new Bundle();
1213         params.putInt("cursorUpdateMode", cursorUpdateMode);
1214         params.putInt("cursorUpdateFilter", cursorUpdateFilter);
1215         return callCommandInternal("requestCursorUpdates", params);
1216     }
1217 
1218     /**
1219      * Lets {@link MockIme} to call {@link InputConnection#getHandler()} with the given parameters.
1220      *
1221      * <p>This triggers {@code getCurrentInputConnection().getHandler()}.</p>
1222      *
1223      * <p>Use {@link ImeEvent#isNullReturnValue()} for {@link ImeEvent} returned from
1224      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1225      * value returned from the API was {@code null} or not.</p>
1226      *
1227      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1228      *
1229      * @return {@link ImeCommand} object that can be passed to
1230      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1231      *         wait until this event is handled by {@link MockIme}
1232      */
1233     @NonNull
callGetHandler()1234     public ImeCommand callGetHandler() {
1235         final Bundle params = new Bundle();
1236         return callCommandInternal("getHandler", params);
1237     }
1238 
1239     /**
1240      * Lets {@link MockIme} to call {@link InputConnection#closeConnection()} with the given
1241      * parameters.
1242      *
1243      * <p>This triggers {@code getCurrentInputConnection().closeConnection()}.</p>
1244      *
1245      * <p>Return value information is not available for this command.</p>
1246      *
1247      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1248      *
1249      * @return {@link ImeCommand} object that can be passed to
1250      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1251      *         wait until this event is handled by {@link MockIme}
1252      */
1253     @NonNull
callCloseConnection()1254     public ImeCommand callCloseConnection() {
1255         final Bundle params = new Bundle();
1256         return callCommandInternal("closeConnection", params);
1257     }
1258 
1259     /**
1260      * Lets {@link MockIme} to call
1261      * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} with the given
1262      * parameters.
1263      *
1264      * <p>This triggers
1265      * {@code getCurrentInputConnection().commitContent(inputContentInfo, flags, opts)}.</p>
1266      *
1267      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1268      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1269      * value returned from the API.</p>
1270      *
1271      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1272      *
1273      * @param inputContentInfo to be passed as the {@code inputContentInfo} parameter
1274      * @param flags to be passed as the {@code flags} parameter
1275      * @param opts to be passed as the {@code opts} parameter
1276      * @return {@link ImeCommand} object that can be passed to
1277      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1278      *         wait until this event is handled by {@link MockIme}
1279      */
1280     @NonNull
callCommitContent(@onNull InputContentInfo inputContentInfo, int flags, @Nullable Bundle opts)1281     public ImeCommand callCommitContent(@NonNull InputContentInfo inputContentInfo, int flags,
1282             @Nullable Bundle opts) {
1283         final Bundle params = new Bundle();
1284         params.putParcelable("inputContentInfo", inputContentInfo);
1285         params.putInt("flags", flags);
1286         params.putBundle("opts", opts);
1287         return callCommandInternal("commitContent", params);
1288     }
1289 
1290     /**
1291      * Lets {@link MockIme} to call {@link InputConnection#setImeConsumesInput(boolean)} with the
1292      * given parameters.
1293      *
1294      * <p>This triggers {@code getCurrentInputConnection().setImeConsumesInput(boolean)}.</p>
1295      *
1296      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1297      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1298      * value returned from the API.</p>
1299      *
1300      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1301      *
1302      * @param imeConsumesInput to be passed as the {@code imeConsumesInput} parameter
1303      * @return {@link ImeCommand} object that can be passed to
1304      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1305      *         wait until this event is handled by {@link MockIme}
1306      */
1307     @NonNull
callSetImeConsumesInput(boolean imeConsumesInput)1308     public ImeCommand callSetImeConsumesInput(boolean imeConsumesInput) {
1309         final Bundle params = new Bundle();
1310         params.putBoolean("imeConsumesInput", imeConsumesInput);
1311         return callCommandInternal("setImeConsumesInput", params);
1312     }
1313 
1314     /**
1315      * Makes {@link MockIme} call {@link
1316      * android.inputmethodservice.InputMethodService#switchInputMethod(String)}
1317      * with the given parameters.
1318      *
1319      * @param id the IME ID.
1320      * @return {@link ImeCommand} object that can be passed to
1321      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1322      *         wait until this event is handled by {@link MockIme}
1323      */
1324     @NonNull
callSwitchInputMethod(String id)1325     public ImeCommand callSwitchInputMethod(String id) {
1326         final Bundle params = new Bundle();
1327         params.putString("id", id);
1328         return callCommandInternal("switchInputMethod", params);
1329     }
1330 
1331     /**
1332      * Lets {@link MockIme} to call {@link
1333      * android.inputmethodservice.InputMethodService#switchInputMethod(String, InputMethodSubtype)}
1334      * with the given parameters.
1335      *
1336      * <p>This triggers {@code switchInputMethod(id, subtype)}.</p>
1337      *
1338      * @param id the IME ID.
1339      * @param subtype {@link InputMethodSubtype} to be switched to. Ignored if {@code null}.
1340      * @return {@link ImeCommand} object that can be passed to
1341      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1342      *         wait until this event is handled by {@link MockIme}
1343      */
1344     @NonNull
callSwitchInputMethod(String id, @Nullable InputMethodSubtype subtype)1345     public ImeCommand callSwitchInputMethod(String id, @Nullable InputMethodSubtype subtype) {
1346         final Bundle params = new Bundle();
1347         params.putString("id", id);
1348         params.putParcelable("subtype", subtype);
1349         return callCommandInternal("switchInputMethod(String,InputMethodSubtype)", params);
1350     }
1351 
1352     /**
1353      * Lets {@link MockIme} to call
1354      * {@link android.inputmethodservice.InputMethodService#setBackDisposition(int)} with the given
1355      * parameters.
1356      *
1357      * <p>This triggers {@code setBackDisposition(backDisposition)}.</p>
1358      *
1359      * @param backDisposition to be passed as the {@code backDisposition} parameter
1360      * @return {@link ImeCommand} object that can be passed to
1361      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1362      *         wait until this event is handled by {@link MockIme}
1363      */
1364     @NonNull
callSetBackDisposition(int backDisposition)1365     public ImeCommand callSetBackDisposition(int backDisposition) {
1366         final Bundle params = new Bundle();
1367         params.putInt("backDisposition", backDisposition);
1368         return callCommandInternal("setBackDisposition", params);
1369     }
1370 
1371     /**
1372      * Lets {@link MockIme} to call
1373      * {@link android.inputmethodservice.InputMethodService#requestHideSelf(int)} with the given
1374      * parameters.
1375      *
1376      * <p>This triggers {@code requestHideSelf(flags)}.</p>
1377      *
1378      * @param flags to be passed as the {@code flags} parameter
1379      * @return {@link ImeCommand} object that can be passed to
1380      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1381      *         wait until this event is handled by {@link MockIme}
1382      */
1383     @NonNull
callRequestHideSelf(int flags)1384     public ImeCommand callRequestHideSelf(int flags) {
1385         final Bundle params = new Bundle();
1386         params.putInt("flags", flags);
1387         return callCommandInternal("requestHideSelf", params);
1388     }
1389 
1390     /**
1391      * Lets {@link MockIme} to call
1392      * {@link android.inputmethodservice.InputMethodService#requestShowSelf(int)} with the given
1393      * parameters.
1394      *
1395      * <p>This triggers {@code requestShowSelf(flags)}.</p>
1396      *
1397      * @param flags to be passed as the {@code flags} parameter
1398      * @return {@link ImeCommand} object that can be passed to
1399      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1400      *         wait until this event is handled by {@link MockIme}
1401      */
1402     @NonNull
callRequestShowSelf(int flags)1403     public ImeCommand callRequestShowSelf(int flags) {
1404         final Bundle params = new Bundle();
1405         params.putInt("flags", flags);
1406         return callCommandInternal("requestShowSelf", params);
1407     }
1408 
1409     /**
1410      * Lets {@link MockIme} call
1411      * {@link android.inputmethodservice.InputMethodService#sendDownUpKeyEvents(int)} with the given
1412      * {@code keyEventCode}.
1413      *
1414      * @param keyEventCode to be passed as the {@code keyEventCode} parameter.
1415      * @return {@link ImeCommand} object that can be passed to
1416      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1417      *         wait until this event is handled by {@link MockIme}
1418      */
1419     @NonNull
callSendDownUpKeyEvents(int keyEventCode)1420     public ImeCommand callSendDownUpKeyEvents(int keyEventCode) {
1421         final Bundle params = new Bundle();
1422         params.putInt("keyEventCode", keyEventCode);
1423         return callCommandInternal("sendDownUpKeyEvents", params);
1424     }
1425 
1426     /**
1427      * Lets {@link MockIme} call
1428      * {@link android.content.pm.PackageManager#getApplicationInfo(String, int)} with the given
1429      * {@code packageName} and {@code flags}.
1430      *
1431      * @param packageName the package name to be passed to
1432      *                    {@link android.content.pm.PackageManager#getApplicationInfo(String, int)}.
1433      * @param flags the flags to be passed to
1434      *                    {@link android.content.pm.PackageManager#getApplicationInfo(String, int)}.
1435      * @return {@link ImeCommand} object that can be passed to
1436      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1437      *         wait until this event is handled by {@link MockIme}.
1438      */
1439     @NonNull
callGetApplicationInfo(@onNull String packageName, int flags)1440     public ImeCommand callGetApplicationInfo(@NonNull String packageName, int flags) {
1441         final Bundle params = new Bundle();
1442         params.putString("packageName", packageName);
1443         params.putInt("flags", flags);
1444         return callCommandInternal("getApplicationInfo", params);
1445     }
1446 
1447     @NonNull
callSetEnableOnBackInvokedCallback(Boolean isEnabled)1448     public ImeCommand callSetEnableOnBackInvokedCallback(Boolean isEnabled) {
1449         final Bundle params = new Bundle();
1450         params.putBoolean("isEnabled", isEnabled);
1451         return callCommandInternal("setEnableOnBackInvokedCallback", params);
1452     }
1453 
1454     @NonNull
callGetDisplayId()1455     public ImeCommand callGetDisplayId() {
1456         final Bundle params = new Bundle();
1457         return callCommandInternal("getDisplayId", params);
1458     }
1459 
1460     /**
1461      * Verifies {@code InputMethodService.getLayoutInflater().getContext()} is equal to
1462      * {@code InputMethodService.this}.
1463      *
1464      * @return {@link ImeCommand} object that can be passed to
1465      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1466      *         wait until this event is handled by {@link MockIme}
1467      */
1468     @NonNull
verifyLayoutInflaterContext()1469     public ImeCommand verifyLayoutInflaterContext() {
1470         final Bundle params = new Bundle();
1471         return callCommandInternal("verifyLayoutInflaterContext", params);
1472     }
1473 
1474     @NonNull
callSetHeight(int height)1475     public ImeCommand callSetHeight(int height) {
1476         final Bundle params = new Bundle();
1477         params.putInt("height", height);
1478         return callCommandInternal("setHeight", params);
1479     }
1480 
1481     @NonNull
1482     @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
callSetInlineSuggestionsExtras(@onNull Bundle bundle)1483     public ImeCommand callSetInlineSuggestionsExtras(@NonNull Bundle bundle) {
1484         return callCommandInternalSticky("setInlineSuggestionsExtras", bundle);
1485     }
1486 
1487     @NonNull
callVerifyExtractViewNotNull()1488     public ImeCommand callVerifyExtractViewNotNull() {
1489         return callCommandInternal("verifyExtractViewNotNull", new Bundle());
1490     }
1491 
1492     @NonNull
callVerifyGetDisplay()1493     public ImeCommand callVerifyGetDisplay() {
1494         return callCommandInternal("verifyGetDisplay", new Bundle());
1495     }
1496 
1497     @NonNull
callVerifyIsUiContext()1498     public ImeCommand callVerifyIsUiContext() {
1499         return callCommandInternal("verifyIsUiContext", new Bundle());
1500     }
1501 
1502     @NonNull
callVerifyGetWindowManager()1503     public ImeCommand callVerifyGetWindowManager() {
1504         return callCommandInternal("verifyGetWindowManager", new Bundle());
1505     }
1506 
1507     @NonNull
callVerifyGetViewConfiguration()1508     public ImeCommand callVerifyGetViewConfiguration() {
1509         return callCommandInternal("verifyGetViewConfiguration", new Bundle());
1510     }
1511 
1512     @NonNull
callVerifyGetGestureDetector()1513     public ImeCommand callVerifyGetGestureDetector() {
1514         return callCommandInternal("verifyGetGestureDetector", new Bundle());
1515     }
1516 
1517     @NonNull
callVerifyGetWindowManagerOnDisplayContext()1518     public ImeCommand callVerifyGetWindowManagerOnDisplayContext() {
1519         return callCommandInternal("verifyGetWindowManagerOnDisplayContext", new Bundle());
1520     }
1521 
1522     @NonNull
callVerifyGetViewConfigurationOnDisplayContext()1523     public ImeCommand callVerifyGetViewConfigurationOnDisplayContext() {
1524         return callCommandInternal("verifyGetViewConfigurationOnDisplayContext", new Bundle());
1525     }
1526 
1527     @NonNull
callVerifyGetGestureDetectorOnDisplayContext()1528     public ImeCommand callVerifyGetGestureDetectorOnDisplayContext() {
1529         return callCommandInternal("verifyGetGestureDetectorOnDisplayContext", new Bundle());
1530     }
1531 
1532     @NonNull
callGetStylusHandwritingWindowVisibility()1533     public ImeCommand callGetStylusHandwritingWindowVisibility() {
1534         return callCommandInternal("getStylusHandwritingWindowVisibility", new Bundle());
1535     }
1536 
1537     @NonNull
callGetWindowLayoutInfo()1538     public ImeCommand callGetWindowLayoutInfo() {
1539         return callCommandInternal("getWindowLayoutInfo", new Bundle());
1540     }
1541 
1542     @NonNull
callSetStylusHandwritingInkView()1543     public ImeCommand callSetStylusHandwritingInkView() {
1544         return callCommandInternal("setStylusHandwritingInkView", new Bundle());
1545     }
1546 
1547     @NonNull
callGetStylusHandwritingEvents()1548     public ImeCommand callGetStylusHandwritingEvents() {
1549         return callCommandInternal("getStylusHandwritingEvents", new Bundle());
1550     }
1551 
1552     @NonNull
callFinishStylusHandwriting()1553     public ImeCommand callFinishStylusHandwriting() {
1554         return callCommandInternal("finishStylusHandwriting", new Bundle());
1555     }
1556 
1557     @NonNull
callGetCurrentWindowMetricsBounds()1558     public ImeCommand callGetCurrentWindowMetricsBounds() {
1559         return callCommandInternal("getCurrentWindowMetricsBounds", new Bundle());
1560     }
1561 }
1562