1 /* 2 * Copyright (C) 2007-2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package android.view.inputmethod; 18 19 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; 20 import static android.Manifest.permission.WRITE_SECURE_SETTINGS; 21 import static android.util.imetracing.ImeTracing.PROTO_ARG; 22 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID; 23 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO; 24 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER; 25 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION; 26 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION_CALL; 27 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER; 28 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL; 29 import static android.view.inputmethod.InputMethodManagerProto.ACTIVE; 30 import static android.view.inputmethod.InputMethodManagerProto.CUR_ID; 31 import static android.view.inputmethod.InputMethodManagerProto.FULLSCREEN_MODE; 32 import static android.view.inputmethod.InputMethodManagerProto.SERVED_CONNECTING; 33 34 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; 35 import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION; 36 37 import android.annotation.DisplayContext; 38 import android.annotation.DrawableRes; 39 import android.annotation.NonNull; 40 import android.annotation.Nullable; 41 import android.annotation.RequiresFeature; 42 import android.annotation.RequiresPermission; 43 import android.annotation.SystemService; 44 import android.annotation.TestApi; 45 import android.annotation.UserIdInt; 46 import android.app.ActivityThread; 47 import android.compat.annotation.UnsupportedAppUsage; 48 import android.content.ComponentName; 49 import android.content.ContentResolver; 50 import android.content.Context; 51 import android.content.pm.PackageManager; 52 import android.graphics.Rect; 53 import android.inputmethodservice.InputMethodService; 54 import android.os.Binder; 55 import android.os.Build; 56 import android.os.Bundle; 57 import android.os.Handler; 58 import android.os.IBinder; 59 import android.os.Looper; 60 import android.os.Message; 61 import android.os.Process; 62 import android.os.RemoteException; 63 import android.os.ResultReceiver; 64 import android.os.ServiceManager; 65 import android.os.ServiceManager.ServiceNotFoundException; 66 import android.os.Trace; 67 import android.os.UserHandle; 68 import android.provider.Settings; 69 import android.text.style.SuggestionSpan; 70 import android.util.Log; 71 import android.util.Pools.Pool; 72 import android.util.Pools.SimplePool; 73 import android.util.PrintWriterPrinter; 74 import android.util.Printer; 75 import android.util.SparseArray; 76 import android.util.imetracing.ImeTracing; 77 import android.util.proto.ProtoOutputStream; 78 import android.view.Display; 79 import android.view.ImeFocusController; 80 import android.view.ImeInsetsSourceConsumer; 81 import android.view.InputChannel; 82 import android.view.InputEvent; 83 import android.view.InputEventSender; 84 import android.view.KeyEvent; 85 import android.view.View; 86 import android.view.ViewRootImpl; 87 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 88 import android.view.autofill.AutofillManager; 89 90 import com.android.internal.annotations.GuardedBy; 91 import com.android.internal.inputmethod.InputMethodDebug; 92 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry; 93 import com.android.internal.inputmethod.SoftInputShowHideReason; 94 import com.android.internal.inputmethod.StartInputFlags; 95 import com.android.internal.inputmethod.StartInputReason; 96 import com.android.internal.inputmethod.UnbindReason; 97 import com.android.internal.os.SomeArgs; 98 import com.android.internal.view.IInputConnectionWrapper; 99 import com.android.internal.view.IInputContext; 100 import com.android.internal.view.IInputMethodClient; 101 import com.android.internal.view.IInputMethodManager; 102 import com.android.internal.view.IInputMethodSession; 103 import com.android.internal.view.InputBindResult; 104 105 import java.io.FileDescriptor; 106 import java.io.PrintWriter; 107 import java.lang.reflect.Proxy; 108 import java.util.Arrays; 109 import java.util.Collections; 110 import java.util.Comparator; 111 import java.util.List; 112 import java.util.Map; 113 import java.util.Objects; 114 import java.util.concurrent.CountDownLatch; 115 import java.util.concurrent.TimeUnit; 116 117 /** 118 * Central system API to the overall input method framework (IMF) architecture, 119 * which arbitrates interaction between applications and the current input method. 120 * 121 * <p>Topics covered here: 122 * <ol> 123 * <li><a href="#ArchitectureOverview">Architecture Overview</a> 124 * <li><a href="#Applications">Applications</a> 125 * <li><a href="#InputMethods">Input Methods</a> 126 * <li><a href="#Security">Security</a> 127 * </ol> 128 * 129 * <a name="ArchitectureOverview"></a> 130 * <h3>Architecture Overview</h3> 131 * 132 * <p>There are three primary parties involved in the input method 133 * framework (IMF) architecture:</p> 134 * 135 * <ul> 136 * <li> The <strong>input method manager</strong> as expressed by this class 137 * is the central point of the system that manages interaction between all 138 * other parts. It is expressed as the client-side API here which exists 139 * in each application context and communicates with a global system service 140 * that manages the interaction across all processes. 141 * <li> An <strong>input method (IME)</strong> implements a particular 142 * interaction model allowing the user to generate text. The system binds 143 * to the current input method that is in use, causing it to be created and run, 144 * and tells it when to hide and show its UI. Only one IME is running at a time. 145 * <li> Multiple <strong>client applications</strong> arbitrate with the input 146 * method manager for input focus and control over the state of the IME. Only 147 * one such client is ever active (working with the IME) at a time. 148 * </ul> 149 * 150 * 151 * <a name="Applications"></a> 152 * <h3>Applications</h3> 153 * 154 * <p>In most cases, applications that are using the standard 155 * {@link android.widget.TextView} or its subclasses will have little they need 156 * to do to work well with soft input methods. The main things you need to 157 * be aware of are:</p> 158 * 159 * <ul> 160 * <li> Properly set the {@link android.R.attr#inputType} in your editable 161 * text views, so that the input method will have enough context to help the 162 * user in entering text into them. 163 * <li> Deal well with losing screen space when the input method is 164 * displayed. Ideally an application should handle its window being resized 165 * smaller, but it can rely on the system performing panning of the window 166 * if needed. You should set the {@link android.R.attr#windowSoftInputMode} 167 * attribute on your activity or the corresponding values on windows you 168 * create to help the system determine whether to pan or resize (it will 169 * try to determine this automatically but may get it wrong). 170 * <li> You can also control the preferred soft input state (open, closed, etc) 171 * for your window using the same {@link android.R.attr#windowSoftInputMode} 172 * attribute. 173 * </ul> 174 * 175 * <p>More finer-grained control is available through the APIs here to directly 176 * interact with the IMF and its IME -- either showing or hiding the input 177 * area, letting the user pick an input method, etc.</p> 178 * 179 * <p>For the rare people amongst us writing their own text editors, you 180 * will need to implement {@link android.view.View#onCreateInputConnection} 181 * to return a new instance of your own {@link InputConnection} interface 182 * allowing the IME to interact with your editor.</p> 183 * 184 * 185 * <a name="InputMethods"></a> 186 * <h3>Input Methods</h3> 187 * 188 * <p>An input method (IME) is implemented 189 * as a {@link android.app.Service}, typically deriving from 190 * {@link android.inputmethodservice.InputMethodService}. It must provide 191 * the core {@link InputMethod} interface, though this is normally handled by 192 * {@link android.inputmethodservice.InputMethodService} and implementors will 193 * only need to deal with the higher-level API there.</p> 194 * 195 * See the {@link android.inputmethodservice.InputMethodService} class for 196 * more information on implementing IMEs. 197 * 198 * 199 * <a name="Security"></a> 200 * <h3>Security</h3> 201 * 202 * <p>There are a lot of security issues associated with input methods, 203 * since they essentially have freedom to completely drive the UI and monitor 204 * everything the user enters. The Android input method framework also allows 205 * arbitrary third party IMEs, so care must be taken to restrict their 206 * selection and interactions.</p> 207 * 208 * <p>Here are some key points about the security architecture behind the 209 * IMF:</p> 210 * 211 * <ul> 212 * <li> <p>Only the system is allowed to directly access an IME's 213 * {@link InputMethod} interface, via the 214 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission. This is 215 * enforced in the system by not binding to an input method service that does 216 * not require this permission, so the system can guarantee no other untrusted 217 * clients are accessing the current input method outside of its control.</p> 218 * 219 * <li> <p>There may be many client processes of the IMF, but only one may 220 * be active at a time. The inactive clients can not interact with key 221 * parts of the IMF through the mechanisms described below.</p> 222 * 223 * <li> <p>Clients of an input method are only given access to its 224 * {@link InputMethodSession} interface. One instance of this interface is 225 * created for each client, and only calls from the session associated with 226 * the active client will be processed by the current IME. This is enforced 227 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal 228 * IMEs, but must be explicitly handled by an IME that is customizing the 229 * raw {@link InputMethodSession} implementation.</p> 230 * 231 * <li> <p>Only the active client's {@link InputConnection} will accept 232 * operations. The IMF tells each client process whether it is active, and 233 * the framework enforces that in inactive processes calls on to the current 234 * InputConnection will be ignored. This ensures that the current IME can 235 * only deliver events and text edits to the UI that the user sees as 236 * being in focus.</p> 237 * 238 * <li> <p>An IME can never interact with an {@link InputConnection} while 239 * the screen is off. This is enforced by making all clients inactive while 240 * the screen is off, and prevents bad IMEs from driving the UI when the user 241 * can not be aware of its behavior.</p> 242 * 243 * <li> <p>A client application can ask that the system let the user pick a 244 * new IME, but can not programmatically switch to one itself. This avoids 245 * malicious applications from switching the user to their own IME, which 246 * remains running when the user navigates away to another application. An 247 * IME, on the other hand, <em>is</em> allowed to programmatically switch 248 * the system to another IME, since it already has full control of user 249 * input.</p> 250 * 251 * <li> <p>The user must explicitly enable a new IME in settings before 252 * they can switch to it, to confirm with the system that they know about it 253 * and want to make it available for use.</p> 254 * </ul> 255 */ 256 @SystemService(Context.INPUT_METHOD_SERVICE) 257 @RequiresFeature(PackageManager.FEATURE_INPUT_METHODS) 258 public final class InputMethodManager { 259 static final boolean DEBUG = false; 260 static final String TAG = "InputMethodManager"; 261 262 static final String PENDING_EVENT_COUNTER = "aq:imm"; 263 264 private static final int NOT_A_SUBTYPE_ID = -1; 265 266 /** 267 * A constant that represents Voice IME. 268 * 269 * @see InputMethodSubtype#getMode() 270 */ 271 private static final String SUBTYPE_MODE_VOICE = "voice"; 272 273 /** 274 * Ensures that {@link #sInstance} becomes non-{@code null} for application that have directly 275 * or indirectly relied on {@link #sInstance} via reflection or something like that. 276 * 277 * <p>Here are scenarios we know and there could be more scenarios we are not 278 * aware of right know.</p> 279 * 280 * <ul> 281 * <li>Apps that directly access {@link #sInstance} via reflection, which is currently 282 * allowed because of {@link UnsupportedAppUsage} annotation. Currently 283 * {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that 284 * {@link #sInstance} is not {@code null} when such an app is accessing it, but removing 285 * that code from {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal 286 * untested code paths in their apps, which probably happen in an early startup time of that 287 * app.</li> 288 * <li>Apps that directly access {@link #peekInstance()} via reflection, which is currently 289 * allowed because of {@link UnsupportedAppUsage} annotation. Currently 290 * {@link android.view.WindowManagerGlobal#getWindowSession()} is likely to guarantee that 291 * {@link #peekInstance()} returns non-{@code null} object when such an app is calling 292 * {@link #peekInstance()}, but removing that code from 293 * {@link android.view.WindowManagerGlobal#getWindowSession()} can reveal untested code 294 * paths in their apps, which probably happen in an early startup time of that app. The good 295 * news is that unlike {@link #sInstance}'s case we can at least work around this scenario 296 * by changing the semantics of {@link #peekInstance()}, which is currently defined as 297 * "retrieve the global {@link InputMethodManager} instance, if it exists" to something that 298 * always returns non-{@code null} {@link InputMethodManager}. However, introducing such an 299 * workaround can also trigger different compatibility issues if {@link #peekInstance()} was 300 * called before {@link android.view.WindowManagerGlobal#getWindowSession()} and it expected 301 * {@link #peekInstance()} to return {@code null} as written in the JavaDoc.</li> 302 * </ul> 303 * 304 * <p>Since this is purely a compatibility hack, this method must be used only from 305 * {@link android.view.WindowManagerGlobal#getWindowSession()} and {@link #getInstance()}.</p> 306 * 307 * <p>TODO(Bug 116157766): Remove this method once we clean up {@link UnsupportedAppUsage}.</p> 308 * @hide 309 */ ensureDefaultInstanceForDefaultDisplayIfNecessary()310 public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() { 311 forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper()); 312 } 313 314 private static final Object sLock = new Object(); 315 316 /** 317 * @deprecated This cannot be compatible with multi-display. Please do not use this. 318 */ 319 @Deprecated 320 @GuardedBy("sLock") 321 @UnsupportedAppUsage 322 static InputMethodManager sInstance; 323 324 /** 325 * Global map between display to {@link InputMethodManager}. 326 * 327 * <p>Currently this map works like a so-called leaky singleton. Once an instance is registered 328 * for the associated display ID, that instance will never be garbage collected.</p> 329 * 330 * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p> 331 */ 332 @GuardedBy("sLock") 333 private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>(); 334 335 /** 336 * Timeout in milliseconds for delivering a key to an IME. 337 */ 338 static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500; 339 340 /** @hide */ 341 public static final int DISPATCH_IN_PROGRESS = -1; 342 343 /** @hide */ 344 public static final int DISPATCH_NOT_HANDLED = 0; 345 346 /** @hide */ 347 public static final int DISPATCH_HANDLED = 1; 348 349 /** @hide */ 350 public static final int SHOW_IM_PICKER_MODE_AUTO = 0; 351 /** @hide */ 352 public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1; 353 /** @hide */ 354 public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2; 355 356 @UnsupportedAppUsage 357 final IInputMethodManager mService; 358 final Looper mMainLooper; 359 360 // For scheduling work on the main thread. This also serves as our 361 // global lock. 362 // Remark on @UnsupportedAppUsage: there were context leaks on old versions 363 // of android (b/37043700), so developers used this field to perform manual clean up. 364 // Leaks were fixed, hacks were backported to AppCompatActivity, 365 // so an access to the field is closed. 366 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 367 final H mH; 368 369 // Our generic input connection if the current target does not have its own. 370 final IInputContext mIInputContext; 371 372 private final int mDisplayId; 373 374 /** 375 * True if this input method client is active, initially false. 376 */ 377 boolean mActive = false; 378 379 /** 380 * {@code true} if next {@link ImeFocusController#onPostWindowFocus} needs to 381 * restart input. 382 */ 383 private boolean mRestartOnNextWindowFocus = true; 384 385 /** 386 * As reported by IME through InputConnection. 387 */ 388 boolean mFullscreenMode; 389 390 // ----------------------------------------------------------- 391 392 /** 393 * This is the root view of the overall window that currently has input 394 * method focus. 395 */ 396 @GuardedBy("mH") 397 ViewRootImpl mCurRootView; 398 /** 399 * This is set when we are in the process of connecting, to determine 400 * when we have actually finished. 401 */ 402 boolean mServedConnecting; 403 /** 404 * This is non-null when we have connected the served view; it holds 405 * the attributes that were last retrieved from the served view and given 406 * to the input connection. 407 */ 408 EditorInfo mCurrentTextBoxAttribute; 409 /** 410 * The InputConnection that was last retrieved from the served view. 411 */ 412 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 413 IInputConnectionWrapper mServedInputConnectionWrapper; 414 /** 415 * The completions that were last provided by the served view. 416 */ 417 CompletionInfo[] mCompletions; 418 419 // Cursor position on the screen. 420 @UnsupportedAppUsage 421 Rect mTmpCursorRect = new Rect(); 422 @UnsupportedAppUsage 423 Rect mCursorRect = new Rect(); 424 int mCursorSelStart; 425 int mCursorSelEnd; 426 int mCursorCandStart; 427 int mCursorCandEnd; 428 429 /** 430 * The instance that has previously been sent to the input method. 431 */ 432 private CursorAnchorInfo mCursorAnchorInfo = null; 433 434 /** 435 * As reported by {@link InputBindResult}. This value is determined by 436 * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}. 437 */ 438 @GuardedBy("mH") 439 private boolean mIsInputMethodSuppressingSpellChecker = false; 440 441 // ----------------------------------------------------------- 442 443 /** 444 * Sequence number of this binding, as returned by the server. 445 */ 446 int mBindSequence = -1; 447 /** 448 * ID of the method we are bound to. 449 */ 450 @UnsupportedAppUsage 451 String mCurId; 452 453 /** 454 * Kept for {@link UnsupportedAppUsage}. Not officially maintained. 455 * 456 * @deprecated New code should use {@link #mCurrentInputMethodSession}. 457 */ 458 @Deprecated 459 @GuardedBy("mH") 460 @Nullable 461 @UnsupportedAppUsage 462 IInputMethodSession mCurMethod; 463 464 /** 465 * Encapsulates IPCs to the currently connected InputMethodService. 466 */ 467 @Nullable 468 @GuardedBy("mH") 469 private InputMethodSessionWrapper mCurrentInputMethodSession = null; 470 471 InputChannel mCurChannel; 472 ImeInputEventSender mCurSender; 473 474 private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0; 475 476 /** 477 * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. 478 */ 479 private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; 480 481 /** 482 * Applies the IME visibility and listens for other state changes. 483 */ 484 private ImeInsetsSourceConsumer mImeInsetsConsumer; 485 486 final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20); 487 final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20); 488 489 final DelegateImpl mDelegate = new DelegateImpl(); 490 491 // ----------------------------------------------------------- 492 493 static final int MSG_DUMP = 1; 494 static final int MSG_BIND = 2; 495 static final int MSG_UNBIND = 3; 496 static final int MSG_SET_ACTIVE = 4; 497 static final int MSG_SEND_INPUT_EVENT = 5; 498 static final int MSG_TIMEOUT_INPUT_EVENT = 6; 499 static final int MSG_FLUSH_INPUT_EVENT = 7; 500 static final int MSG_REPORT_FULLSCREEN_MODE = 10; 501 isAutofillUIShowing(View servedView)502 private static boolean isAutofillUIShowing(View servedView) { 503 AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class); 504 return afm != null && afm.isAutofillUiShowing(); 505 } 506 507 /** 508 * Returns fallback {@link InputMethodManager} if the called one is not likely to be compatible 509 * with the given {@code view}. 510 * 511 * @param view {@link View} to be checked. 512 * @return {@code null} when it is unnecessary (or impossible) to use fallback 513 * {@link InputMethodManager} to which IME API calls need to be re-dispatched. 514 * Non-{@code null} {@link InputMethodManager} if this method believes it'd be safer to 515 * re-dispatch IME APIs calls on it. 516 */ 517 @Nullable getFallbackInputMethodManagerIfNecessary(@ullable View view)518 private InputMethodManager getFallbackInputMethodManagerIfNecessary(@Nullable View view) { 519 if (view == null) { 520 return null; 521 } 522 // As evidenced in Bug 118341760, view.getViewRootImpl().getDisplayId() is supposed to be 523 // more reliable to determine with which display the given view is interacting than 524 // view.getContext().getDisplayId() / view.getContext().getSystemService(), which can be 525 // easily messed up by app developers (or library authors) by creating inconsistent 526 // ContextWrapper objects that re-dispatch those methods to other Context such as 527 // ApplicationContext. 528 final ViewRootImpl viewRootImpl = view.getViewRootImpl(); 529 if (viewRootImpl == null) { 530 return null; 531 } 532 final int viewRootDisplayId = viewRootImpl.getDisplayId(); 533 if (viewRootDisplayId == mDisplayId) { 534 // Expected case. Good to go. 535 return null; 536 } 537 final InputMethodManager fallbackImm = 538 viewRootImpl.mContext.getSystemService(InputMethodManager.class); 539 if (fallbackImm == null) { 540 Log.v(TAG, "b/117267690: Failed to get non-null fallback IMM. view=" + view); 541 return null; 542 } 543 if (fallbackImm.mDisplayId != viewRootDisplayId) { 544 Log.v(TAG, "b/117267690: Failed to get fallback IMM with expected displayId=" 545 + viewRootDisplayId + " actual IMM#displayId=" + fallbackImm.mDisplayId 546 + " view=" + view); 547 return null; 548 } 549 Log.v(TAG, "b/117267690: Display ID mismatch found." 550 + " ViewRootImpl displayId=" + viewRootDisplayId 551 + " InputMethodManager displayId=" + mDisplayId 552 + ". Use the right InputMethodManager instance to avoid performance overhead.", 553 new Throwable()); 554 return fallbackImm; 555 } 556 canStartInput(View servedView)557 private static boolean canStartInput(View servedView) { 558 // We can start input ether the servedView has window focus 559 // or the activity is showing autofill ui. 560 return servedView.hasWindowFocus() || isAutofillUIShowing(servedView); 561 } 562 563 /** 564 * Reports whether the IME is currently perceptible or not, according to the leash applied by 565 * {@link android.view.WindowInsetsController}. 566 * @hide 567 */ reportPerceptible(IBinder windowToken, boolean perceptible)568 public void reportPerceptible(IBinder windowToken, boolean perceptible) { 569 try { 570 mService.reportPerceptibleAsync(windowToken, perceptible); 571 } catch (RemoteException e) { 572 throw e.rethrowFromSystemServer(); 573 } 574 } 575 576 private final class DelegateImpl implements 577 ImeFocusController.InputMethodManagerDelegate { 578 /** 579 * Used by {@link ImeFocusController} to start input connection. 580 */ 581 @Override startInput(@tartInputReason int startInputReason, View focusedView, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)582 public boolean startInput(@StartInputReason int startInputReason, View focusedView, 583 @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, 584 int windowFlags) { 585 final View servedView; 586 ImeTracing.getInstance().triggerClientDump( 587 "InputMethodManager.DelegateImpl#startInput", InputMethodManager.this, 588 null /* icProto */); 589 synchronized (mH) { 590 mCurrentTextBoxAttribute = null; 591 mCompletions = null; 592 mServedConnecting = true; 593 servedView = getServedViewLocked(); 594 } 595 return startInputInner(startInputReason, 596 focusedView != null ? focusedView.getWindowToken() : null, startInputFlags, 597 softInputMode, windowFlags); 598 } 599 600 /** 601 * Used by {@link ImeFocusController} to finish input connection. 602 */ 603 @Override finishInput()604 public void finishInput() { 605 ImeTracing.getInstance().triggerClientDump( 606 "InputMethodManager.DelegateImpl#finishInput", InputMethodManager.this, 607 null /* icProto */); 608 synchronized (mH) { 609 finishInputLocked(); 610 } 611 } 612 613 /** 614 * Used by {@link ImeFocusController} to finish input connection and callback 615 * {@link InputMethodService#onFinishInput()}. 616 * 617 * This method is especially for when ImeFocusController received device screen-off event to 618 * ensure the entire finish input connection and the connection lifecycle callback to 619 * IME can be done for security concern. 620 */ 621 @Override finishInputAndReportToIme()622 public void finishInputAndReportToIme() { 623 synchronized (mH) { 624 finishInputLocked(); 625 if (mCurrentInputMethodSession != null) { 626 mCurrentInputMethodSession.finishInput(); 627 } 628 } 629 } 630 631 /** 632 * Used by {@link ImeFocusController} to hide current input method editor. 633 */ 634 @Override closeCurrentIme()635 public void closeCurrentIme() { 636 closeCurrentInput(); 637 } 638 639 /** 640 * For {@link ImeFocusController} to start input asynchronously when focus gain. 641 */ 642 @Override startInputAsyncOnWindowFocusGain(View focusedView, @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus)643 public void startInputAsyncOnWindowFocusGain(View focusedView, 644 @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) { 645 int startInputFlags = getStartInputFlags(focusedView, 0); 646 startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS; 647 648 ImeTracing.getInstance().triggerClientDump( 649 "InputMethodManager.DelegateImpl#startInputAsyncOnWindowFocusGain", 650 InputMethodManager.this, null /* icProto */); 651 652 final ImeFocusController controller = getFocusController(); 653 if (controller == null) { 654 return; 655 } 656 if (controller.checkFocus(forceNewFocus, false)) { 657 // We need to restart input on the current focus view. This 658 // should be done in conjunction with telling the system service 659 // about the window gaining focus, to help make the transition 660 // smooth. 661 if (startInput(StartInputReason.WINDOW_FOCUS_GAIN, 662 focusedView, startInputFlags, softInputMode, windowFlags)) { 663 return; 664 } 665 } 666 667 synchronized (mH) { 668 // For some reason we didn't do a startInput + windowFocusGain, so 669 // we'll just do a window focus gain and call it a day. 670 try { 671 View servedView = controller.getServedView(); 672 boolean nextFocusHasConnection = servedView != null && servedView == focusedView 673 && hasActiveConnection(focusedView); 674 if (DEBUG) { 675 Log.v(TAG, "Reporting focus gain, without startInput" 676 + ", nextFocusIsServedView=" + nextFocusHasConnection); 677 } 678 679 final int startInputReason = nextFocusHasConnection 680 ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION 681 : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION; 682 // ignore the result 683 mService.startInputOrWindowGainedFocus( 684 startInputReason, mClient, 685 focusedView.getWindowToken(), startInputFlags, softInputMode, 686 windowFlags, 687 null, 688 null, 689 0 /* missingMethodFlags */, 690 mCurRootView.mContext.getApplicationInfo().targetSdkVersion); 691 } catch (RemoteException e) { 692 throw e.rethrowFromSystemServer(); 693 } 694 } 695 } 696 697 /** 698 * Used by {@link ImeFocusController} to finish current composing text. 699 */ 700 @Override finishComposingText()701 public void finishComposingText() { 702 if (mServedInputConnectionWrapper != null) { 703 mServedInputConnectionWrapper.finishComposingText(); 704 } 705 } 706 707 /** 708 * Used for {@link ImeFocusController} to set the current focused root view. 709 */ 710 @Override setCurrentRootView(ViewRootImpl rootView)711 public void setCurrentRootView(ViewRootImpl rootView) { 712 synchronized (mH) { 713 mCurRootView = rootView; 714 } 715 } 716 717 /** 718 * Used for {@link ImeFocusController} to return if the root view from the 719 * controller is this {@link InputMethodManager} currently focused. 720 * TODO: Address event-order problem when get current root view in multi-threads. 721 */ 722 @Override isCurrentRootView(ViewRootImpl rootView)723 public boolean isCurrentRootView(ViewRootImpl rootView) { 724 synchronized (mH) { 725 return mCurRootView == rootView; 726 } 727 } 728 729 /** 730 * For {@link ImeFocusController#checkFocus} if needed to force check new focus. 731 */ 732 @Override isRestartOnNextWindowFocus(boolean reset)733 public boolean isRestartOnNextWindowFocus(boolean reset) { 734 final boolean result = mRestartOnNextWindowFocus; 735 if (reset) { 736 mRestartOnNextWindowFocus = false; 737 } 738 return result; 739 } 740 741 /** 742 * Checks whether the active input connection (if any) is for the given view. 743 * 744 * TODO(b/182259171): Clean-up hasActiveConnection to simplify the logic. 745 * 746 * Note that this method is only intended for restarting input after focus gain 747 * (e.g. b/160391516), DO NOT leverage this method to do another check. 748 */ 749 @Override hasActiveConnection(View view)750 public boolean hasActiveConnection(View view) { 751 synchronized (mH) { 752 if (!hasServedByInputMethodLocked(view) 753 || mCurrentInputMethodSession == null) { 754 return false; 755 } 756 757 return mServedInputConnectionWrapper != null 758 && mServedInputConnectionWrapper.isActive() 759 && mServedInputConnectionWrapper.getServedView() == view; 760 } 761 } 762 } 763 764 /** @hide */ getDelegate()765 public DelegateImpl getDelegate() { 766 return mDelegate; 767 } 768 769 /** 770 * Checks whether the active input connection (if any) is for the given view. 771 * 772 * @hide 773 * @see ImeFocusController#getImmDelegate()#hasActiveInputConnection(View) 774 */ 775 @TestApi hasActiveInputConnection(@ullable View view)776 public boolean hasActiveInputConnection(@Nullable View view) { 777 return mDelegate.hasActiveConnection(view); 778 } 779 getServedViewLocked()780 private View getServedViewLocked() { 781 return mCurRootView != null ? mCurRootView.getImeFocusController().getServedView() : null; 782 } 783 getNextServedViewLocked()784 private View getNextServedViewLocked() { 785 return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedView() 786 : null; 787 } 788 setServedViewLocked(View view)789 private void setServedViewLocked(View view) { 790 if (mCurRootView != null) { 791 mCurRootView.getImeFocusController().setServedView(view); 792 } 793 } 794 setNextServedViewLocked(View view)795 private void setNextServedViewLocked(View view) { 796 if (mCurRootView != null) { 797 mCurRootView.getImeFocusController().setNextServedView(view); 798 } 799 } 800 getFocusController()801 private ImeFocusController getFocusController() { 802 synchronized (mH) { 803 if (mCurRootView != null) { 804 return mCurRootView.getImeFocusController(); 805 } 806 return null; 807 } 808 } 809 810 /** 811 * Returns {@code true} when the given view has been served by Input Method. 812 */ hasServedByInputMethodLocked(View view)813 private boolean hasServedByInputMethodLocked(View view) { 814 final View servedView = getServedViewLocked(); 815 return (servedView == view 816 || (servedView != null && servedView.checkInputConnectionProxy(view))); 817 } 818 819 class H extends Handler { H(Looper looper)820 H(Looper looper) { 821 super(looper, null, true); 822 } 823 824 @Override handleMessage(Message msg)825 public void handleMessage(Message msg) { 826 switch (msg.what) { 827 case MSG_DUMP: { 828 SomeArgs args = (SomeArgs)msg.obj; 829 try { 830 doDump((FileDescriptor)args.arg1, 831 (PrintWriter)args.arg2, (String[])args.arg3); 832 } catch (RuntimeException e) { 833 ((PrintWriter)args.arg2).println("Exception: " + e); 834 } 835 synchronized (args.arg4) { 836 ((CountDownLatch)args.arg4).countDown(); 837 } 838 args.recycle(); 839 return; 840 } 841 case MSG_BIND: { 842 final InputBindResult res = (InputBindResult)msg.obj; 843 if (DEBUG) { 844 Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id); 845 } 846 synchronized (mH) { 847 if (mBindSequence < 0 || mBindSequence != res.sequence) { 848 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence 849 + ", given seq=" + res.sequence); 850 if (res.channel != null && res.channel != mCurChannel) { 851 res.channel.dispose(); 852 } 853 return; 854 } 855 856 mRequestUpdateCursorAnchorInfoMonitorMode = 857 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; 858 859 setInputChannelLocked(res.channel); 860 mCurMethod = res.method; // for @UnsupportedAppUsage 861 mCurrentInputMethodSession = 862 InputMethodSessionWrapper.createOrNull(res.method); 863 mCurId = res.id; 864 mBindSequence = res.sequence; 865 mIsInputMethodSuppressingSpellChecker = 866 res.isInputMethodSuppressingSpellChecker; 867 } 868 startInputInner(StartInputReason.BOUND_TO_IMMS, null, 0, 0, 0); 869 return; 870 } 871 case MSG_UNBIND: { 872 final int sequence = msg.arg1; 873 @UnbindReason 874 final int reason = msg.arg2; 875 if (DEBUG) { 876 Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence + 877 " reason=" + InputMethodDebug.unbindReasonToString(reason)); 878 } 879 final boolean startInput; 880 synchronized (mH) { 881 if (mBindSequence != sequence) { 882 return; 883 } 884 clearBindingLocked(); 885 // If we were actively using the last input method, then 886 // we would like to re-connect to the next input method. 887 final View servedView = getServedViewLocked(); 888 if (servedView != null && servedView.isFocused()) { 889 mServedConnecting = true; 890 } 891 startInput = mActive; 892 } 893 if (startInput) { 894 startInputInner( 895 StartInputReason.UNBOUND_FROM_IMMS, null, 0, 0, 0); 896 } 897 return; 898 } 899 case MSG_SET_ACTIVE: { 900 final boolean active = msg.arg1 != 0; 901 final boolean fullscreen = msg.arg2 != 0; 902 final boolean reportToImeController = msg.obj != null && (boolean) msg.obj; 903 if (DEBUG) { 904 Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive); 905 } 906 synchronized (mH) { 907 mActive = active; 908 mFullscreenMode = fullscreen; 909 910 // Report active state to ImeFocusController to handle IME input 911 // connection lifecycle callback when it allowed. 912 final ImeFocusController controller = getFocusController(); 913 final View rootView = mCurRootView != null ? mCurRootView.getView() : null; 914 if (controller != null && rootView != null && reportToImeController) { 915 rootView.post(() -> controller.onInteractiveChanged(active)); 916 return; 917 } 918 919 if (!active) { 920 // Some other client has starting using the IME, so note 921 // that this happened and make sure our own editor's 922 // state is reset. 923 mRestartOnNextWindowFocus = true; 924 try { 925 // Note that finishComposingText() is allowed to run 926 // even when we are not active. 927 mIInputContext.finishComposingText(); 928 } catch (RemoteException e) { 929 } 930 } 931 // Check focus again in case that "onWindowFocus" is called before 932 // handling this message. 933 final View servedView = getServedViewLocked(); 934 if (servedView != null && canStartInput(servedView)) { 935 if (mCurRootView != null && mCurRootView.getImeFocusController() 936 .checkFocus(mRestartOnNextWindowFocus, false)) { 937 final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS 938 : StartInputReason.DEACTIVATED_BY_IMMS; 939 mDelegate.startInput(reason, null, 0, 0, 0); 940 } 941 } 942 } 943 return; 944 } 945 case MSG_SEND_INPUT_EVENT: { 946 sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj); 947 return; 948 } 949 case MSG_TIMEOUT_INPUT_EVENT: { 950 finishedInputEvent(msg.arg1, false, true); 951 return; 952 } 953 case MSG_FLUSH_INPUT_EVENT: { 954 finishedInputEvent(msg.arg1, false, false); 955 return; 956 } 957 case MSG_REPORT_FULLSCREEN_MODE: { 958 final boolean fullscreen = msg.arg1 != 0; 959 InputConnection ic = null; 960 synchronized (mH) { 961 mFullscreenMode = fullscreen; 962 if (mServedInputConnectionWrapper != null) { 963 ic = mServedInputConnectionWrapper.getInputConnection(); 964 } 965 } 966 if (ic != null) { 967 ic.reportFullscreenMode(fullscreen); 968 } 969 return; 970 } 971 } 972 } 973 } 974 975 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { 976 @Override 977 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 978 // No need to check for dump permission, since we only give this 979 // interface to the system. 980 CountDownLatch latch = new CountDownLatch(1); 981 SomeArgs sargs = SomeArgs.obtain(); 982 sargs.arg1 = fd; 983 sargs.arg2 = fout; 984 sargs.arg3 = args; 985 sargs.arg4 = latch; 986 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs)); 987 try { 988 if (!latch.await(5, TimeUnit.SECONDS)) { 989 fout.println("Timeout waiting for dump"); 990 } 991 } catch (InterruptedException e) { 992 fout.println("Interrupted waiting for dump"); 993 } 994 } 995 996 @Override 997 public void onBindMethod(InputBindResult res) { 998 mH.obtainMessage(MSG_BIND, res).sendToTarget(); 999 } 1000 1001 @Override 1002 public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) { 1003 mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget(); 1004 } 1005 1006 @Override 1007 public void setActive(boolean active, boolean fullscreen, boolean reportToImeController) { 1008 mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0, 1009 reportToImeController).sendToTarget(); 1010 } 1011 1012 @Override 1013 public void scheduleStartInputIfNecessary(boolean fullscreen) { 1014 // TODO(b/149859205): See if we can optimize this by having a fused dedicated operation. 1015 mH.obtainMessage(MSG_SET_ACTIVE, 0 /* active */, fullscreen ? 1 : 0).sendToTarget(); 1016 mH.obtainMessage(MSG_SET_ACTIVE, 1 /* active */, fullscreen ? 1 : 0).sendToTarget(); 1017 } 1018 1019 @Override 1020 public void reportFullscreenMode(boolean fullscreen) { 1021 mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0) 1022 .sendToTarget(); 1023 } 1024 1025 @Override 1026 public void setImeTraceEnabled(boolean enabled) { 1027 ImeTracing.getInstance().setEnabled(enabled); 1028 } 1029 1030 @Override 1031 public void throwExceptionFromSystem(String message) { 1032 throw new RuntimeException(message); 1033 } 1034 }; 1035 1036 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false); 1037 1038 /** 1039 * For layoutlib to clean up static objects inside {@link InputMethodManager}. 1040 */ tearDownEditMode()1041 static void tearDownEditMode() { 1042 if (!isInEditMode()) { 1043 throw new UnsupportedOperationException( 1044 "This method must be called only from layoutlib"); 1045 } 1046 synchronized (sLock) { 1047 sInstance = null; 1048 } 1049 } 1050 1051 /** 1052 * For layoutlib to override this method to return {@code true}. 1053 * 1054 * @return {@code true} if the process is running for developer tools 1055 * @see View#isInEditMode() 1056 */ isInEditMode()1057 private static boolean isInEditMode() { 1058 return false; 1059 } 1060 1061 @NonNull createInstance(int displayId, Looper looper)1062 private static InputMethodManager createInstance(int displayId, Looper looper) { 1063 return isInEditMode() ? createStubInstance(displayId, looper) 1064 : createRealInstance(displayId, looper); 1065 } 1066 1067 @NonNull createRealInstance(int displayId, Looper looper)1068 private static InputMethodManager createRealInstance(int displayId, Looper looper) { 1069 final IInputMethodManager service; 1070 try { 1071 service = IInputMethodManager.Stub.asInterface( 1072 ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); 1073 } catch (ServiceNotFoundException e) { 1074 throw new IllegalStateException(e); 1075 } 1076 final InputMethodManager imm = new InputMethodManager(service, displayId, looper); 1077 // InputMethodManagerService#addClient() relies on Binder.getCalling{Pid, Uid}() to 1078 // associate PID/UID with each IME client. This means: 1079 // A. if this method call will be handled as an IPC, there is no problem. 1080 // B. if this method call will be handled as an in-proc method call, we need to 1081 // ensure that Binder.getCalling{Pid, Uid}() return Process.my{Pid, Uid}() 1082 // Either ways we can always call Binder.{clear, restore}CallingIdentity() because 1083 // 1) doing so has no effect for A and 2) doing so is sufficient for B. 1084 final long identity = Binder.clearCallingIdentity(); 1085 try { 1086 service.addClient(imm.mClient, imm.mIInputContext, displayId); 1087 } catch (RemoteException e) { 1088 e.rethrowFromSystemServer(); 1089 } finally { 1090 Binder.restoreCallingIdentity(identity); 1091 } 1092 return imm; 1093 } 1094 1095 @NonNull createStubInstance(int displayId, Looper looper)1096 private static InputMethodManager createStubInstance(int displayId, Looper looper) { 1097 // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS. 1098 final Class<IInputMethodManager> c = IInputMethodManager.class; 1099 final IInputMethodManager stubInterface = 1100 (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(), 1101 new Class[]{c}, (proxy, method, args) -> { 1102 final Class<?> returnType = method.getReturnType(); 1103 if (returnType == boolean.class) { 1104 return false; 1105 } else if (returnType == int.class) { 1106 return 0; 1107 } else if (returnType == long.class) { 1108 return 0L; 1109 } else if (returnType == short.class) { 1110 return 0; 1111 } else if (returnType == char.class) { 1112 return 0; 1113 } else if (returnType == byte.class) { 1114 return 0; 1115 } else if (returnType == float.class) { 1116 return 0f; 1117 } else if (returnType == double.class) { 1118 return 0.0; 1119 } else { 1120 return null; 1121 } 1122 }); 1123 return new InputMethodManager(stubInterface, displayId, looper); 1124 } 1125 InputMethodManager(IInputMethodManager service, int displayId, Looper looper)1126 private InputMethodManager(IInputMethodManager service, int displayId, Looper looper) { 1127 mService = service; 1128 mMainLooper = looper; 1129 mH = new H(looper); 1130 mDisplayId = displayId; 1131 mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null); 1132 } 1133 1134 /** 1135 * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist. 1136 * 1137 * @param context {@link Context} for which IME APIs need to work 1138 * @return {@link InputMethodManager} instance 1139 * @hide 1140 */ 1141 @NonNull forContext(@isplayContext Context context)1142 public static InputMethodManager forContext(@DisplayContext Context context) { 1143 final int displayId = context.getDisplayId(); 1144 // For better backward compatibility, we always use Looper.getMainLooper() for the default 1145 // display case. 1146 final Looper looper = displayId == Display.DEFAULT_DISPLAY 1147 ? Looper.getMainLooper() : context.getMainLooper(); 1148 return forContextInternal(displayId, looper); 1149 } 1150 1151 @NonNull forContextInternal(int displayId, Looper looper)1152 private static InputMethodManager forContextInternal(int displayId, Looper looper) { 1153 final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY; 1154 synchronized (sLock) { 1155 InputMethodManager instance = sInstanceMap.get(displayId); 1156 if (instance != null) { 1157 return instance; 1158 } 1159 instance = createInstance(displayId, looper); 1160 // For backward compatibility, store the instance also to sInstance for default display. 1161 if (sInstance == null && isDefaultDisplay) { 1162 sInstance = instance; 1163 } 1164 sInstanceMap.put(displayId, instance); 1165 return instance; 1166 } 1167 } 1168 1169 /** 1170 * Deprecated. Do not use. 1171 * 1172 * @return global {@link InputMethodManager} instance 1173 * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully 1174 * support multi-display scenario. 1175 * @hide 1176 */ 1177 @Deprecated 1178 @UnsupportedAppUsage getInstance()1179 public static InputMethodManager getInstance() { 1180 Log.w(TAG, "InputMethodManager.getInstance() is deprecated because it cannot be" 1181 + " compatible with multi-display." 1182 + " Use context.getSystemService(InputMethodManager.class) instead.", 1183 new Throwable()); 1184 ensureDefaultInstanceForDefaultDisplayIfNecessary(); 1185 return peekInstance(); 1186 } 1187 1188 /** 1189 * Deprecated. Do not use. 1190 * 1191 * @return {@link #sInstance} 1192 * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully 1193 * support multi-display scenario. 1194 * @hide 1195 */ 1196 @Deprecated 1197 @UnsupportedAppUsage peekInstance()1198 public static InputMethodManager peekInstance() { 1199 Log.w(TAG, "InputMethodManager.peekInstance() is deprecated because it cannot be" 1200 + " compatible with multi-display." 1201 + " Use context.getSystemService(InputMethodManager.class) instead.", 1202 new Throwable()); 1203 synchronized (sLock) { 1204 return sInstance; 1205 } 1206 } 1207 1208 /** @hide */ 1209 @UnsupportedAppUsage getClient()1210 public IInputMethodClient getClient() { 1211 return mClient; 1212 } 1213 1214 /** @hide */ 1215 @UnsupportedAppUsage getInputContext()1216 public IInputContext getInputContext() { 1217 return mIInputContext; 1218 } 1219 1220 /** 1221 * Returns the list of installed input methods. 1222 * 1223 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1224 * 1225 * @return {@link List} of {@link InputMethodInfo}. 1226 */ getInputMethodList()1227 public List<InputMethodInfo> getInputMethodList() { 1228 try { 1229 // We intentionally do not use UserHandle.getCallingUserId() here because for system 1230 // services InputMethodManagerInternal.getInputMethodListAsUser() should be used 1231 // instead. 1232 return mService.getInputMethodList(UserHandle.myUserId()); 1233 } catch (RemoteException e) { 1234 throw e.rethrowFromSystemServer(); 1235 } 1236 } 1237 1238 /** 1239 * Returns the list of installed input methods for the specified user. 1240 * 1241 * @param userId user ID to query 1242 * @return {@link List} of {@link InputMethodInfo}. 1243 * @hide 1244 */ 1245 @TestApi 1246 @RequiresPermission(INTERACT_ACROSS_USERS_FULL) 1247 @NonNull getInputMethodListAsUser(@serIdInt int userId)1248 public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { 1249 try { 1250 return mService.getInputMethodList(userId); 1251 } catch (RemoteException e) { 1252 throw e.rethrowFromSystemServer(); 1253 } 1254 } 1255 1256 /** 1257 * Returns the list of enabled input methods. 1258 * 1259 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1260 * 1261 * @return {@link List} of {@link InputMethodInfo}. 1262 */ getEnabledInputMethodList()1263 public List<InputMethodInfo> getEnabledInputMethodList() { 1264 try { 1265 // We intentionally do not use UserHandle.getCallingUserId() here because for system 1266 // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used 1267 // instead. 1268 return mService.getEnabledInputMethodList(UserHandle.myUserId()); 1269 } catch (RemoteException e) { 1270 throw e.rethrowFromSystemServer(); 1271 } 1272 } 1273 1274 /** 1275 * Returns the list of enabled input methods for the specified user. 1276 * 1277 * @param userId user ID to query 1278 * @return {@link List} of {@link InputMethodInfo}. 1279 * @hide 1280 */ 1281 @RequiresPermission(INTERACT_ACROSS_USERS_FULL) getEnabledInputMethodListAsUser(@serIdInt int userId)1282 public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) { 1283 try { 1284 return mService.getEnabledInputMethodList(userId); 1285 } catch (RemoteException e) { 1286 throw e.rethrowFromSystemServer(); 1287 } 1288 } 1289 1290 /** 1291 * Returns a list of enabled input method subtypes for the specified input method info. 1292 * 1293 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1294 * 1295 * @param imi An input method info whose subtypes list will be returned. 1296 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly 1297 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework 1298 * will implicitly enable subtypes according to the current system language. 1299 */ getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes)1300 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi, 1301 boolean allowsImplicitlySelectedSubtypes) { 1302 try { 1303 return mService.getEnabledInputMethodSubtypeList( 1304 imi == null ? null : imi.getId(), 1305 allowsImplicitlySelectedSubtypes); 1306 } catch (RemoteException e) { 1307 throw e.rethrowFromSystemServer(); 1308 } 1309 } 1310 1311 /** 1312 * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was 1313 * intended for IME developers who should be accessing APIs through the service. APIs in this 1314 * class are intended for app developers interacting with the IME. 1315 */ 1316 @Deprecated showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId)1317 public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) { 1318 InputMethodPrivilegedOperationsRegistry.get( 1319 imeToken).updateStatusIconAsync(packageName, iconId); 1320 } 1321 1322 /** 1323 * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was 1324 * intended for IME developers who should be accessing APIs through the service. APIs in 1325 * this class are intended for app developers interacting with the IME. 1326 */ 1327 @Deprecated hideStatusIcon(IBinder imeToken)1328 public void hideStatusIcon(IBinder imeToken) { 1329 InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIconAsync(null, 0); 1330 } 1331 1332 /** 1333 * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing. 1334 * 1335 * @param spans will be ignored. 1336 * 1337 * @deprecated Do not use. 1338 * @hide 1339 */ 1340 @Deprecated 1341 @UnsupportedAppUsage registerSuggestionSpansForNotification(SuggestionSpan[] spans)1342 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) { 1343 Log.w(TAG, "registerSuggestionSpansForNotification() is deprecated. Does nothing."); 1344 } 1345 1346 /** 1347 * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing. 1348 * 1349 * @deprecated Do not use. 1350 * @hide 1351 */ 1352 @Deprecated 1353 @UnsupportedAppUsage notifySuggestionPicked(SuggestionSpan span, String originalString, int index)1354 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) { 1355 Log.w(TAG, "notifySuggestionPicked() is deprecated. Does nothing."); 1356 } 1357 1358 /** 1359 * Allows you to discover whether the attached input method is running 1360 * in fullscreen mode. Return true if it is fullscreen, entirely covering 1361 * your UI, else returns false. 1362 */ isFullscreenMode()1363 public boolean isFullscreenMode() { 1364 synchronized (mH) { 1365 return mFullscreenMode; 1366 } 1367 } 1368 1369 /** 1370 * Return true if the given view is the currently active view for the 1371 * input method. 1372 */ isActive(View view)1373 public boolean isActive(View view) { 1374 // Re-dispatch if there is a context mismatch. 1375 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1376 if (fallbackImm != null) { 1377 return fallbackImm.isActive(view); 1378 } 1379 1380 checkFocus(); 1381 synchronized (mH) { 1382 return hasServedByInputMethodLocked(view) && mCurrentTextBoxAttribute != null; 1383 } 1384 } 1385 1386 /** 1387 * Return true if any view is currently active in the input method. 1388 */ isActive()1389 public boolean isActive() { 1390 checkFocus(); 1391 synchronized (mH) { 1392 return getServedViewLocked() != null && mCurrentTextBoxAttribute != null; 1393 } 1394 } 1395 1396 /** 1397 * Return {@code true} if the currently served view is accepting full text edits. 1398 * If {@code false}, it has no input connection, so it can only handle raw key events. 1399 */ isAcceptingText()1400 public boolean isAcceptingText() { 1401 checkFocus(); 1402 synchronized (mH) { 1403 return mServedInputConnectionWrapper != null 1404 && mServedInputConnectionWrapper.getInputConnection() != null; 1405 } 1406 } 1407 1408 /** 1409 * Return {@code true} if the input method is suppressing system spell checker. 1410 */ isInputMethodSuppressingSpellChecker()1411 public boolean isInputMethodSuppressingSpellChecker() { 1412 synchronized (mH) { 1413 return mIsInputMethodSuppressingSpellChecker; 1414 } 1415 } 1416 1417 /** 1418 * Reset all of the state associated with being bound to an input method. 1419 */ clearBindingLocked()1420 void clearBindingLocked() { 1421 if (DEBUG) Log.v(TAG, "Clearing binding!"); 1422 clearConnectionLocked(); 1423 setInputChannelLocked(null); 1424 mBindSequence = -1; 1425 mCurId = null; 1426 mCurMethod = null; // for @UnsupportedAppUsage 1427 mCurrentInputMethodSession = null; 1428 } 1429 setInputChannelLocked(InputChannel channel)1430 void setInputChannelLocked(InputChannel channel) { 1431 if (mCurChannel == channel) { 1432 return; 1433 } 1434 if (mCurChannel != null && channel != null 1435 && mCurChannel.getToken() == channel.getToken()) { 1436 // channel is a dupe of 'mCurChannel', because they have the same token, and represent 1437 // the same connection. Ignore the incoming channel and keep using 'mCurChannel' to 1438 // avoid confusing the InputEventReceiver. 1439 return; 1440 } 1441 if (mCurSender != null) { 1442 flushPendingEventsLocked(); 1443 mCurSender.dispose(); 1444 mCurSender = null; 1445 } 1446 if (mCurChannel != null) { 1447 mCurChannel.dispose(); 1448 } 1449 mCurChannel = channel; 1450 } 1451 1452 /** 1453 * Reset all of the state associated with a served view being connected 1454 * to an input method 1455 */ clearConnectionLocked()1456 void clearConnectionLocked() { 1457 mCurrentTextBoxAttribute = null; 1458 if (mServedInputConnectionWrapper != null) { 1459 mServedInputConnectionWrapper.deactivate(); 1460 mServedInputConnectionWrapper = null; 1461 } 1462 } 1463 1464 /** 1465 * Disconnect any existing input connection, clearing the served view. 1466 */ 1467 @UnsupportedAppUsage finishInputLocked()1468 void finishInputLocked() { 1469 mIsInputMethodSuppressingSpellChecker = false; 1470 setNextServedViewLocked(null); 1471 if (getServedViewLocked() != null) { 1472 if (DEBUG) { 1473 Log.v(TAG, "FINISH INPUT: mServedView=" 1474 + dumpViewInfo(getServedViewLocked())); 1475 } 1476 setServedViewLocked(null); 1477 mCompletions = null; 1478 mServedConnecting = false; 1479 clearConnectionLocked(); 1480 } 1481 } 1482 displayCompletions(View view, CompletionInfo[] completions)1483 public void displayCompletions(View view, CompletionInfo[] completions) { 1484 // Re-dispatch if there is a context mismatch. 1485 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1486 if (fallbackImm != null) { 1487 fallbackImm.displayCompletions(view, completions); 1488 return; 1489 } 1490 1491 checkFocus(); 1492 synchronized (mH) { 1493 if (!hasServedByInputMethodLocked(view)) { 1494 return; 1495 } 1496 1497 mCompletions = completions; 1498 if (mCurrentInputMethodSession != null) { 1499 mCurrentInputMethodSession.displayCompletions(mCompletions); 1500 } 1501 } 1502 } 1503 updateExtractedText(View view, int token, ExtractedText text)1504 public void updateExtractedText(View view, int token, ExtractedText text) { 1505 // Re-dispatch if there is a context mismatch. 1506 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1507 if (fallbackImm != null) { 1508 fallbackImm.updateExtractedText(view, token, text); 1509 return; 1510 } 1511 1512 checkFocus(); 1513 synchronized (mH) { 1514 if (!hasServedByInputMethodLocked(view)) { 1515 return; 1516 } 1517 1518 if (mCurrentInputMethodSession != null) { 1519 mCurrentInputMethodSession.updateExtractedText(token, text); 1520 } 1521 } 1522 } 1523 1524 /** 1525 * Flag for {@link #showSoftInput} to indicate that this is an implicit 1526 * request to show the input window, not as the result of a direct request 1527 * by the user. The window may not be shown in this case. 1528 */ 1529 public static final int SHOW_IMPLICIT = 0x0001; 1530 1531 /** 1532 * Flag for {@link #showSoftInput} to indicate that the user has forced 1533 * the input method open (such as by long-pressing menu) so it should 1534 * not be closed until they explicitly do so. 1535 */ 1536 public static final int SHOW_FORCED = 0x0002; 1537 1538 /** 1539 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without 1540 * a result receiver: explicitly request that the current input method's 1541 * soft input area be shown to the user, if needed. 1542 * 1543 * @param view The currently focused view, which would like to receive 1544 * soft keyboard input. 1545 * @param flags Provides additional operating flags. Currently may be 1546 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 1547 */ showSoftInput(View view, int flags)1548 public boolean showSoftInput(View view, int flags) { 1549 // Re-dispatch if there is a context mismatch. 1550 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1551 if (fallbackImm != null) { 1552 return fallbackImm.showSoftInput(view, flags); 1553 } 1554 1555 return showSoftInput(view, flags, null); 1556 } 1557 1558 /** 1559 * Flag for the {@link ResultReceiver} result code from 1560 * {@link #showSoftInput(View, int, ResultReceiver)} and 1561 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1562 * state of the soft input window was unchanged and remains shown. 1563 */ 1564 public static final int RESULT_UNCHANGED_SHOWN = 0; 1565 1566 /** 1567 * Flag for the {@link ResultReceiver} result code from 1568 * {@link #showSoftInput(View, int, ResultReceiver)} and 1569 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1570 * state of the soft input window was unchanged and remains hidden. 1571 */ 1572 public static final int RESULT_UNCHANGED_HIDDEN = 1; 1573 1574 /** 1575 * Flag for the {@link ResultReceiver} result code from 1576 * {@link #showSoftInput(View, int, ResultReceiver)} and 1577 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1578 * state of the soft input window changed from hidden to shown. 1579 */ 1580 public static final int RESULT_SHOWN = 2; 1581 1582 /** 1583 * Flag for the {@link ResultReceiver} result code from 1584 * {@link #showSoftInput(View, int, ResultReceiver)} and 1585 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1586 * state of the soft input window changed from shown to hidden. 1587 */ 1588 public static final int RESULT_HIDDEN = 3; 1589 1590 /** 1591 * Explicitly request that the current input method's soft input area be 1592 * shown to the user, if needed. Call this if the user interacts with 1593 * your view in such a way that they have expressed they would like to 1594 * start performing input into it. 1595 * 1596 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to 1597 * this method can be a long-lived object, because it may not be 1598 * garbage-collected until all the corresponding {@link ResultReceiver} 1599 * objects transferred to different processes get garbage-collected. 1600 * Follow the general patterns to avoid memory leaks in Android. 1601 * Consider to use {@link java.lang.ref.WeakReference} so that application 1602 * logic objects such as {@link android.app.Activity} and {@link Context} 1603 * can be garbage collected regardless of the lifetime of 1604 * {@link ResultReceiver}. 1605 * 1606 * @param view The currently focused view, which would like to receive 1607 * soft keyboard input. 1608 * @param flags Provides additional operating flags. Currently may be 1609 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 1610 * @param resultReceiver If non-null, this will be called by the IME when 1611 * it has processed your request to tell you what it has done. The result 1612 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 1613 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 1614 * {@link #RESULT_HIDDEN}. 1615 */ showSoftInput(View view, int flags, ResultReceiver resultReceiver)1616 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) { 1617 return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT); 1618 } 1619 showSoftInput(View view, int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)1620 private boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver, 1621 @SoftInputShowHideReason int reason) { 1622 ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this, 1623 null /* icProto */); 1624 // Re-dispatch if there is a context mismatch. 1625 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1626 if (fallbackImm != null) { 1627 return fallbackImm.showSoftInput(view, flags, resultReceiver); 1628 } 1629 1630 checkFocus(); 1631 synchronized (mH) { 1632 if (!hasServedByInputMethodLocked(view)) { 1633 Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served."); 1634 return false; 1635 } 1636 1637 try { 1638 Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags + " reason=" 1639 + InputMethodDebug.softInputDisplayReasonToString(reason)); 1640 return mService.showSoftInput( 1641 mClient, 1642 view.getWindowToken(), 1643 flags, 1644 resultReceiver, 1645 reason); 1646 } catch (RemoteException e) { 1647 throw e.rethrowFromSystemServer(); 1648 } 1649 } 1650 } 1651 1652 /** 1653 * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0 1654 * is publicly released because previous implementations of that class had relied on this method 1655 * via reflection. 1656 * 1657 * @deprecated This is a hidden API. You should never use this. 1658 * @hide 1659 */ 1660 @Deprecated 1661 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499) showSoftInputUnchecked(int flags, ResultReceiver resultReceiver)1662 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { 1663 synchronized (mH) { 1664 try { 1665 Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be" 1666 + " removed soon. If you are using android.support.v7.widget.SearchView," 1667 + " please update to version 26.0 or newer version."); 1668 if (mCurRootView == null || mCurRootView.getView() == null) { 1669 Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()"); 1670 return; 1671 } 1672 mService.showSoftInput( 1673 mClient, 1674 mCurRootView.getView().getWindowToken(), 1675 flags, 1676 resultReceiver, 1677 SoftInputShowHideReason.SHOW_SOFT_INPUT); 1678 } catch (RemoteException e) { 1679 throw e.rethrowFromSystemServer(); 1680 } 1681 } 1682 } 1683 1684 /** 1685 * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)} 1686 * to indicate that the soft input window should only be hidden if it was not explicitly shown 1687 * by the user. 1688 */ 1689 public static final int HIDE_IMPLICIT_ONLY = 0x0001; 1690 1691 /** 1692 * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestShowSelf(int)} 1693 * to indicate that the soft input window should normally be hidden, unless it was originally 1694 * shown with {@link #SHOW_FORCED}. 1695 */ 1696 public static final int HIDE_NOT_ALWAYS = 0x0002; 1697 1698 /** 1699 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} 1700 * without a result: request to hide the soft input window from the 1701 * context of the window that is currently accepting input. 1702 * 1703 * @param windowToken The token of the window that is making the request, 1704 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1705 * @param flags Provides additional operating flags. Currently may be 1706 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1707 */ hideSoftInputFromWindow(IBinder windowToken, int flags)1708 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) { 1709 return hideSoftInputFromWindow(windowToken, flags, null); 1710 } 1711 1712 /** 1713 * Request to hide the soft input window from the context of the window 1714 * that is currently accepting input. This should be called as a result 1715 * of the user doing some actually than fairly explicitly requests to 1716 * have the input window hidden. 1717 * 1718 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to 1719 * this method can be a long-lived object, because it may not be 1720 * garbage-collected until all the corresponding {@link ResultReceiver} 1721 * objects transferred to different processes get garbage-collected. 1722 * Follow the general patterns to avoid memory leaks in Android. 1723 * Consider to use {@link java.lang.ref.WeakReference} so that application 1724 * logic objects such as {@link android.app.Activity} and {@link Context} 1725 * can be garbage collected regardless of the lifetime of 1726 * {@link ResultReceiver}. 1727 * 1728 * @param windowToken The token of the window that is making the request, 1729 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1730 * @param flags Provides additional operating flags. Currently may be 1731 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1732 * @param resultReceiver If non-null, this will be called by the IME when 1733 * it has processed your request to tell you what it has done. The result 1734 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 1735 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 1736 * {@link #RESULT_HIDDEN}. 1737 */ hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)1738 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, 1739 ResultReceiver resultReceiver) { 1740 return hideSoftInputFromWindow(windowToken, flags, resultReceiver, 1741 SoftInputShowHideReason.HIDE_SOFT_INPUT); 1742 } 1743 hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason)1744 private boolean hideSoftInputFromWindow(IBinder windowToken, int flags, 1745 ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { 1746 ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow", 1747 this, null /* icProto */); 1748 checkFocus(); 1749 synchronized (mH) { 1750 final View servedView = getServedViewLocked(); 1751 if (servedView == null || servedView.getWindowToken() != windowToken) { 1752 return false; 1753 } 1754 1755 try { 1756 return mService.hideSoftInput(mClient, windowToken, flags, resultReceiver, reason); 1757 } catch (RemoteException e) { 1758 throw e.rethrowFromSystemServer(); 1759 } 1760 } 1761 } 1762 1763 /** 1764 * This method toggles the input method window display. 1765 * If the input window is already displayed, it gets hidden. 1766 * If not the input window will be displayed. 1767 * @param windowToken The token of the window that is making the request, 1768 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1769 * @param showFlags Provides additional operating flags. May be 1770 * 0 or have the {@link #SHOW_IMPLICIT}, 1771 * {@link #SHOW_FORCED} bit set. 1772 * @param hideFlags Provides additional operating flags. May be 1773 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1774 * {@link #HIDE_NOT_ALWAYS} bit set. 1775 * 1776 * @deprecated Use {@link #showSoftInput(View, int)} or 1777 * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead. 1778 * In particular during focus changes, the current visibility of the IME is not 1779 * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only 1780 * has an effect if the calling app is the current IME focus. 1781 */ 1782 @Deprecated toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)1783 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) { 1784 ImeTracing.getInstance().triggerClientDump( 1785 "InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this, 1786 null /* icProto */); 1787 synchronized (mH) { 1788 final View servedView = getServedViewLocked(); 1789 if (servedView == null || servedView.getWindowToken() != windowToken) { 1790 return; 1791 } 1792 toggleSoftInput(showFlags, hideFlags); 1793 } 1794 } 1795 1796 /** 1797 * This method toggles the input method window display. 1798 * 1799 * If the input window is already displayed, it gets hidden. 1800 * If not the input window will be displayed. 1801 * @param showFlags Provides additional operating flags. May be 1802 * 0 or have the {@link #SHOW_IMPLICIT}, 1803 * {@link #SHOW_FORCED} bit set. 1804 * @param hideFlags Provides additional operating flags. May be 1805 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1806 * {@link #HIDE_NOT_ALWAYS} bit set. 1807 * 1808 * @deprecated Use {@link #showSoftInput(View, int)} or 1809 * {@link #hideSoftInputFromWindow(IBinder, int)} explicitly instead. 1810 * In particular during focus changes, the current visibility of the IME is not 1811 * well defined. Starting in {@link Build.VERSION_CODES#S Android S}, this only 1812 * has an effect if the calling app is the current IME focus. 1813 */ 1814 @Deprecated toggleSoftInput(int showFlags, int hideFlags)1815 public void toggleSoftInput(int showFlags, int hideFlags) { 1816 ImeTracing.getInstance().triggerClientDump( 1817 "InputMethodManager#toggleSoftInput", InputMethodManager.this, 1818 null /* icProto */); 1819 synchronized (mH) { 1820 final View view = getServedViewLocked(); 1821 if (mImeInsetsConsumer != null && view != null) { 1822 if (mImeInsetsConsumer.isRequestedVisible()) { 1823 hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null, 1824 SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT); 1825 } else { 1826 showSoftInput(view, showFlags, null, 1827 SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT); 1828 } 1829 } 1830 } 1831 } 1832 1833 /** 1834 * If the input method is currently connected to the given view, 1835 * restart it with its new contents. You should call this when the text 1836 * within your view changes outside of the normal input method or key 1837 * input flow, such as when an application calls TextView.setText(). 1838 * 1839 * @param view The view whose text has changed. 1840 */ restartInput(View view)1841 public void restartInput(View view) { 1842 // Re-dispatch if there is a context mismatch. 1843 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1844 if (fallbackImm != null) { 1845 fallbackImm.restartInput(view); 1846 return; 1847 } 1848 1849 checkFocus(); 1850 synchronized (mH) { 1851 if (!hasServedByInputMethodLocked(view)) { 1852 return; 1853 } 1854 1855 mServedConnecting = true; 1856 } 1857 1858 startInputInner(StartInputReason.APP_CALLED_RESTART_INPUT_API, null, 0, 0, 0); 1859 } 1860 1861 /** 1862 * Called when {@link DelegateImpl#startInput}, {@link #restartInput(View)}, 1863 * {@link #MSG_BIND} or {@link #MSG_UNBIND}. 1864 * Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input 1865 * background thread may blocked by other methods which already inside {@code mH} lock. 1866 */ startInputInner(@tartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)1867 boolean startInputInner(@StartInputReason int startInputReason, 1868 @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, 1869 @SoftInputModeFlags int softInputMode, int windowFlags) { 1870 final View view; 1871 synchronized (mH) { 1872 view = getServedViewLocked(); 1873 1874 // Make sure we have a window token for the served view. 1875 if (DEBUG) { 1876 Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) + 1877 " reason=" + InputMethodDebug.startInputReasonToString(startInputReason)); 1878 } 1879 if (view == null) { 1880 if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); 1881 return false; 1882 } 1883 } 1884 1885 if (windowGainingFocus == null) { 1886 windowGainingFocus = view.getWindowToken(); 1887 if (windowGainingFocus == null) { 1888 Log.e(TAG, "ABORT input: ServedView must be attached to a Window"); 1889 return false; 1890 } 1891 startInputFlags = getStartInputFlags(view, startInputFlags); 1892 softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode; 1893 windowFlags = view.getViewRootImpl().mWindowAttributes.flags; 1894 } 1895 1896 // Now we need to get an input connection from the served view. 1897 // This is complicated in a couple ways: we can't be holding our lock 1898 // when calling out to the view, and we need to make sure we call into 1899 // the view on the same thread that is driving its view hierarchy. 1900 Handler vh = view.getHandler(); 1901 if (vh == null) { 1902 // If the view doesn't have a handler, something has changed out 1903 // from under us, so just close the current input. 1904 // If we don't close the current input, the current input method can remain on the 1905 // screen without a connection. 1906 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input."); 1907 closeCurrentInput(); 1908 return false; 1909 } 1910 if (vh.getLooper() != Looper.myLooper()) { 1911 // The view is running on a different thread than our own, so 1912 // we need to reschedule our work for over there. 1913 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); 1914 vh.post(() -> mDelegate.startInput(startInputReason, null, 0, 0, 0)); 1915 return false; 1916 } 1917 1918 // Okay we are now ready to call into the served view and have it 1919 // do its stuff. 1920 // Life is good: let's hook everything up! 1921 EditorInfo tba = new EditorInfo(); 1922 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the 1923 // system can verify the consistency between the uid of this process and package name passed 1924 // from here. See comment of Context#getOpPackageName() for details. 1925 tba.packageName = view.getContext().getOpPackageName(); 1926 tba.autofillId = view.getAutofillId(); 1927 tba.fieldId = view.getId(); 1928 InputConnection ic = view.onCreateInputConnection(tba); 1929 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); 1930 1931 final Handler icHandler; 1932 InputBindResult res = null; 1933 synchronized (mH) { 1934 // Now that we are locked again, validate that our state hasn't 1935 // changed. 1936 final View servedView = getServedViewLocked(); 1937 if (servedView != view || !mServedConnecting) { 1938 // Something else happened, so abort. 1939 if (DEBUG) Log.v(TAG, 1940 "Starting input: finished by someone else. view=" + dumpViewInfo(view) 1941 + " servedView=" + dumpViewInfo(servedView) 1942 + " mServedConnecting=" + mServedConnecting); 1943 return false; 1944 } 1945 1946 // If we already have a text box, then this view is already 1947 // connected so we want to restart it. 1948 if (mCurrentTextBoxAttribute == null) { 1949 startInputFlags |= StartInputFlags.INITIAL_CONNECTION; 1950 } 1951 1952 // Hook 'em up and let 'er rip. 1953 mCurrentTextBoxAttribute = tba; 1954 1955 mServedConnecting = false; 1956 if (mServedInputConnectionWrapper != null) { 1957 mServedInputConnectionWrapper.deactivate(); 1958 mServedInputConnectionWrapper = null; 1959 } 1960 IInputConnectionWrapper servedContext; 1961 final int missingMethodFlags; 1962 if (ic != null) { 1963 mCursorSelStart = tba.initialSelStart; 1964 mCursorSelEnd = tba.initialSelEnd; 1965 mCursorCandStart = -1; 1966 mCursorCandEnd = -1; 1967 mCursorRect.setEmpty(); 1968 mCursorAnchorInfo = null; 1969 missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic); 1970 if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER) 1971 != 0) { 1972 // InputConnection#getHandler() is not implemented. 1973 icHandler = null; 1974 } else { 1975 icHandler = ic.getHandler(); 1976 } 1977 servedContext = new IInputConnectionWrapper( 1978 icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view); 1979 } else { 1980 servedContext = null; 1981 missingMethodFlags = 0; 1982 icHandler = null; 1983 } 1984 mServedInputConnectionWrapper = servedContext; 1985 1986 if (DEBUG) { 1987 Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic=" 1988 + ic + " tba=" + tba + " startInputFlags=" 1989 + InputMethodDebug.startInputFlagsToString(startInputFlags)); 1990 } 1991 try { 1992 res = mService.startInputOrWindowGainedFocus( 1993 startInputReason, mClient, windowGainingFocus, startInputFlags, 1994 softInputMode, windowFlags, tba, servedContext, missingMethodFlags, 1995 view.getContext().getApplicationInfo().targetSdkVersion); 1996 } catch (RemoteException e) { 1997 throw e.rethrowFromSystemServer(); 1998 } 1999 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); 2000 if (res == null) { 2001 Log.wtf(TAG, "startInputOrWindowGainedFocus must not return" 2002 + " null. startInputReason=" 2003 + InputMethodDebug.startInputReasonToString(startInputReason) 2004 + " editorInfo=" + tba 2005 + " startInputFlags=" 2006 + InputMethodDebug.startInputFlagsToString(startInputFlags)); 2007 return false; 2008 } 2009 mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker; 2010 if (res.id != null) { 2011 setInputChannelLocked(res.channel); 2012 mBindSequence = res.sequence; 2013 mCurMethod = res.method; // for @UnsupportedAppUsage 2014 mCurrentInputMethodSession = InputMethodSessionWrapper.createOrNull(res.method); 2015 mCurId = res.id; 2016 } else if (res.channel != null && res.channel != mCurChannel) { 2017 res.channel.dispose(); 2018 } 2019 switch (res.result) { 2020 case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW: 2021 mRestartOnNextWindowFocus = true; 2022 break; 2023 } 2024 if (mCurrentInputMethodSession != null && mCompletions != null) { 2025 mCurrentInputMethodSession.displayCompletions(mCompletions); 2026 } 2027 } 2028 2029 // Notify the app that the InputConnection is initialized and ready for use. 2030 if (ic != null && res != null && res.method != null) { 2031 if (DEBUG) { 2032 Log.v(TAG, "Calling View.onInputConnectionOpened: view= " + view 2033 + ", ic=" + ic + ", tba=" + tba + ", handler=" + icHandler); 2034 } 2035 view.onInputConnectionOpenedInternal(ic, tba, icHandler); 2036 } 2037 2038 return true; 2039 } 2040 2041 /** 2042 * An empty method only to avoid crashes of apps that call this method via reflection and do not 2043 * handle {@link NoSuchMethodException} in a graceful manner. 2044 * 2045 * @deprecated This is an empty method. No framework method must call this method. 2046 * @hide 2047 */ 2048 @Deprecated 2049 @UnsupportedAppUsage(trackingBug = 37122102, maxTargetSdk = Build.VERSION_CODES.Q, 2050 publicAlternatives = "{@code androidx.activity.ComponentActivity}") windowDismissed(IBinder appWindowToken)2051 public void windowDismissed(IBinder appWindowToken) { 2052 // Intentionally empty. 2053 // 2054 // It seems that some applications call this method via reflection to null clear the 2055 // following fields that used to exist in InputMethodManager: 2056 // * InputMethodManager#mCurRootView 2057 // * InputMethodManager#mServedView 2058 // * InputMethodManager#mNextServedView 2059 // so that these objects can be garbage-collected when an Activity gets dismissed. 2060 // 2061 // It is indeed true that older versions of InputMethodManager had issues that prevented 2062 // these fields from being null-cleared when it should have been, but the understanding of 2063 // the engineering team is that all known issues have already been fixed as of Android 10. 2064 // 2065 // For older devices, developers can work around the object leaks by using 2066 // androidx.activity.ComponentActivity. 2067 // See https://issuetracker.google.com/u/1/issues/37122102 for details. 2068 // 2069 // If you believe InputMethodManager is leaking objects in API 24 or any later version, 2070 // please file a bug at https://issuetracker.google.com/issues/new?component=192705. 2071 } 2072 getStartInputFlags(View focusedView, int startInputFlags)2073 private int getStartInputFlags(View focusedView, int startInputFlags) { 2074 startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS; 2075 if (focusedView.onCheckIsTextEditor()) { 2076 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR; 2077 } 2078 return startInputFlags; 2079 } 2080 2081 /** 2082 * Check the next served view from {@link ImeFocusController} if needs to start input. 2083 * Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input 2084 * background thread may blocked by other methods which already inside {@code mH} lock. 2085 * @hide 2086 */ 2087 @UnsupportedAppUsage checkFocus()2088 public void checkFocus() { 2089 final ImeFocusController controller = getFocusController(); 2090 if (controller != null) { 2091 controller.checkFocus(false /* forceNewFocus */, true /* startInput */); 2092 } 2093 } 2094 2095 @UnsupportedAppUsage closeCurrentInput()2096 void closeCurrentInput() { 2097 synchronized (mH) { 2098 if (mCurRootView == null || mCurRootView.getView() == null) { 2099 Log.w(TAG, "No current root view, ignoring closeCurrentInput()"); 2100 return; 2101 } 2102 try { 2103 mService.hideSoftInput( 2104 mClient, 2105 mCurRootView.getView().getWindowToken(), 2106 HIDE_NOT_ALWAYS, 2107 null, 2108 SoftInputShowHideReason.HIDE_SOFT_INPUT); 2109 } catch (RemoteException e) { 2110 throw e.rethrowFromSystemServer(); 2111 } 2112 } 2113 } 2114 2115 /** 2116 * Register for IME state callbacks and applying visibility in 2117 * {@link android.view.ImeInsetsSourceConsumer}. 2118 * @hide 2119 */ registerImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2120 public void registerImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { 2121 if (imeInsetsConsumer == null) { 2122 throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); 2123 } 2124 2125 synchronized (mH) { 2126 mImeInsetsConsumer = imeInsetsConsumer; 2127 } 2128 } 2129 2130 /** 2131 * Unregister for IME state callbacks and applying visibility in 2132 * {@link android.view.ImeInsetsSourceConsumer}. 2133 * @hide 2134 */ unregisterImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2135 public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { 2136 if (imeInsetsConsumer == null) { 2137 throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); 2138 } 2139 2140 synchronized (mH) { 2141 if (mImeInsetsConsumer == imeInsetsConsumer) { 2142 mImeInsetsConsumer = null; 2143 } 2144 } 2145 } 2146 2147 /** 2148 * Call showSoftInput with currently focused view. 2149 * 2150 * @param windowToken the window from which this request originates. If this doesn't match the 2151 * currently served view, the request is ignored and returns {@code false}. 2152 * 2153 * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise. 2154 * @hide 2155 */ requestImeShow(IBinder windowToken)2156 public boolean requestImeShow(IBinder windowToken) { 2157 synchronized (mH) { 2158 final View servedView = getServedViewLocked(); 2159 if (servedView == null || servedView.getWindowToken() != windowToken) { 2160 return false; 2161 } 2162 showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */, 2163 SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API); 2164 return true; 2165 } 2166 } 2167 2168 /** 2169 * Notify IME directly that it is no longer visible. 2170 * 2171 * @param windowToken the window from which this request originates. If this doesn't match the 2172 * currently served view, the request is ignored. 2173 * @hide 2174 */ notifyImeHidden(IBinder windowToken)2175 public void notifyImeHidden(IBinder windowToken) { 2176 ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this, 2177 null /* icProto */); 2178 synchronized (mH) { 2179 if (mCurrentInputMethodSession != null && mCurRootView != null 2180 && mCurRootView.getWindowToken() == windowToken) { 2181 mCurrentInputMethodSession.notifyImeHidden(); 2182 } 2183 } 2184 } 2185 2186 /** 2187 * Notify IME directly to remove surface as it is no longer visible. 2188 * @param windowToken The client window token that requests the IME to remove its surface. 2189 * @hide 2190 */ removeImeSurface(IBinder windowToken)2191 public void removeImeSurface(IBinder windowToken) { 2192 synchronized (mH) { 2193 try { 2194 mService.removeImeSurfaceFromWindowAsync(windowToken); 2195 } catch (RemoteException e) { 2196 throw e.rethrowFromSystemServer(); 2197 } 2198 } 2199 } 2200 2201 /** 2202 * Report the current selection range. 2203 * 2204 * <p><strong>Editor authors</strong>, you need to call this method whenever 2205 * the cursor moves in your editor. Remember that in addition to doing this, your 2206 * editor needs to always supply current cursor values in 2207 * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every 2208 * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is 2209 * called, which happens whenever the keyboard shows up or the focus changes 2210 * to a text field, among other cases.</p> 2211 */ updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)2212 public void updateSelection(View view, int selStart, int selEnd, 2213 int candidatesStart, int candidatesEnd) { 2214 // Re-dispatch if there is a context mismatch. 2215 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2216 if (fallbackImm != null) { 2217 fallbackImm.updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd); 2218 return; 2219 } 2220 2221 checkFocus(); 2222 synchronized (mH) { 2223 if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null 2224 || mCurrentInputMethodSession == null) { 2225 return; 2226 } 2227 2228 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd 2229 || mCursorCandStart != candidatesStart 2230 || mCursorCandEnd != candidatesEnd) { 2231 if (DEBUG) Log.d(TAG, "updateSelection"); 2232 2233 if (DEBUG) { 2234 Log.v(TAG, "SELECTION CHANGE: " + mCurrentInputMethodSession); 2235 } 2236 final int oldSelStart = mCursorSelStart; 2237 final int oldSelEnd = mCursorSelEnd; 2238 // Update internal values before sending updateSelection to the IME, because 2239 // if it changes the text within its onUpdateSelection handler in a way that 2240 // does not move the cursor we don't want to call it again with the same values. 2241 mCursorSelStart = selStart; 2242 mCursorSelEnd = selEnd; 2243 mCursorCandStart = candidatesStart; 2244 mCursorCandEnd = candidatesEnd; 2245 mCurrentInputMethodSession.updateSelection( 2246 oldSelStart, oldSelEnd, selStart, selEnd, candidatesStart, candidatesEnd); 2247 } 2248 } 2249 } 2250 2251 /** 2252 * Notify the event when the user tapped or clicked the text view. 2253 * 2254 * @param view {@link View} which is being clicked. 2255 * @see InputMethodService#onViewClicked(boolean) 2256 * @deprecated The semantics of this method can never be defined well for composite {@link View} 2257 * that works as a giant "Canvas", which can host its own UI hierarchy and sub focus 2258 * state. {@link android.webkit.WebView} is a good example. Application / IME 2259 * developers should not rely on this method. 2260 */ 2261 @Deprecated viewClicked(View view)2262 public void viewClicked(View view) { 2263 // Re-dispatch if there is a context mismatch. 2264 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2265 if (fallbackImm != null) { 2266 fallbackImm.viewClicked(view); 2267 return; 2268 } 2269 2270 final View servedView; 2271 final View nextServedView; 2272 synchronized (mH) { 2273 servedView = getServedViewLocked(); 2274 nextServedView = getNextServedViewLocked(); 2275 } 2276 final boolean focusChanged = servedView != nextServedView; 2277 checkFocus(); 2278 synchronized (mH) { 2279 if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null 2280 || mCurrentInputMethodSession == null) { 2281 return; 2282 } 2283 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged); 2284 mCurrentInputMethodSession.viewClicked(focusChanged); 2285 } 2286 } 2287 2288 /** 2289 * Return true if the current input method wants to watch the location 2290 * of the input editor's cursor in its window. 2291 * 2292 * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead. 2293 */ 2294 @Deprecated isWatchingCursor(View view)2295 public boolean isWatchingCursor(View view) { 2296 return false; 2297 } 2298 2299 /** 2300 * Return true if the current input method wants to be notified when cursor/anchor location 2301 * is changed. 2302 * 2303 * @hide 2304 */ 2305 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isCursorAnchorInfoEnabled()2306 public boolean isCursorAnchorInfoEnabled() { 2307 synchronized (mH) { 2308 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 2309 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 2310 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode & 2311 InputConnection.CURSOR_UPDATE_MONITOR) != 0; 2312 return isImmediate || isMonitoring; 2313 } 2314 } 2315 2316 /** 2317 * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. 2318 * 2319 * @hide 2320 */ 2321 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setUpdateCursorAnchorInfoMode(int flags)2322 public void setUpdateCursorAnchorInfoMode(int flags) { 2323 synchronized (mH) { 2324 mRequestUpdateCursorAnchorInfoMonitorMode = flags; 2325 } 2326 } 2327 2328 /** 2329 * Report the current cursor location in its window. 2330 * 2331 * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead. 2332 */ 2333 @Deprecated updateCursor(View view, int left, int top, int right, int bottom)2334 public void updateCursor(View view, int left, int top, int right, int bottom) { 2335 // Re-dispatch if there is a context mismatch. 2336 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2337 if (fallbackImm != null) { 2338 fallbackImm.updateCursor(view, left, top, right, bottom); 2339 return; 2340 } 2341 2342 checkFocus(); 2343 synchronized (mH) { 2344 if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null 2345 || mCurrentInputMethodSession == null) { 2346 return; 2347 } 2348 2349 mTmpCursorRect.set(left, top, right, bottom); 2350 if (!mCursorRect.equals(mTmpCursorRect)) { 2351 if (DEBUG) Log.d(TAG, "updateCursor: " + mCurrentInputMethodSession); 2352 2353 mCurrentInputMethodSession.updateCursor(mTmpCursorRect); 2354 mCursorRect.set(mTmpCursorRect); 2355 } 2356 } 2357 } 2358 2359 /** 2360 * Report positional change of the text insertion point and/or characters in the composition 2361 * string. 2362 */ updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo)2363 public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) { 2364 if (view == null || cursorAnchorInfo == null) { 2365 return; 2366 } 2367 // Re-dispatch if there is a context mismatch. 2368 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2369 if (fallbackImm != null) { 2370 fallbackImm.updateCursorAnchorInfo(view, cursorAnchorInfo); 2371 return; 2372 } 2373 2374 checkFocus(); 2375 synchronized (mH) { 2376 if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null 2377 || mCurrentInputMethodSession == null) { 2378 return; 2379 } 2380 // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has 2381 // not been changed from the previous call. 2382 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 2383 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 2384 if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) { 2385 // TODO: Consider always emitting this message once we have addressed redundant 2386 // calls of this method from android.widget.Editor. 2387 if (DEBUG) { 2388 Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" 2389 + cursorAnchorInfo); 2390 } 2391 return; 2392 } 2393 if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo); 2394 mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo); 2395 mCursorAnchorInfo = cursorAnchorInfo; 2396 // Clear immediate bit (if any). 2397 mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE; 2398 } 2399 } 2400 2401 /** 2402 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) 2403 * InputMethodSession.appPrivateCommand()} on the current Input Method. 2404 * @param view Optional View that is sending the command, or null if 2405 * you want to send the command regardless of the view that is attached 2406 * to the input method. 2407 * @param action Name of the command to be performed. This <em>must</em> 2408 * be a scoped name, i.e. prefixed with a package name you own, so that 2409 * different developers will not create conflicting commands. 2410 * @param data Any data to include with the command. 2411 */ sendAppPrivateCommand(View view, String action, Bundle data)2412 public void sendAppPrivateCommand(View view, String action, Bundle data) { 2413 // Re-dispatch if there is a context mismatch. 2414 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2415 if (fallbackImm != null) { 2416 fallbackImm.sendAppPrivateCommand(view, action, data); 2417 return; 2418 } 2419 2420 checkFocus(); 2421 synchronized (mH) { 2422 if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null 2423 || mCurrentInputMethodSession == null) { 2424 return; 2425 } 2426 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data); 2427 mCurrentInputMethodSession.appPrivateCommand(action, data); 2428 } 2429 } 2430 2431 /** 2432 * Force switch to a new input method component. This can only be called 2433 * from an application or a service which has a token of the currently active input method. 2434 * 2435 * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that 2436 * token can be {@code null} when the caller has 2437 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update 2438 * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and 2439 * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p> 2440 * 2441 * @param token Supplies the identifying token given to an input method 2442 * when it was started, which allows it to perform this operation on 2443 * itself. 2444 * @param id The unique identifier for the new input method to be switched to. 2445 * @deprecated Use {@link InputMethodService#switchInputMethod(String)} 2446 * instead. This method was intended for IME developers who should be accessing APIs through 2447 * the service. APIs in this class are intended for app developers interacting with the IME. 2448 */ 2449 @Deprecated setInputMethod(IBinder token, String id)2450 public void setInputMethod(IBinder token, String id) { 2451 if (token == null) { 2452 // There are still some system components that rely on this undocumented behavior 2453 // regarding null IME token with WRITE_SECURE_SETTINGS. Provide a fallback logic as a 2454 // temporary remedy. 2455 if (id == null) { 2456 return; 2457 } 2458 if (Process.myUid() == Process.SYSTEM_UID) { 2459 Log.w(TAG, "System process should not be calling setInputMethod() because almost " 2460 + "always it is a bug under multi-user / multi-profile environment. " 2461 + "Consider interacting with InputMethodManagerService directly via " 2462 + "LocalServices."); 2463 return; 2464 } 2465 final Context fallbackContext = ActivityThread.currentApplication(); 2466 if (fallbackContext == null) { 2467 return; 2468 } 2469 if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS) 2470 != PackageManager.PERMISSION_GRANTED) { 2471 return; 2472 } 2473 final List<InputMethodInfo> imis = getEnabledInputMethodList(); 2474 final int numImis = imis.size(); 2475 boolean found = false; 2476 for (int i = 0; i < numImis; ++i) { 2477 final InputMethodInfo imi = imis.get(i); 2478 if (id.equals(imi.getId())) { 2479 found = true; 2480 break; 2481 } 2482 } 2483 if (!found) { 2484 Log.e(TAG, "Ignoring setInputMethod(null, " + id + ") because the specified " 2485 + "id not found in enabled IMEs."); 2486 return; 2487 } 2488 Log.w(TAG, "The undocumented behavior that setInputMethod() accepts null token " 2489 + "when the caller has WRITE_SECURE_SETTINGS is deprecated. This behavior may " 2490 + "be completely removed in a future version. Update secure settings directly " 2491 + "instead."); 2492 final ContentResolver resolver = fallbackContext.getContentResolver(); 2493 Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, 2494 NOT_A_SUBTYPE_ID); 2495 Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, id); 2496 return; 2497 } 2498 InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id); 2499 } 2500 2501 /** 2502 * Force switch to a new input method and subtype. This can only be called 2503 * from an application or a service which has a token of the currently active input method. 2504 * 2505 * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, {@code token} cannot be 2506 * {@code null} even with {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}. Instead, 2507 * update {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and 2508 * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p> 2509 * 2510 * @param token Supplies the identifying token given to an input method 2511 * when it was started, which allows it to perform this operation on 2512 * itself. 2513 * @param id The unique identifier for the new input method to be switched to. 2514 * @param subtype The new subtype of the new input method to be switched to. 2515 * @deprecated Use 2516 * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)} 2517 * instead. This method was intended for IME developers who should be accessing APIs through 2518 * the service. APIs in this class are intended for app developers interacting with the IME. 2519 */ 2520 @Deprecated setInputMethodAndSubtype(@onNull IBinder token, String id, InputMethodSubtype subtype)2521 public void setInputMethodAndSubtype(@NonNull IBinder token, String id, 2522 InputMethodSubtype subtype) { 2523 if (token == null) { 2524 Log.e(TAG, "setInputMethodAndSubtype() does not accept null token on Android Q " 2525 + "and later."); 2526 return; 2527 } 2528 InputMethodPrivilegedOperationsRegistry.get(token).setInputMethodAndSubtype(id, subtype); 2529 } 2530 2531 /** 2532 * Close/hide the input method's soft input area, so the user no longer 2533 * sees it or can interact with it. This can only be called 2534 * from the currently active input method, as validated by the given token. 2535 * 2536 * @param token Supplies the identifying token given to an input method 2537 * when it was started, which allows it to perform this operation on 2538 * itself. 2539 * @param flags Provides additional operating flags. Currently may be 2540 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 2541 * {@link #HIDE_NOT_ALWAYS} bit set. 2542 * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was 2543 * intended for IME developers who should be accessing APIs through the service. APIs in this 2544 * class are intended for app developers interacting with the IME. 2545 */ 2546 @Deprecated hideSoftInputFromInputMethod(IBinder token, int flags)2547 public void hideSoftInputFromInputMethod(IBinder token, int flags) { 2548 InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags); 2549 } 2550 2551 /** 2552 * Show the input method's soft input area, so the user 2553 * sees the input method window and can interact with it. 2554 * This can only be called from the currently active input method, 2555 * as validated by the given token. 2556 * 2557 * @param token Supplies the identifying token given to an input method 2558 * when it was started, which allows it to perform this operation on 2559 * itself. 2560 * @param flags Provides additional operating flags. Currently may be 2561 * 0 or have the {@link #SHOW_IMPLICIT} or 2562 * {@link #SHOW_FORCED} bit set. 2563 * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was 2564 * intended for IME developers who should be accessing APIs through the service. APIs in this 2565 * class are intended for app developers interacting with the IME. 2566 */ 2567 @Deprecated showSoftInputFromInputMethod(IBinder token, int flags)2568 public void showSoftInputFromInputMethod(IBinder token, int flags) { 2569 InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags); 2570 } 2571 2572 /** 2573 * Dispatches an input event to the IME. 2574 * 2575 * Returns {@link #DISPATCH_HANDLED} if the event was handled. 2576 * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled. 2577 * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the 2578 * callback will be invoked later. 2579 * 2580 * @hide 2581 */ dispatchInputEvent(InputEvent event, Object token, FinishedInputEventCallback callback, Handler handler)2582 public int dispatchInputEvent(InputEvent event, Object token, 2583 FinishedInputEventCallback callback, Handler handler) { 2584 synchronized (mH) { 2585 if (mCurrentInputMethodSession != null) { 2586 if (event instanceof KeyEvent) { 2587 KeyEvent keyEvent = (KeyEvent)event; 2588 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN 2589 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM 2590 && keyEvent.getRepeatCount() == 0) { 2591 showInputMethodPickerLocked(); 2592 return DISPATCH_HANDLED; 2593 } 2594 } 2595 2596 if (DEBUG) { 2597 Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurrentInputMethodSession); 2598 } 2599 2600 PendingEvent p = obtainPendingEventLocked( 2601 event, token, mCurId, callback, handler); 2602 if (mMainLooper.isCurrentThread()) { 2603 // Already running on the IMM thread so we can send the event immediately. 2604 return sendInputEventOnMainLooperLocked(p); 2605 } 2606 2607 // Post the event to the IMM thread. 2608 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p); 2609 msg.setAsynchronous(true); 2610 mH.sendMessage(msg); 2611 return DISPATCH_IN_PROGRESS; 2612 } 2613 } 2614 return DISPATCH_NOT_HANDLED; 2615 } 2616 2617 /** 2618 * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which 2619 * is expected to dispatch an keyboard event sent from the IME to an appropriate event target 2620 * depending on the given {@link View} and the current focus state. 2621 * 2622 * <p>CAUTION: This method is provided only for the situation where 2623 * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on 2624 * {@link BaseInputConnection}. Do not use this API for anything else.</p> 2625 * 2626 * @param targetView the default target view. If {@code null} is specified, then this method 2627 * tries to find a good event target based on the current focus state. 2628 * @param event the key event to be dispatched. 2629 */ dispatchKeyEventFromInputMethod(@ullable View targetView, @NonNull KeyEvent event)2630 public void dispatchKeyEventFromInputMethod(@Nullable View targetView, 2631 @NonNull KeyEvent event) { 2632 // Re-dispatch if there is a context mismatch. 2633 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(targetView); 2634 if (fallbackImm != null) { 2635 fallbackImm.dispatchKeyEventFromInputMethod(targetView, event); 2636 return; 2637 } 2638 2639 synchronized (mH) { 2640 ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; 2641 if (viewRootImpl == null) { 2642 final View servedView = getServedViewLocked(); 2643 if (servedView != null) { 2644 viewRootImpl = servedView.getViewRootImpl(); 2645 } 2646 } 2647 if (viewRootImpl != null) { 2648 viewRootImpl.dispatchKeyFromIme(event); 2649 } 2650 } 2651 } 2652 2653 // Must be called on the main looper sendInputEventAndReportResultOnMainLooper(PendingEvent p)2654 void sendInputEventAndReportResultOnMainLooper(PendingEvent p) { 2655 final boolean handled; 2656 synchronized (mH) { 2657 int result = sendInputEventOnMainLooperLocked(p); 2658 if (result == DISPATCH_IN_PROGRESS) { 2659 return; 2660 } 2661 2662 handled = (result == DISPATCH_HANDLED); 2663 } 2664 2665 invokeFinishedInputEventCallback(p, handled); 2666 } 2667 2668 // Must be called on the main looper sendInputEventOnMainLooperLocked(PendingEvent p)2669 int sendInputEventOnMainLooperLocked(PendingEvent p) { 2670 if (mCurChannel != null) { 2671 if (mCurSender == null) { 2672 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper()); 2673 } 2674 2675 final InputEvent event = p.mEvent; 2676 final int seq = event.getSequenceNumber(); 2677 if (mCurSender.sendInputEvent(seq, event)) { 2678 mPendingEvents.put(seq, p); 2679 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, 2680 mPendingEvents.size()); 2681 2682 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p); 2683 msg.setAsynchronous(true); 2684 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT); 2685 return DISPATCH_IN_PROGRESS; 2686 } 2687 2688 Log.w(TAG, "Unable to send input event to IME: " + mCurId + " dropping: " + event); 2689 } 2690 return DISPATCH_NOT_HANDLED; 2691 } 2692 finishedInputEvent(int seq, boolean handled, boolean timeout)2693 void finishedInputEvent(int seq, boolean handled, boolean timeout) { 2694 final PendingEvent p; 2695 synchronized (mH) { 2696 int index = mPendingEvents.indexOfKey(seq); 2697 if (index < 0) { 2698 return; // spurious, event already finished or timed out 2699 } 2700 2701 p = mPendingEvents.valueAt(index); 2702 mPendingEvents.removeAt(index); 2703 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size()); 2704 2705 if (timeout) { 2706 Log.w(TAG, "Timeout waiting for IME to handle input event after " 2707 + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId); 2708 } else { 2709 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p); 2710 } 2711 } 2712 2713 invokeFinishedInputEventCallback(p, handled); 2714 } 2715 2716 // Assumes the event has already been removed from the queue. invokeFinishedInputEventCallback(PendingEvent p, boolean handled)2717 void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) { 2718 p.mHandled = handled; 2719 if (p.mHandler.getLooper().isCurrentThread()) { 2720 // Already running on the callback handler thread so we can send the 2721 // callback immediately. 2722 p.run(); 2723 } else { 2724 // Post the event to the callback handler thread. 2725 // In this case, the callback will be responsible for recycling the event. 2726 Message msg = Message.obtain(p.mHandler, p); 2727 msg.setAsynchronous(true); 2728 msg.sendToTarget(); 2729 } 2730 } 2731 flushPendingEventsLocked()2732 private void flushPendingEventsLocked() { 2733 mH.removeMessages(MSG_FLUSH_INPUT_EVENT); 2734 2735 final int count = mPendingEvents.size(); 2736 for (int i = 0; i < count; i++) { 2737 int seq = mPendingEvents.keyAt(i); 2738 Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0); 2739 msg.setAsynchronous(true); 2740 msg.sendToTarget(); 2741 } 2742 } 2743 obtainPendingEventLocked(InputEvent event, Object token, String inputMethodId, FinishedInputEventCallback callback, Handler handler)2744 private PendingEvent obtainPendingEventLocked(InputEvent event, Object token, 2745 String inputMethodId, FinishedInputEventCallback callback, Handler handler) { 2746 PendingEvent p = mPendingEventPool.acquire(); 2747 if (p == null) { 2748 p = new PendingEvent(); 2749 } 2750 p.mEvent = event; 2751 p.mToken = token; 2752 p.mInputMethodId = inputMethodId; 2753 p.mCallback = callback; 2754 p.mHandler = handler; 2755 return p; 2756 } 2757 recyclePendingEventLocked(PendingEvent p)2758 private void recyclePendingEventLocked(PendingEvent p) { 2759 p.recycle(); 2760 mPendingEventPool.release(p); 2761 } 2762 2763 /** 2764 * Show IME picker popup window. 2765 * 2766 * <p>Requires the {@link PackageManager#FEATURE_INPUT_METHODS} feature which can be detected 2767 * using {@link PackageManager#hasSystemFeature(String)}. 2768 */ showInputMethodPicker()2769 public void showInputMethodPicker() { 2770 synchronized (mH) { 2771 showInputMethodPickerLocked(); 2772 } 2773 } 2774 2775 /** 2776 * Shows the input method chooser dialog from system. 2777 * 2778 * @param showAuxiliarySubtypes Set true to show auxiliary input methods. 2779 * @param displayId The ID of the display where the chooser dialog should be shown. 2780 * @hide 2781 */ 2782 @RequiresPermission(WRITE_SECURE_SETTINGS) showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId)2783 public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) { 2784 final int mode = showAuxiliarySubtypes 2785 ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES 2786 : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES; 2787 try { 2788 mService.showInputMethodPickerFromSystem(mClient, mode, displayId); 2789 } catch (RemoteException e) { 2790 throw e.rethrowFromSystemServer(); 2791 } 2792 } 2793 showInputMethodPickerLocked()2794 private void showInputMethodPickerLocked() { 2795 try { 2796 mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO); 2797 } catch (RemoteException e) { 2798 throw e.rethrowFromSystemServer(); 2799 } 2800 } 2801 2802 /** 2803 * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected. 2804 * 2805 * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure 2806 * that this test API returns when and only while and only while 2807 * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not 2808 * pass CTS.</p> 2809 * 2810 * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI. 2811 * @hide 2812 */ 2813 @TestApi isInputMethodPickerShown()2814 public boolean isInputMethodPickerShown() { 2815 try { 2816 return mService.isInputMethodPickerShownForTest(); 2817 } catch (RemoteException e) { 2818 throw e.rethrowFromSystemServer(); 2819 } 2820 } 2821 2822 /** 2823 * Show the settings for enabling subtypes of the specified input method. 2824 * 2825 * @param imiId An input method, whose subtypes settings will be shown. If imiId is null, 2826 * subtypes of all input methods will be shown. 2827 */ showInputMethodAndSubtypeEnabler(String imiId)2828 public void showInputMethodAndSubtypeEnabler(String imiId) { 2829 try { 2830 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId); 2831 } catch (RemoteException e) { 2832 throw e.rethrowFromSystemServer(); 2833 } 2834 } 2835 2836 /** 2837 * Returns the current input method subtype. This subtype is one of the subtypes in 2838 * the current input method. This method returns null when the current input method doesn't 2839 * have any input method subtype. 2840 */ getCurrentInputMethodSubtype()2841 public InputMethodSubtype getCurrentInputMethodSubtype() { 2842 try { 2843 return mService.getCurrentInputMethodSubtype(); 2844 } catch (RemoteException e) { 2845 throw e.rethrowFromSystemServer(); 2846 } 2847 } 2848 2849 /** 2850 * Switch to a new input method subtype of the current input method. 2851 * @param subtype A new input method subtype to switch. 2852 * @return true if the current subtype was successfully switched. When the specified subtype is 2853 * null, this method returns false. 2854 * @deprecated If the calling process is an IME, use 2855 * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which 2856 * does not require any permission as long as the caller is the current IME. 2857 * If the calling process is some privileged app that already has 2858 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission, just 2859 * directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}. 2860 */ 2861 @Deprecated 2862 @RequiresPermission(WRITE_SECURE_SETTINGS) setCurrentInputMethodSubtype(InputMethodSubtype subtype)2863 public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) { 2864 if (Process.myUid() == Process.SYSTEM_UID) { 2865 Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because " 2866 + "almost always it is a bug under multi-user / multi-profile environment. " 2867 + "Consider directly interacting with InputMethodManagerService " 2868 + "via LocalServices."); 2869 return false; 2870 } 2871 if (subtype == null) { 2872 // See the JavaDoc. This is how this method has worked. 2873 return false; 2874 } 2875 final Context fallbackContext = ActivityThread.currentApplication(); 2876 if (fallbackContext == null) { 2877 return false; 2878 } 2879 if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS) 2880 != PackageManager.PERMISSION_GRANTED) { 2881 return false; 2882 } 2883 final ContentResolver contentResolver = fallbackContext.getContentResolver(); 2884 final String imeId = Settings.Secure.getString(contentResolver, 2885 Settings.Secure.DEFAULT_INPUT_METHOD); 2886 if (ComponentName.unflattenFromString(imeId) == null) { 2887 // Null or invalid IME ID format. 2888 return false; 2889 } 2890 final List<InputMethodSubtype> enabledSubtypes; 2891 try { 2892 enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true); 2893 } catch (RemoteException e) { 2894 return false; 2895 } 2896 final int numSubtypes = enabledSubtypes.size(); 2897 for (int i = 0; i < numSubtypes; ++i) { 2898 final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i); 2899 if (enabledSubtype.equals(subtype)) { 2900 Settings.Secure.putInt(contentResolver, 2901 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, enabledSubtype.hashCode()); 2902 return true; 2903 } 2904 } 2905 return false; 2906 } 2907 2908 /** 2909 * Notify that a user took some action with this input method. 2910 * 2911 * @deprecated Just kept to avoid possible app compat issue. 2912 * @hide 2913 */ 2914 @Deprecated 2915 @UnsupportedAppUsage(trackingBug = 114740982, maxTargetSdk = Build.VERSION_CODES.P) notifyUserAction()2916 public void notifyUserAction() { 2917 Log.w(TAG, "notifyUserAction() is a hidden method, which is now just a stub method" 2918 + " that does nothing. Leave comments in b.android.com/114740982 if your " 2919 + " application still depends on the previous behavior of this method."); 2920 } 2921 2922 /** 2923 * Returns a map of all shortcut input method info and their subtypes. 2924 */ getShortcutInputMethodsAndSubtypes()2925 public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() { 2926 final List<InputMethodInfo> enabledImes = getEnabledInputMethodList(); 2927 2928 // Ensure we check system IMEs first. 2929 enabledImes.sort(Comparator.comparingInt(imi -> imi.isSystem() ? 0 : 1)); 2930 2931 final int numEnabledImes = enabledImes.size(); 2932 for (int imiIndex = 0; imiIndex < numEnabledImes; ++imiIndex) { 2933 final InputMethodInfo imi = enabledImes.get(imiIndex); 2934 final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList( 2935 imi, true); 2936 final int subtypeCount = subtypes.size(); 2937 for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) { 2938 final InputMethodSubtype subtype = imi.getSubtypeAt(subtypeIndex); 2939 if (SUBTYPE_MODE_VOICE.equals(subtype.getMode())) { 2940 return Collections.singletonMap(imi, Collections.singletonList(subtype)); 2941 } 2942 } 2943 } 2944 return Collections.emptyMap(); 2945 } 2946 2947 /** 2948 * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}. 2949 * 2950 * <p>TODO(Bug 113914148): Check if we can remove this. We have accidentally exposed 2951 * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them 2952 * started relying on it.</p> 2953 * 2954 * @return Something that is not well-defined. 2955 * @hide 2956 */ 2957 @UnsupportedAppUsage getInputMethodWindowVisibleHeight()2958 public int getInputMethodWindowVisibleHeight() { 2959 try { 2960 return mService.getInputMethodWindowVisibleHeight(); 2961 } catch (RemoteException e) { 2962 throw e.rethrowFromSystemServer(); 2963 } 2964 } 2965 2966 /** 2967 * Force switch to the last used input method and subtype. If the last input method didn't have 2968 * any subtypes, the framework will simply switch to the last input method with no subtype 2969 * specified. 2970 * @param imeToken Supplies the identifying token given to an input method when it was started, 2971 * which allows it to perform this operation on itself. 2972 * @return true if the current input method and subtype was successfully switched to the last 2973 * used input method and subtype. 2974 * @deprecated Use {@link InputMethodService#switchToPreviousInputMethod()} instead. This method 2975 * was intended for IME developers who should be accessing APIs through the service. APIs in 2976 * this class are intended for app developers interacting with the IME. 2977 */ 2978 @Deprecated switchToLastInputMethod(IBinder imeToken)2979 public boolean switchToLastInputMethod(IBinder imeToken) { 2980 return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod(); 2981 } 2982 2983 /** 2984 * Force switch to the next input method and subtype. If there is no IME enabled except 2985 * current IME and subtype, do nothing. 2986 * @param imeToken Supplies the identifying token given to an input method when it was started, 2987 * which allows it to perform this operation on itself. 2988 * @param onlyCurrentIme if true, the framework will find the next subtype which 2989 * belongs to the current IME 2990 * @return true if the current input method and subtype was successfully switched to the next 2991 * input method and subtype. 2992 * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This 2993 * method was intended for IME developers who should be accessing APIs through the service. 2994 * APIs in this class are intended for app developers interacting with the IME. 2995 */ 2996 @Deprecated switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme)2997 public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) { 2998 return InputMethodPrivilegedOperationsRegistry.get(imeToken) 2999 .switchToNextInputMethod(onlyCurrentIme); 3000 } 3001 3002 /** 3003 * Returns true if the current IME needs to offer the users ways to switch to a next input 3004 * method (e.g. a globe key.). 3005 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true, 3006 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly. 3007 * <p> Note that the system determines the most appropriate next input method 3008 * and subtype in order to provide the consistent user experience in switching 3009 * between IMEs and subtypes. 3010 * @param imeToken Supplies the identifying token given to an input method when it was started, 3011 * which allows it to perform this operation on itself. 3012 * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()} 3013 * instead. This method was intended for IME developers who should be accessing APIs through 3014 * the service. APIs in this class are intended for app developers interacting with the IME. 3015 */ 3016 @Deprecated shouldOfferSwitchingToNextInputMethod(IBinder imeToken)3017 public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) { 3018 return InputMethodPrivilegedOperationsRegistry.get(imeToken) 3019 .shouldOfferSwitchingToNextInputMethod(); 3020 } 3021 3022 /** 3023 * Set additional input method subtypes. Only a process which shares the same uid with the IME 3024 * can add additional input method subtypes to the IME. 3025 * Please note that a subtype's status is stored in the system. 3026 * For example, enabled subtypes are remembered by the framework even after they are removed 3027 * by using this method. If you re-add the same subtypes again, 3028 * they will just get enabled. If you want to avoid such conflicts, for instance, you may 3029 * want to create a "different" new subtype even with the same locale and mode, 3030 * by changing its extra value. The different subtype won't get affected by the stored past 3031 * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer 3032 * to the current implementation.) 3033 * 3034 * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes 3035 * specified by {@code subtypes}, those multiple instances are automatically merged into one 3036 * instance.</p> 3037 * 3038 * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty 3039 * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing 3040 * the last one entry of additional subtypes. If your IME statically defines one or more 3041 * subtypes in the manifest XML file, you may be able to work around this limitation by 3042 * specifying one of those statically defined subtypes in {@code subtypes}.</p> 3043 * 3044 * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to. 3045 * @param subtypes subtypes will be added as additional subtypes of the current input method. 3046 * @deprecated For IMEs that have already implemented features like customizable/downloadable 3047 * keyboard layouts/languages, please start migration to other approaches. One idea 3048 * would be exposing only one unified {@link InputMethodSubtype} then implement 3049 * IME's own language switching mechanism within that unified subtype. The support 3050 * of "Additional Subtype" may be completely dropped in a future version of Android. 3051 */ 3052 @Deprecated setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes)3053 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) { 3054 try { 3055 mService.setAdditionalInputMethodSubtypes(imiId, subtypes); 3056 } catch (RemoteException e) { 3057 throw e.rethrowFromSystemServer(); 3058 } 3059 } 3060 getLastInputMethodSubtype()3061 public InputMethodSubtype getLastInputMethodSubtype() { 3062 try { 3063 return mService.getLastInputMethodSubtype(); 3064 } catch (RemoteException e) { 3065 throw e.rethrowFromSystemServer(); 3066 } 3067 } 3068 3069 /** 3070 * <p>This is used for CTS test only. Do not use this method outside of CTS package.<p/> 3071 * @return the ID of this display which this {@link InputMethodManager} resides 3072 * @hide 3073 */ 3074 @TestApi getDisplayId()3075 public int getDisplayId() { 3076 return mDisplayId; 3077 } 3078 doDump(FileDescriptor fd, PrintWriter fout, String[] args)3079 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { 3080 if (processDump(fd, args)) { 3081 return; 3082 } 3083 3084 final Printer p = new PrintWriterPrinter(fout); 3085 p.println("Input method client state for " + this + ":"); 3086 3087 p.println(" mService=" + mService); 3088 p.println(" mMainLooper=" + mMainLooper); 3089 p.println(" mIInputContext=" + mIInputContext); 3090 p.println(" mActive=" + mActive 3091 + " mRestartOnNextWindowFocus=" + mRestartOnNextWindowFocus 3092 + " mBindSequence=" + mBindSequence 3093 + " mCurId=" + mCurId); 3094 p.println(" mFullscreenMode=" + mFullscreenMode); 3095 if (mCurrentInputMethodSession != null) { 3096 p.println(" mCurMethod=" + mCurrentInputMethodSession); 3097 } else { 3098 p.println(" mCurMethod= null"); 3099 } 3100 p.println(" mCurRootView=" + mCurRootView); 3101 p.println(" mServedView=" + getServedViewLocked()); 3102 p.println(" mNextServedView=" + getNextServedViewLocked()); 3103 p.println(" mServedConnecting=" + mServedConnecting); 3104 if (mCurrentTextBoxAttribute != null) { 3105 p.println(" mCurrentTextBoxAttribute:"); 3106 mCurrentTextBoxAttribute.dump(p, " "); 3107 } else { 3108 p.println(" mCurrentTextBoxAttribute: null"); 3109 } 3110 p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper); 3111 p.println(" mCompletions=" + Arrays.toString(mCompletions)); 3112 p.println(" mCursorRect=" + mCursorRect); 3113 p.println(" mCursorSelStart=" + mCursorSelStart 3114 + " mCursorSelEnd=" + mCursorSelEnd 3115 + " mCursorCandStart=" + mCursorCandStart 3116 + " mCursorCandEnd=" + mCursorCandEnd); 3117 } 3118 3119 /** 3120 * Callback that is invoked when an input event that was dispatched to 3121 * the IME has been finished. 3122 * @hide 3123 */ 3124 public interface FinishedInputEventCallback { onFinishedInputEvent(Object token, boolean handled)3125 public void onFinishedInputEvent(Object token, boolean handled); 3126 } 3127 3128 private final class ImeInputEventSender extends InputEventSender { ImeInputEventSender(InputChannel inputChannel, Looper looper)3129 public ImeInputEventSender(InputChannel inputChannel, Looper looper) { 3130 super(inputChannel, looper); 3131 } 3132 3133 @Override onInputEventFinished(int seq, boolean handled)3134 public void onInputEventFinished(int seq, boolean handled) { 3135 finishedInputEvent(seq, handled, false); 3136 } 3137 } 3138 3139 private final class PendingEvent implements Runnable { 3140 public InputEvent mEvent; 3141 public Object mToken; 3142 public String mInputMethodId; 3143 public FinishedInputEventCallback mCallback; 3144 public Handler mHandler; 3145 public boolean mHandled; 3146 recycle()3147 public void recycle() { 3148 mEvent = null; 3149 mToken = null; 3150 mInputMethodId = null; 3151 mCallback = null; 3152 mHandler = null; 3153 mHandled = false; 3154 } 3155 3156 @Override run()3157 public void run() { 3158 mCallback.onFinishedInputEvent(mToken, mHandled); 3159 3160 synchronized (mH) { 3161 recyclePendingEventLocked(this); 3162 } 3163 } 3164 } 3165 dumpViewInfo(@ullable final View view)3166 private static String dumpViewInfo(@Nullable final View view) { 3167 if (view == null) { 3168 return "null"; 3169 } 3170 final StringBuilder sb = new StringBuilder(); 3171 sb.append(view); 3172 sb.append(",focus=" + view.hasFocus()); 3173 sb.append(",windowFocus=" + view.hasWindowFocus()); 3174 sb.append(",autofillUiShowing=" + isAutofillUIShowing(view)); 3175 sb.append(",window=" + view.getWindowToken()); 3176 sb.append(",displayId=" + view.getContext().getDisplayId()); 3177 sb.append(",temporaryDetach=" + view.isTemporarilyDetached()); 3178 sb.append(",hasImeFocus=" + view.hasImeFocus()); 3179 3180 return sb.toString(); 3181 } 3182 3183 /** 3184 * Checks the args to see if a proto-based ime dump was requested and writes the client side 3185 * ime dump to the given {@link FileDescriptor}. 3186 * 3187 * @return {@code true} if a proto-based ime dump was requested. 3188 */ processDump(final FileDescriptor fd, final String[] args)3189 private boolean processDump(final FileDescriptor fd, final String[] args) { 3190 if (args == null) { 3191 return false; 3192 } 3193 3194 for (String arg : args) { 3195 if (arg.equals(PROTO_ARG)) { 3196 final ProtoOutputStream proto = new ProtoOutputStream(fd); 3197 dumpDebug(proto, null /* icProto */); 3198 proto.flush(); 3199 return true; 3200 } 3201 } 3202 return false; 3203 } 3204 3205 /** 3206 * Write the proto dump of various client side components to the provided 3207 * {@link ProtoOutputStream}. 3208 * 3209 * @param proto The proto stream to which the dumps are written. 3210 * @param icProto {@link InputConnection} call data in proto format. 3211 * @hide 3212 */ 3213 @GuardedBy("mH") dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto)3214 public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) { 3215 if (mCurrentInputMethodSession == null) { 3216 return; 3217 } 3218 3219 proto.write(DISPLAY_ID, mDisplayId); 3220 final long token = proto.start(INPUT_METHOD_MANAGER); 3221 synchronized (mH) { 3222 proto.write(CUR_ID, mCurId); 3223 proto.write(FULLSCREEN_MODE, mFullscreenMode); 3224 proto.write(ACTIVE, mActive); 3225 proto.write(SERVED_CONNECTING, mServedConnecting); 3226 proto.end(token); 3227 if (mCurRootView != null) { 3228 mCurRootView.dumpDebug(proto, VIEW_ROOT_IMPL); 3229 } 3230 if (mCurrentTextBoxAttribute != null) { 3231 mCurrentTextBoxAttribute.dumpDebug(proto, EDITOR_INFO); 3232 } 3233 if (mImeInsetsConsumer != null) { 3234 mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER); 3235 } 3236 if (mServedInputConnectionWrapper != null) { 3237 mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION); 3238 } 3239 if (icProto != null) { 3240 proto.write(INPUT_CONNECTION_CALL, icProto.getBytes()); 3241 } 3242 } 3243 } 3244 } 3245