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