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.UserIdInt; 30 import android.app.ActivityThread; 31 import android.compat.annotation.UnsupportedAppUsage; 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 || mActivityViewToScreenMatrix == null) { 711 // Either InputBoundResult#mActivityViewToScreenMatrixValues is null 712 // OR this app is unbound from the parent ActivityView. In this case, 713 // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix. 714 mActivityViewToScreenMatrix = null; 715 return; 716 } 717 718 final float[] currentValues = new float[9]; 719 mActivityViewToScreenMatrix.getValues(currentValues); 720 if (Arrays.equals(currentValues, matrixValues)) { 721 return; 722 } 723 mActivityViewToScreenMatrix.setValues(matrixValues); 724 725 if (mCursorAnchorInfo == null || mCurMethod == null 726 || mServedInputConnectionWrapper == null) { 727 return; 728 } 729 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode 730 & InputConnection.CURSOR_UPDATE_MONITOR) != 0; 731 if (!isMonitoring) { 732 return; 733 } 734 // Since the host ActivityView is moved, we need to issue 735 // IMS#updateCursorAnchorInfo() again. 736 try { 737 mCurMethod.updateCursorAnchorInfo( 738 CursorAnchorInfo.createForAdditionalParentMatrix( 739 mCursorAnchorInfo, mActivityViewToScreenMatrix)); 740 } catch (RemoteException e) { 741 Log.w(TAG, "IME died: " + mCurId, e); 742 } 743 } 744 return; 745 } 746 } 747 } 748 } 749 750 private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper { 751 private final InputMethodManager mParentInputMethodManager; 752 ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, final InputMethodManager inputMethodManager)753 public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, 754 final InputMethodManager inputMethodManager) { 755 super(mainLooper, conn); 756 mParentInputMethodManager = inputMethodManager; 757 } 758 759 @Override isActive()760 public boolean isActive() { 761 return mParentInputMethodManager.mActive && !isFinished(); 762 } 763 deactivate()764 void deactivate() { 765 if (isFinished()) { 766 // This is a small performance optimization. Still only the 1st call of 767 // reportFinish() will take effect. 768 return; 769 } 770 closeConnection(); 771 } 772 773 @Override toString()774 public String toString() { 775 return "ControlledInputConnectionWrapper{" 776 + "connection=" + getInputConnection() 777 + " finished=" + isFinished() 778 + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive 779 + "}"; 780 } 781 } 782 783 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { 784 @Override 785 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 786 // No need to check for dump permission, since we only give this 787 // interface to the system. 788 CountDownLatch latch = new CountDownLatch(1); 789 SomeArgs sargs = SomeArgs.obtain(); 790 sargs.arg1 = fd; 791 sargs.arg2 = fout; 792 sargs.arg3 = args; 793 sargs.arg4 = latch; 794 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs)); 795 try { 796 if (!latch.await(5, TimeUnit.SECONDS)) { 797 fout.println("Timeout waiting for dump"); 798 } 799 } catch (InterruptedException e) { 800 fout.println("Interrupted waiting for dump"); 801 } 802 } 803 804 @Override 805 public void onBindMethod(InputBindResult res) { 806 mH.obtainMessage(MSG_BIND, res).sendToTarget(); 807 } 808 809 @Override 810 public void onUnbindMethod(int sequence, @UnbindReason int unbindReason) { 811 mH.obtainMessage(MSG_UNBIND, sequence, unbindReason).sendToTarget(); 812 } 813 814 @Override 815 public void setActive(boolean active, boolean fullscreen) { 816 mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, fullscreen ? 1 : 0).sendToTarget(); 817 } 818 819 @Override 820 public void reportFullscreenMode(boolean fullscreen) { 821 mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0) 822 .sendToTarget(); 823 } 824 825 @Override 826 public void reportPreRendered(EditorInfo info) { 827 mH.obtainMessage(MSG_REPORT_PRE_RENDERED, 0, 0, info) 828 .sendToTarget(); 829 } 830 831 @Override 832 public void applyImeVisibility(boolean setVisible) { 833 mH.obtainMessage(MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, 0) 834 .sendToTarget(); 835 } 836 837 @Override 838 public void updateActivityViewToScreenMatrix(int bindSequence, float[] matrixValues) { 839 mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0, 840 matrixValues).sendToTarget(); 841 } 842 }; 843 844 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false); 845 846 /** 847 * For layoutlib to clean up static objects inside {@link InputMethodManager}. 848 */ tearDownEditMode()849 static void tearDownEditMode() { 850 if (!isInEditMode()) { 851 throw new UnsupportedOperationException( 852 "This method must be called only from layoutlib"); 853 } 854 synchronized (sLock) { 855 sInstance = null; 856 } 857 } 858 859 /** 860 * For layoutlib to override this method to return {@code true}. 861 * 862 * @return {@code true} if the process is running for developer tools 863 * @see View#isInEditMode() 864 */ isInEditMode()865 private static boolean isInEditMode() { 866 return false; 867 } 868 869 @NonNull createInstance(int displayId, Looper looper)870 private static InputMethodManager createInstance(int displayId, Looper looper) { 871 return isInEditMode() ? createStubInstance(displayId, looper) 872 : createRealInstance(displayId, looper); 873 } 874 875 @NonNull createRealInstance(int displayId, Looper looper)876 private static InputMethodManager createRealInstance(int displayId, Looper looper) { 877 final IInputMethodManager service; 878 try { 879 service = IInputMethodManager.Stub.asInterface( 880 ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); 881 } catch (ServiceNotFoundException e) { 882 throw new IllegalStateException(e); 883 } 884 final InputMethodManager imm = new InputMethodManager(service, displayId, looper); 885 // InputMethodManagerService#addClient() relies on Binder.getCalling{Pid, Uid}() to 886 // associate PID/UID with each IME client. This means: 887 // A. if this method call will be handled as an IPC, there is no problem. 888 // B. if this method call will be handled as an in-proc method call, we need to 889 // ensure that Binder.getCalling{Pid, Uid}() return Process.my{Pid, Uid}() 890 // Either ways we can always call Binder.{clear, restore}CallingIdentity() because 891 // 1) doing so has no effect for A and 2) doing so is sufficient for B. 892 final long identity = Binder.clearCallingIdentity(); 893 try { 894 service.addClient(imm.mClient, imm.mIInputContext, displayId); 895 } catch (RemoteException e) { 896 e.rethrowFromSystemServer(); 897 } finally { 898 Binder.restoreCallingIdentity(identity); 899 } 900 return imm; 901 } 902 903 @NonNull createStubInstance(int displayId, Looper looper)904 private static InputMethodManager createStubInstance(int displayId, Looper looper) { 905 // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS. 906 final Class<IInputMethodManager> c = IInputMethodManager.class; 907 final IInputMethodManager stubInterface = 908 (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(), 909 new Class[]{c}, (proxy, method, args) -> { 910 final Class<?> returnType = method.getReturnType(); 911 if (returnType == boolean.class) { 912 return false; 913 } else if (returnType == int.class) { 914 return 0; 915 } else if (returnType == long.class) { 916 return 0L; 917 } else if (returnType == short.class) { 918 return 0; 919 } else if (returnType == char.class) { 920 return 0; 921 } else if (returnType == byte.class) { 922 return 0; 923 } else if (returnType == float.class) { 924 return 0f; 925 } else if (returnType == double.class) { 926 return 0.0; 927 } else { 928 return null; 929 } 930 }); 931 return new InputMethodManager(stubInterface, displayId, looper); 932 } 933 InputMethodManager(IInputMethodManager service, int displayId, Looper looper)934 private InputMethodManager(IInputMethodManager service, int displayId, Looper looper) { 935 mService = service; 936 mMainLooper = looper; 937 mH = new H(looper); 938 mDisplayId = displayId; 939 mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this); 940 } 941 942 /** 943 * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist. 944 * 945 * @param context {@link Context} for which IME APIs need to work 946 * @return {@link InputMethodManager} instance 947 * @hide 948 */ 949 @NonNull forContext(Context context)950 public static InputMethodManager forContext(Context context) { 951 final int displayId = context.getDisplayId(); 952 // For better backward compatibility, we always use Looper.getMainLooper() for the default 953 // display case. 954 final Looper looper = displayId == Display.DEFAULT_DISPLAY 955 ? Looper.getMainLooper() : context.getMainLooper(); 956 return forContextInternal(displayId, looper); 957 } 958 959 @NonNull forContextInternal(int displayId, Looper looper)960 private static InputMethodManager forContextInternal(int displayId, Looper looper) { 961 final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY; 962 synchronized (sLock) { 963 InputMethodManager instance = sInstanceMap.get(displayId); 964 if (instance != null) { 965 return instance; 966 } 967 instance = createInstance(displayId, looper); 968 // For backward compatibility, store the instance also to sInstance for default display. 969 if (sInstance == null && isDefaultDisplay) { 970 sInstance = instance; 971 } 972 sInstanceMap.put(displayId, instance); 973 return instance; 974 } 975 } 976 977 /** 978 * Deprecated. Do not use. 979 * 980 * @return global {@link InputMethodManager} instance 981 * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully 982 * support multi-display scenario. 983 * @hide 984 */ 985 @Deprecated 986 @UnsupportedAppUsage getInstance()987 public static InputMethodManager getInstance() { 988 Log.w(TAG, "InputMethodManager.getInstance() is deprecated because it cannot be" 989 + " compatible with multi-display." 990 + " Use context.getSystemService(InputMethodManager.class) instead.", 991 new Throwable()); 992 ensureDefaultInstanceForDefaultDisplayIfNecessary(); 993 return peekInstance(); 994 } 995 996 /** 997 * Deprecated. Do not use. 998 * 999 * @return {@link #sInstance} 1000 * @deprecated Use {@link Context#getSystemService(Class)} instead. This method cannot fully 1001 * support multi-display scenario. 1002 * @hide 1003 */ 1004 @Deprecated 1005 @UnsupportedAppUsage peekInstance()1006 public static InputMethodManager peekInstance() { 1007 Log.w(TAG, "InputMethodManager.peekInstance() is deprecated because it cannot be" 1008 + " compatible with multi-display." 1009 + " Use context.getSystemService(InputMethodManager.class) instead.", 1010 new Throwable()); 1011 synchronized (sLock) { 1012 return sInstance; 1013 } 1014 } 1015 1016 /** @hide */ 1017 @UnsupportedAppUsage getClient()1018 public IInputMethodClient getClient() { 1019 return mClient; 1020 } 1021 1022 /** @hide */ 1023 @UnsupportedAppUsage getInputContext()1024 public IInputContext getInputContext() { 1025 return mIInputContext; 1026 } 1027 1028 /** 1029 * Returns the list of installed input methods. 1030 * 1031 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1032 * 1033 * @return {@link List} of {@link InputMethodInfo}. 1034 */ getInputMethodList()1035 public List<InputMethodInfo> getInputMethodList() { 1036 try { 1037 // We intentionally do not use UserHandle.getCallingUserId() here because for system 1038 // services InputMethodManagerInternal.getInputMethodListAsUser() should be used 1039 // instead. 1040 return mService.getInputMethodList(UserHandle.myUserId()); 1041 } catch (RemoteException e) { 1042 throw e.rethrowFromSystemServer(); 1043 } 1044 } 1045 1046 /** 1047 * Returns the list of installed input methods for the specified user. 1048 * 1049 * @param userId user ID to query 1050 * @return {@link List} of {@link InputMethodInfo}. 1051 * @hide 1052 */ 1053 @RequiresPermission(INTERACT_ACROSS_USERS_FULL) getInputMethodListAsUser(@serIdInt int userId)1054 public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { 1055 try { 1056 return mService.getInputMethodList(userId); 1057 } catch (RemoteException e) { 1058 throw e.rethrowFromSystemServer(); 1059 } 1060 } 1061 1062 /** 1063 * Returns the list of enabled input methods. 1064 * 1065 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1066 * 1067 * @return {@link List} of {@link InputMethodInfo}. 1068 */ getEnabledInputMethodList()1069 public List<InputMethodInfo> getEnabledInputMethodList() { 1070 try { 1071 // We intentionally do not use UserHandle.getCallingUserId() here because for system 1072 // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used 1073 // instead. 1074 return mService.getEnabledInputMethodList(UserHandle.myUserId()); 1075 } catch (RemoteException e) { 1076 throw e.rethrowFromSystemServer(); 1077 } 1078 } 1079 1080 /** 1081 * Returns the list of enabled input methods for the specified user. 1082 * 1083 * @param userId user ID to query 1084 * @return {@link List} of {@link InputMethodInfo}. 1085 * @hide 1086 */ 1087 @RequiresPermission(INTERACT_ACROSS_USERS_FULL) getEnabledInputMethodListAsUser(@serIdInt int userId)1088 public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) { 1089 try { 1090 return mService.getEnabledInputMethodList(userId); 1091 } catch (RemoteException e) { 1092 throw e.rethrowFromSystemServer(); 1093 } 1094 } 1095 1096 /** 1097 * Returns a list of enabled input method subtypes for the specified input method info. 1098 * 1099 * <p>On multi user environment, this API returns a result for the calling process user.</p> 1100 * 1101 * @param imi An input method info whose subtypes list will be returned. 1102 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly 1103 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework 1104 * will implicitly enable subtypes according to the current system language. 1105 */ getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes)1106 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi, 1107 boolean allowsImplicitlySelectedSubtypes) { 1108 try { 1109 return mService.getEnabledInputMethodSubtypeList( 1110 imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes); 1111 } catch (RemoteException e) { 1112 throw e.rethrowFromSystemServer(); 1113 } 1114 } 1115 1116 /** 1117 * @deprecated Use {@link InputMethodService#showStatusIcon(int)} instead. This method was 1118 * intended for IME developers who should be accessing APIs through the service. APIs in this 1119 * class are intended for app developers interacting with the IME. 1120 */ 1121 @Deprecated showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId)1122 public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) { 1123 InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(packageName, iconId); 1124 } 1125 1126 /** 1127 * @deprecated Use {@link InputMethodService#hideStatusIcon()} instead. This method was 1128 * intended for IME developers who should be accessing APIs through the service. APIs in 1129 * this class are intended for app developers interacting with the IME. 1130 */ 1131 @Deprecated hideStatusIcon(IBinder imeToken)1132 public void hideStatusIcon(IBinder imeToken) { 1133 InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(null, 0); 1134 } 1135 1136 /** 1137 * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing. 1138 * 1139 * @param spans will be ignored. 1140 * 1141 * @deprecated Do not use. 1142 * @hide 1143 */ 1144 @Deprecated 1145 @UnsupportedAppUsage registerSuggestionSpansForNotification(SuggestionSpan[] spans)1146 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) { 1147 Log.w(TAG, "registerSuggestionSpansForNotification() is deprecated. Does nothing."); 1148 } 1149 1150 /** 1151 * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing. 1152 * 1153 * @deprecated Do not use. 1154 * @hide 1155 */ 1156 @Deprecated 1157 @UnsupportedAppUsage notifySuggestionPicked(SuggestionSpan span, String originalString, int index)1158 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) { 1159 Log.w(TAG, "notifySuggestionPicked() is deprecated. Does nothing."); 1160 } 1161 1162 /** 1163 * Allows you to discover whether the attached input method is running 1164 * in fullscreen mode. Return true if it is fullscreen, entirely covering 1165 * your UI, else returns false. 1166 */ isFullscreenMode()1167 public boolean isFullscreenMode() { 1168 synchronized (mH) { 1169 return mFullscreenMode; 1170 } 1171 } 1172 1173 /** 1174 * Return true if the given view is the currently active view for the 1175 * input method. 1176 */ isActive(View view)1177 public boolean isActive(View view) { 1178 // Re-dispatch if there is a context mismatch. 1179 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1180 if (fallbackImm != null) { 1181 return fallbackImm.isActive(view); 1182 } 1183 1184 checkFocus(); 1185 synchronized (mH) { 1186 return (mServedView == view 1187 || (mServedView != null 1188 && mServedView.checkInputConnectionProxy(view))) 1189 && mCurrentTextBoxAttribute != null; 1190 } 1191 } 1192 1193 /** 1194 * Return true if any view is currently active in the input method. 1195 */ isActive()1196 public boolean isActive() { 1197 checkFocus(); 1198 synchronized (mH) { 1199 return mServedView != null && mCurrentTextBoxAttribute != null; 1200 } 1201 } 1202 1203 /** 1204 * Return true if the currently served view is accepting full text edits. 1205 * If false, it has no input connection, so can only handle raw key events. 1206 */ isAcceptingText()1207 public boolean isAcceptingText() { 1208 checkFocus(); 1209 return mServedInputConnectionWrapper != null && 1210 mServedInputConnectionWrapper.getInputConnection() != null; 1211 } 1212 1213 /** 1214 * Reset all of the state associated with being bound to an input method. 1215 */ clearBindingLocked()1216 void clearBindingLocked() { 1217 if (DEBUG) Log.v(TAG, "Clearing binding!"); 1218 clearConnectionLocked(); 1219 setInputChannelLocked(null); 1220 mBindSequence = -1; 1221 mCurId = null; 1222 mCurMethod = null; 1223 } 1224 setInputChannelLocked(InputChannel channel)1225 void setInputChannelLocked(InputChannel channel) { 1226 if (mCurChannel != channel) { 1227 if (mCurSender != null) { 1228 flushPendingEventsLocked(); 1229 mCurSender.dispose(); 1230 mCurSender = null; 1231 } 1232 if (mCurChannel != null) { 1233 mCurChannel.dispose(); 1234 } 1235 mCurChannel = channel; 1236 } 1237 } 1238 1239 /** 1240 * Reset all of the state associated with a served view being connected 1241 * to an input method 1242 */ clearConnectionLocked()1243 void clearConnectionLocked() { 1244 mCurrentTextBoxAttribute = null; 1245 if (mServedInputConnectionWrapper != null) { 1246 mServedInputConnectionWrapper.deactivate(); 1247 mServedInputConnectionWrapper = null; 1248 } 1249 } 1250 1251 /** 1252 * Disconnect any existing input connection, clearing the served view. 1253 */ 1254 @UnsupportedAppUsage finishInputLocked()1255 void finishInputLocked() { 1256 mNextServedView = null; 1257 mActivityViewToScreenMatrix = null; 1258 if (mServedView != null) { 1259 if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView)); 1260 mServedView = null; 1261 mCompletions = null; 1262 mServedConnecting = false; 1263 clearConnectionLocked(); 1264 } 1265 } 1266 displayCompletions(View view, CompletionInfo[] completions)1267 public void displayCompletions(View view, CompletionInfo[] completions) { 1268 // Re-dispatch if there is a context mismatch. 1269 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1270 if (fallbackImm != null) { 1271 fallbackImm.displayCompletions(view, completions); 1272 return; 1273 } 1274 1275 checkFocus(); 1276 synchronized (mH) { 1277 if (mServedView != view && (mServedView == null 1278 || !mServedView.checkInputConnectionProxy(view))) { 1279 return; 1280 } 1281 1282 mCompletions = completions; 1283 if (mCurMethod != null) { 1284 try { 1285 mCurMethod.displayCompletions(mCompletions); 1286 } catch (RemoteException e) { 1287 } 1288 } 1289 } 1290 } 1291 updateExtractedText(View view, int token, ExtractedText text)1292 public void updateExtractedText(View view, int token, ExtractedText text) { 1293 // Re-dispatch if there is a context mismatch. 1294 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1295 if (fallbackImm != null) { 1296 fallbackImm.updateExtractedText(view, token, text); 1297 return; 1298 } 1299 1300 checkFocus(); 1301 synchronized (mH) { 1302 if (mServedView != view && (mServedView == null 1303 || !mServedView.checkInputConnectionProxy(view))) { 1304 return; 1305 } 1306 1307 if (mCurMethod != null) { 1308 try { 1309 mCurMethod.updateExtractedText(token, text); 1310 } catch (RemoteException e) { 1311 } 1312 } 1313 } 1314 } 1315 1316 /** 1317 * Flag for {@link #showSoftInput} to indicate that this is an implicit 1318 * request to show the input window, not as the result of a direct request 1319 * by the user. The window may not be shown in this case. 1320 */ 1321 public static final int SHOW_IMPLICIT = 0x0001; 1322 1323 /** 1324 * Flag for {@link #showSoftInput} to indicate that the user has forced 1325 * the input method open (such as by long-pressing menu) so it should 1326 * not be closed until they explicitly do so. 1327 */ 1328 public static final int SHOW_FORCED = 0x0002; 1329 1330 /** 1331 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without 1332 * a result receiver: explicitly request that the current input method's 1333 * soft input area be shown to the user, if needed. 1334 * 1335 * @param view The currently focused view, which would like to receive 1336 * soft keyboard input. 1337 * @param flags Provides additional operating flags. Currently may be 1338 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 1339 */ showSoftInput(View view, int flags)1340 public boolean showSoftInput(View view, int flags) { 1341 // Re-dispatch if there is a context mismatch. 1342 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1343 if (fallbackImm != null) { 1344 return fallbackImm.showSoftInput(view, flags); 1345 } 1346 1347 return showSoftInput(view, flags, null); 1348 } 1349 1350 /** 1351 * Flag for the {@link ResultReceiver} result code from 1352 * {@link #showSoftInput(View, int, ResultReceiver)} and 1353 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1354 * state of the soft input window was unchanged and remains shown. 1355 */ 1356 public static final int RESULT_UNCHANGED_SHOWN = 0; 1357 1358 /** 1359 * Flag for the {@link ResultReceiver} result code from 1360 * {@link #showSoftInput(View, int, ResultReceiver)} and 1361 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1362 * state of the soft input window was unchanged and remains hidden. 1363 */ 1364 public static final int RESULT_UNCHANGED_HIDDEN = 1; 1365 1366 /** 1367 * Flag for the {@link ResultReceiver} result code from 1368 * {@link #showSoftInput(View, int, ResultReceiver)} and 1369 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1370 * state of the soft input window changed from hidden to shown. 1371 */ 1372 public static final int RESULT_SHOWN = 2; 1373 1374 /** 1375 * Flag for the {@link ResultReceiver} result code from 1376 * {@link #showSoftInput(View, int, ResultReceiver)} and 1377 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 1378 * state of the soft input window changed from shown to hidden. 1379 */ 1380 public static final int RESULT_HIDDEN = 3; 1381 1382 /** 1383 * Explicitly request that the current input method's soft input area be 1384 * shown to the user, if needed. Call this if the user interacts with 1385 * your view in such a way that they have expressed they would like to 1386 * start performing input into it. 1387 * 1388 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to 1389 * this method can be a long-lived object, because it may not be 1390 * garbage-collected until all the corresponding {@link ResultReceiver} 1391 * objects transferred to different processes get garbage-collected. 1392 * Follow the general patterns to avoid memory leaks in Android. 1393 * Consider to use {@link java.lang.ref.WeakReference} so that application 1394 * logic objects such as {@link android.app.Activity} and {@link Context} 1395 * can be garbage collected regardless of the lifetime of 1396 * {@link ResultReceiver}. 1397 * 1398 * @param view The currently focused view, which would like to receive 1399 * soft keyboard input. 1400 * @param flags Provides additional operating flags. Currently may be 1401 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 1402 * @param resultReceiver If non-null, this will be called by the IME when 1403 * it has processed your request to tell you what it has done. The result 1404 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 1405 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 1406 * {@link #RESULT_HIDDEN}. 1407 */ showSoftInput(View view, int flags, ResultReceiver resultReceiver)1408 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) { 1409 // Re-dispatch if there is a context mismatch. 1410 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1411 if (fallbackImm != null) { 1412 return fallbackImm.showSoftInput(view, flags, resultReceiver); 1413 } 1414 1415 checkFocus(); 1416 synchronized (mH) { 1417 if (mServedView != view && (mServedView == null 1418 || !mServedView.checkInputConnectionProxy(view))) { 1419 return false; 1420 } 1421 1422 try { 1423 return mService.showSoftInput(mClient, flags, resultReceiver); 1424 } catch (RemoteException e) { 1425 throw e.rethrowFromSystemServer(); 1426 } 1427 } 1428 } 1429 1430 /** 1431 * This method is still kept for a while until android.support.v7.widget.SearchView ver. 26.0 1432 * is publicly released because previous implementations of that class had relied on this method 1433 * via reflection. 1434 * 1435 * @deprecated This is a hidden API. You should never use this. 1436 * @hide 1437 */ 1438 @Deprecated 1439 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499) showSoftInputUnchecked(int flags, ResultReceiver resultReceiver)1440 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { 1441 try { 1442 Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed " 1443 + "soon. If you are using android.support.v7.widget.SearchView, please update " 1444 + "to version 26.0 or newer version."); 1445 mService.showSoftInput(mClient, flags, resultReceiver); 1446 } catch (RemoteException e) { 1447 throw e.rethrowFromSystemServer(); 1448 } 1449 } 1450 1451 /** 1452 * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestHideSelf(int)} 1453 * to indicate that the soft input window should only be hidden if it was not explicitly shown 1454 * by the user. 1455 */ 1456 public static final int HIDE_IMPLICIT_ONLY = 0x0001; 1457 1458 /** 1459 * Flag for {@link #hideSoftInputFromWindow} and {@link InputMethodService#requestShowSelf(int)} 1460 * to indicate that the soft input window should normally be hidden, unless it was originally 1461 * shown with {@link #SHOW_FORCED}. 1462 */ 1463 public static final int HIDE_NOT_ALWAYS = 0x0002; 1464 1465 /** 1466 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} 1467 * without a result: request to hide the soft input window from the 1468 * context of the window that is currently accepting input. 1469 * 1470 * @param windowToken The token of the window that is making the request, 1471 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1472 * @param flags Provides additional operating flags. Currently may be 1473 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1474 */ hideSoftInputFromWindow(IBinder windowToken, int flags)1475 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) { 1476 return hideSoftInputFromWindow(windowToken, flags, null); 1477 } 1478 1479 /** 1480 * Request to hide the soft input window from the context of the window 1481 * that is currently accepting input. This should be called as a result 1482 * of the user doing some actually than fairly explicitly requests to 1483 * have the input window hidden. 1484 * 1485 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to 1486 * this method can be a long-lived object, because it may not be 1487 * garbage-collected until all the corresponding {@link ResultReceiver} 1488 * objects transferred to different processes get garbage-collected. 1489 * Follow the general patterns to avoid memory leaks in Android. 1490 * Consider to use {@link java.lang.ref.WeakReference} so that application 1491 * logic objects such as {@link android.app.Activity} and {@link Context} 1492 * can be garbage collected regardless of the lifetime of 1493 * {@link ResultReceiver}. 1494 * 1495 * @param windowToken The token of the window that is making the request, 1496 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1497 * @param flags Provides additional operating flags. Currently may be 1498 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1499 * @param resultReceiver If non-null, this will be called by the IME when 1500 * it has processed your request to tell you what it has done. The result 1501 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 1502 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 1503 * {@link #RESULT_HIDDEN}. 1504 */ hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)1505 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, 1506 ResultReceiver resultReceiver) { 1507 checkFocus(); 1508 synchronized (mH) { 1509 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 1510 return false; 1511 } 1512 1513 try { 1514 return mService.hideSoftInput(mClient, flags, resultReceiver); 1515 } catch (RemoteException e) { 1516 throw e.rethrowFromSystemServer(); 1517 } 1518 } 1519 } 1520 1521 /** 1522 * This method toggles the input method window display. 1523 * If the input window is already displayed, it gets hidden. 1524 * If not the input window will be displayed. 1525 * @param windowToken The token of the window that is making the request, 1526 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1527 * @param showFlags Provides additional operating flags. May be 1528 * 0 or have the {@link #SHOW_IMPLICIT}, 1529 * {@link #SHOW_FORCED} bit set. 1530 * @param hideFlags Provides additional operating flags. May be 1531 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1532 * {@link #HIDE_NOT_ALWAYS} bit set. 1533 **/ toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)1534 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) { 1535 synchronized (mH) { 1536 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 1537 return; 1538 } 1539 if (mCurMethod != null) { 1540 try { 1541 mCurMethod.toggleSoftInput(showFlags, hideFlags); 1542 } catch (RemoteException e) { 1543 } 1544 } 1545 } 1546 } 1547 1548 /** 1549 * This method toggles the input method window display. 1550 * 1551 * If the input window is already displayed, it gets hidden. 1552 * If not the input window will be displayed. 1553 * @param showFlags Provides additional operating flags. May be 1554 * 0 or have the {@link #SHOW_IMPLICIT}, 1555 * {@link #SHOW_FORCED} bit set. 1556 * @param hideFlags Provides additional operating flags. May be 1557 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1558 * {@link #HIDE_NOT_ALWAYS} bit set. 1559 */ toggleSoftInput(int showFlags, int hideFlags)1560 public void toggleSoftInput(int showFlags, int hideFlags) { 1561 if (mCurMethod != null) { 1562 try { 1563 mCurMethod.toggleSoftInput(showFlags, hideFlags); 1564 } catch (RemoteException e) { 1565 } 1566 } 1567 } 1568 1569 /** 1570 * If the input method is currently connected to the given view, 1571 * restart it with its new contents. You should call this when the text 1572 * within your view changes outside of the normal input method or key 1573 * input flow, such as when an application calls TextView.setText(). 1574 * 1575 * @param view The view whose text has changed. 1576 */ restartInput(View view)1577 public void restartInput(View view) { 1578 // Re-dispatch if there is a context mismatch. 1579 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 1580 if (fallbackImm != null) { 1581 fallbackImm.restartInput(view); 1582 return; 1583 } 1584 1585 checkFocus(); 1586 synchronized (mH) { 1587 if (mServedView != view && (mServedView == null 1588 || !mServedView.checkInputConnectionProxy(view))) { 1589 return; 1590 } 1591 1592 mServedConnecting = true; 1593 } 1594 1595 startInputInner(StartInputReason.APP_CALLED_RESTART_INPUT_API, null, 0, 0, 0); 1596 } 1597 startInputInner(@tartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags)1598 boolean startInputInner(@StartInputReason int startInputReason, 1599 @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, 1600 @SoftInputModeFlags int softInputMode, int windowFlags) { 1601 final View view; 1602 synchronized (mH) { 1603 view = mServedView; 1604 1605 // Make sure we have a window token for the served view. 1606 if (DEBUG) { 1607 Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) + 1608 " reason=" + InputMethodDebug.startInputReasonToString(startInputReason)); 1609 } 1610 if (view == null) { 1611 if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); 1612 return false; 1613 } 1614 } 1615 1616 if (windowGainingFocus == null) { 1617 windowGainingFocus = view.getWindowToken(); 1618 if (windowGainingFocus == null) { 1619 Log.e(TAG, "ABORT input: ServedView must be attached to a Window"); 1620 return false; 1621 } 1622 startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS; 1623 if (view.onCheckIsTextEditor()) { 1624 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR; 1625 } 1626 softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode; 1627 windowFlags = view.getViewRootImpl().mWindowAttributes.flags; 1628 } 1629 1630 // Now we need to get an input connection from the served view. 1631 // This is complicated in a couple ways: we can't be holding our lock 1632 // when calling out to the view, and we need to make sure we call into 1633 // the view on the same thread that is driving its view hierarchy. 1634 Handler vh = view.getHandler(); 1635 if (vh == null) { 1636 // If the view doesn't have a handler, something has changed out 1637 // from under us, so just close the current input. 1638 // If we don't close the current input, the current input method can remain on the 1639 // screen without a connection. 1640 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input."); 1641 closeCurrentInput(); 1642 return false; 1643 } 1644 if (vh.getLooper() != Looper.myLooper()) { 1645 // The view is running on a different thread than our own, so 1646 // we need to reschedule our work for over there. 1647 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); 1648 vh.post(() -> startInputInner(startInputReason, null, 0, 0, 0)); 1649 return false; 1650 } 1651 1652 // Okay we are now ready to call into the served view and have it 1653 // do its stuff. 1654 // Life is good: let's hook everything up! 1655 EditorInfo tba = new EditorInfo(); 1656 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the 1657 // system can verify the consistency between the uid of this process and package name passed 1658 // from here. See comment of Context#getOpPackageName() for details. 1659 tba.packageName = view.getContext().getOpPackageName(); 1660 tba.fieldId = view.getId(); 1661 InputConnection ic = view.onCreateInputConnection(tba); 1662 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); 1663 1664 synchronized (mH) { 1665 // Now that we are locked again, validate that our state hasn't 1666 // changed. 1667 if (mServedView != view || !mServedConnecting) { 1668 // Something else happened, so abort. 1669 if (DEBUG) Log.v(TAG, 1670 "Starting input: finished by someone else. view=" + dumpViewInfo(view) 1671 + " mServedView=" + dumpViewInfo(mServedView) 1672 + " mServedConnecting=" + mServedConnecting); 1673 return false; 1674 } 1675 1676 // If we already have a text box, then this view is already 1677 // connected so we want to restart it. 1678 if (mCurrentTextBoxAttribute == null) { 1679 startInputFlags |= StartInputFlags.INITIAL_CONNECTION; 1680 } 1681 1682 // Hook 'em up and let 'er rip. 1683 mCurrentTextBoxAttribute = tba; 1684 maybeCallServedViewChangedLocked(tba); 1685 mServedConnecting = false; 1686 if (mServedInputConnectionWrapper != null) { 1687 mServedInputConnectionWrapper.deactivate(); 1688 mServedInputConnectionWrapper = null; 1689 } 1690 ControlledInputConnectionWrapper servedContext; 1691 final int missingMethodFlags; 1692 if (ic != null) { 1693 mCursorSelStart = tba.initialSelStart; 1694 mCursorSelEnd = tba.initialSelEnd; 1695 mCursorCandStart = -1; 1696 mCursorCandEnd = -1; 1697 mCursorRect.setEmpty(); 1698 mCursorAnchorInfo = null; 1699 final Handler icHandler; 1700 missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic); 1701 if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER) 1702 != 0) { 1703 // InputConnection#getHandler() is not implemented. 1704 icHandler = null; 1705 } else { 1706 icHandler = ic.getHandler(); 1707 } 1708 servedContext = new ControlledInputConnectionWrapper( 1709 icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this); 1710 } else { 1711 servedContext = null; 1712 missingMethodFlags = 0; 1713 } 1714 mServedInputConnectionWrapper = servedContext; 1715 1716 try { 1717 if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic=" 1718 + ic + " tba=" + tba + " startInputFlags=" 1719 + InputMethodDebug.startInputFlagsToString(startInputFlags)); 1720 final InputBindResult res = mService.startInputOrWindowGainedFocus( 1721 startInputReason, mClient, windowGainingFocus, startInputFlags, 1722 softInputMode, windowFlags, tba, servedContext, missingMethodFlags, 1723 view.getContext().getApplicationInfo().targetSdkVersion); 1724 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); 1725 if (res == null) { 1726 Log.wtf(TAG, "startInputOrWindowGainedFocus must not return" 1727 + " null. startInputReason=" 1728 + InputMethodDebug.startInputReasonToString(startInputReason) 1729 + " editorInfo=" + tba 1730 + " startInputFlags=" 1731 + InputMethodDebug.startInputFlagsToString(startInputFlags)); 1732 return false; 1733 } 1734 mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix(); 1735 if (res.id != null) { 1736 setInputChannelLocked(res.channel); 1737 mBindSequence = res.sequence; 1738 mCurMethod = res.method; 1739 mCurId = res.id; 1740 } else if (res.channel != null && res.channel != mCurChannel) { 1741 res.channel.dispose(); 1742 } 1743 switch (res.result) { 1744 case InputBindResult.ResultCode.ERROR_NOT_IME_TARGET_WINDOW: 1745 mRestartOnNextWindowFocus = true; 1746 break; 1747 } 1748 if (mCurMethod != null && mCompletions != null) { 1749 try { 1750 mCurMethod.displayCompletions(mCompletions); 1751 } catch (RemoteException e) { 1752 } 1753 } 1754 } catch (RemoteException e) { 1755 Log.w(TAG, "IME died: " + mCurId, e); 1756 } 1757 } 1758 1759 return true; 1760 } 1761 1762 /** 1763 * When the focused window is dismissed, this method is called to finish the 1764 * input method started before. 1765 * @hide 1766 */ 1767 @UnsupportedAppUsage windowDismissed(IBinder appWindowToken)1768 public void windowDismissed(IBinder appWindowToken) { 1769 checkFocus(); 1770 synchronized (mH) { 1771 if (mServedView != null && 1772 mServedView.getWindowToken() == appWindowToken) { 1773 finishInputLocked(); 1774 } 1775 if (mCurRootView != null && 1776 mCurRootView.getWindowToken() == appWindowToken) { 1777 mCurRootView = null; 1778 } 1779 } 1780 } 1781 1782 /** 1783 * Call this when a view receives focus. 1784 * @hide 1785 */ 1786 @UnsupportedAppUsage focusIn(View view)1787 public void focusIn(View view) { 1788 synchronized (mH) { 1789 focusInLocked(view); 1790 } 1791 } 1792 focusInLocked(View view)1793 void focusInLocked(View view) { 1794 if (DEBUG) Log.v(TAG, "focusIn: " + dumpViewInfo(view)); 1795 1796 if (view != null && view.isTemporarilyDetached()) { 1797 // This is a request from a view that is temporarily detached from a window. 1798 if (DEBUG) Log.v(TAG, "Temporarily detached view, ignoring"); 1799 return; 1800 } 1801 1802 if (mCurRootView != view.getRootView()) { 1803 // This is a request from a window that isn't in the window with 1804 // IME focus, so ignore it. 1805 if (DEBUG) Log.v(TAG, "Not IME target window, ignoring"); 1806 return; 1807 } 1808 1809 mNextServedView = view; 1810 scheduleCheckFocusLocked(view); 1811 } 1812 1813 /** 1814 * Call this when a view loses focus. 1815 * @hide 1816 */ 1817 @UnsupportedAppUsage focusOut(View view)1818 public void focusOut(View view) { 1819 synchronized (mH) { 1820 if (DEBUG) Log.v(TAG, "focusOut: view=" + dumpViewInfo(view) 1821 + " mServedView=" + dumpViewInfo(mServedView)); 1822 if (mServedView != view) { 1823 // The following code would auto-hide the IME if we end up 1824 // with no more views with focus. This can happen, however, 1825 // whenever we go into touch mode, so it ends up hiding 1826 // at times when we don't really want it to. For now it 1827 // seems better to just turn it all off. 1828 // TODO: Check view.isTemporarilyDetached() when re-enable the following code. 1829 if (false && canStartInput(view)) { 1830 mNextServedView = null; 1831 scheduleCheckFocusLocked(view); 1832 } 1833 } 1834 } 1835 } 1836 1837 /** 1838 * Call this when a view is being detached from a {@link android.view.Window}. 1839 * @hide 1840 */ onViewDetachedFromWindow(View view)1841 public void onViewDetachedFromWindow(View view) { 1842 synchronized (mH) { 1843 if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: view=" + dumpViewInfo(view) 1844 + " mServedView=" + dumpViewInfo(mServedView)); 1845 if (mServedView == view) { 1846 mNextServedView = null; 1847 scheduleCheckFocusLocked(view); 1848 } 1849 } 1850 } 1851 scheduleCheckFocusLocked(View view)1852 static void scheduleCheckFocusLocked(View view) { 1853 ViewRootImpl viewRootImpl = view.getViewRootImpl(); 1854 if (viewRootImpl != null) { 1855 viewRootImpl.dispatchCheckFocus(); 1856 } 1857 } 1858 1859 /** 1860 * @hide 1861 */ 1862 @UnsupportedAppUsage checkFocus()1863 public void checkFocus() { 1864 if (checkFocusNoStartInput(false)) { 1865 startInputInner(StartInputReason.CHECK_FOCUS, null, 0, 0, 0); 1866 } 1867 } 1868 checkFocusNoStartInput(boolean forceNewFocus)1869 private boolean checkFocusNoStartInput(boolean forceNewFocus) { 1870 // This is called a lot, so short-circuit before locking. 1871 if (mServedView == mNextServedView && !forceNewFocus) { 1872 return false; 1873 } 1874 1875 final ControlledInputConnectionWrapper ic; 1876 synchronized (mH) { 1877 if (mServedView == mNextServedView && !forceNewFocus) { 1878 return false; 1879 } 1880 if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView 1881 + " next=" + mNextServedView 1882 + " forceNewFocus=" + forceNewFocus 1883 + " package=" 1884 + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>")); 1885 1886 if (mNextServedView == null) { 1887 finishInputLocked(); 1888 // In this case, we used to have a focused view on the window, 1889 // but no longer do. We should make sure the input method is 1890 // no longer shown, since it serves no purpose. 1891 closeCurrentInput(); 1892 return false; 1893 } 1894 1895 ic = mServedInputConnectionWrapper; 1896 1897 mServedView = mNextServedView; 1898 mCurrentTextBoxAttribute = null; 1899 mCompletions = null; 1900 mServedConnecting = true; 1901 // servedView has changed and it's not editable. 1902 if (!mServedView.onCheckIsTextEditor()) { 1903 maybeCallServedViewChangedLocked(null); 1904 } 1905 } 1906 1907 if (ic != null) { 1908 ic.finishComposingText(); 1909 } 1910 1911 return true; 1912 } 1913 1914 @UnsupportedAppUsage closeCurrentInput()1915 void closeCurrentInput() { 1916 try { 1917 mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null); 1918 } catch (RemoteException e) { 1919 throw e.rethrowFromSystemServer(); 1920 } 1921 } 1922 1923 /** 1924 * Called by ViewAncestor when its window gets input focus. 1925 * @hide 1926 */ onPostWindowFocus(View rootView, View focusedView, @SoftInputModeFlags int softInputMode, boolean first, int windowFlags)1927 public void onPostWindowFocus(View rootView, View focusedView, 1928 @SoftInputModeFlags int softInputMode, boolean first, int windowFlags) { 1929 boolean forceNewFocus = false; 1930 synchronized (mH) { 1931 if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView 1932 + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode) 1933 + " first=" + first + " flags=#" 1934 + Integer.toHexString(windowFlags)); 1935 if (mRestartOnNextWindowFocus) { 1936 if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus"); 1937 mRestartOnNextWindowFocus = false; 1938 forceNewFocus = true; 1939 } 1940 focusInLocked(focusedView != null ? focusedView : rootView); 1941 } 1942 1943 int startInputFlags = 0; 1944 if (focusedView != null) { 1945 startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS; 1946 if (focusedView.onCheckIsTextEditor()) { 1947 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR; 1948 } 1949 } 1950 if (first) { 1951 startInputFlags |= StartInputFlags.FIRST_WINDOW_FOCUS_GAIN; 1952 } 1953 1954 if (checkFocusNoStartInput(forceNewFocus)) { 1955 // We need to restart input on the current focus view. This 1956 // should be done in conjunction with telling the system service 1957 // about the window gaining focus, to help make the transition 1958 // smooth. 1959 if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), 1960 startInputFlags, softInputMode, windowFlags)) { 1961 return; 1962 } 1963 } 1964 1965 // For some reason we didn't do a startInput + windowFocusGain, so 1966 // we'll just do a window focus gain and call it a day. 1967 synchronized (mH) { 1968 try { 1969 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); 1970 mService.startInputOrWindowGainedFocus( 1971 StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, 1972 rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags, 1973 null, null, 0 /* missingMethodFlags */, 1974 rootView.getContext().getApplicationInfo().targetSdkVersion); 1975 } catch (RemoteException e) { 1976 throw e.rethrowFromSystemServer(); 1977 } 1978 } 1979 } 1980 1981 /** @hide */ 1982 @UnsupportedAppUsage onPreWindowFocus(View rootView, boolean hasWindowFocus)1983 public void onPreWindowFocus(View rootView, boolean hasWindowFocus) { 1984 synchronized (mH) { 1985 if (rootView == null) { 1986 mCurRootView = null; 1987 } if (hasWindowFocus) { 1988 mCurRootView = rootView; 1989 } else if (rootView == mCurRootView) { 1990 // If the mCurRootView is losing window focus, release the strong reference to it 1991 // so as not to prevent it from being garbage-collected. 1992 mCurRootView = null; 1993 } else { 1994 if (DEBUG) { 1995 Log.v(TAG, "Ignoring onPreWindowFocus()." 1996 + " mCurRootView=" + mCurRootView + " rootView=" + rootView); 1997 } 1998 } 1999 } 2000 } 2001 2002 /** 2003 * Register for IME state callbacks and applying visibility in 2004 * {@link android.view.ImeInsetsSourceConsumer}. 2005 * @hide 2006 */ registerImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2007 public void registerImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { 2008 if (imeInsetsConsumer == null) { 2009 throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); 2010 } 2011 2012 synchronized (mH) { 2013 mImeInsetsConsumer = imeInsetsConsumer; 2014 } 2015 } 2016 2017 /** 2018 * Unregister for IME state callbacks and applying visibility in 2019 * {@link android.view.ImeInsetsSourceConsumer}. 2020 * @hide 2021 */ unregisterImeConsumer(@onNull ImeInsetsSourceConsumer imeInsetsConsumer)2022 public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) { 2023 if (imeInsetsConsumer == null) { 2024 throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null."); 2025 } 2026 2027 synchronized (mH) { 2028 if (mImeInsetsConsumer == imeInsetsConsumer) { 2029 mImeInsetsConsumer = null; 2030 } 2031 } 2032 } 2033 2034 /** 2035 * Call showSoftInput with currently focused view. 2036 * @return {@code true} if IME can be shown. 2037 * @hide 2038 */ requestImeShow(ResultReceiver resultReceiver)2039 public boolean requestImeShow(ResultReceiver resultReceiver) { 2040 synchronized (mH) { 2041 if (mServedView == null) { 2042 return false; 2043 } 2044 showSoftInput(mServedView, 0 /* flags */, resultReceiver); 2045 return true; 2046 } 2047 } 2048 2049 /** 2050 * Notify IME directly that it is no longer visible. 2051 * @hide 2052 */ notifyImeHidden()2053 public void notifyImeHidden() { 2054 synchronized (mH) { 2055 try { 2056 if (mCurMethod != null) { 2057 mCurMethod.notifyImeHidden(); 2058 } 2059 } catch (RemoteException re) { 2060 } 2061 } 2062 } 2063 2064 /** 2065 * Report the current selection range. 2066 * 2067 * <p><strong>Editor authors</strong>, you need to call this method whenever 2068 * the cursor moves in your editor. Remember that in addition to doing this, your 2069 * editor needs to always supply current cursor values in 2070 * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every 2071 * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is 2072 * called, which happens whenever the keyboard shows up or the focus changes 2073 * to a text field, among other cases.</p> 2074 */ updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)2075 public void updateSelection(View view, int selStart, int selEnd, 2076 int candidatesStart, int candidatesEnd) { 2077 // Re-dispatch if there is a context mismatch. 2078 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2079 if (fallbackImm != null) { 2080 fallbackImm.updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd); 2081 return; 2082 } 2083 2084 checkFocus(); 2085 synchronized (mH) { 2086 if ((mServedView != view && (mServedView == null 2087 || !mServedView.checkInputConnectionProxy(view))) 2088 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 2089 return; 2090 } 2091 2092 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd 2093 || mCursorCandStart != candidatesStart 2094 || mCursorCandEnd != candidatesEnd) { 2095 if (DEBUG) Log.d(TAG, "updateSelection"); 2096 2097 try { 2098 if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod); 2099 final int oldSelStart = mCursorSelStart; 2100 final int oldSelEnd = mCursorSelEnd; 2101 // Update internal values before sending updateSelection to the IME, because 2102 // if it changes the text within its onUpdateSelection handler in a way that 2103 // does not move the cursor we don't want to call it again with the same values. 2104 mCursorSelStart = selStart; 2105 mCursorSelEnd = selEnd; 2106 mCursorCandStart = candidatesStart; 2107 mCursorCandEnd = candidatesEnd; 2108 mCurMethod.updateSelection(oldSelStart, oldSelEnd, 2109 selStart, selEnd, candidatesStart, candidatesEnd); 2110 } catch (RemoteException e) { 2111 Log.w(TAG, "IME died: " + mCurId, e); 2112 } 2113 } 2114 } 2115 } 2116 2117 /** 2118 * Notify the event when the user tapped or clicked the text view. 2119 * 2120 * @param view {@link View} which is being clicked. 2121 * @see InputMethodService#onViewClicked(boolean) 2122 * @deprecated The semantics of this method can never be defined well for composite {@link View} 2123 * that works as a giant "Canvas", which can host its own UI hierarchy and sub focus 2124 * state. {@link android.webkit.WebView} is a good example. Application / IME 2125 * developers should not rely on this method. 2126 */ 2127 @Deprecated viewClicked(View view)2128 public void viewClicked(View view) { 2129 // Re-dispatch if there is a context mismatch. 2130 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2131 if (fallbackImm != null) { 2132 fallbackImm.viewClicked(view); 2133 return; 2134 } 2135 2136 final boolean focusChanged = mServedView != mNextServedView; 2137 checkFocus(); 2138 synchronized (mH) { 2139 if ((mServedView != view && (mServedView == null 2140 || !mServedView.checkInputConnectionProxy(view))) 2141 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 2142 return; 2143 } 2144 try { 2145 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged); 2146 mCurMethod.viewClicked(focusChanged); 2147 } catch (RemoteException e) { 2148 Log.w(TAG, "IME died: " + mCurId, e); 2149 } 2150 } 2151 } 2152 2153 /** 2154 * Return true if the current input method wants to watch the location 2155 * of the input editor's cursor in its window. 2156 * 2157 * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead. 2158 */ 2159 @Deprecated isWatchingCursor(View view)2160 public boolean isWatchingCursor(View view) { 2161 return false; 2162 } 2163 2164 /** 2165 * Return true if the current input method wants to be notified when cursor/anchor location 2166 * is changed. 2167 * 2168 * @hide 2169 */ 2170 @UnsupportedAppUsage isCursorAnchorInfoEnabled()2171 public boolean isCursorAnchorInfoEnabled() { 2172 synchronized (mH) { 2173 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 2174 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 2175 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode & 2176 InputConnection.CURSOR_UPDATE_MONITOR) != 0; 2177 return isImmediate || isMonitoring; 2178 } 2179 } 2180 2181 /** 2182 * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. 2183 * 2184 * @hide 2185 */ 2186 @UnsupportedAppUsage setUpdateCursorAnchorInfoMode(int flags)2187 public void setUpdateCursorAnchorInfoMode(int flags) { 2188 synchronized (mH) { 2189 mRequestUpdateCursorAnchorInfoMonitorMode = flags; 2190 } 2191 } 2192 2193 /** 2194 * Report the current cursor location in its window. 2195 * 2196 * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead. 2197 */ 2198 @Deprecated updateCursor(View view, int left, int top, int right, int bottom)2199 public void updateCursor(View view, int left, int top, int right, int bottom) { 2200 // Re-dispatch if there is a context mismatch. 2201 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2202 if (fallbackImm != null) { 2203 fallbackImm.updateCursor(view, left, top, right, bottom); 2204 return; 2205 } 2206 2207 checkFocus(); 2208 synchronized (mH) { 2209 if ((mServedView != view && (mServedView == null 2210 || !mServedView.checkInputConnectionProxy(view))) 2211 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 2212 return; 2213 } 2214 2215 mTmpCursorRect.set(left, top, right, bottom); 2216 if (!mCursorRect.equals(mTmpCursorRect)) { 2217 if (DEBUG) Log.d(TAG, "updateCursor"); 2218 2219 try { 2220 if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod); 2221 mCurMethod.updateCursor(mTmpCursorRect); 2222 mCursorRect.set(mTmpCursorRect); 2223 } catch (RemoteException e) { 2224 Log.w(TAG, "IME died: " + mCurId, e); 2225 } 2226 } 2227 } 2228 } 2229 2230 /** 2231 * Report positional change of the text insertion point and/or characters in the composition 2232 * string. 2233 */ updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo)2234 public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) { 2235 if (view == null || cursorAnchorInfo == null) { 2236 return; 2237 } 2238 // Re-dispatch if there is a context mismatch. 2239 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2240 if (fallbackImm != null) { 2241 fallbackImm.updateCursorAnchorInfo(view, cursorAnchorInfo); 2242 return; 2243 } 2244 2245 checkFocus(); 2246 synchronized (mH) { 2247 if ((mServedView != view && 2248 (mServedView == null || !mServedView.checkInputConnectionProxy(view))) 2249 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 2250 return; 2251 } 2252 // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has 2253 // not been changed from the previous call. 2254 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 2255 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 2256 if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) { 2257 // TODO: Consider always emitting this message once we have addressed redundant 2258 // calls of this method from android.widget.Editor. 2259 if (DEBUG) { 2260 Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" 2261 + cursorAnchorInfo); 2262 } 2263 return; 2264 } 2265 if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo); 2266 try { 2267 if (mActivityViewToScreenMatrix != null) { 2268 mCurMethod.updateCursorAnchorInfo( 2269 CursorAnchorInfo.createForAdditionalParentMatrix( 2270 cursorAnchorInfo, mActivityViewToScreenMatrix)); 2271 } else { 2272 mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo); 2273 } 2274 mCursorAnchorInfo = cursorAnchorInfo; 2275 // Clear immediate bit (if any). 2276 mRequestUpdateCursorAnchorInfoMonitorMode &= 2277 ~InputConnection.CURSOR_UPDATE_IMMEDIATE; 2278 } catch (RemoteException e) { 2279 Log.w(TAG, "IME died: " + mCurId, e); 2280 } 2281 } 2282 } 2283 2284 /** 2285 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) 2286 * InputMethodSession.appPrivateCommand()} on the current Input Method. 2287 * @param view Optional View that is sending the command, or null if 2288 * you want to send the command regardless of the view that is attached 2289 * to the input method. 2290 * @param action Name of the command to be performed. This <em>must</em> 2291 * be a scoped name, i.e. prefixed with a package name you own, so that 2292 * different developers will not create conflicting commands. 2293 * @param data Any data to include with the command. 2294 */ sendAppPrivateCommand(View view, String action, Bundle data)2295 public void sendAppPrivateCommand(View view, String action, Bundle data) { 2296 // Re-dispatch if there is a context mismatch. 2297 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view); 2298 if (fallbackImm != null) { 2299 fallbackImm.sendAppPrivateCommand(view, action, data); 2300 return; 2301 } 2302 2303 checkFocus(); 2304 synchronized (mH) { 2305 if ((mServedView != view && (mServedView == null 2306 || !mServedView.checkInputConnectionProxy(view))) 2307 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 2308 return; 2309 } 2310 try { 2311 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data); 2312 mCurMethod.appPrivateCommand(action, data); 2313 } catch (RemoteException e) { 2314 Log.w(TAG, "IME died: " + mCurId, e); 2315 } 2316 } 2317 } 2318 2319 /** 2320 * Force switch to a new input method component. This can only be called 2321 * from an application or a service which has a token of the currently active input method. 2322 * 2323 * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that 2324 * token can be {@code null} when the caller has 2325 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update 2326 * {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and 2327 * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p> 2328 * 2329 * @param token Supplies the identifying token given to an input method 2330 * when it was started, which allows it to perform this operation on 2331 * itself. 2332 * @param id The unique identifier for the new input method to be switched to. 2333 * @deprecated Use {@link InputMethodService#switchInputMethod(String)} 2334 * instead. This method was intended for IME developers who should be accessing APIs through 2335 * the service. APIs in this class are intended for app developers interacting with the IME. 2336 */ 2337 @Deprecated setInputMethod(IBinder token, String id)2338 public void setInputMethod(IBinder token, String id) { 2339 if (token == null) { 2340 // There are still some system components that rely on this undocumented behavior 2341 // regarding null IME token with WRITE_SECURE_SETTINGS. Provide a fallback logic as a 2342 // temporary remedy. 2343 if (id == null) { 2344 return; 2345 } 2346 if (Process.myUid() == Process.SYSTEM_UID) { 2347 Log.w(TAG, "System process should not be calling setInputMethod() because almost " 2348 + "always it is a bug under multi-user / multi-profile environment. " 2349 + "Consider interacting with InputMethodManagerService directly via " 2350 + "LocalServices."); 2351 return; 2352 } 2353 final Context fallbackContext = ActivityThread.currentApplication(); 2354 if (fallbackContext == null) { 2355 return; 2356 } 2357 if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS) 2358 != PackageManager.PERMISSION_GRANTED) { 2359 return; 2360 } 2361 final List<InputMethodInfo> imis = getEnabledInputMethodList(); 2362 final int numImis = imis.size(); 2363 boolean found = false; 2364 for (int i = 0; i < numImis; ++i) { 2365 final InputMethodInfo imi = imis.get(i); 2366 if (id.equals(imi.getId())) { 2367 found = true; 2368 break; 2369 } 2370 } 2371 if (!found) { 2372 Log.e(TAG, "Ignoring setInputMethod(null, " + id + ") because the specified " 2373 + "id not found in enabled IMEs."); 2374 return; 2375 } 2376 Log.w(TAG, "The undocumented behavior that setInputMethod() accepts null token " 2377 + "when the caller has WRITE_SECURE_SETTINGS is deprecated. This behavior may " 2378 + "be completely removed in a future version. Update secure settings directly " 2379 + "instead."); 2380 final ContentResolver resolver = fallbackContext.getContentResolver(); 2381 Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, 2382 NOT_A_SUBTYPE_ID); 2383 Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, id); 2384 return; 2385 } 2386 InputMethodPrivilegedOperationsRegistry.get(token).setInputMethod(id); 2387 } 2388 2389 /** 2390 * Force switch to a new input method and subtype. This can only be called 2391 * from an application or a service which has a token of the currently active input method. 2392 * 2393 * <p>On Android {@link Build.VERSION_CODES#Q} and later devices, {@code token} cannot be 2394 * {@code null} even with {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}. Instead, 2395 * update {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and 2396 * {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p> 2397 * 2398 * @param token Supplies the identifying token given to an input method 2399 * when it was started, which allows it to perform this operation on 2400 * itself. 2401 * @param id The unique identifier for the new input method to be switched to. 2402 * @param subtype The new subtype of the new input method to be switched to. 2403 * @deprecated Use 2404 * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)} 2405 * instead. This method was intended for IME developers who should be accessing APIs through 2406 * the service. APIs in this class are intended for app developers interacting with the IME. 2407 */ 2408 @Deprecated setInputMethodAndSubtype(@onNull IBinder token, String id, InputMethodSubtype subtype)2409 public void setInputMethodAndSubtype(@NonNull IBinder token, String id, 2410 InputMethodSubtype subtype) { 2411 if (token == null) { 2412 Log.e(TAG, "setInputMethodAndSubtype() does not accept null token on Android Q " 2413 + "and later."); 2414 return; 2415 } 2416 InputMethodPrivilegedOperationsRegistry.get(token).setInputMethodAndSubtype(id, subtype); 2417 } 2418 2419 /** 2420 * Close/hide the input method's soft input area, so the user no longer 2421 * sees it or can interact with it. This can only be called 2422 * from the currently active input method, as validated by the given token. 2423 * 2424 * @param token Supplies the identifying token given to an input method 2425 * when it was started, which allows it to perform this operation on 2426 * itself. 2427 * @param flags Provides additional operating flags. Currently may be 2428 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 2429 * {@link #HIDE_NOT_ALWAYS} bit set. 2430 * @deprecated Use {@link InputMethodService#requestHideSelf(int)} instead. This method was 2431 * intended for IME developers who should be accessing APIs through the service. APIs in this 2432 * class are intended for app developers interacting with the IME. 2433 */ 2434 @Deprecated hideSoftInputFromInputMethod(IBinder token, int flags)2435 public void hideSoftInputFromInputMethod(IBinder token, int flags) { 2436 InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(flags); 2437 } 2438 2439 /** 2440 * Show the input method's soft input area, so the user 2441 * sees the input method window and can interact with it. 2442 * This can only be called from the currently active input method, 2443 * as validated by the given token. 2444 * 2445 * @param token Supplies the identifying token given to an input method 2446 * when it was started, which allows it to perform this operation on 2447 * itself. 2448 * @param flags Provides additional operating flags. Currently may be 2449 * 0 or have the {@link #SHOW_IMPLICIT} or 2450 * {@link #SHOW_FORCED} bit set. 2451 * @deprecated Use {@link InputMethodService#requestShowSelf(int)} instead. This method was 2452 * intended for IME developers who should be accessing APIs through the service. APIs in this 2453 * class are intended for app developers interacting with the IME. 2454 */ 2455 @Deprecated showSoftInputFromInputMethod(IBinder token, int flags)2456 public void showSoftInputFromInputMethod(IBinder token, int flags) { 2457 InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags); 2458 } 2459 2460 /** 2461 * Dispatches an input event to the IME. 2462 * 2463 * Returns {@link #DISPATCH_HANDLED} if the event was handled. 2464 * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled. 2465 * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the 2466 * callback will be invoked later. 2467 * 2468 * @hide 2469 */ dispatchInputEvent(InputEvent event, Object token, FinishedInputEventCallback callback, Handler handler)2470 public int dispatchInputEvent(InputEvent event, Object token, 2471 FinishedInputEventCallback callback, Handler handler) { 2472 synchronized (mH) { 2473 if (mCurMethod != null) { 2474 if (event instanceof KeyEvent) { 2475 KeyEvent keyEvent = (KeyEvent)event; 2476 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN 2477 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM 2478 && keyEvent.getRepeatCount() == 0) { 2479 showInputMethodPickerLocked(); 2480 return DISPATCH_HANDLED; 2481 } 2482 } 2483 2484 if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod); 2485 2486 PendingEvent p = obtainPendingEventLocked( 2487 event, token, mCurId, callback, handler); 2488 if (mMainLooper.isCurrentThread()) { 2489 // Already running on the IMM thread so we can send the event immediately. 2490 return sendInputEventOnMainLooperLocked(p); 2491 } 2492 2493 // Post the event to the IMM thread. 2494 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p); 2495 msg.setAsynchronous(true); 2496 mH.sendMessage(msg); 2497 return DISPATCH_IN_PROGRESS; 2498 } 2499 } 2500 return DISPATCH_NOT_HANDLED; 2501 } 2502 2503 /** 2504 * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which 2505 * is expected to dispatch an keyboard event sent from the IME to an appropriate event target 2506 * depending on the given {@link View} and the current focus state. 2507 * 2508 * <p>CAUTION: This method is provided only for the situation where 2509 * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on 2510 * {@link BaseInputConnection}. Do not use this API for anything else.</p> 2511 * 2512 * @param targetView the default target view. If {@code null} is specified, then this method 2513 * tries to find a good event target based on the current focus state. 2514 * @param event the key event to be dispatched. 2515 */ dispatchKeyEventFromInputMethod(@ullable View targetView, @NonNull KeyEvent event)2516 public void dispatchKeyEventFromInputMethod(@Nullable View targetView, 2517 @NonNull KeyEvent event) { 2518 // Re-dispatch if there is a context mismatch. 2519 final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(targetView); 2520 if (fallbackImm != null) { 2521 fallbackImm.dispatchKeyEventFromInputMethod(targetView, event); 2522 return; 2523 } 2524 2525 synchronized (mH) { 2526 ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; 2527 if (viewRootImpl == null) { 2528 if (mServedView != null) { 2529 viewRootImpl = mServedView.getViewRootImpl(); 2530 } 2531 } 2532 if (viewRootImpl != null) { 2533 viewRootImpl.dispatchKeyFromIme(event); 2534 } 2535 } 2536 } 2537 2538 // Must be called on the main looper sendInputEventAndReportResultOnMainLooper(PendingEvent p)2539 void sendInputEventAndReportResultOnMainLooper(PendingEvent p) { 2540 final boolean handled; 2541 synchronized (mH) { 2542 int result = sendInputEventOnMainLooperLocked(p); 2543 if (result == DISPATCH_IN_PROGRESS) { 2544 return; 2545 } 2546 2547 handled = (result == DISPATCH_HANDLED); 2548 } 2549 2550 invokeFinishedInputEventCallback(p, handled); 2551 } 2552 2553 // Must be called on the main looper sendInputEventOnMainLooperLocked(PendingEvent p)2554 int sendInputEventOnMainLooperLocked(PendingEvent p) { 2555 if (mCurChannel != null) { 2556 if (mCurSender == null) { 2557 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper()); 2558 } 2559 2560 final InputEvent event = p.mEvent; 2561 final int seq = event.getSequenceNumber(); 2562 if (mCurSender.sendInputEvent(seq, event)) { 2563 mPendingEvents.put(seq, p); 2564 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, 2565 mPendingEvents.size()); 2566 2567 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p); 2568 msg.setAsynchronous(true); 2569 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT); 2570 return DISPATCH_IN_PROGRESS; 2571 } 2572 2573 Log.w(TAG, "Unable to send input event to IME: " 2574 + mCurId + " dropping: " + event); 2575 } 2576 return DISPATCH_NOT_HANDLED; 2577 } 2578 finishedInputEvent(int seq, boolean handled, boolean timeout)2579 void finishedInputEvent(int seq, boolean handled, boolean timeout) { 2580 final PendingEvent p; 2581 synchronized (mH) { 2582 int index = mPendingEvents.indexOfKey(seq); 2583 if (index < 0) { 2584 return; // spurious, event already finished or timed out 2585 } 2586 2587 p = mPendingEvents.valueAt(index); 2588 mPendingEvents.removeAt(index); 2589 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size()); 2590 2591 if (timeout) { 2592 Log.w(TAG, "Timeout waiting for IME to handle input event after " 2593 + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId); 2594 } else { 2595 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p); 2596 } 2597 } 2598 2599 invokeFinishedInputEventCallback(p, handled); 2600 } 2601 2602 // Assumes the event has already been removed from the queue. invokeFinishedInputEventCallback(PendingEvent p, boolean handled)2603 void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) { 2604 p.mHandled = handled; 2605 if (p.mHandler.getLooper().isCurrentThread()) { 2606 // Already running on the callback handler thread so we can send the 2607 // callback immediately. 2608 p.run(); 2609 } else { 2610 // Post the event to the callback handler thread. 2611 // In this case, the callback will be responsible for recycling the event. 2612 Message msg = Message.obtain(p.mHandler, p); 2613 msg.setAsynchronous(true); 2614 msg.sendToTarget(); 2615 } 2616 } 2617 flushPendingEventsLocked()2618 private void flushPendingEventsLocked() { 2619 mH.removeMessages(MSG_FLUSH_INPUT_EVENT); 2620 2621 final int count = mPendingEvents.size(); 2622 for (int i = 0; i < count; i++) { 2623 int seq = mPendingEvents.keyAt(i); 2624 Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0); 2625 msg.setAsynchronous(true); 2626 msg.sendToTarget(); 2627 } 2628 } 2629 obtainPendingEventLocked(InputEvent event, Object token, String inputMethodId, FinishedInputEventCallback callback, Handler handler)2630 private PendingEvent obtainPendingEventLocked(InputEvent event, Object token, 2631 String inputMethodId, FinishedInputEventCallback callback, Handler handler) { 2632 PendingEvent p = mPendingEventPool.acquire(); 2633 if (p == null) { 2634 p = new PendingEvent(); 2635 } 2636 p.mEvent = event; 2637 p.mToken = token; 2638 p.mInputMethodId = inputMethodId; 2639 p.mCallback = callback; 2640 p.mHandler = handler; 2641 return p; 2642 } 2643 recyclePendingEventLocked(PendingEvent p)2644 private void recyclePendingEventLocked(PendingEvent p) { 2645 p.recycle(); 2646 mPendingEventPool.release(p); 2647 } 2648 2649 /** 2650 * Show IME picker popup window. 2651 * 2652 * <p>Requires the {@link PackageManager#FEATURE_INPUT_METHODS} feature which can be detected 2653 * using {@link PackageManager#hasSystemFeature(String)}. 2654 */ showInputMethodPicker()2655 public void showInputMethodPicker() { 2656 synchronized (mH) { 2657 showInputMethodPickerLocked(); 2658 } 2659 } 2660 2661 /** 2662 * Shows the input method chooser dialog from system. 2663 * 2664 * @param showAuxiliarySubtypes Set true to show auxiliary input methods. 2665 * @param displayId The ID of the display where the chooser dialog should be shown. 2666 * @hide 2667 */ 2668 @RequiresPermission(WRITE_SECURE_SETTINGS) showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId)2669 public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) { 2670 final int mode = showAuxiliarySubtypes 2671 ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES 2672 : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES; 2673 try { 2674 mService.showInputMethodPickerFromSystem(mClient, mode, displayId); 2675 } catch (RemoteException e) { 2676 throw e.rethrowFromSystemServer(); 2677 } 2678 } 2679 showInputMethodPickerLocked()2680 private void showInputMethodPickerLocked() { 2681 try { 2682 mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO); 2683 } catch (RemoteException e) { 2684 throw e.rethrowFromSystemServer(); 2685 } 2686 } 2687 2688 /** 2689 * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected. 2690 * 2691 * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure 2692 * that this test API returns when and only while and only while 2693 * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not 2694 * pass CTS.</p> 2695 * 2696 * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI. 2697 * @hide 2698 */ 2699 @TestApi isInputMethodPickerShown()2700 public boolean isInputMethodPickerShown() { 2701 try { 2702 return mService.isInputMethodPickerShownForTest(); 2703 } catch (RemoteException e) { 2704 throw e.rethrowFromSystemServer(); 2705 } 2706 } 2707 2708 /** 2709 * Show the settings for enabling subtypes of the specified input method. 2710 * @param imiId An input method, whose subtypes settings will be shown. If imiId is null, 2711 * subtypes of all input methods will be shown. 2712 */ showInputMethodAndSubtypeEnabler(String imiId)2713 public void showInputMethodAndSubtypeEnabler(String imiId) { 2714 try { 2715 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId); 2716 } catch (RemoteException e) { 2717 throw e.rethrowFromSystemServer(); 2718 } 2719 } 2720 2721 /** 2722 * Returns the current input method subtype. This subtype is one of the subtypes in 2723 * the current input method. This method returns null when the current input method doesn't 2724 * have any input method subtype. 2725 */ getCurrentInputMethodSubtype()2726 public InputMethodSubtype getCurrentInputMethodSubtype() { 2727 try { 2728 return mService.getCurrentInputMethodSubtype(); 2729 } catch (RemoteException e) { 2730 throw e.rethrowFromSystemServer(); 2731 } 2732 } 2733 2734 /** 2735 * Switch to a new input method subtype of the current input method. 2736 * @param subtype A new input method subtype to switch. 2737 * @return true if the current subtype was successfully switched. When the specified subtype is 2738 * null, this method returns false. 2739 * @deprecated If the calling process is an IME, use 2740 * {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which 2741 * does not require any permission as long as the caller is the current IME. 2742 * If the calling process is some privileged app that already has 2743 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission, just 2744 * directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}. 2745 */ 2746 @Deprecated 2747 @RequiresPermission(WRITE_SECURE_SETTINGS) setCurrentInputMethodSubtype(InputMethodSubtype subtype)2748 public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) { 2749 if (Process.myUid() == Process.SYSTEM_UID) { 2750 Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because " 2751 + "almost always it is a bug under multi-user / multi-profile environment. " 2752 + "Consider directly interacting with InputMethodManagerService " 2753 + "via LocalServices."); 2754 return false; 2755 } 2756 if (subtype == null) { 2757 // See the JavaDoc. This is how this method has worked. 2758 return false; 2759 } 2760 final Context fallbackContext = ActivityThread.currentApplication(); 2761 if (fallbackContext == null) { 2762 return false; 2763 } 2764 if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS) 2765 != PackageManager.PERMISSION_GRANTED) { 2766 return false; 2767 } 2768 final ContentResolver contentResolver = fallbackContext.getContentResolver(); 2769 final String imeId = Settings.Secure.getString(contentResolver, 2770 Settings.Secure.DEFAULT_INPUT_METHOD); 2771 if (ComponentName.unflattenFromString(imeId) == null) { 2772 // Null or invalid IME ID format. 2773 return false; 2774 } 2775 final List<InputMethodSubtype> enabledSubtypes; 2776 try { 2777 enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true); 2778 } catch (RemoteException e) { 2779 return false; 2780 } 2781 final int numSubtypes = enabledSubtypes.size(); 2782 for (int i = 0; i < numSubtypes; ++i) { 2783 final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i); 2784 if (enabledSubtype.equals(subtype)) { 2785 Settings.Secure.putInt(contentResolver, 2786 Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, enabledSubtype.hashCode()); 2787 return true; 2788 } 2789 } 2790 return false; 2791 } 2792 2793 /** 2794 * Notify that a user took some action with this input method. 2795 * 2796 * @deprecated Just kept to avoid possible app compat issue. 2797 * @hide 2798 */ 2799 @Deprecated 2800 @UnsupportedAppUsage(trackingBug = 114740982, maxTargetSdk = Build.VERSION_CODES.P) notifyUserAction()2801 public void notifyUserAction() { 2802 Log.w(TAG, "notifyUserAction() is a hidden method, which is now just a stub method" 2803 + " that does nothing. Leave comments in b.android.com/114740982 if your " 2804 + " application still depends on the previous behavior of this method."); 2805 } 2806 2807 /** 2808 * Returns a map of all shortcut input method info and their subtypes. 2809 */ getShortcutInputMethodsAndSubtypes()2810 public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() { 2811 final List<InputMethodInfo> enabledImes = getEnabledInputMethodList(); 2812 2813 // Ensure we check system IMEs first. 2814 enabledImes.sort(Comparator.comparingInt(imi -> imi.isSystem() ? 0 : 1)); 2815 2816 final int numEnabledImes = enabledImes.size(); 2817 for (int imiIndex = 0; imiIndex < numEnabledImes; ++imiIndex) { 2818 final InputMethodInfo imi = enabledImes.get(imiIndex); 2819 final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList( 2820 imi, true); 2821 final int subtypeCount = subtypes.size(); 2822 for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) { 2823 final InputMethodSubtype subtype = imi.getSubtypeAt(subtypeIndex); 2824 if (SUBTYPE_MODE_VOICE.equals(subtype.getMode())) { 2825 return Collections.singletonMap(imi, Collections.singletonList(subtype)); 2826 } 2827 } 2828 } 2829 return Collections.emptyMap(); 2830 } 2831 2832 /** 2833 * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}. 2834 * 2835 * <p>TODO(Bug 113914148): Check if we can remove this. We have accidentally exposed 2836 * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them 2837 * started relying on it.</p> 2838 * 2839 * @return Something that is not well-defined. 2840 * @hide 2841 */ 2842 @UnsupportedAppUsage getInputMethodWindowVisibleHeight()2843 public int getInputMethodWindowVisibleHeight() { 2844 try { 2845 return mService.getInputMethodWindowVisibleHeight(); 2846 } catch (RemoteException e) { 2847 throw e.rethrowFromSystemServer(); 2848 } 2849 } 2850 2851 /** 2852 * An internal API for {@link android.app.ActivityView} to report where its embedded virtual 2853 * display is placed. 2854 * 2855 * @param childDisplayId Display ID of the embedded virtual display. 2856 * @param matrix {@link Matrix} to convert virtual display screen coordinates to 2857 * the host screen coordinates. {@code null} to clear the relationship. 2858 * @hide 2859 */ reportActivityView(int childDisplayId, @Nullable Matrix matrix)2860 public void reportActivityView(int childDisplayId, @Nullable Matrix matrix) { 2861 try { 2862 final float[] matrixValues; 2863 if (matrix == null) { 2864 matrixValues = null; 2865 } else { 2866 matrixValues = new float[9]; 2867 matrix.getValues(matrixValues); 2868 } 2869 mService.reportActivityView(mClient, childDisplayId, matrixValues); 2870 } catch (RemoteException e) { 2871 throw e.rethrowFromSystemServer(); 2872 } 2873 } 2874 2875 /** 2876 * Force switch to the last used input method and subtype. If the last input method didn't have 2877 * any subtypes, the framework will simply switch to the last input method with no subtype 2878 * specified. 2879 * @param imeToken Supplies the identifying token given to an input method when it was started, 2880 * which allows it to perform this operation on itself. 2881 * @return true if the current input method and subtype was successfully switched to the last 2882 * used input method and subtype. 2883 * @deprecated Use {@link InputMethodService#switchToPreviousInputMethod()} instead. This method 2884 * was intended for IME developers who should be accessing APIs through the service. APIs in 2885 * this class are intended for app developers interacting with the IME. 2886 */ 2887 @Deprecated switchToLastInputMethod(IBinder imeToken)2888 public boolean switchToLastInputMethod(IBinder imeToken) { 2889 return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod(); 2890 } 2891 2892 /** 2893 * Force switch to the next input method and subtype. If there is no IME enabled except 2894 * current IME and subtype, do nothing. 2895 * @param imeToken Supplies the identifying token given to an input method when it was started, 2896 * which allows it to perform this operation on itself. 2897 * @param onlyCurrentIme if true, the framework will find the next subtype which 2898 * belongs to the current IME 2899 * @return true if the current input method and subtype was successfully switched to the next 2900 * input method and subtype. 2901 * @deprecated Use {@link InputMethodService#switchToNextInputMethod(boolean)} instead. This 2902 * method was intended for IME developers who should be accessing APIs through the service. 2903 * APIs in this class are intended for app developers interacting with the IME. 2904 */ 2905 @Deprecated switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme)2906 public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) { 2907 return InputMethodPrivilegedOperationsRegistry.get(imeToken) 2908 .switchToNextInputMethod(onlyCurrentIme); 2909 } 2910 2911 /** 2912 * Returns true if the current IME needs to offer the users ways to switch to a next input 2913 * method (e.g. a globe key.). 2914 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true, 2915 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly. 2916 * <p> Note that the system determines the most appropriate next input method 2917 * and subtype in order to provide the consistent user experience in switching 2918 * between IMEs and subtypes. 2919 * @param imeToken Supplies the identifying token given to an input method when it was started, 2920 * which allows it to perform this operation on itself. 2921 * @deprecated Use {@link InputMethodService#shouldOfferSwitchingToNextInputMethod()} 2922 * instead. This method was intended for IME developers who should be accessing APIs through 2923 * the service. APIs in this class are intended for app developers interacting with the IME. 2924 */ 2925 @Deprecated shouldOfferSwitchingToNextInputMethod(IBinder imeToken)2926 public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) { 2927 return InputMethodPrivilegedOperationsRegistry.get(imeToken) 2928 .shouldOfferSwitchingToNextInputMethod(); 2929 } 2930 2931 /** 2932 * Set additional input method subtypes. Only a process which shares the same uid with the IME 2933 * can add additional input method subtypes to the IME. 2934 * Please note that a subtype's status is stored in the system. 2935 * For example, enabled subtypes are remembered by the framework even after they are removed 2936 * by using this method. If you re-add the same subtypes again, 2937 * they will just get enabled. If you want to avoid such conflicts, for instance, you may 2938 * want to create a "different" new subtype even with the same locale and mode, 2939 * by changing its extra value. The different subtype won't get affected by the stored past 2940 * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer 2941 * to the current implementation.) 2942 * 2943 * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes 2944 * specified by {@code subtypes}, those multiple instances are automatically merged into one 2945 * instance.</p> 2946 * 2947 * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty 2948 * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing 2949 * the last one entry of additional subtypes. If your IME statically defines one or more 2950 * subtypes in the manifest XML file, you may be able to work around this limitation by 2951 * specifying one of those statically defined subtypes in {@code subtypes}.</p> 2952 * 2953 * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to. 2954 * @param subtypes subtypes will be added as additional subtypes of the current input method. 2955 * @deprecated For IMEs that have already implemented features like customizable/downloadable 2956 * keyboard layouts/languages, please start migration to other approaches. One idea 2957 * would be exposing only one unified {@link InputMethodSubtype} then implement 2958 * IME's own language switching mechanism within that unified subtype. The support 2959 * of "Additional Subtype" may be completely dropped in a future version of Android. 2960 */ 2961 @Deprecated setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes)2962 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) { 2963 try { 2964 mService.setAdditionalInputMethodSubtypes(imiId, subtypes); 2965 } catch (RemoteException e) { 2966 throw e.rethrowFromSystemServer(); 2967 } 2968 } 2969 getLastInputMethodSubtype()2970 public InputMethodSubtype getLastInputMethodSubtype() { 2971 try { 2972 return mService.getLastInputMethodSubtype(); 2973 } catch (RemoteException e) { 2974 throw e.rethrowFromSystemServer(); 2975 } 2976 } 2977 maybeCallServedViewChangedLocked(EditorInfo tba)2978 private void maybeCallServedViewChangedLocked(EditorInfo tba) { 2979 if (mImeInsetsConsumer != null) { 2980 mImeInsetsConsumer.onServedEditorChanged(tba); 2981 } 2982 } 2983 2984 /** 2985 * <p>This is used for CTS test only. Do not use this method outside of CTS package.<p/> 2986 * @return the ID of this display which this {@link InputMethodManager} resides 2987 * @hide 2988 */ 2989 @TestApi getDisplayId()2990 public int getDisplayId() { 2991 return mDisplayId; 2992 } 2993 doDump(FileDescriptor fd, PrintWriter fout, String[] args)2994 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { 2995 final Printer p = new PrintWriterPrinter(fout); 2996 p.println("Input method client state for " + this + ":"); 2997 2998 p.println(" mService=" + mService); 2999 p.println(" mMainLooper=" + mMainLooper); 3000 p.println(" mIInputContext=" + mIInputContext); 3001 p.println(" mActive=" + mActive 3002 + " mRestartOnNextWindowFocus=" + mRestartOnNextWindowFocus 3003 + " mBindSequence=" + mBindSequence 3004 + " mCurId=" + mCurId); 3005 p.println(" mFullscreenMode=" + mFullscreenMode); 3006 p.println(" mCurMethod=" + mCurMethod); 3007 p.println(" mCurRootView=" + mCurRootView); 3008 p.println(" mServedView=" + mServedView); 3009 p.println(" mNextServedView=" + mNextServedView); 3010 p.println(" mServedConnecting=" + mServedConnecting); 3011 if (mCurrentTextBoxAttribute != null) { 3012 p.println(" mCurrentTextBoxAttribute:"); 3013 mCurrentTextBoxAttribute.dump(p, " "); 3014 } else { 3015 p.println(" mCurrentTextBoxAttribute: null"); 3016 } 3017 p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper); 3018 p.println(" mCompletions=" + Arrays.toString(mCompletions)); 3019 p.println(" mCursorRect=" + mCursorRect); 3020 p.println(" mCursorSelStart=" + mCursorSelStart 3021 + " mCursorSelEnd=" + mCursorSelEnd 3022 + " mCursorCandStart=" + mCursorCandStart 3023 + " mCursorCandEnd=" + mCursorCandEnd); 3024 } 3025 3026 /** 3027 * Callback that is invoked when an input event that was dispatched to 3028 * the IME has been finished. 3029 * @hide 3030 */ 3031 public interface FinishedInputEventCallback { onFinishedInputEvent(Object token, boolean handled)3032 public void onFinishedInputEvent(Object token, boolean handled); 3033 } 3034 3035 private final class ImeInputEventSender extends InputEventSender { ImeInputEventSender(InputChannel inputChannel, Looper looper)3036 public ImeInputEventSender(InputChannel inputChannel, Looper looper) { 3037 super(inputChannel, looper); 3038 } 3039 3040 @Override onInputEventFinished(int seq, boolean handled)3041 public void onInputEventFinished(int seq, boolean handled) { 3042 finishedInputEvent(seq, handled, false); 3043 } 3044 } 3045 3046 private final class PendingEvent implements Runnable { 3047 public InputEvent mEvent; 3048 public Object mToken; 3049 public String mInputMethodId; 3050 public FinishedInputEventCallback mCallback; 3051 public Handler mHandler; 3052 public boolean mHandled; 3053 recycle()3054 public void recycle() { 3055 mEvent = null; 3056 mToken = null; 3057 mInputMethodId = null; 3058 mCallback = null; 3059 mHandler = null; 3060 mHandled = false; 3061 } 3062 3063 @Override run()3064 public void run() { 3065 mCallback.onFinishedInputEvent(mToken, mHandled); 3066 3067 synchronized (mH) { 3068 recyclePendingEventLocked(this); 3069 } 3070 } 3071 } 3072 dumpViewInfo(@ullable final View view)3073 private static String dumpViewInfo(@Nullable final View view) { 3074 if (view == null) { 3075 return "null"; 3076 } 3077 final StringBuilder sb = new StringBuilder(); 3078 sb.append(view); 3079 sb.append(",focus=" + view.hasFocus()); 3080 sb.append(",windowFocus=" + view.hasWindowFocus()); 3081 sb.append(",autofillUiShowing=" + isAutofillUIShowing(view)); 3082 sb.append(",window=" + view.getWindowToken()); 3083 sb.append(",displayId=" + view.getContext().getDisplayId()); 3084 sb.append(",temporaryDetach=" + view.isTemporarilyDetached()); 3085 return sb.toString(); 3086 } 3087 } 3088