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.Bundle;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.ParcelFileDescriptor;
37 import android.os.SystemClock;
38 import android.os.UserHandle;
39 import android.provider.Settings;
40 import android.text.TextUtils;
41 import android.view.KeyEvent;
42 import android.view.inputmethod.CompletionInfo;
43 import android.view.inputmethod.CorrectionInfo;
44 import android.view.inputmethod.ExtractedTextRequest;
45 import android.view.inputmethod.InputConnection;
46 import android.view.inputmethod.InputContentInfo;
47 import android.view.inputmethod.InputMethodManager;
48 
49 import androidx.annotation.GuardedBy;
50 import androidx.annotation.NonNull;
51 import androidx.annotation.Nullable;
52 
53 import com.android.compatibility.common.util.PollingCheck;
54 
55 import org.junit.AssumptionViolatedException;
56 
57 import java.io.IOException;
58 import java.util.concurrent.TimeUnit;
59 import java.util.concurrent.atomic.AtomicBoolean;
60 
61 /**
62  * Represents an active Mock IME session, which provides basic primitives to write end-to-end tests
63  * for IME APIs.
64  *
65  * <p>To use {@link MockIme} via {@link MockImeSession}, you need to </p>
66  * <p>Public methods are not thread-safe.</p>
67  */
68 public class MockImeSession implements AutoCloseable {
69     private final String mImeEventActionName =
70             "com.android.cts.mockime.action.IME_EVENT." + SystemClock.elapsedRealtimeNanos();
71 
72     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10);
73 
74     @NonNull
75     private final Context mContext;
76     @NonNull
77     private final UiAutomation mUiAutomation;
78 
79     private final HandlerThread mHandlerThread = new HandlerThread("EventReceiver");
80 
81     private static final class EventStore {
82         private static final int INITIAL_ARRAY_SIZE = 32;
83 
84         @NonNull
85         public final ImeEvent[] mArray;
86         public int mLength;
87 
EventStore()88         EventStore() {
89             mArray = new ImeEvent[INITIAL_ARRAY_SIZE];
90             mLength = 0;
91         }
92 
EventStore(EventStore src, int newLength)93         EventStore(EventStore src, int newLength) {
94             mArray = new ImeEvent[newLength];
95             mLength = src.mLength;
96             System.arraycopy(src.mArray, 0, mArray, 0, src.mLength);
97         }
98 
add(ImeEvent event)99         public EventStore add(ImeEvent event) {
100             if (mLength + 1 <= mArray.length) {
101                 mArray[mLength] = event;
102                 ++mLength;
103                 return this;
104             } else {
105                 return new EventStore(this, mLength * 2).add(event);
106             }
107         }
108 
takeSnapshot()109         public ImeEventStream.ImeEventArray takeSnapshot() {
110             return new ImeEventStream.ImeEventArray(mArray, mLength);
111         }
112     }
113 
114     private static final class MockImeEventReceiver extends BroadcastReceiver {
115         private final Object mLock = new Object();
116 
117         @GuardedBy("mLock")
118         @NonNull
119         private EventStore mCurrentEventStore = new EventStore();
120 
121         @NonNull
122         private final String mActionName;
123 
MockImeEventReceiver(@onNull String actionName)124         MockImeEventReceiver(@NonNull String actionName) {
125             mActionName = actionName;
126         }
127 
128         @Override
onReceive(Context context, Intent intent)129         public void onReceive(Context context, Intent intent) {
130             if (TextUtils.equals(mActionName, intent.getAction())) {
131                 synchronized (mLock) {
132                     mCurrentEventStore =
133                             mCurrentEventStore.add(ImeEvent.fromBundle(intent.getExtras()));
134                 }
135             }
136         }
137 
takeEventSnapshot()138         public ImeEventStream.ImeEventArray takeEventSnapshot() {
139             synchronized (mLock) {
140                 return mCurrentEventStore.takeSnapshot();
141             }
142         }
143     }
144     private final MockImeEventReceiver mEventReceiver =
145             new MockImeEventReceiver(mImeEventActionName);
146 
147     private final ImeEventStream mEventStream =
148             new ImeEventStream(mEventReceiver::takeEventSnapshot);
149 
executeShellCommand( @onNull UiAutomation uiAutomation, @NonNull String command)150     private static String executeShellCommand(
151             @NonNull UiAutomation uiAutomation, @NonNull String command) throws IOException {
152         try (ParcelFileDescriptor.AutoCloseInputStream in =
153                      new ParcelFileDescriptor.AutoCloseInputStream(
154                              uiAutomation.executeShellCommand(command))) {
155             final StringBuilder sb = new StringBuilder();
156             final byte[] buffer = new byte[4096];
157             while (true) {
158                 final int numRead = in.read(buffer);
159                 if (numRead <= 0) {
160                     break;
161                 }
162                 sb.append(new String(buffer, 0, numRead));
163             }
164             return sb.toString();
165         }
166     }
167 
168     @Nullable
getCurrentInputMethodId()169     private String getCurrentInputMethodId() {
170         // TODO: Replace this with IMM#getCurrentInputMethodIdForTesting()
171         return Settings.Secure.getString(mContext.getContentResolver(),
172                 Settings.Secure.DEFAULT_INPUT_METHOD);
173     }
174 
175     @Nullable
writeMockImeSettings(@onNull Context context, @NonNull String imeEventActionName, @Nullable ImeSettings.Builder imeSettings)176     private static void writeMockImeSettings(@NonNull Context context,
177             @NonNull String imeEventActionName,
178             @Nullable ImeSettings.Builder imeSettings) throws Exception {
179         final Bundle bundle = ImeSettings.serializeToBundle(imeEventActionName, imeSettings);
180         context.getContentResolver().call(SettingsProvider.AUTHORITY, "write", null, bundle);
181     }
182 
getMockImeComponentName()183     private ComponentName getMockImeComponentName() {
184         return MockIme.getComponentName();
185     }
186 
getMockImeId()187     private String getMockImeId() {
188         return MockIme.getImeId();
189     }
190 
MockImeSession(@onNull Context context, @NonNull UiAutomation uiAutomation)191     private MockImeSession(@NonNull Context context, @NonNull UiAutomation uiAutomation) {
192         mContext = context;
193         mUiAutomation = uiAutomation;
194     }
195 
initialize(@ullable ImeSettings.Builder imeSettings)196     private void initialize(@Nullable ImeSettings.Builder imeSettings) throws Exception {
197         // Make sure that MockIME is not selected.
198         if (mContext.getSystemService(InputMethodManager.class)
199                 .getInputMethodList()
200                 .stream()
201                 .anyMatch(info -> getMockImeComponentName().equals(info.getComponent()))) {
202             executeShellCommand(mUiAutomation, "ime reset");
203         }
204         if (mContext.getSystemService(InputMethodManager.class)
205                 .getEnabledInputMethodList()
206                 .stream()
207                 .anyMatch(info -> getMockImeComponentName().equals(info.getComponent()))) {
208             throw new IllegalStateException();
209         }
210 
211         writeMockImeSettings(mContext, mImeEventActionName, imeSettings);
212 
213         mHandlerThread.start();
214         mContext.registerReceiver(mEventReceiver,
215                 new IntentFilter(mImeEventActionName), null /* broadcastPermission */,
216                 new Handler(mHandlerThread.getLooper()));
217 
218         executeShellCommand(mUiAutomation, "ime enable " + getMockImeId());
219         executeShellCommand(mUiAutomation, "ime set " + getMockImeId());
220 
221         PollingCheck.check("Make sure that MockIME becomes available", TIMEOUT,
222                 () -> getMockImeId().equals(getCurrentInputMethodId()));
223     }
224 
225     /** @see #create(Context, UiAutomation, ImeSettings.Builder) */
226     @NonNull
create(@onNull Context context)227     public static MockImeSession create(@NonNull Context context) throws Exception {
228         return create(context, getInstrumentation().getUiAutomation(), new ImeSettings.Builder());
229     }
230 
231     /**
232      * Creates a new Mock IME session. During this session, you can receive various events from
233      * {@link MockIme}.
234      *
235      * @param context {@link Context} to be used to receive inter-process events from the
236      *                {@link MockIme} (e.g. via {@link BroadcastReceiver}
237      * @param uiAutomation {@link UiAutomation} object to change the device state that are typically
238      *                     guarded by permissions.
239      * @param imeSettings Key-value pairs to be passed to the {@link MockIme}.
240      * @return A session object, with which you can retrieve event logs from the {@link MockIme} and
241      *         can clean up the session.
242      */
243     @NonNull
create( @onNull Context context, @NonNull UiAutomation uiAutomation, @Nullable ImeSettings.Builder imeSettings)244     public static MockImeSession create(
245             @NonNull Context context,
246             @NonNull UiAutomation uiAutomation,
247             @Nullable ImeSettings.Builder imeSettings) throws Exception {
248         final String unavailabilityReason = getUnavailabilityReason(context);
249         if (unavailabilityReason != null) {
250             throw new AssumptionViolatedException(unavailabilityReason);
251         }
252 
253         final MockImeSession client = new MockImeSession(context, uiAutomation);
254         client.initialize(imeSettings);
255         return client;
256     }
257 
258     /**
259      * Checks if the {@link MockIme} can be used in this device.
260      *
261      * @return {@code null} if it can be used, or message describing why if it cannot.
262      */
263     @Nullable
getUnavailabilityReason(@onNull Context context)264     public static String getUnavailabilityReason(@NonNull Context context) {
265         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
266             return "Device must support installable IMEs that implement InputMethodService API";
267         }
268         return null;
269     }
270 
271     /**
272      * Whether {@link MockIme} enabled a compatibility flag to finish input without fallback
273      * input connection when device interactive state changed. See detailed description in
274      * {@link MockImeSession#setEnabledFinishInputNoFallbackConnection}.
275      *
276      * @return {@code true} if the compatibility flag is enabled.
277      */
isFinishInputNoFallbackConnectionEnabled()278     public static boolean isFinishInputNoFallbackConnectionEnabled() {
279         AtomicBoolean result = new AtomicBoolean();
280         runWithShellPermissionIdentity(() ->
281                 result.set(CompatChanges.isChangeEnabled(FINISH_INPUT_NO_FALLBACK_CONNECTION,
282                         MockIme.getComponentName().getPackageName(), UserHandle.CURRENT)));
283         return result.get();
284     }
285 
286     /**
287      * @return {@link ImeEventStream} object that stores events sent from {@link MockIme} since the
288      *         session is created.
289      */
openEventStream()290     public ImeEventStream openEventStream() {
291         return mEventStream.copy();
292     }
293 
294     /**
295      * Closes the active session and de-selects {@link MockIme}. Currently which IME will be
296      * selected next is up to the system.
297      */
close()298     public void close() throws Exception {
299         executeShellCommand(mUiAutomation, "ime reset");
300 
301         PollingCheck.check("Make sure that MockIME becomes unavailable", TIMEOUT, () ->
302                 mContext.getSystemService(InputMethodManager.class)
303                         .getEnabledInputMethodList()
304                         .stream()
305                         .noneMatch(info -> getMockImeComponentName().equals(info.getComponent())));
306         mContext.unregisterReceiver(mEventReceiver);
307         mHandlerThread.quitSafely();
308         mContext.getContentResolver().call(SettingsProvider.AUTHORITY, "delete", null, null);
309     }
310 
311     /**
312      * Common logic to send a special command to {@link MockIme}.
313      *
314      * @param commandName command to be passed to {@link MockIme}
315      * @param params {@link Bundle} to be passed to {@link MockIme} as a parameter set of
316      *               {@code commandName}
317      * @return {@link ImeCommand} that is sent to {@link MockIme}.  It can be passed to
318      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
319      *         wait until this event is handled by {@link MockIme}.
320      */
321     @NonNull
callCommandInternal(@onNull String commandName, @NonNull Bundle params)322     private ImeCommand callCommandInternal(@NonNull String commandName, @NonNull Bundle params) {
323         final ImeCommand command = new ImeCommand(
324                 commandName, SystemClock.elapsedRealtimeNanos(), true, params);
325         final Intent intent = new Intent();
326         intent.setPackage(MockIme.getComponentName().getPackageName());
327         intent.setAction(MockIme.getCommandActionName(mImeEventActionName));
328         intent.putExtras(command.toBundle());
329         mContext.sendBroadcast(intent);
330         return command;
331     }
332 
333     /**
334      * Lets {@link MockIme} to call
335      * {@link android.inputmethodservice.InputMethodService#getCurrentInputConnection()} and
336      * memorize  it for later {@link InputConnection}-related operations.
337      *
338      * <p>Only the last one will be memorized if this method gets called multiple times.</p>
339      *
340      * @return {@link ImeCommand} object that can be passed to
341      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
342      *         wait until this event is handled by {@link MockIme}.
343      * @see #unmemorizeCurrentInputConnection()
344      */
345     @NonNull
memorizeCurrentInputConnection()346     public ImeCommand memorizeCurrentInputConnection() {
347         final Bundle params = new Bundle();
348         return callCommandInternal("memorizeCurrentInputConnection", params);
349     }
350 
351     /**
352      * Lets {@link MockIme} to forget memorized {@link InputConnection} if any. Does nothing
353      * otherwise.
354      *
355      * @return {@link ImeCommand} object that can be passed to
356      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
357      *         wait until this event is handled by {@link MockIme}.
358      * @see #memorizeCurrentInputConnection()
359      */
360     @NonNull
unmemorizeCurrentInputConnection()361     public ImeCommand unmemorizeCurrentInputConnection() {
362         final Bundle params = new Bundle();
363         return callCommandInternal("unmemorizeCurrentInputConnection", params);
364     }
365 
366     /**
367      * Lets {@link MockIme} to call {@link InputConnection#getTextBeforeCursor(int, int)} with the
368      * given parameters.
369      *
370      * <p>This triggers {@code getCurrentInputConnection().getTextBeforeCursor(n, flag)}.</p>
371      *
372      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
373      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
374      * value returned from the API.</p>
375      *
376      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
377      *
378      * @param n to be passed as the {@code n} parameter.
379      * @param flag to be passed as the {@code flag} parameter.
380      * @return {@link ImeCommand} object that can be passed to
381      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
382      *         wait until this event is handled by {@link MockIme}.
383      */
384     @NonNull
callGetTextBeforeCursor(int n, int flag)385     public ImeCommand callGetTextBeforeCursor(int n, int flag) {
386         final Bundle params = new Bundle();
387         params.putInt("n", n);
388         params.putInt("flag", flag);
389         return callCommandInternal("getTextBeforeCursor", params);
390     }
391 
392     /**
393      * Lets {@link MockIme} to call {@link InputConnection#getTextAfterCursor(int, int)} with the
394      * given parameters.
395      *
396      * <p>This triggers {@code getCurrentInputConnection().getTextAfterCursor(n, flag)}.</p>
397      *
398      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
399      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
400      * value returned from the API.</p>
401      *
402      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
403      *
404      * @param n to be passed as the {@code n} parameter.
405      * @param flag to be passed as the {@code flag} parameter.
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
callGetTextAfterCursor(int n, int flag)411     public ImeCommand callGetTextAfterCursor(int n, int flag) {
412         final Bundle params = new Bundle();
413         params.putInt("n", n);
414         params.putInt("flag", flag);
415         return callCommandInternal("getTextAfterCursor", params);
416     }
417 
418     /**
419      * Lets {@link MockIme} to call {@link InputConnection#getSelectedText(int)} with the
420      * given parameters.
421      *
422      * <p>This triggers {@code getCurrentInputConnection().getSelectedText(flag)}.</p>
423      *
424      * <p>Use {@link ImeEvent#getReturnCharSequenceValue()} for {@link ImeEvent} returned from
425      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
426      * value returned from the API.</p>
427      *
428      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
429      *
430      * @param flag to be passed as the {@code flag} parameter.
431      * @return {@link ImeCommand} object that can be passed to
432      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
433      *         wait until this event is handled by {@link MockIme}.
434      */
435     @NonNull
callGetSelectedText(int flag)436     public ImeCommand callGetSelectedText(int flag) {
437         final Bundle params = new Bundle();
438         params.putInt("flag", flag);
439         return callCommandInternal("getSelectedText", params);
440     }
441 
442     /**
443      * Lets {@link MockIme} to call {@link InputConnection#getCursorCapsMode(int)} with the given
444      * parameters.
445      *
446      * <p>This triggers {@code getCurrentInputConnection().getCursorCapsMode(reqModes)}.</p>
447      *
448      * <p>Use {@link ImeEvent#getReturnIntegerValue()} for {@link ImeEvent} returned from
449      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
450      * value returned from the API.</p>
451      *
452      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
453      *
454      * @param reqModes to be passed as the {@code reqModes} parameter.
455      * @return {@link ImeCommand} object that can be passed to
456      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
457      *         wait until this event is handled by {@link MockIme}.
458      */
459     @NonNull
callGetCursorCapsMode(int reqModes)460     public ImeCommand callGetCursorCapsMode(int reqModes) {
461         final Bundle params = new Bundle();
462         params.putInt("reqModes", reqModes);
463         return callCommandInternal("getCursorCapsMode", params);
464     }
465 
466     /**
467      * Lets {@link MockIme} to call
468      * {@link InputConnection#getExtractedText(ExtractedTextRequest, int)} with the given
469      * parameters.
470      *
471      * <p>This triggers {@code getCurrentInputConnection().getExtractedText(request, flags)}.</p>
472      *
473      * <p>Use {@link ImeEvent#getReturnParcelableValue()} for {@link ImeEvent} returned from
474      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
475      * value returned from the API.</p>
476      *
477      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
478      *
479      * @param request to be passed as the {@code request} parameter
480      * @param flags to be passed as the {@code flags} parameter
481      * @return {@link ImeCommand} object that can be passed to
482      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
483      *         wait until this event is handled by {@link MockIme}.
484      */
485     @NonNull
callGetExtractedText(@ullable ExtractedTextRequest request, int flags)486     public ImeCommand callGetExtractedText(@Nullable ExtractedTextRequest request, int flags) {
487         final Bundle params = new Bundle();
488         params.putParcelable("request", request);
489         params.putInt("flags", flags);
490         return callCommandInternal("getExtractedText", params);
491     }
492 
493     /**
494      * Lets {@link MockIme} to call {@link InputConnection#deleteSurroundingText(int, int)} with the
495      * given parameters.
496      *
497      * <p>This triggers
498      * {@code getCurrentInputConnection().deleteSurroundingText(beforeLength, afterLength)}.</p>
499      *
500      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
501      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
502      * value returned from the API.</p>
503      *
504      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
505      *
506      * @param beforeLength to be passed as the {@code beforeLength} parameter
507      * @param afterLength to be passed as the {@code afterLength} parameter
508      * @return {@link ImeCommand} object that can be passed to
509      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
510      *         wait until this event is handled by {@link MockIme}.
511      */
512     @NonNull
callDeleteSurroundingText(int beforeLength, int afterLength)513     public ImeCommand callDeleteSurroundingText(int beforeLength, int afterLength) {
514         final Bundle params = new Bundle();
515         params.putInt("beforeLength", beforeLength);
516         params.putInt("afterLength", afterLength);
517         return callCommandInternal("deleteSurroundingText", params);
518     }
519 
520     /**
521      * Lets {@link MockIme} to call
522      * {@link InputConnection#deleteSurroundingTextInCodePoints(int, int)} with the given
523      * parameters.
524      *
525      * <p>This triggers {@code getCurrentInputConnection().deleteSurroundingTextInCodePoints(
526      * beforeLength, afterLength)}.</p>
527      *
528      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
529      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
530      * value returned from the API.</p>
531      *
532      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
533      *
534      * @param beforeLength to be passed as the {@code beforeLength} parameter
535      * @param afterLength to be passed as the {@code afterLength} parameter
536      * @return {@link ImeCommand} object that can be passed to
537      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
538      *         wait until this event is handled by {@link MockIme}.
539      */
540     @NonNull
callDeleteSurroundingTextInCodePoints(int beforeLength, int afterLength)541     public ImeCommand callDeleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
542         final Bundle params = new Bundle();
543         params.putInt("beforeLength", beforeLength);
544         params.putInt("afterLength", afterLength);
545         return callCommandInternal("deleteSurroundingTextInCodePoints", params);
546     }
547 
548     /**
549      * Lets {@link MockIme} to call {@link InputConnection#setComposingText(CharSequence, int)} with
550      * the given parameters.
551      *
552      * <p>This triggers
553      * {@code getCurrentInputConnection().setComposingText(text, newCursorPosition)}.</p>
554      *
555      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
556      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
557      * value returned from the API.</p>
558      *
559      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
560      *
561      * @param text to be passed as the {@code text} parameter
562      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
563      * @return {@link ImeCommand} object that can be passed to
564      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
565      *         wait until this event is handled by {@link MockIme}.
566      */
567     @NonNull
callSetComposingText(@ullable CharSequence text, int newCursorPosition)568     public ImeCommand callSetComposingText(@Nullable CharSequence text, int newCursorPosition) {
569         final Bundle params = new Bundle();
570         params.putCharSequence("text", text);
571         params.putInt("newCursorPosition", newCursorPosition);
572         return callCommandInternal("setComposingText", params);
573     }
574 
575     /**
576      * Lets {@link MockIme} to call {@link InputConnection#setComposingRegion(int, int)} with the
577      * given parameters.
578      *
579      * <p>This triggers {@code getCurrentInputConnection().setComposingRegion(start, end)}.</p>
580      *
581      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
582      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
583      * value returned from the API.</p>
584      *
585      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
586      *
587      * @param start to be passed as the {@code start} parameter
588      * @param end to be passed as the {@code end} parameter
589      * @return {@link ImeCommand} object that can be passed to
590      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
591      *         wait until this event is handled by {@link MockIme}.
592      */
593     @NonNull
callSetComposingRegion(int start, int end)594     public ImeCommand callSetComposingRegion(int start, int end) {
595         final Bundle params = new Bundle();
596         params.putInt("start", start);
597         params.putInt("end", end);
598         return callCommandInternal("setComposingRegion", params);
599     }
600 
601     /**
602      * Lets {@link MockIme} to call {@link InputConnection#finishComposingText()} with the given
603      * parameters.
604      *
605      * <p>This triggers {@code getCurrentInputConnection().finishComposingText()}.</p>
606      *
607      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
608      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
609      * value returned from the API.</p>
610      *
611      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
612      *
613      * @return {@link ImeCommand} object that can be passed to
614      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
615      *         wait until this event is handled by {@link MockIme}.
616      */
617     @NonNull
callFinishComposingText()618     public ImeCommand callFinishComposingText() {
619         final Bundle params = new Bundle();
620         return callCommandInternal("finishComposingText", params);
621     }
622 
623     /**
624      * Lets {@link MockIme} to call {@link InputConnection#commitText(CharSequence, int)} with the
625      * given parameters.
626      *
627      * <p>This triggers {@code getCurrentInputConnection().commitText(text, newCursorPosition)}.</p>
628      *
629      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
630      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
631      * value returned from the API.</p>
632      *
633      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
634      *
635      * @param text to be passed as the {@code text} parameter
636      * @param newCursorPosition to be passed as the {@code newCursorPosition} parameter
637      * @return {@link ImeCommand} object that can be passed to
638      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
639      *         wait until this event is handled by {@link MockIme}
640      */
641     @NonNull
callCommitText(@ullable CharSequence text, int newCursorPosition)642     public ImeCommand callCommitText(@Nullable CharSequence text, int newCursorPosition) {
643         final Bundle params = new Bundle();
644         params.putCharSequence("text", text);
645         params.putInt("newCursorPosition", newCursorPosition);
646         return callCommandInternal("commitText", params);
647     }
648 
649     /**
650      * Lets {@link MockIme} to call {@link InputConnection#commitCompletion(CompletionInfo)} with
651      * the given parameters.
652      *
653      * <p>This triggers {@code getCurrentInputConnection().commitCompletion(text)}.</p>
654      *
655      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
656      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
657      * value returned from the API.</p>
658      *
659      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
660      *
661      * @param text to be passed as the {@code text} parameter
662      * @return {@link ImeCommand} object that can be passed to
663      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
664      *         wait until this event is handled by {@link MockIme}
665      */
666     @NonNull
callCommitCompletion(@ullable CompletionInfo text)667     public ImeCommand callCommitCompletion(@Nullable CompletionInfo text) {
668         final Bundle params = new Bundle();
669         params.putParcelable("text", text);
670         return callCommandInternal("commitCompletion", params);
671     }
672 
673     /**
674      * Lets {@link MockIme} to call {@link InputConnection#commitCorrection(CorrectionInfo)} with
675      * the given parameters.
676      *
677      * <p>This triggers {@code getCurrentInputConnection().commitCorrection(correctionInfo)}.</p>
678      *
679      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
680      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
681      * value returned from the API.</p>
682      *
683      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
684      *
685      * @param correctionInfo to be passed as the {@code correctionInfo} parameter
686      * @return {@link ImeCommand} object that can be passed to
687      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
688      *         wait until this event is handled by {@link MockIme}
689      */
690     @NonNull
callCommitCorrection(@ullable CorrectionInfo correctionInfo)691     public ImeCommand callCommitCorrection(@Nullable CorrectionInfo correctionInfo) {
692         final Bundle params = new Bundle();
693         params.putParcelable("correctionInfo", correctionInfo);
694         return callCommandInternal("commitCorrection", params);
695     }
696 
697     /**
698      * Lets {@link MockIme} to call {@link InputConnection#setSelection(int, int)} with the given
699      * parameters.
700      *
701      * <p>This triggers {@code getCurrentInputConnection().setSelection(start, end)}.</p>
702      *
703      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
704      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
705      * value returned from the API.</p>
706      *
707      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
708      *
709      * @param start to be passed as the {@code start} parameter
710      * @param end to be passed as the {@code end} parameter
711      * @return {@link ImeCommand} object that can be passed to
712      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
713      *         wait until this event is handled by {@link MockIme}
714      */
715     @NonNull
callSetSelection(int start, int end)716     public ImeCommand callSetSelection(int start, int end) {
717         final Bundle params = new Bundle();
718         params.putInt("start", start);
719         params.putInt("end", end);
720         return callCommandInternal("setSelection", params);
721     }
722 
723     /**
724      * Lets {@link MockIme} to call {@link InputConnection#performEditorAction(int)} with the given
725      * parameters.
726      *
727      * <p>This triggers {@code getCurrentInputConnection().performEditorAction(editorAction)}.</p>
728      *
729      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
730      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
731      * value returned from the API.</p>
732      *
733      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
734      *
735      * @param editorAction to be passed as the {@code editorAction} parameter
736      * @return {@link ImeCommand} object that can be passed to
737      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
738      *         wait until this event is handled by {@link MockIme}
739      */
740     @NonNull
callPerformEditorAction(int editorAction)741     public ImeCommand callPerformEditorAction(int editorAction) {
742         final Bundle params = new Bundle();
743         params.putInt("editorAction", editorAction);
744         return callCommandInternal("performEditorAction", params);
745     }
746 
747     /**
748      * Lets {@link MockIme} to call {@link InputConnection#performContextMenuAction(int)} with the
749      * given parameters.
750      *
751      * <p>This triggers {@code getCurrentInputConnection().performContextMenuAction(id)}.</p>
752      *
753      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
754      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
755      * value returned from the API.</p>
756      *
757      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
758      *
759      * @param id to be passed as the {@code id} parameter
760      * @return {@link ImeCommand} object that can be passed to
761      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
762      *         wait until this event is handled by {@link MockIme}
763      */
764     @NonNull
callPerformContextMenuAction(int id)765     public ImeCommand callPerformContextMenuAction(int id) {
766         final Bundle params = new Bundle();
767         params.putInt("id", id);
768         return callCommandInternal("performContextMenuAction", params);
769     }
770 
771     /**
772      * Lets {@link MockIme} to call {@link InputConnection#beginBatchEdit()} with the given
773      * parameters.
774      *
775      * <p>This triggers {@code getCurrentInputConnection().beginBatchEdit()}.</p>
776      *
777      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
778      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
779      * value returned from the API.</p>
780      *
781      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
782      *
783      * @return {@link ImeCommand} object that can be passed to
784      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
785      *         wait until this event is handled by {@link MockIme}
786      */
787     @NonNull
callBeginBatchEdit()788     public ImeCommand callBeginBatchEdit() {
789         final Bundle params = new Bundle();
790         return callCommandInternal("beginBatchEdit", params);
791     }
792 
793     /**
794      * Lets {@link MockIme} to call {@link InputConnection#endBatchEdit()} with the given
795      * parameters.
796      *
797      * <p>This triggers {@code getCurrentInputConnection().endBatchEdit()}.</p>
798      *
799      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
800      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
801      * value returned from the API.</p>
802      *
803      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
804      *
805      * @return {@link ImeCommand} object that can be passed to
806      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
807      *         wait until this event is handled by {@link MockIme}
808      */
809     @NonNull
callEndBatchEdit()810     public ImeCommand callEndBatchEdit() {
811         final Bundle params = new Bundle();
812         return callCommandInternal("endBatchEdit", params);
813     }
814 
815     /**
816      * Lets {@link MockIme} to call {@link InputConnection#sendKeyEvent(KeyEvent)} with the given
817      * parameters.
818      *
819      * <p>This triggers {@code getCurrentInputConnection().sendKeyEvent(event)}.</p>
820      *
821      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
822      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
823      * value returned from the API.</p>
824      *
825      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
826      *
827      * @param event to be passed as the {@code event} parameter
828      * @return {@link ImeCommand} object that can be passed to
829      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
830      *         wait until this event is handled by {@link MockIme}
831      */
832     @NonNull
callSendKeyEvent(@ullable KeyEvent event)833     public ImeCommand callSendKeyEvent(@Nullable KeyEvent event) {
834         final Bundle params = new Bundle();
835         params.putParcelable("event", event);
836         return callCommandInternal("sendKeyEvent", params);
837     }
838 
839     /**
840      * Lets {@link MockIme} to call {@link InputConnection#performSpellCheck()}.
841      *
842      * <p>This triggers {@code getCurrentInputConnection().performSpellCheck()}.</p>
843      *
844      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
845 
846      * @return {@link ImeCommand} object that can be passed to
847      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
848      *         wait until this event is handled by {@link MockIme}
849      */
850     @NonNull
callPerformSpellCheck()851     public ImeCommand callPerformSpellCheck() {
852         return callCommandInternal("performSpellCheck", new Bundle());
853     }
854 
855     /**
856      * Lets {@link MockIme} to call {@link InputConnection#clearMetaKeyStates(int)} with the given
857      * parameters.
858      *
859      * <p>This triggers {@code getCurrentInputConnection().sendKeyEvent(event)}.</p>
860      *
861      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
862      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
863      * value returned from the API.</p>
864      *
865      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
866      *
867      * @param states to be passed as the {@code states} parameter
868      * @return {@link ImeCommand} object that can be passed to
869      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
870      *         wait until this event is handled by {@link MockIme}
871      */
872     @NonNull
callClearMetaKeyStates(int states)873     public ImeCommand callClearMetaKeyStates(int states) {
874         final Bundle params = new Bundle();
875         params.putInt("states", states);
876         return callCommandInternal("clearMetaKeyStates", params);
877     }
878 
879     /**
880      * Lets {@link MockIme} to call {@link InputConnection#reportFullscreenMode(boolean)} with the
881      * given parameters.
882      *
883      * <p>This triggers {@code getCurrentInputConnection().reportFullscreenMode(enabled)}.</p>
884      *
885      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
886      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
887      * value returned from the API.</p>
888      *
889      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
890      *
891      * @param enabled to be passed as the {@code enabled} parameter
892      * @return {@link ImeCommand} object that can be passed to
893      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
894      *         wait until this event is handled by {@link MockIme}
895      */
896     @NonNull
callReportFullscreenMode(boolean enabled)897     public ImeCommand callReportFullscreenMode(boolean enabled) {
898         final Bundle params = new Bundle();
899         params.putBoolean("enabled", enabled);
900         return callCommandInternal("reportFullscreenMode", params);
901     }
902 
903     /**
904      * Lets {@link MockIme} to call {@link InputConnection#performPrivateCommand(String, Bundle)}
905      * with the given parameters.
906      *
907      * <p>This triggers {@code getCurrentInputConnection().performPrivateCommand(action, data)}.</p>
908      *
909      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
910      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
911      * value returned from the API.</p>
912      *
913      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
914      *
915      * @param action to be passed as the {@code action} parameter
916      * @param data to be passed as the {@code data} parameter
917      * @return {@link ImeCommand} object that can be passed to
918      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
919      *         wait until this event is handled by {@link MockIme}
920      */
921     @NonNull
callPerformPrivateCommand(@ullable String action, Bundle data)922     public ImeCommand callPerformPrivateCommand(@Nullable String action, Bundle data) {
923         final Bundle params = new Bundle();
924         params.putString("action", action);
925         params.putBundle("data", data);
926         return callCommandInternal("performPrivateCommand", params);
927     }
928 
929     /**
930      * Lets {@link MockIme} to call {@link InputConnection#requestCursorUpdates(int)} with the given
931      * parameters.
932      *
933      * <p>This triggers {@code getCurrentInputConnection().requestCursorUpdates(cursorUpdateMode)}.
934      * </p>
935      *
936      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
937      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
938      * value returned from the API.</p>
939      *
940      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
941      *
942      * @param cursorUpdateMode to be passed as the {@code cursorUpdateMode} parameter
943      * @return {@link ImeCommand} object that can be passed to
944      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
945      *         wait until this event is handled by {@link MockIme}
946      */
947     @NonNull
callRequestCursorUpdates(int cursorUpdateMode)948     public ImeCommand callRequestCursorUpdates(int cursorUpdateMode) {
949         final Bundle params = new Bundle();
950         params.putInt("cursorUpdateMode", cursorUpdateMode);
951         return callCommandInternal("requestCursorUpdates", params);
952     }
953 
954     /**
955      * Lets {@link MockIme} to call {@link InputConnection#getHandler()} with the given parameters.
956      *
957      * <p>This triggers {@code getCurrentInputConnection().getHandler()}.</p>
958      *
959      * <p>Use {@link ImeEvent#isNullReturnValue()} for {@link ImeEvent} returned from
960      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
961      * value returned from the API was {@code null} or not.</p>
962      *
963      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
964      *
965      * @return {@link ImeCommand} object that can be passed to
966      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
967      *         wait until this event is handled by {@link MockIme}
968      */
969     @NonNull
callGetHandler()970     public ImeCommand callGetHandler() {
971         final Bundle params = new Bundle();
972         return callCommandInternal("getHandler", params);
973     }
974 
975     /**
976      * Lets {@link MockIme} to call {@link InputConnection#closeConnection()} with the given
977      * parameters.
978      *
979      * <p>This triggers {@code getCurrentInputConnection().closeConnection()}.</p>
980      *
981      * <p>Return value information is not available for this command.</p>
982      *
983      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
984      *
985      * @return {@link ImeCommand} object that can be passed to
986      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
987      *         wait until this event is handled by {@link MockIme}
988      */
989     @NonNull
callCloseConnection()990     public ImeCommand callCloseConnection() {
991         final Bundle params = new Bundle();
992         return callCommandInternal("closeConnection", params);
993     }
994 
995     /**
996      * Lets {@link MockIme} to call
997      * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} with the given
998      * parameters.
999      *
1000      * <p>This triggers
1001      * {@code getCurrentInputConnection().commitContent(inputContentInfo, flags, opts)}.</p>
1002      *
1003      * <p>Use {@link ImeEvent#getReturnBooleanValue()} for {@link ImeEvent} returned from
1004      * {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to see the
1005      * value returned from the API.</p>
1006      *
1007      * <p>This can be affected by {@link #memorizeCurrentInputConnection()}.</p>
1008      *
1009      * @param inputContentInfo to be passed as the {@code inputContentInfo} parameter
1010      * @param flags to be passed as the {@code flags} parameter
1011      * @param opts to be passed as the {@code opts} parameter
1012      * @return {@link ImeCommand} object that can be passed to
1013      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1014      *         wait until this event is handled by {@link MockIme}
1015      */
1016     @NonNull
callCommitContent(@onNull InputContentInfo inputContentInfo, int flags, @Nullable Bundle opts)1017     public ImeCommand callCommitContent(@NonNull InputContentInfo inputContentInfo, int flags,
1018             @Nullable Bundle opts) {
1019         final Bundle params = new Bundle();
1020         params.putParcelable("inputContentInfo", inputContentInfo);
1021         params.putInt("flags", flags);
1022         params.putBundle("opts", opts);
1023         return callCommandInternal("commitContent", params);
1024     }
1025 
1026     /**
1027      * Lets {@link MockIme} to call
1028      * {@link android.inputmethodservice.InputMethodService#setBackDisposition(int)} with the given
1029      * parameters.
1030      *
1031      * <p>This triggers {@code setBackDisposition(backDisposition)}.</p>
1032      *
1033      * @param backDisposition to be passed as the {@code backDisposition} parameter
1034      * @return {@link ImeCommand} object that can be passed to
1035      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1036      *         wait until this event is handled by {@link MockIme}
1037      */
1038     @NonNull
callSetBackDisposition(int backDisposition)1039     public ImeCommand callSetBackDisposition(int backDisposition) {
1040         final Bundle params = new Bundle();
1041         params.putInt("backDisposition", backDisposition);
1042         return callCommandInternal("setBackDisposition", params);
1043     }
1044 
1045     /**
1046      * Lets {@link MockIme} to call
1047      * {@link android.inputmethodservice.InputMethodService#requestHideSelf(int)} with the given
1048      * parameters.
1049      *
1050      * <p>This triggers {@code requestHideSelf(flags)}.</p>
1051      *
1052      * @param flags to be passed as the {@code flags} parameter
1053      * @return {@link ImeCommand} object that can be passed to
1054      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1055      *         wait until this event is handled by {@link MockIme}
1056      */
1057     @NonNull
callRequestHideSelf(int flags)1058     public ImeCommand callRequestHideSelf(int flags) {
1059         final Bundle params = new Bundle();
1060         params.putInt("flags", flags);
1061         return callCommandInternal("requestHideSelf", params);
1062     }
1063 
1064     /**
1065      * Lets {@link MockIme} to call
1066      * {@link android.inputmethodservice.InputMethodService#requestShowSelf(int)} with the given
1067      * parameters.
1068      *
1069      * <p>This triggers {@code requestShowSelf(flags)}.</p>
1070      *
1071      * @param flags to be passed as the {@code flags} parameter
1072      * @return {@link ImeCommand} object that can be passed to
1073      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1074      *         wait until this event is handled by {@link MockIme}
1075      */
1076     @NonNull
callRequestShowSelf(int flags)1077     public ImeCommand callRequestShowSelf(int flags) {
1078         final Bundle params = new Bundle();
1079         params.putInt("flags", flags);
1080         return callCommandInternal("requestShowSelf", params);
1081     }
1082 
1083     /**
1084      * Lets {@link MockIme} call
1085      * {@link android.inputmethodservice.InputMethodService#sendDownUpKeyEvents(int)} with the given
1086      * {@code keyEventCode}.
1087      *
1088      * @param keyEventCode to be passed as the {@code keyEventCode} parameter.
1089      * @return {@link ImeCommand} object that can be passed to
1090      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1091      *         wait until this event is handled by {@link MockIme}
1092      */
1093     @NonNull
callSendDownUpKeyEvents(int keyEventCode)1094     public ImeCommand callSendDownUpKeyEvents(int keyEventCode) {
1095         final Bundle params = new Bundle();
1096         params.putInt("keyEventCode", keyEventCode);
1097         return callCommandInternal("sendDownUpKeyEvents", params);
1098     }
1099 
1100     /**
1101      * Lets {@link MockIme} call
1102      * {@link android.content.pm.PackageManager#getApplicationInfo(String, int)} with the given
1103      * {@code packageName} and {@code flags}.
1104      *
1105      * @param packageName the package name to be passed to
1106      *                    {@link android.content.pm.PackageManager#getApplicationInfo(String, int)}.
1107      * @param flags the flags to be passed to
1108      *                    {@link android.content.pm.PackageManager#getApplicationInfo(String, int)}.
1109      * @return {@link ImeCommand} object that can be passed to
1110      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1111      *         wait until this event is handled by {@link MockIme}.
1112      */
1113     @NonNull
callGetApplicationInfo(@onNull String packageName, int flags)1114     public ImeCommand callGetApplicationInfo(@NonNull String packageName, int flags) {
1115         final Bundle params = new Bundle();
1116         params.putString("packageName", packageName);
1117         params.putInt("flags", flags);
1118         return callCommandInternal("getApplicationInfo", params);
1119     }
1120 
1121     @NonNull
callGetDisplayId()1122     public ImeCommand callGetDisplayId() {
1123         final Bundle params = new Bundle();
1124         return callCommandInternal("getDisplayId", params);
1125     }
1126 
1127     /**
1128      * Verifies {@code InputMethodService.getLayoutInflater().getContext()} is equal to
1129      * {@code InputMethodService.this}.
1130      *
1131      * @return {@link ImeCommand} object that can be passed to
1132      *         {@link ImeEventStreamTestUtils#expectCommand(ImeEventStream, ImeCommand, long)} to
1133      *         wait until this event is handled by {@link MockIme}
1134      */
1135     @NonNull
verifyLayoutInflaterContext()1136     public ImeCommand verifyLayoutInflaterContext() {
1137         final Bundle params = new Bundle();
1138         return callCommandInternal("verifyLayoutInflaterContext", params);
1139     }
1140 
1141     @NonNull
callSetHeight(int height)1142     public ImeCommand callSetHeight(int height) {
1143         final Bundle params = new Bundle();
1144         params.putInt("height", height);
1145         return callCommandInternal("setHeight", params);
1146     }
1147 
1148     @NonNull
callSetInlineSuggestionsExtras(@onNull Bundle bundle)1149     public ImeCommand callSetInlineSuggestionsExtras(@NonNull Bundle bundle) {
1150         return callCommandInternal("setInlineSuggestionsExtras", bundle);
1151     }
1152 
1153     @NonNull
callVerifyGetDisplay()1154     public ImeCommand callVerifyGetDisplay() {
1155         return callCommandInternal("verifyGetDisplay", new Bundle());
1156     }
1157 
1158     @NonNull
callVerifyGetWindowManager()1159     public ImeCommand callVerifyGetWindowManager() {
1160         return callCommandInternal("verifyGetWindowManager", new Bundle());
1161     }
1162 
1163     @NonNull
callVerifyGetViewConfiguration()1164     public ImeCommand callVerifyGetViewConfiguration() {
1165         return callCommandInternal("verifyGetViewConfiguration", new Bundle());
1166     }
1167 
1168     @NonNull
callVerifyGetGestureDetector()1169     public ImeCommand callVerifyGetGestureDetector() {
1170         return callCommandInternal("verifyGetGestureDetector", new Bundle());
1171     }
1172 
1173     @NonNull
callVerifyGetWindowManagerOnDisplayContext()1174     public ImeCommand callVerifyGetWindowManagerOnDisplayContext() {
1175         return callCommandInternal("verifyGetWindowManagerOnDisplayContext", new Bundle());
1176     }
1177 
1178     @NonNull
callVerifyGetViewConfigurationOnDisplayContext()1179     public ImeCommand callVerifyGetViewConfigurationOnDisplayContext() {
1180         return callCommandInternal("verifyGetViewConfigurationOnDisplayContext", new Bundle());
1181     }
1182 
1183     @NonNull
callVerifyGetGestureDetectorOnDisplayContext()1184     public ImeCommand callVerifyGetGestureDetectorOnDisplayContext() {
1185         return callCommandInternal("verifyGetGestureDetectorOnDisplayContext", new Bundle());
1186     }
1187 }
1188