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