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 com.android.internal.os.SomeArgs; 20 import com.android.internal.view.IInputConnectionWrapper; 21 import com.android.internal.view.IInputContext; 22 import com.android.internal.view.IInputMethodClient; 23 import com.android.internal.view.IInputMethodManager; 24 import com.android.internal.view.IInputMethodSession; 25 import com.android.internal.view.InputBindResult; 26 27 import android.annotation.RequiresPermission; 28 import android.content.Context; 29 import android.graphics.Matrix; 30 import android.graphics.Rect; 31 import android.os.Bundle; 32 import android.os.Handler; 33 import android.os.IBinder; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.RemoteException; 37 import android.os.ResultReceiver; 38 import android.os.ServiceManager; 39 import android.os.Trace; 40 import android.text.style.SuggestionSpan; 41 import android.util.Log; 42 import android.util.Pools.Pool; 43 import android.util.Pools.SimplePool; 44 import android.util.PrintWriterPrinter; 45 import android.util.Printer; 46 import android.util.SparseArray; 47 import android.view.InputChannel; 48 import android.view.InputEvent; 49 import android.view.InputEventSender; 50 import android.view.KeyEvent; 51 import android.view.View; 52 import android.view.ViewRootImpl; 53 54 import java.io.FileDescriptor; 55 import java.io.PrintWriter; 56 import java.util.ArrayList; 57 import java.util.HashMap; 58 import java.util.List; 59 import java.util.Map; 60 import java.util.Objects; 61 import java.util.concurrent.CountDownLatch; 62 import java.util.concurrent.TimeUnit; 63 64 import static android.Manifest.permission.WRITE_SECURE_SETTINGS; 65 66 /** 67 * Central system API to the overall input method framework (IMF) architecture, 68 * which arbitrates interaction between applications and the current input method. 69 * You can retrieve an instance of this interface with 70 * {@link Context#getSystemService(String) Context.getSystemService()}. 71 * 72 * <p>Topics covered here: 73 * <ol> 74 * <li><a href="#ArchitectureOverview">Architecture Overview</a> 75 * <li><a href="#Applications">Applications</a> 76 * <li><a href="#InputMethods">Input Methods</a> 77 * <li><a href="#Security">Security</a> 78 * </ol> 79 * 80 * <a name="ArchitectureOverview"></a> 81 * <h3>Architecture Overview</h3> 82 * 83 * <p>There are three primary parties involved in the input method 84 * framework (IMF) architecture:</p> 85 * 86 * <ul> 87 * <li> The <strong>input method manager</strong> as expressed by this class 88 * is the central point of the system that manages interaction between all 89 * other parts. It is expressed as the client-side API here which exists 90 * in each application context and communicates with a global system service 91 * that manages the interaction across all processes. 92 * <li> An <strong>input method (IME)</strong> implements a particular 93 * interaction model allowing the user to generate text. The system binds 94 * to the current input method that is use, causing it to be created and run, 95 * and tells it when to hide and show its UI. Only one IME is running at a time. 96 * <li> Multiple <strong>client applications</strong> arbitrate with the input 97 * method manager for input focus and control over the state of the IME. Only 98 * one such client is ever active (working with the IME) at a time. 99 * </ul> 100 * 101 * 102 * <a name="Applications"></a> 103 * <h3>Applications</h3> 104 * 105 * <p>In most cases, applications that are using the standard 106 * {@link android.widget.TextView} or its subclasses will have little they need 107 * to do to work well with soft input methods. The main things you need to 108 * be aware of are:</p> 109 * 110 * <ul> 111 * <li> Properly set the {@link android.R.attr#inputType} in your editable 112 * text views, so that the input method will have enough context to help the 113 * user in entering text into them. 114 * <li> Deal well with losing screen space when the input method is 115 * displayed. Ideally an application should handle its window being resized 116 * smaller, but it can rely on the system performing panning of the window 117 * if needed. You should set the {@link android.R.attr#windowSoftInputMode} 118 * attribute on your activity or the corresponding values on windows you 119 * create to help the system determine whether to pan or resize (it will 120 * try to determine this automatically but may get it wrong). 121 * <li> You can also control the preferred soft input state (open, closed, etc) 122 * for your window using the same {@link android.R.attr#windowSoftInputMode} 123 * attribute. 124 * </ul> 125 * 126 * <p>More finer-grained control is available through the APIs here to directly 127 * interact with the IMF and its IME -- either showing or hiding the input 128 * area, letting the user pick an input method, etc.</p> 129 * 130 * <p>For the rare people amongst us writing their own text editors, you 131 * will need to implement {@link android.view.View#onCreateInputConnection} 132 * to return a new instance of your own {@link InputConnection} interface 133 * allowing the IME to interact with your editor.</p> 134 * 135 * 136 * <a name="InputMethods"></a> 137 * <h3>Input Methods</h3> 138 * 139 * <p>An input method (IME) is implemented 140 * as a {@link android.app.Service}, typically deriving from 141 * {@link android.inputmethodservice.InputMethodService}. It must provide 142 * the core {@link InputMethod} interface, though this is normally handled by 143 * {@link android.inputmethodservice.InputMethodService} and implementors will 144 * only need to deal with the higher-level API there.</p> 145 * 146 * See the {@link android.inputmethodservice.InputMethodService} class for 147 * more information on implementing IMEs. 148 * 149 * 150 * <a name="Security"></a> 151 * <h3>Security</h3> 152 * 153 * <p>There are a lot of security issues associated with input methods, 154 * since they essentially have freedom to completely drive the UI and monitor 155 * everything the user enters. The Android input method framework also allows 156 * arbitrary third party IMEs, so care must be taken to restrict their 157 * selection and interactions.</p> 158 * 159 * <p>Here are some key points about the security architecture behind the 160 * IMF:</p> 161 * 162 * <ul> 163 * <li> <p>Only the system is allowed to directly access an IME's 164 * {@link InputMethod} interface, via the 165 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission. This is 166 * enforced in the system by not binding to an input method service that does 167 * not require this permission, so the system can guarantee no other untrusted 168 * clients are accessing the current input method outside of its control.</p> 169 * 170 * <li> <p>There may be many client processes of the IMF, but only one may 171 * be active at a time. The inactive clients can not interact with key 172 * parts of the IMF through the mechanisms described below.</p> 173 * 174 * <li> <p>Clients of an input method are only given access to its 175 * {@link InputMethodSession} interface. One instance of this interface is 176 * created for each client, and only calls from the session associated with 177 * the active client will be processed by the current IME. This is enforced 178 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal 179 * IMEs, but must be explicitly handled by an IME that is customizing the 180 * raw {@link InputMethodSession} implementation.</p> 181 * 182 * <li> <p>Only the active client's {@link InputConnection} will accept 183 * operations. The IMF tells each client process whether it is active, and 184 * the framework enforces that in inactive processes calls on to the current 185 * InputConnection will be ignored. This ensures that the current IME can 186 * only deliver events and text edits to the UI that the user sees as 187 * being in focus.</p> 188 * 189 * <li> <p>An IME can never interact with an {@link InputConnection} while 190 * the screen is off. This is enforced by making all clients inactive while 191 * the screen is off, and prevents bad IMEs from driving the UI when the user 192 * can not be aware of its behavior.</p> 193 * 194 * <li> <p>A client application can ask that the system let the user pick a 195 * new IME, but can not programmatically switch to one itself. This avoids 196 * malicious applications from switching the user to their own IME, which 197 * remains running when the user navigates away to another application. An 198 * IME, on the other hand, <em>is</em> allowed to programmatically switch 199 * the system to another IME, since it already has full control of user 200 * input.</p> 201 * 202 * <li> <p>The user must explicitly enable a new IME in settings before 203 * they can switch to it, to confirm with the system that they know about it 204 * and want to make it available for use.</p> 205 * </ul> 206 */ 207 public final class InputMethodManager { 208 static final boolean DEBUG = false; 209 static final String TAG = "InputMethodManager"; 210 211 static final String PENDING_EVENT_COUNTER = "aq:imm"; 212 213 static InputMethodManager sInstance; 214 215 /** 216 * @hide Flag for IInputMethodManager.windowGainedFocus: a view in 217 * the window has input focus. 218 */ 219 public static final int CONTROL_WINDOW_VIEW_HAS_FOCUS = 1<<0; 220 221 /** 222 * @hide Flag for IInputMethodManager.windowGainedFocus: the focus 223 * is a text editor. 224 */ 225 public static final int CONTROL_WINDOW_IS_TEXT_EDITOR = 1<<1; 226 227 /** 228 * @hide Flag for IInputMethodManager.windowGainedFocus: this is the first 229 * time the window has gotten focus. 230 */ 231 public static final int CONTROL_WINDOW_FIRST = 1<<2; 232 233 /** 234 * @hide Flag for IInputMethodManager.startInput: this is the first 235 * time the window has gotten focus. 236 */ 237 public static final int CONTROL_START_INITIAL = 1<<8; 238 239 /** 240 * Timeout in milliseconds for delivering a key to an IME. 241 */ 242 static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500; 243 244 /** @hide */ 245 public static final int DISPATCH_IN_PROGRESS = -1; 246 247 /** @hide */ 248 public static final int DISPATCH_NOT_HANDLED = 0; 249 250 /** @hide */ 251 public static final int DISPATCH_HANDLED = 1; 252 253 /** @hide */ 254 public static final int SHOW_IM_PICKER_MODE_AUTO = 0; 255 /** @hide */ 256 public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1; 257 /** @hide */ 258 public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2; 259 260 final IInputMethodManager mService; 261 final Looper mMainLooper; 262 263 // For scheduling work on the main thread. This also serves as our 264 // global lock. 265 final H mH; 266 267 // Our generic input connection if the current target does not have its own. 268 final IInputContext mIInputContext; 269 270 /** 271 * True if this input method client is active, initially false. 272 */ 273 boolean mActive = false; 274 275 /** 276 * Set whenever this client becomes inactive, to know we need to reset 277 * state with the IME the next time we receive focus. 278 */ 279 boolean mHasBeenInactive = true; 280 281 /** 282 * As reported by IME through InputConnection. 283 */ 284 boolean mFullscreenMode; 285 286 // ----------------------------------------------------------- 287 288 /** 289 * This is the root view of the overall window that currently has input 290 * method focus. 291 */ 292 View mCurRootView; 293 /** 294 * This is the view that should currently be served by an input method, 295 * regardless of the state of setting that up. 296 */ 297 View mServedView; 298 /** 299 * This is then next view that will be served by the input method, when 300 * we get around to updating things. 301 */ 302 View mNextServedView; 303 /** 304 * This is set when we are in the process of connecting, to determine 305 * when we have actually finished. 306 */ 307 boolean mServedConnecting; 308 /** 309 * This is non-null when we have connected the served view; it holds 310 * the attributes that were last retrieved from the served view and given 311 * to the input connection. 312 */ 313 EditorInfo mCurrentTextBoxAttribute; 314 /** 315 * The InputConnection that was last retrieved from the served view. 316 */ 317 InputConnection mServedInputConnection; 318 ControlledInputConnectionWrapper mServedInputConnectionWrapper; 319 /** 320 * The completions that were last provided by the served view. 321 */ 322 CompletionInfo[] mCompletions; 323 324 // Cursor position on the screen. 325 Rect mTmpCursorRect = new Rect(); 326 Rect mCursorRect = new Rect(); 327 int mCursorSelStart; 328 int mCursorSelEnd; 329 int mCursorCandStart; 330 int mCursorCandEnd; 331 332 /** 333 * Represents an invalid action notification sequence number. {@link InputMethodManagerService} 334 * always issues a positive integer for action notification sequence numbers. Thus -1 is 335 * guaranteed to be different from any valid sequence number. 336 */ 337 private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1; 338 /** 339 * The next sequence number that is to be sent to {@link InputMethodManagerService} via 340 * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed. 341 */ 342 private int mNextUserActionNotificationSequenceNumber = 343 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER; 344 345 /** 346 * The last sequence number that is already sent to {@link InputMethodManagerService}. 347 */ 348 private int mLastSentUserActionNotificationSequenceNumber = 349 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER; 350 351 /** 352 * The instance that has previously been sent to the input method. 353 */ 354 private CursorAnchorInfo mCursorAnchorInfo = null; 355 356 // ----------------------------------------------------------- 357 358 /** 359 * Sequence number of this binding, as returned by the server. 360 */ 361 int mBindSequence = -1; 362 /** 363 * ID of the method we are bound to. 364 */ 365 String mCurId; 366 /** 367 * The actual instance of the method to make calls on it. 368 */ 369 IInputMethodSession mCurMethod; 370 InputChannel mCurChannel; 371 ImeInputEventSender mCurSender; 372 373 private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0; 374 375 /** 376 * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. 377 */ 378 private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; 379 380 final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20); 381 final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20); 382 383 // ----------------------------------------------------------- 384 385 static final int MSG_DUMP = 1; 386 static final int MSG_BIND = 2; 387 static final int MSG_UNBIND = 3; 388 static final int MSG_SET_ACTIVE = 4; 389 static final int MSG_SEND_INPUT_EVENT = 5; 390 static final int MSG_TIMEOUT_INPUT_EVENT = 6; 391 static final int MSG_FLUSH_INPUT_EVENT = 7; 392 static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9; 393 394 class H extends Handler { H(Looper looper)395 H(Looper looper) { 396 super(looper, null, true); 397 } 398 399 @Override handleMessage(Message msg)400 public void handleMessage(Message msg) { 401 switch (msg.what) { 402 case MSG_DUMP: { 403 SomeArgs args = (SomeArgs)msg.obj; 404 try { 405 doDump((FileDescriptor)args.arg1, 406 (PrintWriter)args.arg2, (String[])args.arg3); 407 } catch (RuntimeException e) { 408 ((PrintWriter)args.arg2).println("Exception: " + e); 409 } 410 synchronized (args.arg4) { 411 ((CountDownLatch)args.arg4).countDown(); 412 } 413 args.recycle(); 414 return; 415 } 416 case MSG_BIND: { 417 final InputBindResult res = (InputBindResult)msg.obj; 418 if (DEBUG) { 419 Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id); 420 } 421 synchronized (mH) { 422 if (mBindSequence < 0 || mBindSequence != res.sequence) { 423 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence 424 + ", given seq=" + res.sequence); 425 if (res.channel != null && res.channel != mCurChannel) { 426 res.channel.dispose(); 427 } 428 return; 429 } 430 431 mRequestUpdateCursorAnchorInfoMonitorMode = 432 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE; 433 434 setInputChannelLocked(res.channel); 435 mCurMethod = res.method; 436 mCurId = res.id; 437 mBindSequence = res.sequence; 438 } 439 startInputInner(null, 0, 0, 0); 440 return; 441 } 442 case MSG_UNBIND: { 443 final int sequence = msg.arg1; 444 if (DEBUG) { 445 Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence); 446 } 447 boolean startInput = false; 448 synchronized (mH) { 449 if (mBindSequence == sequence) { 450 if (false) { 451 // XXX the server has already unbound! 452 if (mCurMethod != null && mCurrentTextBoxAttribute != null) { 453 try { 454 mCurMethod.finishInput(); 455 } catch (RemoteException e) { 456 Log.w(TAG, "IME died: " + mCurId, e); 457 } 458 } 459 } 460 clearBindingLocked(); 461 462 // If we were actively using the last input method, then 463 // we would like to re-connect to the next input method. 464 if (mServedView != null && mServedView.isFocused()) { 465 mServedConnecting = true; 466 } 467 if (mActive) { 468 startInput = true; 469 } 470 } 471 } 472 if (startInput) { 473 startInputInner(null, 0, 0, 0); 474 } 475 return; 476 } 477 case MSG_SET_ACTIVE: { 478 final boolean active = msg.arg1 != 0; 479 if (DEBUG) { 480 Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive); 481 } 482 synchronized (mH) { 483 mActive = active; 484 mFullscreenMode = false; 485 if (!active) { 486 // Some other client has starting using the IME, so note 487 // that this happened and make sure our own editor's 488 // state is reset. 489 mHasBeenInactive = true; 490 try { 491 // Note that finishComposingText() is allowed to run 492 // even when we are not active. 493 mIInputContext.finishComposingText(); 494 } catch (RemoteException e) { 495 } 496 } 497 // Check focus again in case that "onWindowFocus" is called before 498 // handling this message. 499 if (mServedView != null && mServedView.hasWindowFocus()) { 500 // Please note that this handler thread could be different 501 // from a thread that created mServedView. That could happen 502 // the current activity is running in the system process. 503 // In that case, we really should not call 504 // mServedInputConnection.finishComposingText. 505 if (checkFocusNoStartInput(mHasBeenInactive, false)) { 506 startInputInner(null, 0, 0, 0); 507 } 508 } 509 } 510 return; 511 } 512 case MSG_SEND_INPUT_EVENT: { 513 sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj); 514 return; 515 } 516 case MSG_TIMEOUT_INPUT_EVENT: { 517 finishedInputEvent(msg.arg1, false, true); 518 return; 519 } 520 case MSG_FLUSH_INPUT_EVENT: { 521 finishedInputEvent(msg.arg1, false, false); 522 return; 523 } 524 case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: { 525 synchronized (mH) { 526 mNextUserActionNotificationSequenceNumber = msg.arg1; 527 } 528 } 529 } 530 } 531 } 532 533 private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper { 534 private final InputMethodManager mParentInputMethodManager; 535 private boolean mActive; 536 ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, final InputMethodManager inputMethodManager)537 public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn, 538 final InputMethodManager inputMethodManager) { 539 super(mainLooper, conn); 540 mParentInputMethodManager = inputMethodManager; 541 mActive = true; 542 } 543 544 @Override isActive()545 public boolean isActive() { 546 return mParentInputMethodManager.mActive && mActive; 547 } 548 deactivate()549 void deactivate() { 550 mActive = false; 551 } 552 } 553 554 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { 555 @Override 556 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 557 // No need to check for dump permission, since we only give this 558 // interface to the system. 559 CountDownLatch latch = new CountDownLatch(1); 560 SomeArgs sargs = SomeArgs.obtain(); 561 sargs.arg1 = fd; 562 sargs.arg2 = fout; 563 sargs.arg3 = args; 564 sargs.arg4 = latch; 565 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs)); 566 try { 567 if (!latch.await(5, TimeUnit.SECONDS)) { 568 fout.println("Timeout waiting for dump"); 569 } 570 } catch (InterruptedException e) { 571 fout.println("Interrupted waiting for dump"); 572 } 573 } 574 575 @Override 576 public void setUsingInputMethod(boolean state) { 577 } 578 579 @Override 580 public void onBindMethod(InputBindResult res) { 581 mH.sendMessage(mH.obtainMessage(MSG_BIND, res)); 582 } 583 584 @Override 585 public void onUnbindMethod(int sequence) { 586 mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, 0)); 587 } 588 589 @Override 590 public void setActive(boolean active) { 591 mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0)); 592 } 593 594 @Override 595 public void setUserActionNotificationSequenceNumber(int sequenceNumber) { 596 mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER, 597 sequenceNumber, 0)); 598 } 599 }; 600 601 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false); 602 InputMethodManager(IInputMethodManager service, Looper looper)603 InputMethodManager(IInputMethodManager service, Looper looper) { 604 mService = service; 605 mMainLooper = looper; 606 mH = new H(looper); 607 mIInputContext = new ControlledInputConnectionWrapper(looper, 608 mDummyInputConnection, this); 609 } 610 611 /** 612 * Retrieve the global InputMethodManager instance, creating it if it 613 * doesn't already exist. 614 * @hide 615 */ getInstance()616 public static InputMethodManager getInstance() { 617 synchronized (InputMethodManager.class) { 618 if (sInstance == null) { 619 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE); 620 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); 621 sInstance = new InputMethodManager(service, Looper.getMainLooper()); 622 } 623 return sInstance; 624 } 625 } 626 627 /** 628 * Private optimization: retrieve the global InputMethodManager instance, 629 * if it exists. 630 * @hide 631 */ peekInstance()632 public static InputMethodManager peekInstance() { 633 return sInstance; 634 } 635 636 /** @hide */ getClient()637 public IInputMethodClient getClient() { 638 return mClient; 639 } 640 641 /** @hide */ getInputContext()642 public IInputContext getInputContext() { 643 return mIInputContext; 644 } 645 getInputMethodList()646 public List<InputMethodInfo> getInputMethodList() { 647 try { 648 return mService.getInputMethodList(); 649 } catch (RemoteException e) { 650 throw new RuntimeException(e); 651 } 652 } 653 getEnabledInputMethodList()654 public List<InputMethodInfo> getEnabledInputMethodList() { 655 try { 656 return mService.getEnabledInputMethodList(); 657 } catch (RemoteException e) { 658 throw new RuntimeException(e); 659 } 660 } 661 662 /** 663 * Returns a list of enabled input method subtypes for the specified input method info. 664 * @param imi An input method info whose subtypes list will be returned. 665 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly 666 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework 667 * will implicitly enable subtypes according to the current system language. 668 */ getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes)669 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi, 670 boolean allowsImplicitlySelectedSubtypes) { 671 try { 672 return mService.getEnabledInputMethodSubtypeList( 673 imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes); 674 } catch (RemoteException e) { 675 throw new RuntimeException(e); 676 } 677 } 678 showStatusIcon(IBinder imeToken, String packageName, int iconId)679 public void showStatusIcon(IBinder imeToken, String packageName, int iconId) { 680 try { 681 mService.updateStatusIcon(imeToken, packageName, iconId); 682 } catch (RemoteException e) { 683 throw new RuntimeException(e); 684 } 685 } 686 hideStatusIcon(IBinder imeToken)687 public void hideStatusIcon(IBinder imeToken) { 688 try { 689 mService.updateStatusIcon(imeToken, null, 0); 690 } catch (RemoteException e) { 691 throw new RuntimeException(e); 692 } 693 } 694 695 /** @hide */ setImeWindowStatus(IBinder imeToken, int vis, int backDisposition)696 public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) { 697 try { 698 mService.setImeWindowStatus(imeToken, vis, backDisposition); 699 } catch (RemoteException e) { 700 throw new RuntimeException(e); 701 } 702 } 703 704 /** @hide */ setFullscreenMode(boolean fullScreen)705 public void setFullscreenMode(boolean fullScreen) { 706 mFullscreenMode = fullScreen; 707 } 708 709 /** @hide */ registerSuggestionSpansForNotification(SuggestionSpan[] spans)710 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) { 711 try { 712 mService.registerSuggestionSpansForNotification(spans); 713 } catch (RemoteException e) { 714 throw new RuntimeException(e); 715 } 716 } 717 718 /** @hide */ notifySuggestionPicked(SuggestionSpan span, String originalString, int index)719 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) { 720 try { 721 mService.notifySuggestionPicked(span, originalString, index); 722 } catch (RemoteException e) { 723 throw new RuntimeException(e); 724 } 725 } 726 727 /** 728 * Allows you to discover whether the attached input method is running 729 * in fullscreen mode. Return true if it is fullscreen, entirely covering 730 * your UI, else returns false. 731 */ isFullscreenMode()732 public boolean isFullscreenMode() { 733 return mFullscreenMode; 734 } 735 736 /** 737 * Return true if the given view is the currently active view for the 738 * input method. 739 */ isActive(View view)740 public boolean isActive(View view) { 741 checkFocus(); 742 synchronized (mH) { 743 return (mServedView == view 744 || (mServedView != null 745 && mServedView.checkInputConnectionProxy(view))) 746 && mCurrentTextBoxAttribute != null; 747 } 748 } 749 750 /** 751 * Return true if any view is currently active in the input method. 752 */ isActive()753 public boolean isActive() { 754 checkFocus(); 755 synchronized (mH) { 756 return mServedView != null && mCurrentTextBoxAttribute != null; 757 } 758 } 759 760 /** 761 * Return true if the currently served view is accepting full text edits. 762 * If false, it has no input connection, so can only handle raw key events. 763 */ isAcceptingText()764 public boolean isAcceptingText() { 765 checkFocus(); 766 return mServedInputConnection != null; 767 } 768 769 /** 770 * Reset all of the state associated with being bound to an input method. 771 */ clearBindingLocked()772 void clearBindingLocked() { 773 if (DEBUG) Log.v(TAG, "Clearing binding!"); 774 clearConnectionLocked(); 775 setInputChannelLocked(null); 776 mBindSequence = -1; 777 mCurId = null; 778 mCurMethod = null; 779 } 780 setInputChannelLocked(InputChannel channel)781 void setInputChannelLocked(InputChannel channel) { 782 if (mCurChannel != channel) { 783 if (mCurSender != null) { 784 flushPendingEventsLocked(); 785 mCurSender.dispose(); 786 mCurSender = null; 787 } 788 if (mCurChannel != null) { 789 mCurChannel.dispose(); 790 } 791 mCurChannel = channel; 792 } 793 } 794 795 /** 796 * Reset all of the state associated with a served view being connected 797 * to an input method 798 */ clearConnectionLocked()799 void clearConnectionLocked() { 800 mCurrentTextBoxAttribute = null; 801 mServedInputConnection = null; 802 if (mServedInputConnectionWrapper != null) { 803 mServedInputConnectionWrapper.deactivate(); 804 mServedInputConnectionWrapper = null; 805 } 806 } 807 808 /** 809 * Disconnect any existing input connection, clearing the served view. 810 */ finishInputLocked()811 void finishInputLocked() { 812 mNextServedView = null; 813 if (mServedView != null) { 814 if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView); 815 if (mCurrentTextBoxAttribute != null) { 816 try { 817 mService.finishInput(mClient); 818 } catch (RemoteException e) { 819 } 820 } 821 notifyInputConnectionFinished(); 822 mServedView = null; 823 mCompletions = null; 824 mServedConnecting = false; 825 clearConnectionLocked(); 826 } 827 } 828 829 /** 830 * Notifies the served view that the current InputConnection will no longer be used. 831 */ notifyInputConnectionFinished()832 private void notifyInputConnectionFinished() { 833 if (mServedView != null && mServedInputConnection != null) { 834 // We need to tell the previously served view that it is no 835 // longer the input target, so it can reset its state. Schedule 836 // this call on its window's Handler so it will be on the correct 837 // thread and outside of our lock. 838 ViewRootImpl viewRootImpl = mServedView.getViewRootImpl(); 839 if (viewRootImpl != null) { 840 // This will result in a call to reportFinishInputConnection() below. 841 viewRootImpl.dispatchFinishInputConnection(mServedInputConnection); 842 } 843 } 844 } 845 846 /** 847 * Called from the FINISH_INPUT_CONNECTION message above. 848 * @hide 849 */ reportFinishInputConnection(InputConnection ic)850 public void reportFinishInputConnection(InputConnection ic) { 851 if (mServedInputConnection != ic) { 852 ic.finishComposingText(); 853 // To avoid modifying the public InputConnection interface 854 if (ic instanceof BaseInputConnection) { 855 ((BaseInputConnection) ic).reportFinish(); 856 } 857 } 858 } 859 displayCompletions(View view, CompletionInfo[] completions)860 public void displayCompletions(View view, CompletionInfo[] completions) { 861 checkFocus(); 862 synchronized (mH) { 863 if (mServedView != view && (mServedView == null 864 || !mServedView.checkInputConnectionProxy(view))) { 865 return; 866 } 867 868 mCompletions = completions; 869 if (mCurMethod != null) { 870 try { 871 mCurMethod.displayCompletions(mCompletions); 872 } catch (RemoteException e) { 873 } 874 } 875 } 876 } 877 updateExtractedText(View view, int token, ExtractedText text)878 public void updateExtractedText(View view, int token, ExtractedText text) { 879 checkFocus(); 880 synchronized (mH) { 881 if (mServedView != view && (mServedView == null 882 || !mServedView.checkInputConnectionProxy(view))) { 883 return; 884 } 885 886 if (mCurMethod != null) { 887 try { 888 mCurMethod.updateExtractedText(token, text); 889 } catch (RemoteException e) { 890 } 891 } 892 } 893 } 894 895 /** 896 * Flag for {@link #showSoftInput} to indicate that this is an implicit 897 * request to show the input window, not as the result of a direct request 898 * by the user. The window may not be shown in this case. 899 */ 900 public static final int SHOW_IMPLICIT = 0x0001; 901 902 /** 903 * Flag for {@link #showSoftInput} to indicate that the user has forced 904 * the input method open (such as by long-pressing menu) so it should 905 * not be closed until they explicitly do so. 906 */ 907 public static final int SHOW_FORCED = 0x0002; 908 909 /** 910 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without 911 * a result receiver: explicitly request that the current input method's 912 * soft input area be shown to the user, if needed. 913 * 914 * @param view The currently focused view, which would like to receive 915 * soft keyboard input. 916 * @param flags Provides additional operating flags. Currently may be 917 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 918 */ showSoftInput(View view, int flags)919 public boolean showSoftInput(View view, int flags) { 920 return showSoftInput(view, flags, null); 921 } 922 923 /** 924 * Flag for the {@link ResultReceiver} result code from 925 * {@link #showSoftInput(View, int, ResultReceiver)} and 926 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 927 * state of the soft input window was unchanged and remains shown. 928 */ 929 public static final int RESULT_UNCHANGED_SHOWN = 0; 930 931 /** 932 * Flag for the {@link ResultReceiver} result code from 933 * {@link #showSoftInput(View, int, ResultReceiver)} and 934 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 935 * state of the soft input window was unchanged and remains hidden. 936 */ 937 public static final int RESULT_UNCHANGED_HIDDEN = 1; 938 939 /** 940 * Flag for the {@link ResultReceiver} result code from 941 * {@link #showSoftInput(View, int, ResultReceiver)} and 942 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 943 * state of the soft input window changed from hidden to shown. 944 */ 945 public static final int RESULT_SHOWN = 2; 946 947 /** 948 * Flag for the {@link ResultReceiver} result code from 949 * {@link #showSoftInput(View, int, ResultReceiver)} and 950 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 951 * state of the soft input window changed from shown to hidden. 952 */ 953 public static final int RESULT_HIDDEN = 3; 954 955 /** 956 * Explicitly request that the current input method's soft input area be 957 * shown to the user, if needed. Call this if the user interacts with 958 * your view in such a way that they have expressed they would like to 959 * start performing input into it. 960 * 961 * @param view The currently focused view, which would like to receive 962 * soft keyboard input. 963 * @param flags Provides additional operating flags. Currently may be 964 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 965 * @param resultReceiver If non-null, this will be called by the IME when 966 * it has processed your request to tell you what it has done. The result 967 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 968 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 969 * {@link #RESULT_HIDDEN}. 970 */ showSoftInput(View view, int flags, ResultReceiver resultReceiver)971 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) { 972 checkFocus(); 973 synchronized (mH) { 974 if (mServedView != view && (mServedView == null 975 || !mServedView.checkInputConnectionProxy(view))) { 976 return false; 977 } 978 979 try { 980 return mService.showSoftInput(mClient, flags, resultReceiver); 981 } catch (RemoteException e) { 982 } 983 984 return false; 985 } 986 } 987 988 /** @hide */ showSoftInputUnchecked(int flags, ResultReceiver resultReceiver)989 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { 990 try { 991 mService.showSoftInput(mClient, flags, resultReceiver); 992 } catch (RemoteException e) { 993 } 994 } 995 996 /** 997 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft 998 * input window should only be hidden if it was not explicitly shown 999 * by the user. 1000 */ 1001 public static final int HIDE_IMPLICIT_ONLY = 0x0001; 1002 1003 /** 1004 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft 1005 * input window should normally be hidden, unless it was originally 1006 * shown with {@link #SHOW_FORCED}. 1007 */ 1008 public static final int HIDE_NOT_ALWAYS = 0x0002; 1009 1010 /** 1011 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} 1012 * without a result: request to hide the soft input window from the 1013 * context of the window that is currently accepting input. 1014 * 1015 * @param windowToken The token of the window that is making the request, 1016 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1017 * @param flags Provides additional operating flags. Currently may be 1018 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1019 */ hideSoftInputFromWindow(IBinder windowToken, int flags)1020 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) { 1021 return hideSoftInputFromWindow(windowToken, flags, null); 1022 } 1023 1024 /** 1025 * Request to hide the soft input window from the context of the window 1026 * that is currently accepting input. This should be called as a result 1027 * of the user doing some actually than fairly explicitly requests to 1028 * have the input window hidden. 1029 * 1030 * @param windowToken The token of the window that is making the request, 1031 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1032 * @param flags Provides additional operating flags. Currently may be 1033 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 1034 * @param resultReceiver If non-null, this will be called by the IME when 1035 * it has processed your request to tell you what it has done. The result 1036 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 1037 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 1038 * {@link #RESULT_HIDDEN}. 1039 */ hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)1040 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, 1041 ResultReceiver resultReceiver) { 1042 checkFocus(); 1043 synchronized (mH) { 1044 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 1045 return false; 1046 } 1047 1048 try { 1049 return mService.hideSoftInput(mClient, flags, resultReceiver); 1050 } catch (RemoteException e) { 1051 } 1052 return false; 1053 } 1054 } 1055 1056 1057 /** 1058 * This method toggles the input method window display. 1059 * If the input window is already displayed, it gets hidden. 1060 * If not the input window will be displayed. 1061 * @param windowToken The token of the window that is making the request, 1062 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 1063 * @param showFlags Provides additional operating flags. May be 1064 * 0 or have the {@link #SHOW_IMPLICIT}, 1065 * {@link #SHOW_FORCED} bit set. 1066 * @param hideFlags Provides additional operating flags. May be 1067 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1068 * {@link #HIDE_NOT_ALWAYS} bit set. 1069 **/ toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)1070 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) { 1071 synchronized (mH) { 1072 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 1073 return; 1074 } 1075 if (mCurMethod != null) { 1076 try { 1077 mCurMethod.toggleSoftInput(showFlags, hideFlags); 1078 } catch (RemoteException e) { 1079 } 1080 } 1081 } 1082 } 1083 1084 /* 1085 * This method toggles the input method window display. 1086 * If the input window is already displayed, it gets hidden. 1087 * If not the input window will be displayed. 1088 * @param showFlags Provides additional operating flags. May be 1089 * 0 or have the {@link #SHOW_IMPLICIT}, 1090 * {@link #SHOW_FORCED} bit set. 1091 * @param hideFlags Provides additional operating flags. May be 1092 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1093 * {@link #HIDE_NOT_ALWAYS} bit set. 1094 * @hide 1095 */ toggleSoftInput(int showFlags, int hideFlags)1096 public void toggleSoftInput(int showFlags, int hideFlags) { 1097 if (mCurMethod != null) { 1098 try { 1099 mCurMethod.toggleSoftInput(showFlags, hideFlags); 1100 } catch (RemoteException e) { 1101 } 1102 } 1103 } 1104 1105 /** 1106 * If the input method is currently connected to the given view, 1107 * restart it with its new contents. You should call this when the text 1108 * within your view changes outside of the normal input method or key 1109 * input flow, such as when an application calls TextView.setText(). 1110 * 1111 * @param view The view whose text has changed. 1112 */ restartInput(View view)1113 public void restartInput(View view) { 1114 checkFocus(); 1115 synchronized (mH) { 1116 if (mServedView != view && (mServedView == null 1117 || !mServedView.checkInputConnectionProxy(view))) { 1118 return; 1119 } 1120 1121 mServedConnecting = true; 1122 } 1123 1124 startInputInner(null, 0, 0, 0); 1125 } 1126 startInputInner(IBinder windowGainingFocus, int controlFlags, int softInputMode, int windowFlags)1127 boolean startInputInner(IBinder windowGainingFocus, int controlFlags, int softInputMode, 1128 int windowFlags) { 1129 final View view; 1130 synchronized (mH) { 1131 view = mServedView; 1132 1133 // Make sure we have a window token for the served view. 1134 if (DEBUG) Log.v(TAG, "Starting input: view=" + view); 1135 if (view == null) { 1136 if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); 1137 return false; 1138 } 1139 } 1140 1141 // Now we need to get an input connection from the served view. 1142 // This is complicated in a couple ways: we can't be holding our lock 1143 // when calling out to the view, and we need to make sure we call into 1144 // the view on the same thread that is driving its view hierarchy. 1145 Handler vh = view.getHandler(); 1146 if (vh == null) { 1147 // If the view doesn't have a handler, something has changed out 1148 // from under us, so just close the current input. 1149 // If we don't close the current input, the current input method can remain on the 1150 // screen without a connection. 1151 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input."); 1152 closeCurrentInput(); 1153 return false; 1154 } 1155 if (vh.getLooper() != Looper.myLooper()) { 1156 // The view is running on a different thread than our own, so 1157 // we need to reschedule our work for over there. 1158 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); 1159 vh.post(new Runnable() { 1160 @Override 1161 public void run() { 1162 startInputInner(null, 0, 0, 0); 1163 } 1164 }); 1165 return false; 1166 } 1167 1168 // Okay we are now ready to call into the served view and have it 1169 // do its stuff. 1170 // Life is good: let's hook everything up! 1171 EditorInfo tba = new EditorInfo(); 1172 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the 1173 // system can verify the consistency between the uid of this process and package name passed 1174 // from here. See comment of Context#getOpPackageName() for details. 1175 tba.packageName = view.getContext().getOpPackageName(); 1176 tba.fieldId = view.getId(); 1177 InputConnection ic = view.onCreateInputConnection(tba); 1178 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); 1179 1180 synchronized (mH) { 1181 // Now that we are locked again, validate that our state hasn't 1182 // changed. 1183 if (mServedView != view || !mServedConnecting) { 1184 // Something else happened, so abort. 1185 if (DEBUG) Log.v(TAG, 1186 "Starting input: finished by someone else (view=" 1187 + mServedView + " conn=" + mServedConnecting + ")"); 1188 return false; 1189 } 1190 1191 // If we already have a text box, then this view is already 1192 // connected so we want to restart it. 1193 if (mCurrentTextBoxAttribute == null) { 1194 controlFlags |= CONTROL_START_INITIAL; 1195 } 1196 1197 // Hook 'em up and let 'er rip. 1198 mCurrentTextBoxAttribute = tba; 1199 mServedConnecting = false; 1200 // Notify the served view that its previous input connection is finished 1201 notifyInputConnectionFinished(); 1202 mServedInputConnection = ic; 1203 ControlledInputConnectionWrapper servedContext; 1204 if (ic != null) { 1205 mCursorSelStart = tba.initialSelStart; 1206 mCursorSelEnd = tba.initialSelEnd; 1207 mCursorCandStart = -1; 1208 mCursorCandEnd = -1; 1209 mCursorRect.setEmpty(); 1210 mCursorAnchorInfo = null; 1211 servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this); 1212 } else { 1213 servedContext = null; 1214 } 1215 if (mServedInputConnectionWrapper != null) { 1216 mServedInputConnectionWrapper.deactivate(); 1217 } 1218 mServedInputConnectionWrapper = servedContext; 1219 1220 try { 1221 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" 1222 + ic + " tba=" + tba + " controlFlags=#" 1223 + Integer.toHexString(controlFlags)); 1224 InputBindResult res; 1225 if (windowGainingFocus != null) { 1226 res = mService.windowGainedFocus(mClient, windowGainingFocus, 1227 controlFlags, softInputMode, windowFlags, 1228 tba, servedContext); 1229 } else { 1230 res = mService.startInput(mClient, 1231 servedContext, tba, controlFlags); 1232 } 1233 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); 1234 if (res != null) { 1235 if (res.id != null) { 1236 setInputChannelLocked(res.channel); 1237 mBindSequence = res.sequence; 1238 mCurMethod = res.method; 1239 mCurId = res.id; 1240 mNextUserActionNotificationSequenceNumber = 1241 res.userActionNotificationSequenceNumber; 1242 } else { 1243 if (res.channel != null && res.channel != mCurChannel) { 1244 res.channel.dispose(); 1245 } 1246 if (mCurMethod == null) { 1247 // This means there is no input method available. 1248 if (DEBUG) Log.v(TAG, "ABORT input: no input method!"); 1249 return true; 1250 } 1251 } 1252 } 1253 if (mCurMethod != null && mCompletions != null) { 1254 try { 1255 mCurMethod.displayCompletions(mCompletions); 1256 } catch (RemoteException e) { 1257 } 1258 } 1259 } catch (RemoteException e) { 1260 Log.w(TAG, "IME died: " + mCurId, e); 1261 } 1262 } 1263 1264 return true; 1265 } 1266 1267 /** 1268 * When the focused window is dismissed, this method is called to finish the 1269 * input method started before. 1270 * @hide 1271 */ windowDismissed(IBinder appWindowToken)1272 public void windowDismissed(IBinder appWindowToken) { 1273 checkFocus(); 1274 synchronized (mH) { 1275 if (mServedView != null && 1276 mServedView.getWindowToken() == appWindowToken) { 1277 finishInputLocked(); 1278 } 1279 } 1280 } 1281 1282 /** 1283 * Call this when a view receives focus. 1284 * @hide 1285 */ focusIn(View view)1286 public void focusIn(View view) { 1287 synchronized (mH) { 1288 focusInLocked(view); 1289 } 1290 } 1291 focusInLocked(View view)1292 void focusInLocked(View view) { 1293 if (DEBUG) Log.v(TAG, "focusIn: " + view); 1294 1295 if (mCurRootView != view.getRootView()) { 1296 // This is a request from a window that isn't in the window with 1297 // IME focus, so ignore it. 1298 if (DEBUG) Log.v(TAG, "Not IME target window, ignoring"); 1299 return; 1300 } 1301 1302 mNextServedView = view; 1303 scheduleCheckFocusLocked(view); 1304 } 1305 1306 /** 1307 * Call this when a view loses focus. 1308 * @hide 1309 */ focusOut(View view)1310 public void focusOut(View view) { 1311 synchronized (mH) { 1312 if (DEBUG) Log.v(TAG, "focusOut: " + view 1313 + " mServedView=" + mServedView 1314 + " winFocus=" + view.hasWindowFocus()); 1315 if (mServedView != view) { 1316 // The following code would auto-hide the IME if we end up 1317 // with no more views with focus. This can happen, however, 1318 // whenever we go into touch mode, so it ends up hiding 1319 // at times when we don't really want it to. For now it 1320 // seems better to just turn it all off. 1321 if (false && view.hasWindowFocus()) { 1322 mNextServedView = null; 1323 scheduleCheckFocusLocked(view); 1324 } 1325 } 1326 } 1327 } 1328 1329 /** 1330 * Call this when a view is being detached from a {@link android.view.Window}. 1331 * @hide 1332 */ onViewDetachedFromWindow(View view)1333 public void onViewDetachedFromWindow(View view) { 1334 synchronized (mH) { 1335 if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: " + view 1336 + " mServedView=" + mServedView 1337 + " hasWindowFocus=" + view.hasWindowFocus()); 1338 if (mServedView == view && view.hasWindowFocus()) { 1339 mNextServedView = null; 1340 scheduleCheckFocusLocked(view); 1341 } 1342 } 1343 } 1344 scheduleCheckFocusLocked(View view)1345 static void scheduleCheckFocusLocked(View view) { 1346 ViewRootImpl viewRootImpl = view.getViewRootImpl(); 1347 if (viewRootImpl != null) { 1348 viewRootImpl.dispatchCheckFocus(); 1349 } 1350 } 1351 1352 /** 1353 * @hide 1354 */ checkFocus()1355 public void checkFocus() { 1356 if (checkFocusNoStartInput(false, true)) { 1357 startInputInner(null, 0, 0, 0); 1358 } 1359 } 1360 checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText)1361 private boolean checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText) { 1362 // This is called a lot, so short-circuit before locking. 1363 if (mServedView == mNextServedView && !forceNewFocus) { 1364 return false; 1365 } 1366 1367 InputConnection ic = null; 1368 synchronized (mH) { 1369 if (mServedView == mNextServedView && !forceNewFocus) { 1370 return false; 1371 } 1372 if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView 1373 + " next=" + mNextServedView 1374 + " forceNewFocus=" + forceNewFocus 1375 + " package=" 1376 + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>")); 1377 1378 if (mNextServedView == null) { 1379 finishInputLocked(); 1380 // In this case, we used to have a focused view on the window, 1381 // but no longer do. We should make sure the input method is 1382 // no longer shown, since it serves no purpose. 1383 closeCurrentInput(); 1384 return false; 1385 } 1386 1387 ic = mServedInputConnection; 1388 1389 mServedView = mNextServedView; 1390 mCurrentTextBoxAttribute = null; 1391 mCompletions = null; 1392 mServedConnecting = true; 1393 } 1394 1395 if (finishComposingText && ic != null) { 1396 ic.finishComposingText(); 1397 } 1398 1399 return true; 1400 } 1401 closeCurrentInput()1402 void closeCurrentInput() { 1403 try { 1404 mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null); 1405 } catch (RemoteException e) { 1406 } 1407 } 1408 1409 /** 1410 * Called by ViewAncestor when its window gets input focus. 1411 * @hide 1412 */ onPostWindowFocus(View rootView, View focusedView, int softInputMode, boolean first, int windowFlags)1413 public void onPostWindowFocus(View rootView, View focusedView, int softInputMode, 1414 boolean first, int windowFlags) { 1415 boolean forceNewFocus = false; 1416 synchronized (mH) { 1417 if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView 1418 + " softInputMode=" + softInputMode 1419 + " first=" + first + " flags=#" 1420 + Integer.toHexString(windowFlags)); 1421 if (mHasBeenInactive) { 1422 if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh"); 1423 mHasBeenInactive = false; 1424 forceNewFocus = true; 1425 } 1426 focusInLocked(focusedView != null ? focusedView : rootView); 1427 } 1428 1429 int controlFlags = 0; 1430 if (focusedView != null) { 1431 controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS; 1432 if (focusedView.onCheckIsTextEditor()) { 1433 controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR; 1434 } 1435 } 1436 if (first) { 1437 controlFlags |= CONTROL_WINDOW_FIRST; 1438 } 1439 1440 if (checkFocusNoStartInput(forceNewFocus, true)) { 1441 // We need to restart input on the current focus view. This 1442 // should be done in conjunction with telling the system service 1443 // about the window gaining focus, to help make the transition 1444 // smooth. 1445 if (startInputInner(rootView.getWindowToken(), 1446 controlFlags, softInputMode, windowFlags)) { 1447 return; 1448 } 1449 } 1450 1451 // For some reason we didn't do a startInput + windowFocusGain, so 1452 // we'll just do a window focus gain and call it a day. 1453 synchronized (mH) { 1454 try { 1455 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); 1456 mService.windowGainedFocus(mClient, rootView.getWindowToken(), 1457 controlFlags, softInputMode, windowFlags, null, null); 1458 } catch (RemoteException e) { 1459 } 1460 } 1461 } 1462 1463 /** @hide */ onPreWindowFocus(View rootView, boolean hasWindowFocus)1464 public void onPreWindowFocus(View rootView, boolean hasWindowFocus) { 1465 synchronized (mH) { 1466 if (rootView == null) { 1467 mCurRootView = null; 1468 } if (hasWindowFocus) { 1469 mCurRootView = rootView; 1470 } else if (rootView == mCurRootView) { 1471 // If the mCurRootView is losing window focus, release the strong reference to it 1472 // so as not to prevent it from being garbage-collected. 1473 mCurRootView = null; 1474 } else { 1475 if (DEBUG) { 1476 Log.v(TAG, "Ignoring onPreWindowFocus()." 1477 + " mCurRootView=" + mCurRootView + " rootView=" + rootView); 1478 } 1479 } 1480 } 1481 } 1482 1483 /** 1484 * Report the current selection range. 1485 * 1486 * <p><strong>Editor authors</strong>, you need to call this method whenever 1487 * the cursor moves in your editor. Remember that in addition to doing this, your 1488 * editor needs to always supply current cursor values in 1489 * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every 1490 * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is 1491 * called, which happens whenever the keyboard shows up or the focus changes 1492 * to a text field, among other cases.</p> 1493 */ updateSelection(View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd)1494 public void updateSelection(View view, int selStart, int selEnd, 1495 int candidatesStart, int candidatesEnd) { 1496 checkFocus(); 1497 synchronized (mH) { 1498 if ((mServedView != view && (mServedView == null 1499 || !mServedView.checkInputConnectionProxy(view))) 1500 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1501 return; 1502 } 1503 1504 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd 1505 || mCursorCandStart != candidatesStart 1506 || mCursorCandEnd != candidatesEnd) { 1507 if (DEBUG) Log.d(TAG, "updateSelection"); 1508 1509 try { 1510 if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod); 1511 final int oldSelStart = mCursorSelStart; 1512 final int oldSelEnd = mCursorSelEnd; 1513 // Update internal values before sending updateSelection to the IME, because 1514 // if it changes the text within its onUpdateSelection handler in a way that 1515 // does not move the cursor we don't want to call it again with the same values. 1516 mCursorSelStart = selStart; 1517 mCursorSelEnd = selEnd; 1518 mCursorCandStart = candidatesStart; 1519 mCursorCandEnd = candidatesEnd; 1520 mCurMethod.updateSelection(oldSelStart, oldSelEnd, 1521 selStart, selEnd, candidatesStart, candidatesEnd); 1522 } catch (RemoteException e) { 1523 Log.w(TAG, "IME died: " + mCurId, e); 1524 } 1525 } 1526 } 1527 } 1528 1529 /** 1530 * Notify the event when the user tapped or clicked the text view. 1531 */ viewClicked(View view)1532 public void viewClicked(View view) { 1533 final boolean focusChanged = mServedView != mNextServedView; 1534 checkFocus(); 1535 synchronized (mH) { 1536 if ((mServedView != view && (mServedView == null 1537 || !mServedView.checkInputConnectionProxy(view))) 1538 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1539 return; 1540 } 1541 try { 1542 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged); 1543 mCurMethod.viewClicked(focusChanged); 1544 } catch (RemoteException e) { 1545 Log.w(TAG, "IME died: " + mCurId, e); 1546 } 1547 } 1548 } 1549 1550 /** 1551 * Return true if the current input method wants to watch the location 1552 * of the input editor's cursor in its window. 1553 * 1554 * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead. 1555 */ 1556 @Deprecated isWatchingCursor(View view)1557 public boolean isWatchingCursor(View view) { 1558 return false; 1559 } 1560 1561 /** 1562 * Return true if the current input method wants to be notified when cursor/anchor location 1563 * is changed. 1564 * 1565 * @hide 1566 */ isCursorAnchorInfoEnabled()1567 public boolean isCursorAnchorInfoEnabled() { 1568 synchronized (mH) { 1569 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 1570 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 1571 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode & 1572 InputConnection.CURSOR_UPDATE_MONITOR) != 0; 1573 return isImmediate || isMonitoring; 1574 } 1575 } 1576 1577 /** 1578 * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}. 1579 * 1580 * @hide 1581 */ setUpdateCursorAnchorInfoMode(int flags)1582 public void setUpdateCursorAnchorInfoMode(int flags) { 1583 synchronized (mH) { 1584 mRequestUpdateCursorAnchorInfoMonitorMode = flags; 1585 } 1586 } 1587 1588 /** 1589 * Report the current cursor location in its window. 1590 * 1591 * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead. 1592 */ 1593 @Deprecated updateCursor(View view, int left, int top, int right, int bottom)1594 public void updateCursor(View view, int left, int top, int right, int bottom) { 1595 checkFocus(); 1596 synchronized (mH) { 1597 if ((mServedView != view && (mServedView == null 1598 || !mServedView.checkInputConnectionProxy(view))) 1599 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1600 return; 1601 } 1602 1603 mTmpCursorRect.set(left, top, right, bottom); 1604 if (!mCursorRect.equals(mTmpCursorRect)) { 1605 if (DEBUG) Log.d(TAG, "updateCursor"); 1606 1607 try { 1608 if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod); 1609 mCurMethod.updateCursor(mTmpCursorRect); 1610 mCursorRect.set(mTmpCursorRect); 1611 } catch (RemoteException e) { 1612 Log.w(TAG, "IME died: " + mCurId, e); 1613 } 1614 } 1615 } 1616 } 1617 1618 /** 1619 * Report positional change of the text insertion point and/or characters in the composition 1620 * string. 1621 */ updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo)1622 public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) { 1623 if (view == null || cursorAnchorInfo == null) { 1624 return; 1625 } 1626 checkFocus(); 1627 synchronized (mH) { 1628 if ((mServedView != view && 1629 (mServedView == null || !mServedView.checkInputConnectionProxy(view))) 1630 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1631 return; 1632 } 1633 // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has 1634 // not been changed from the previous call. 1635 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode & 1636 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; 1637 if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) { 1638 // TODO: Consider always emitting this message once we have addressed redundant 1639 // calls of this method from android.widget.Editor. 1640 if (DEBUG) { 1641 Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" 1642 + cursorAnchorInfo); 1643 } 1644 return; 1645 } 1646 if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo); 1647 try { 1648 mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo); 1649 mCursorAnchorInfo = cursorAnchorInfo; 1650 // Clear immediate bit (if any). 1651 mRequestUpdateCursorAnchorInfoMonitorMode &= 1652 ~InputConnection.CURSOR_UPDATE_IMMEDIATE; 1653 } catch (RemoteException e) { 1654 Log.w(TAG, "IME died: " + mCurId, e); 1655 } 1656 } 1657 } 1658 1659 /** 1660 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) 1661 * InputMethodSession.appPrivateCommand()} on the current Input Method. 1662 * @param view Optional View that is sending the command, or null if 1663 * you want to send the command regardless of the view that is attached 1664 * to the input method. 1665 * @param action Name of the command to be performed. This <em>must</em> 1666 * be a scoped name, i.e. prefixed with a package name you own, so that 1667 * different developers will not create conflicting commands. 1668 * @param data Any data to include with the command. 1669 */ sendAppPrivateCommand(View view, String action, Bundle data)1670 public void sendAppPrivateCommand(View view, String action, Bundle data) { 1671 checkFocus(); 1672 synchronized (mH) { 1673 if ((mServedView != view && (mServedView == null 1674 || !mServedView.checkInputConnectionProxy(view))) 1675 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1676 return; 1677 } 1678 try { 1679 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data); 1680 mCurMethod.appPrivateCommand(action, data); 1681 } catch (RemoteException e) { 1682 Log.w(TAG, "IME died: " + mCurId, e); 1683 } 1684 } 1685 } 1686 1687 /** 1688 * Force switch to a new input method component. This can only be called 1689 * from an application or a service which has a token of the currently active input method. 1690 * @param token Supplies the identifying token given to an input method 1691 * when it was started, which allows it to perform this operation on 1692 * itself. 1693 * @param id The unique identifier for the new input method to be switched to. 1694 */ setInputMethod(IBinder token, String id)1695 public void setInputMethod(IBinder token, String id) { 1696 try { 1697 mService.setInputMethod(token, id); 1698 } catch (RemoteException e) { 1699 throw new RuntimeException(e); 1700 } 1701 } 1702 1703 /** 1704 * Force switch to a new input method and subtype. This can only be called 1705 * from an application or a service which has a token of the currently active input method. 1706 * @param token Supplies the identifying token given to an input method 1707 * when it was started, which allows it to perform this operation on 1708 * itself. 1709 * @param id The unique identifier for the new input method to be switched to. 1710 * @param subtype The new subtype of the new input method to be switched to. 1711 */ setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype)1712 public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) { 1713 try { 1714 mService.setInputMethodAndSubtype(token, id, subtype); 1715 } catch (RemoteException e) { 1716 throw new RuntimeException(e); 1717 } 1718 } 1719 1720 /** 1721 * Close/hide the input method's soft input area, so the user no longer 1722 * sees it or can interact with it. This can only be called 1723 * from the currently active input method, as validated by the given token. 1724 * 1725 * @param token Supplies the identifying token given to an input method 1726 * when it was started, which allows it to perform this operation on 1727 * itself. 1728 * @param flags Provides additional operating flags. Currently may be 1729 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1730 * {@link #HIDE_NOT_ALWAYS} bit set. 1731 */ hideSoftInputFromInputMethod(IBinder token, int flags)1732 public void hideSoftInputFromInputMethod(IBinder token, int flags) { 1733 try { 1734 mService.hideMySoftInput(token, flags); 1735 } catch (RemoteException e) { 1736 throw new RuntimeException(e); 1737 } 1738 } 1739 1740 /** 1741 * Show the input method's soft input area, so the user 1742 * sees the input method window and can interact with it. 1743 * This can only be called from the currently active input method, 1744 * as validated by the given token. 1745 * 1746 * @param token Supplies the identifying token given to an input method 1747 * when it was started, which allows it to perform this operation on 1748 * itself. 1749 * @param flags Provides additional operating flags. Currently may be 1750 * 0 or have the {@link #SHOW_IMPLICIT} or 1751 * {@link #SHOW_FORCED} bit set. 1752 */ showSoftInputFromInputMethod(IBinder token, int flags)1753 public void showSoftInputFromInputMethod(IBinder token, int flags) { 1754 try { 1755 mService.showMySoftInput(token, flags); 1756 } catch (RemoteException e) { 1757 throw new RuntimeException(e); 1758 } 1759 } 1760 1761 /** 1762 * Dispatches an input event to the IME. 1763 * 1764 * Returns {@link #DISPATCH_HANDLED} if the event was handled. 1765 * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled. 1766 * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the 1767 * callback will be invoked later. 1768 * 1769 * @hide 1770 */ dispatchInputEvent(InputEvent event, Object token, FinishedInputEventCallback callback, Handler handler)1771 public int dispatchInputEvent(InputEvent event, Object token, 1772 FinishedInputEventCallback callback, Handler handler) { 1773 synchronized (mH) { 1774 if (mCurMethod != null) { 1775 if (event instanceof KeyEvent) { 1776 KeyEvent keyEvent = (KeyEvent)event; 1777 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN 1778 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM 1779 && keyEvent.getRepeatCount() == 0) { 1780 showInputMethodPickerLocked(); 1781 return DISPATCH_HANDLED; 1782 } 1783 } 1784 1785 if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod); 1786 1787 PendingEvent p = obtainPendingEventLocked( 1788 event, token, mCurId, callback, handler); 1789 if (mMainLooper.isCurrentThread()) { 1790 // Already running on the IMM thread so we can send the event immediately. 1791 return sendInputEventOnMainLooperLocked(p); 1792 } 1793 1794 // Post the event to the IMM thread. 1795 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p); 1796 msg.setAsynchronous(true); 1797 mH.sendMessage(msg); 1798 return DISPATCH_IN_PROGRESS; 1799 } 1800 } 1801 return DISPATCH_NOT_HANDLED; 1802 } 1803 1804 // Must be called on the main looper sendInputEventAndReportResultOnMainLooper(PendingEvent p)1805 void sendInputEventAndReportResultOnMainLooper(PendingEvent p) { 1806 final boolean handled; 1807 synchronized (mH) { 1808 int result = sendInputEventOnMainLooperLocked(p); 1809 if (result == DISPATCH_IN_PROGRESS) { 1810 return; 1811 } 1812 1813 handled = (result == DISPATCH_HANDLED); 1814 } 1815 1816 invokeFinishedInputEventCallback(p, handled); 1817 } 1818 1819 // Must be called on the main looper sendInputEventOnMainLooperLocked(PendingEvent p)1820 int sendInputEventOnMainLooperLocked(PendingEvent p) { 1821 if (mCurChannel != null) { 1822 if (mCurSender == null) { 1823 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper()); 1824 } 1825 1826 final InputEvent event = p.mEvent; 1827 final int seq = event.getSequenceNumber(); 1828 if (mCurSender.sendInputEvent(seq, event)) { 1829 mPendingEvents.put(seq, p); 1830 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, 1831 mPendingEvents.size()); 1832 1833 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p); 1834 msg.setAsynchronous(true); 1835 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT); 1836 return DISPATCH_IN_PROGRESS; 1837 } 1838 1839 Log.w(TAG, "Unable to send input event to IME: " 1840 + mCurId + " dropping: " + event); 1841 } 1842 return DISPATCH_NOT_HANDLED; 1843 } 1844 finishedInputEvent(int seq, boolean handled, boolean timeout)1845 void finishedInputEvent(int seq, boolean handled, boolean timeout) { 1846 final PendingEvent p; 1847 synchronized (mH) { 1848 int index = mPendingEvents.indexOfKey(seq); 1849 if (index < 0) { 1850 return; // spurious, event already finished or timed out 1851 } 1852 1853 p = mPendingEvents.valueAt(index); 1854 mPendingEvents.removeAt(index); 1855 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size()); 1856 1857 if (timeout) { 1858 Log.w(TAG, "Timeout waiting for IME to handle input event after " 1859 + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId); 1860 } else { 1861 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p); 1862 } 1863 } 1864 1865 invokeFinishedInputEventCallback(p, handled); 1866 } 1867 1868 // Assumes the event has already been removed from the queue. invokeFinishedInputEventCallback(PendingEvent p, boolean handled)1869 void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) { 1870 p.mHandled = handled; 1871 if (p.mHandler.getLooper().isCurrentThread()) { 1872 // Already running on the callback handler thread so we can send the 1873 // callback immediately. 1874 p.run(); 1875 } else { 1876 // Post the event to the callback handler thread. 1877 // In this case, the callback will be responsible for recycling the event. 1878 Message msg = Message.obtain(p.mHandler, p); 1879 msg.setAsynchronous(true); 1880 msg.sendToTarget(); 1881 } 1882 } 1883 flushPendingEventsLocked()1884 private void flushPendingEventsLocked() { 1885 mH.removeMessages(MSG_FLUSH_INPUT_EVENT); 1886 1887 final int count = mPendingEvents.size(); 1888 for (int i = 0; i < count; i++) { 1889 int seq = mPendingEvents.keyAt(i); 1890 Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0); 1891 msg.setAsynchronous(true); 1892 msg.sendToTarget(); 1893 } 1894 } 1895 obtainPendingEventLocked(InputEvent event, Object token, String inputMethodId, FinishedInputEventCallback callback, Handler handler)1896 private PendingEvent obtainPendingEventLocked(InputEvent event, Object token, 1897 String inputMethodId, FinishedInputEventCallback callback, Handler handler) { 1898 PendingEvent p = mPendingEventPool.acquire(); 1899 if (p == null) { 1900 p = new PendingEvent(); 1901 } 1902 p.mEvent = event; 1903 p.mToken = token; 1904 p.mInputMethodId = inputMethodId; 1905 p.mCallback = callback; 1906 p.mHandler = handler; 1907 return p; 1908 } 1909 recyclePendingEventLocked(PendingEvent p)1910 private void recyclePendingEventLocked(PendingEvent p) { 1911 p.recycle(); 1912 mPendingEventPool.release(p); 1913 } 1914 showInputMethodPicker()1915 public void showInputMethodPicker() { 1916 synchronized (mH) { 1917 showInputMethodPickerLocked(); 1918 } 1919 } 1920 1921 /** 1922 * Shows the input method chooser dialog. 1923 * 1924 * @param showAuxiliarySubtypes Set true to show auxiliary input methods. 1925 * @hide 1926 */ showInputMethodPicker(boolean showAuxiliarySubtypes)1927 public void showInputMethodPicker(boolean showAuxiliarySubtypes) { 1928 synchronized (mH) { 1929 try { 1930 final int mode = showAuxiliarySubtypes ? 1931 SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES: 1932 SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES; 1933 mService.showInputMethodPickerFromClient(mClient, mode); 1934 } catch (RemoteException e) { 1935 Log.w(TAG, "IME died: " + mCurId, e); 1936 } 1937 } 1938 } 1939 showInputMethodPickerLocked()1940 private void showInputMethodPickerLocked() { 1941 try { 1942 mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO); 1943 } catch (RemoteException e) { 1944 Log.w(TAG, "IME died: " + mCurId, e); 1945 } 1946 } 1947 1948 /** 1949 * Show the settings for enabling subtypes of the specified input method. 1950 * @param imiId An input method, whose subtypes settings will be shown. If imiId is null, 1951 * subtypes of all input methods will be shown. 1952 */ showInputMethodAndSubtypeEnabler(String imiId)1953 public void showInputMethodAndSubtypeEnabler(String imiId) { 1954 synchronized (mH) { 1955 try { 1956 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId); 1957 } catch (RemoteException e) { 1958 Log.w(TAG, "IME died: " + mCurId, e); 1959 } 1960 } 1961 } 1962 1963 /** 1964 * Returns the current input method subtype. This subtype is one of the subtypes in 1965 * the current input method. This method returns null when the current input method doesn't 1966 * have any input method subtype. 1967 */ getCurrentInputMethodSubtype()1968 public InputMethodSubtype getCurrentInputMethodSubtype() { 1969 synchronized (mH) { 1970 try { 1971 return mService.getCurrentInputMethodSubtype(); 1972 } catch (RemoteException e) { 1973 Log.w(TAG, "IME died: " + mCurId, e); 1974 return null; 1975 } 1976 } 1977 } 1978 1979 /** 1980 * Switch to a new input method subtype of the current input method. 1981 * @param subtype A new input method subtype to switch. 1982 * @return true if the current subtype was successfully switched. When the specified subtype is 1983 * null, this method returns false. 1984 */ 1985 @RequiresPermission(WRITE_SECURE_SETTINGS) setCurrentInputMethodSubtype(InputMethodSubtype subtype)1986 public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) { 1987 synchronized (mH) { 1988 try { 1989 return mService.setCurrentInputMethodSubtype(subtype); 1990 } catch (RemoteException e) { 1991 Log.w(TAG, "IME died: " + mCurId, e); 1992 return false; 1993 } 1994 } 1995 } 1996 1997 /** 1998 * Notify that a user took some action with this input method. 1999 * @hide 2000 */ notifyUserAction()2001 public void notifyUserAction() { 2002 synchronized (mH) { 2003 if (mLastSentUserActionNotificationSequenceNumber == 2004 mNextUserActionNotificationSequenceNumber) { 2005 if (DEBUG) { 2006 Log.w(TAG, "Ignoring notifyUserAction as it has already been sent." 2007 + " mLastSentUserActionNotificationSequenceNumber: " 2008 + mLastSentUserActionNotificationSequenceNumber 2009 + " mNextUserActionNotificationSequenceNumber: " 2010 + mNextUserActionNotificationSequenceNumber); 2011 } 2012 return; 2013 } 2014 try { 2015 if (DEBUG) { 2016 Log.w(TAG, "notifyUserAction: " 2017 + " mLastSentUserActionNotificationSequenceNumber: " 2018 + mLastSentUserActionNotificationSequenceNumber 2019 + " mNextUserActionNotificationSequenceNumber: " 2020 + mNextUserActionNotificationSequenceNumber); 2021 } 2022 mService.notifyUserAction(mNextUserActionNotificationSequenceNumber); 2023 mLastSentUserActionNotificationSequenceNumber = 2024 mNextUserActionNotificationSequenceNumber; 2025 } catch (RemoteException e) { 2026 Log.w(TAG, "IME died: " + mCurId, e); 2027 } 2028 } 2029 } 2030 2031 /** 2032 * Returns a map of all shortcut input method info and their subtypes. 2033 */ getShortcutInputMethodsAndSubtypes()2034 public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() { 2035 synchronized (mH) { 2036 HashMap<InputMethodInfo, List<InputMethodSubtype>> ret = 2037 new HashMap<InputMethodInfo, List<InputMethodSubtype>>(); 2038 try { 2039 // TODO: We should change the return type from List<Object> to List<Parcelable> 2040 List<Object> info = mService.getShortcutInputMethodsAndSubtypes(); 2041 // "info" has imi1, subtype1, subtype2, imi2, subtype2, imi3, subtype3..in the list 2042 ArrayList<InputMethodSubtype> subtypes = null; 2043 if (info != null && !info.isEmpty()) { 2044 final int N = info.size(); 2045 for (int i = 0; i < N; ++i) { 2046 Object o = info.get(i); 2047 if (o instanceof InputMethodInfo) { 2048 if (ret.containsKey(o)) { 2049 Log.e(TAG, "IMI list already contains the same InputMethod."); 2050 break; 2051 } 2052 subtypes = new ArrayList<InputMethodSubtype>(); 2053 ret.put((InputMethodInfo)o, subtypes); 2054 } else if (subtypes != null && o instanceof InputMethodSubtype) { 2055 subtypes.add((InputMethodSubtype)o); 2056 } 2057 } 2058 } 2059 } catch (RemoteException e) { 2060 Log.w(TAG, "IME died: " + mCurId, e); 2061 } 2062 return ret; 2063 } 2064 } 2065 2066 /** 2067 * @return The current height of the input method window. 2068 * @hide 2069 */ getInputMethodWindowVisibleHeight()2070 public int getInputMethodWindowVisibleHeight() { 2071 synchronized (mH) { 2072 try { 2073 return mService.getInputMethodWindowVisibleHeight(); 2074 } catch (RemoteException e) { 2075 Log.w(TAG, "IME died: " + mCurId, e); 2076 return 0; 2077 } 2078 } 2079 } 2080 2081 /** 2082 * Force switch to the last used input method and subtype. If the last input method didn't have 2083 * any subtypes, the framework will simply switch to the last input method with no subtype 2084 * specified. 2085 * @param imeToken Supplies the identifying token given to an input method when it was started, 2086 * which allows it to perform this operation on itself. 2087 * @return true if the current input method and subtype was successfully switched to the last 2088 * used input method and subtype. 2089 */ switchToLastInputMethod(IBinder imeToken)2090 public boolean switchToLastInputMethod(IBinder imeToken) { 2091 synchronized (mH) { 2092 try { 2093 return mService.switchToLastInputMethod(imeToken); 2094 } catch (RemoteException e) { 2095 Log.w(TAG, "IME died: " + mCurId, e); 2096 return false; 2097 } 2098 } 2099 } 2100 2101 /** 2102 * Force switch to the next input method and subtype. If there is no IME enabled except 2103 * current IME and subtype, do nothing. 2104 * @param imeToken Supplies the identifying token given to an input method when it was started, 2105 * which allows it to perform this operation on itself. 2106 * @param onlyCurrentIme if true, the framework will find the next subtype which 2107 * belongs to the current IME 2108 * @return true if the current input method and subtype was successfully switched to the next 2109 * input method and subtype. 2110 */ switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme)2111 public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) { 2112 synchronized (mH) { 2113 try { 2114 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme); 2115 } catch (RemoteException e) { 2116 Log.w(TAG, "IME died: " + mCurId, e); 2117 return false; 2118 } 2119 } 2120 } 2121 2122 /** 2123 * Returns true if the current IME needs to offer the users ways to switch to a next input 2124 * method (e.g. a globe key.). 2125 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true, 2126 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly. 2127 * <p> Note that the system determines the most appropriate next input method 2128 * and subtype in order to provide the consistent user experience in switching 2129 * between IMEs and subtypes. 2130 * @param imeToken Supplies the identifying token given to an input method when it was started, 2131 * which allows it to perform this operation on itself. 2132 */ shouldOfferSwitchingToNextInputMethod(IBinder imeToken)2133 public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) { 2134 synchronized (mH) { 2135 try { 2136 return mService.shouldOfferSwitchingToNextInputMethod(imeToken); 2137 } catch (RemoteException e) { 2138 Log.w(TAG, "IME died: " + mCurId, e); 2139 return false; 2140 } 2141 } 2142 } 2143 2144 /** 2145 * Set additional input method subtypes. Only a process which shares the same uid with the IME 2146 * can add additional input method subtypes to the IME. 2147 * Please note that a subtype's status is stored in the system. 2148 * For example, enabled subtypes are remembered by the framework even after they are removed 2149 * by using this method. If you re-add the same subtypes again, 2150 * they will just get enabled. If you want to avoid such conflicts, for instance, you may 2151 * want to create a "different" new subtype even with the same locale and mode, 2152 * by changing its extra value. The different subtype won't get affected by the stored past 2153 * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer 2154 * to the current implementation.) 2155 * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to. 2156 * @param subtypes subtypes will be added as additional subtypes of the current input method. 2157 */ setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes)2158 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) { 2159 synchronized (mH) { 2160 try { 2161 mService.setAdditionalInputMethodSubtypes(imiId, subtypes); 2162 } catch (RemoteException e) { 2163 Log.w(TAG, "IME died: " + mCurId, e); 2164 } 2165 } 2166 } 2167 getLastInputMethodSubtype()2168 public InputMethodSubtype getLastInputMethodSubtype() { 2169 synchronized (mH) { 2170 try { 2171 return mService.getLastInputMethodSubtype(); 2172 } catch (RemoteException e) { 2173 Log.w(TAG, "IME died: " + mCurId, e); 2174 return null; 2175 } 2176 } 2177 } 2178 doDump(FileDescriptor fd, PrintWriter fout, String[] args)2179 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { 2180 final Printer p = new PrintWriterPrinter(fout); 2181 p.println("Input method client state for " + this + ":"); 2182 2183 p.println(" mService=" + mService); 2184 p.println(" mMainLooper=" + mMainLooper); 2185 p.println(" mIInputContext=" + mIInputContext); 2186 p.println(" mActive=" + mActive 2187 + " mHasBeenInactive=" + mHasBeenInactive 2188 + " mBindSequence=" + mBindSequence 2189 + " mCurId=" + mCurId); 2190 p.println(" mCurMethod=" + mCurMethod); 2191 p.println(" mCurRootView=" + mCurRootView); 2192 p.println(" mServedView=" + mServedView); 2193 p.println(" mNextServedView=" + mNextServedView); 2194 p.println(" mServedConnecting=" + mServedConnecting); 2195 if (mCurrentTextBoxAttribute != null) { 2196 p.println(" mCurrentTextBoxAttribute:"); 2197 mCurrentTextBoxAttribute.dump(p, " "); 2198 } else { 2199 p.println(" mCurrentTextBoxAttribute: null"); 2200 } 2201 p.println(" mServedInputConnection=" + mServedInputConnection); 2202 p.println(" mCompletions=" + mCompletions); 2203 p.println(" mCursorRect=" + mCursorRect); 2204 p.println(" mCursorSelStart=" + mCursorSelStart 2205 + " mCursorSelEnd=" + mCursorSelEnd 2206 + " mCursorCandStart=" + mCursorCandStart 2207 + " mCursorCandEnd=" + mCursorCandEnd); 2208 p.println(" mNextUserActionNotificationSequenceNumber=" 2209 + mNextUserActionNotificationSequenceNumber 2210 + " mLastSentUserActionNotificationSequenceNumber=" 2211 + mLastSentUserActionNotificationSequenceNumber); 2212 } 2213 2214 /** 2215 * Callback that is invoked when an input event that was dispatched to 2216 * the IME has been finished. 2217 * @hide 2218 */ 2219 public interface FinishedInputEventCallback { onFinishedInputEvent(Object token, boolean handled)2220 public void onFinishedInputEvent(Object token, boolean handled); 2221 } 2222 2223 private final class ImeInputEventSender extends InputEventSender { ImeInputEventSender(InputChannel inputChannel, Looper looper)2224 public ImeInputEventSender(InputChannel inputChannel, Looper looper) { 2225 super(inputChannel, looper); 2226 } 2227 2228 @Override onInputEventFinished(int seq, boolean handled)2229 public void onInputEventFinished(int seq, boolean handled) { 2230 finishedInputEvent(seq, handled, false); 2231 } 2232 } 2233 2234 private final class PendingEvent implements Runnable { 2235 public InputEvent mEvent; 2236 public Object mToken; 2237 public String mInputMethodId; 2238 public FinishedInputEventCallback mCallback; 2239 public Handler mHandler; 2240 public boolean mHandled; 2241 recycle()2242 public void recycle() { 2243 mEvent = null; 2244 mToken = null; 2245 mInputMethodId = null; 2246 mCallback = null; 2247 mHandler = null; 2248 mHandled = false; 2249 } 2250 2251 @Override run()2252 public void run() { 2253 mCallback.onFinishedInputEvent(mToken, mHandled); 2254 2255 synchronized (mH) { 2256 recyclePendingEventLocked(this); 2257 } 2258 } 2259 } 2260 } 2261