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