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