InputMethodManager.java revision 06487a58be22b100daf3f950b9a1d25c3ea42aa2
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 17package android.view.inputmethod; 18 19import android.content.Context; 20import android.graphics.Rect; 21import android.os.Bundle; 22import android.os.Handler; 23import android.os.IBinder; 24import android.os.Looper; 25import android.os.Message; 26import android.os.RemoteException; 27import android.os.ResultReceiver; 28import android.os.ServiceManager; 29import android.util.Log; 30import android.util.PrintWriterPrinter; 31import android.util.Printer; 32import android.view.KeyEvent; 33import android.view.MotionEvent; 34import android.view.View; 35import android.view.ViewRoot; 36import android.view.inputmethod.InputMethodSubtype; 37 38import com.android.internal.os.HandlerCaller; 39import com.android.internal.view.IInputConnectionWrapper; 40import com.android.internal.view.IInputContext; 41import com.android.internal.view.IInputMethodCallback; 42import com.android.internal.view.IInputMethodClient; 43import com.android.internal.view.IInputMethodManager; 44import com.android.internal.view.IInputMethodSession; 45import com.android.internal.view.InputBindResult; 46 47import java.io.FileDescriptor; 48import java.io.PrintWriter; 49import java.util.List; 50import java.util.concurrent.CountDownLatch; 51import java.util.concurrent.TimeUnit; 52 53/** 54 * Central system API to the overall input method framework (IMF) architecture, 55 * which arbitrates interaction between applications and the current input method. 56 * You can retrieve an instance of this interface with 57 * {@link Context#getSystemService(String) Context.getSystemService()}. 58 * 59 * <p>Topics covered here: 60 * <ol> 61 * <li><a href="#ArchitectureOverview">Architecture Overview</a> 62 * </ol> 63 * 64 * <a name="ArchitectureOverview"></a> 65 * <h3>Architecture Overview</h3> 66 * 67 * <p>There are three primary parties involved in the input method 68 * framework (IMF) architecture:</p> 69 * 70 * <ul> 71 * <li> The <strong>input method manager</strong> as expressed by this class 72 * is the central point of the system that manages interaction between all 73 * other parts. It is expressed as the client-side API here which exists 74 * in each application context and communicates with a global system service 75 * that manages the interaction across all processes. 76 * <li> An <strong>input method (IME)</strong> implements a particular 77 * interaction model allowing the user to generate text. The system binds 78 * to the current input method that is use, causing it to be created and run, 79 * and tells it when to hide and show its UI. Only one IME is running at a time. 80 * <li> Multiple <strong>client applications</strong> arbitrate with the input 81 * method manager for input focus and control over the state of the IME. Only 82 * one such client is ever active (working with the IME) at a time. 83 * </ul> 84 * 85 * 86 * <a name="Applications"></a> 87 * <h3>Applications</h3> 88 * 89 * <p>In most cases, applications that are using the standard 90 * {@link android.widget.TextView} or its subclasses will have little they need 91 * to do to work well with soft input methods. The main things you need to 92 * be aware of are:</p> 93 * 94 * <ul> 95 * <li> Properly set the {@link android.R.attr#inputType} if your editable 96 * text views, so that the input method will have enough context to help the 97 * user in entering text into them. 98 * <li> Deal well with losing screen space when the input method is 99 * displayed. Ideally an application should handle its window being resized 100 * smaller, but it can rely on the system performing panning of the window 101 * if needed. You should set the {@link android.R.attr#windowSoftInputMode} 102 * attribute on your activity or the corresponding values on windows you 103 * create to help the system determine whether to pan or resize (it will 104 * try to determine this automatically but may get it wrong). 105 * <li> You can also control the preferred soft input state (open, closed, etc) 106 * for your window using the same {@link android.R.attr#windowSoftInputMode} 107 * attribute. 108 * </ul> 109 * 110 * <p>More finer-grained control is available through the APIs here to directly 111 * interact with the IMF and its IME -- either showing or hiding the input 112 * area, letting the user pick an input method, etc.</p> 113 * 114 * <p>For the rare people amongst us writing their own text editors, you 115 * will need to implement {@link android.view.View#onCreateInputConnection} 116 * to return a new instance of your own {@link InputConnection} interface 117 * allowing the IME to interact with your editor.</p> 118 * 119 * 120 * <a name="InputMethods"></a> 121 * <h3>Input Methods</h3> 122 * 123 * <p>An input method (IME) is implemented 124 * as a {@link android.app.Service}, typically deriving from 125 * {@link android.inputmethodservice.InputMethodService}. It must provide 126 * the core {@link InputMethod} interface, though this is normally handled by 127 * {@link android.inputmethodservice.InputMethodService} and implementors will 128 * only need to deal with the higher-level API there.</p> 129 * 130 * See the {@link android.inputmethodservice.InputMethodService} class for 131 * more information on implementing IMEs. 132 * 133 * 134 * <a name="Security"></a> 135 * <h3>Security</h3> 136 * 137 * <p>There are a lot of security issues associated with input methods, 138 * since they essentially have freedom to completely drive the UI and monitor 139 * everything the user enters. The Android input method framework also allows 140 * arbitrary third party IMEs, so care must be taken to restrict their 141 * selection and interactions.</p> 142 * 143 * <p>Here are some key points about the security architecture behind the 144 * IMF:</p> 145 * 146 * <ul> 147 * <li> <p>Only the system is allowed to directly access an IME's 148 * {@link InputMethod} interface, via the 149 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission. This is 150 * enforced in the system by not binding to an input method service that does 151 * not require this permission, so the system can guarantee no other untrusted 152 * clients are accessing the current input method outside of its control.</p> 153 * 154 * <li> <p>There may be many client processes of the IMF, but only one may 155 * be active at a time. The inactive clients can not interact with key 156 * parts of the IMF through the mechanisms described below.</p> 157 * 158 * <li> <p>Clients of an input method are only given access to its 159 * {@link InputMethodSession} interface. One instance of this interface is 160 * created for each client, and only calls from the session associated with 161 * the active client will be processed by the current IME. This is enforced 162 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal 163 * IMEs, but must be explicitly handled by an IME that is customizing the 164 * raw {@link InputMethodSession} implementation.</p> 165 * 166 * <li> <p>Only the active client's {@link InputConnection} will accept 167 * operations. The IMF tells each client process whether it is active, and 168 * the framework enforces that in inactive processes calls on to the current 169 * InputConnection will be ignored. This ensures that the current IME can 170 * only deliver events and text edits to the UI that the user sees as 171 * being in focus.</p> 172 * 173 * <li> <p>An IME can never interact with an {@link InputConnection} while 174 * the screen is off. This is enforced by making all clients inactive while 175 * the screen is off, and prevents bad IMEs from driving the UI when the user 176 * can not be aware of its behavior.</p> 177 * 178 * <li> <p>A client application can ask that the system let the user pick a 179 * new IME, but can not programmatically switch to one itself. This avoids 180 * malicious applications from switching the user to their own IME, which 181 * remains running when the user navigates away to another application. An 182 * IME, on the other hand, <em>is</em> allowed to programmatically switch 183 * the system to another IME, since it already has full control of user 184 * input.</p> 185 * 186 * <li> <p>The user must explicitly enable a new IME in settings before 187 * they can switch to it, to confirm with the system that they know about it 188 * and want to make it available for use.</p> 189 * </ul> 190 */ 191public final class InputMethodManager { 192 static final boolean DEBUG = false; 193 static final String TAG = "InputMethodManager"; 194 195 static final Object mInstanceSync = new Object(); 196 static InputMethodManager mInstance; 197 198 final IInputMethodManager mService; 199 final Looper mMainLooper; 200 201 // For scheduling work on the main thread. This also serves as our 202 // global lock. 203 final H mH; 204 205 // Our generic input connection if the current target does not have its own. 206 final IInputContext mIInputContext; 207 208 /** 209 * True if this input method client is active, initially false. 210 */ 211 boolean mActive = false; 212 213 /** 214 * Set whenever this client becomes inactive, to know we need to reset 215 * state with the IME then next time we receive focus. 216 */ 217 boolean mHasBeenInactive = true; 218 219 /** 220 * As reported by IME through InputConnection. 221 */ 222 boolean mFullscreenMode; 223 224 // ----------------------------------------------------------- 225 226 /** 227 * This is the root view of the overall window that currently has input 228 * method focus. 229 */ 230 View mCurRootView; 231 /** 232 * This is the view that should currently be served by an input method, 233 * regardless of the state of setting that up. 234 */ 235 View mServedView; 236 /** 237 * This is then next view that will be served by the input method, when 238 * we get around to updating things. 239 */ 240 View mNextServedView; 241 /** 242 * True if we should restart input in the next served view, even if the 243 * view hasn't actually changed from the current serve view. 244 */ 245 boolean mNextServedNeedsStart; 246 /** 247 * This is set when we are in the process of connecting, to determine 248 * when we have actually finished. 249 */ 250 boolean mServedConnecting; 251 /** 252 * This is non-null when we have connected the served view; it holds 253 * the attributes that were last retrieved from the served view and given 254 * to the input connection. 255 */ 256 EditorInfo mCurrentTextBoxAttribute; 257 /** 258 * The InputConnection that was last retrieved from the served view. 259 */ 260 InputConnection mServedInputConnection; 261 /** 262 * The completions that were last provided by the served view. 263 */ 264 CompletionInfo[] mCompletions; 265 266 // Cursor position on the screen. 267 Rect mTmpCursorRect = new Rect(); 268 Rect mCursorRect = new Rect(); 269 int mCursorSelStart; 270 int mCursorSelEnd; 271 int mCursorCandStart; 272 int mCursorCandEnd; 273 274 // ----------------------------------------------------------- 275 276 /** 277 * Sequence number of this binding, as returned by the server. 278 */ 279 int mBindSequence = -1; 280 /** 281 * ID of the method we are bound to. 282 */ 283 String mCurId; 284 /** 285 * The actual instance of the method to make calls on it. 286 */ 287 IInputMethodSession mCurMethod; 288 289 // ----------------------------------------------------------- 290 291 static final int MSG_DUMP = 1; 292 static final int MSG_BIND = 2; 293 static final int MSG_UNBIND = 3; 294 static final int MSG_SET_ACTIVE = 4; 295 296 class H extends Handler { 297 H(Looper looper) { 298 super(looper); 299 } 300 301 @Override 302 public void handleMessage(Message msg) { 303 switch (msg.what) { 304 case MSG_DUMP: { 305 HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; 306 try { 307 doDump((FileDescriptor)args.arg1, 308 (PrintWriter)args.arg2, (String[])args.arg3); 309 } catch (RuntimeException e) { 310 ((PrintWriter)args.arg2).println("Exception: " + e); 311 } 312 synchronized (args.arg4) { 313 ((CountDownLatch)args.arg4).countDown(); 314 } 315 return; 316 } 317 case MSG_BIND: { 318 final InputBindResult res = (InputBindResult)msg.obj; 319 synchronized (mH) { 320 if (mBindSequence < 0 || mBindSequence != res.sequence) { 321 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence 322 + ", given seq=" + res.sequence); 323 return; 324 } 325 326 mCurMethod = res.method; 327 mCurId = res.id; 328 mBindSequence = res.sequence; 329 } 330 startInputInner(); 331 return; 332 } 333 case MSG_UNBIND: { 334 final int sequence = msg.arg1; 335 synchronized (mH) { 336 if (mBindSequence == sequence) { 337 if (false) { 338 // XXX the server has already unbound! 339 if (mCurMethod != null && mCurrentTextBoxAttribute != null) { 340 try { 341 mCurMethod.finishInput(); 342 } catch (RemoteException e) { 343 Log.w(TAG, "IME died: " + mCurId, e); 344 } 345 } 346 } 347 clearBindingLocked(); 348 349 // If we were actively using the last input method, then 350 // we would like to re-connect to the next input method. 351 if (mServedView != null && mServedView.isFocused()) { 352 mServedConnecting = true; 353 } 354 } 355 startInputInner(); 356 } 357 return; 358 } 359 case MSG_SET_ACTIVE: { 360 final boolean active = msg.arg1 != 0; 361 synchronized (mH) { 362 mActive = active; 363 mFullscreenMode = false; 364 if (!active) { 365 // Some other client has starting using the IME, so note 366 // that this happened and make sure our own editor's 367 // state is reset. 368 mHasBeenInactive = true; 369 try { 370 // Note that finishComposingText() is allowed to run 371 // even when we are not active. 372 mIInputContext.finishComposingText(); 373 } catch (RemoteException e) { 374 } 375 } 376 } 377 return; 378 } 379 } 380 } 381 } 382 383 class ControlledInputConnectionWrapper extends IInputConnectionWrapper { 384 public ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn) { 385 super(mainLooper, conn); 386 } 387 388 public boolean isActive() { 389 return mActive; 390 } 391 } 392 393 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { 394 @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 395 // No need to check for dump permission, since we only give this 396 // interface to the system. 397 398 CountDownLatch latch = new CountDownLatch(1); 399 HandlerCaller.SomeArgs sargs = new HandlerCaller.SomeArgs(); 400 sargs.arg1 = fd; 401 sargs.arg2 = fout; 402 sargs.arg3 = args; 403 sargs.arg4 = latch; 404 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs)); 405 try { 406 if (!latch.await(5, TimeUnit.SECONDS)) { 407 fout.println("Timeout waiting for dump"); 408 } 409 } catch (InterruptedException e) { 410 fout.println("Interrupted waiting for dump"); 411 } 412 } 413 414 public void setUsingInputMethod(boolean state) { 415 } 416 417 public void onBindMethod(InputBindResult res) { 418 mH.sendMessage(mH.obtainMessage(MSG_BIND, res)); 419 } 420 421 public void onUnbindMethod(int sequence) { 422 mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, 0)); 423 } 424 425 public void setActive(boolean active) { 426 mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0)); 427 } 428 }; 429 430 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false); 431 432 InputMethodManager(IInputMethodManager service, Looper looper) { 433 mService = service; 434 mMainLooper = looper; 435 mH = new H(looper); 436 mIInputContext = new ControlledInputConnectionWrapper(looper, 437 mDummyInputConnection); 438 439 if (mInstance == null) { 440 mInstance = this; 441 } 442 } 443 444 /** 445 * Retrieve the global InputMethodManager instance, creating it if it 446 * doesn't already exist. 447 * @hide 448 */ 449 static public InputMethodManager getInstance(Context context) { 450 return getInstance(context.getMainLooper()); 451 } 452 453 /** 454 * Internally, the input method manager can't be context-dependent, so 455 * we have this here for the places that need it. 456 * @hide 457 */ 458 static public InputMethodManager getInstance(Looper mainLooper) { 459 synchronized (mInstanceSync) { 460 if (mInstance != null) { 461 return mInstance; 462 } 463 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE); 464 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); 465 mInstance = new InputMethodManager(service, mainLooper); 466 } 467 return mInstance; 468 } 469 470 /** 471 * Private optimization: retrieve the global InputMethodManager instance, 472 * if it exists. 473 * @hide 474 */ 475 static public InputMethodManager peekInstance() { 476 return mInstance; 477 } 478 479 /** @hide */ 480 public IInputMethodClient getClient() { 481 return mClient; 482 } 483 484 /** @hide */ 485 public IInputContext getInputContext() { 486 return mIInputContext; 487 } 488 489 public List<InputMethodInfo> getInputMethodList() { 490 try { 491 return mService.getInputMethodList(); 492 } catch (RemoteException e) { 493 throw new RuntimeException(e); 494 } 495 } 496 497 public List<InputMethodInfo> getEnabledInputMethodList() { 498 try { 499 return mService.getEnabledInputMethodList(); 500 } catch (RemoteException e) { 501 throw new RuntimeException(e); 502 } 503 } 504 505 public void showStatusIcon(IBinder imeToken, String packageName, int iconId) { 506 try { 507 mService.updateStatusIcon(imeToken, packageName, iconId); 508 } catch (RemoteException e) { 509 throw new RuntimeException(e); 510 } 511 } 512 513 public void hideStatusIcon(IBinder imeToken) { 514 try { 515 mService.updateStatusIcon(imeToken, null, 0); 516 } catch (RemoteException e) { 517 throw new RuntimeException(e); 518 } 519 } 520 521 /** @hide */ 522 public void setIMEButtonVisible(IBinder imeToken, boolean visible) { 523 try { 524 mService.setIMEButtonVisible(imeToken, visible); 525 } catch (RemoteException e) { 526 throw new RuntimeException(e); 527 } 528 } 529 530 /** @hide */ 531 public void setFullscreenMode(boolean fullScreen) { 532 mFullscreenMode = fullScreen; 533 } 534 535 /** 536 * Allows you to discover whether the attached input method is running 537 * in fullscreen mode. Return true if it is fullscreen, entirely covering 538 * your UI, else returns false. 539 */ 540 public boolean isFullscreenMode() { 541 return mFullscreenMode; 542 } 543 544 /** 545 * Return true if the given view is the currently active view for the 546 * input method. 547 */ 548 public boolean isActive(View view) { 549 checkFocus(); 550 synchronized (mH) { 551 return (mServedView == view 552 || (mServedView != null 553 && mServedView.checkInputConnectionProxy(view))) 554 && mCurrentTextBoxAttribute != null; 555 } 556 } 557 558 /** 559 * Return true if any view is currently active in the input method. 560 */ 561 public boolean isActive() { 562 checkFocus(); 563 synchronized (mH) { 564 return mServedView != null && mCurrentTextBoxAttribute != null; 565 } 566 } 567 568 /** 569 * Return true if the currently served view is accepting full text edits. 570 * If false, it has no input connection, so can only handle raw key events. 571 */ 572 public boolean isAcceptingText() { 573 checkFocus(); 574 return mServedInputConnection != null; 575 } 576 577 /** 578 * Reset all of the state associated with being bound to an input method. 579 */ 580 void clearBindingLocked() { 581 clearConnectionLocked(); 582 mBindSequence = -1; 583 mCurId = null; 584 mCurMethod = null; 585 } 586 587 /** 588 * Reset all of the state associated with a served view being connected 589 * to an input method 590 */ 591 void clearConnectionLocked() { 592 mCurrentTextBoxAttribute = null; 593 mServedInputConnection = null; 594 } 595 596 /** 597 * Disconnect any existing input connection, clearing the served view. 598 */ 599 void finishInputLocked() { 600 mNextServedView = null; 601 if (mServedView != null) { 602 if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView); 603 604 if (mCurrentTextBoxAttribute != null) { 605 try { 606 mService.finishInput(mClient); 607 } catch (RemoteException e) { 608 } 609 } 610 611 if (mServedInputConnection != null) { 612 // We need to tell the previously served view that it is no 613 // longer the input target, so it can reset its state. Schedule 614 // this call on its window's Handler so it will be on the correct 615 // thread and outside of our lock. 616 Handler vh = mServedView.getHandler(); 617 if (vh != null) { 618 // This will result in a call to reportFinishInputConnection() 619 // below. 620 vh.sendMessage(vh.obtainMessage(ViewRoot.FINISH_INPUT_CONNECTION, 621 mServedInputConnection)); 622 } 623 } 624 625 mServedView = null; 626 mCompletions = null; 627 mServedConnecting = false; 628 clearConnectionLocked(); 629 } 630 } 631 632 /** 633 * Called from the FINISH_INPUT_CONNECTION message above. 634 * @hide 635 */ 636 public void reportFinishInputConnection(InputConnection ic) { 637 if (mServedInputConnection != ic) { 638 ic.finishComposingText(); 639 } 640 } 641 642 public void displayCompletions(View view, CompletionInfo[] completions) { 643 checkFocus(); 644 synchronized (mH) { 645 if (mServedView != view && (mServedView == null 646 || !mServedView.checkInputConnectionProxy(view))) { 647 return; 648 } 649 650 mCompletions = completions; 651 if (mCurMethod != null) { 652 try { 653 mCurMethod.displayCompletions(mCompletions); 654 } catch (RemoteException e) { 655 } 656 } 657 } 658 } 659 660 public void updateExtractedText(View view, int token, ExtractedText text) { 661 checkFocus(); 662 synchronized (mH) { 663 if (mServedView != view && (mServedView == null 664 || !mServedView.checkInputConnectionProxy(view))) { 665 return; 666 } 667 668 if (mCurMethod != null) { 669 try { 670 mCurMethod.updateExtractedText(token, text); 671 } catch (RemoteException e) { 672 } 673 } 674 } 675 } 676 677 /** 678 * Flag for {@link #showSoftInput} to indicate that this is an implicit 679 * request to show the input window, not as the result of a direct request 680 * by the user. The window may not be shown in this case. 681 */ 682 public static final int SHOW_IMPLICIT = 0x0001; 683 684 /** 685 * Flag for {@link #showSoftInput} to indicate that the user has forced 686 * the input method open (such as by long-pressing menu) so it should 687 * not be closed until they explicitly do so. 688 */ 689 public static final int SHOW_FORCED = 0x0002; 690 691 /** 692 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without 693 * a result receiver: explicitly request that the current input method's 694 * soft input area be shown to the user, if needed. 695 * 696 * @param view The currently focused view, which would like to receive 697 * soft keyboard input. 698 * @param flags Provides additional operating flags. Currently may be 699 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 700 */ 701 public boolean showSoftInput(View view, int flags) { 702 return showSoftInput(view, flags, null); 703 } 704 705 /** 706 * Flag for the {@link ResultReceiver} result code from 707 * {@link #showSoftInput(View, int, ResultReceiver)} and 708 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 709 * state of the soft input window was unchanged and remains shown. 710 */ 711 public static final int RESULT_UNCHANGED_SHOWN = 0; 712 713 /** 714 * Flag for the {@link ResultReceiver} result code from 715 * {@link #showSoftInput(View, int, ResultReceiver)} and 716 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 717 * state of the soft input window was unchanged and remains hidden. 718 */ 719 public static final int RESULT_UNCHANGED_HIDDEN = 1; 720 721 /** 722 * Flag for the {@link ResultReceiver} result code from 723 * {@link #showSoftInput(View, int, ResultReceiver)} and 724 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 725 * state of the soft input window changed from hidden to shown. 726 */ 727 public static final int RESULT_SHOWN = 2; 728 729 /** 730 * Flag for the {@link ResultReceiver} result code from 731 * {@link #showSoftInput(View, int, ResultReceiver)} and 732 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the 733 * state of the soft input window changed from shown to hidden. 734 */ 735 public static final int RESULT_HIDDEN = 3; 736 737 /** 738 * Explicitly request that the current input method's soft input area be 739 * shown to the user, if needed. Call this if the user interacts with 740 * your view in such a way that they have expressed they would like to 741 * start performing input into it. 742 * 743 * @param view The currently focused view, which would like to receive 744 * soft keyboard input. 745 * @param flags Provides additional operating flags. Currently may be 746 * 0 or have the {@link #SHOW_IMPLICIT} bit set. 747 * @param resultReceiver If non-null, this will be called by the IME when 748 * it has processed your request to tell you what it has done. The result 749 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 750 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 751 * {@link #RESULT_HIDDEN}. 752 */ 753 public boolean showSoftInput(View view, int flags, 754 ResultReceiver resultReceiver) { 755 checkFocus(); 756 synchronized (mH) { 757 if (mServedView != view && (mServedView == null 758 || !mServedView.checkInputConnectionProxy(view))) { 759 return false; 760 } 761 762 try { 763 return mService.showSoftInput(mClient, flags, resultReceiver); 764 } catch (RemoteException e) { 765 } 766 767 return false; 768 } 769 } 770 771 /** @hide */ 772 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) { 773 try { 774 mService.showSoftInput(mClient, flags, resultReceiver); 775 } catch (RemoteException e) { 776 } 777 } 778 779 /** 780 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft 781 * input window should only be hidden if it was not explicitly shown 782 * by the user. 783 */ 784 public static final int HIDE_IMPLICIT_ONLY = 0x0001; 785 786 /** 787 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft 788 * input window should normally be hidden, unless it was originally 789 * shown with {@link #SHOW_FORCED}. 790 */ 791 public static final int HIDE_NOT_ALWAYS = 0x0002; 792 793 /** 794 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver) 795 * without a result: request to hide the soft input window from the 796 * context of the window that is currently accepting input. 797 * 798 * @param windowToken The token of the window that is making the request, 799 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 800 * @param flags Provides additional operating flags. Currently may be 801 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 802 */ 803 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) { 804 return hideSoftInputFromWindow(windowToken, flags, null); 805 } 806 807 /** 808 * Request to hide the soft input window from the context of the window 809 * that is currently accepting input. This should be called as a result 810 * of the user doing some actually than fairly explicitly requests to 811 * have the input window hidden. 812 * 813 * @param windowToken The token of the window that is making the request, 814 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 815 * @param flags Provides additional operating flags. Currently may be 816 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set. 817 * @param resultReceiver If non-null, this will be called by the IME when 818 * it has processed your request to tell you what it has done. The result 819 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN}, 820 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or 821 * {@link #RESULT_HIDDEN}. 822 */ 823 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, 824 ResultReceiver resultReceiver) { 825 checkFocus(); 826 synchronized (mH) { 827 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 828 return false; 829 } 830 831 try { 832 return mService.hideSoftInput(mClient, flags, resultReceiver); 833 } catch (RemoteException e) { 834 } 835 return false; 836 } 837 } 838 839 840 /** 841 * This method toggles the input method window display. 842 * If the input window is already displayed, it gets hidden. 843 * If not the input window will be displayed. 844 * @param windowToken The token of the window that is making the request, 845 * as returned by {@link View#getWindowToken() View.getWindowToken()}. 846 * @param showFlags Provides additional operating flags. May be 847 * 0 or have the {@link #SHOW_IMPLICIT}, 848 * {@link #SHOW_FORCED} bit set. 849 * @param hideFlags Provides additional operating flags. May be 850 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 851 * {@link #HIDE_NOT_ALWAYS} bit set. 852 **/ 853 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) { 854 synchronized (mH) { 855 if (mServedView == null || mServedView.getWindowToken() != windowToken) { 856 return; 857 } 858 if (mCurMethod != null) { 859 try { 860 mCurMethod.toggleSoftInput(showFlags, hideFlags); 861 } catch (RemoteException e) { 862 } 863 } 864 } 865 } 866 867 /* 868 * This method toggles the input method window display. 869 * If the input window is already displayed, it gets hidden. 870 * If not the input window will be displayed. 871 * @param showFlags Provides additional operating flags. May be 872 * 0 or have the {@link #SHOW_IMPLICIT}, 873 * {@link #SHOW_FORCED} bit set. 874 * @param hideFlags Provides additional operating flags. May be 875 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 876 * {@link #HIDE_NOT_ALWAYS} bit set. 877 * @hide 878 */ 879 public void toggleSoftInput(int showFlags, int hideFlags) { 880 if (mCurMethod != null) { 881 try { 882 mCurMethod.toggleSoftInput(showFlags, hideFlags); 883 } catch (RemoteException e) { 884 } 885 } 886 } 887 888 /** 889 * If the input method is currently connected to the given view, 890 * restart it with its new contents. You should call this when the text 891 * within your view changes outside of the normal input method or key 892 * input flow, such as when an application calls TextView.setText(). 893 * 894 * @param view The view whose text has changed. 895 */ 896 public void restartInput(View view) { 897 checkFocus(); 898 synchronized (mH) { 899 if (mServedView != view && (mServedView == null 900 || !mServedView.checkInputConnectionProxy(view))) { 901 return; 902 } 903 904 mServedConnecting = true; 905 } 906 907 startInputInner(); 908 } 909 910 void startInputInner() { 911 final View view; 912 synchronized (mH) { 913 view = mServedView; 914 915 // Make sure we have a window token for the served view. 916 if (DEBUG) Log.v(TAG, "Starting input: view=" + view); 917 if (view == null) { 918 if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); 919 return; 920 } 921 } 922 923 // Now we need to get an input connection from the served view. 924 // This is complicated in a couple ways: we can't be holding our lock 925 // when calling out to the view, and we need to make sure we call into 926 // the view on the same thread that is driving its view hierarchy. 927 Handler vh = view.getHandler(); 928 if (vh == null) { 929 // If the view doesn't have a handler, something has changed out 930 // from under us, so just bail. 931 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!"); 932 return; 933 } 934 if (vh.getLooper() != Looper.myLooper()) { 935 // The view is running on a different thread than our own, so 936 // we need to reschedule our work for over there. 937 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); 938 vh.post(new Runnable() { 939 public void run() { 940 startInputInner(); 941 } 942 }); 943 return; 944 } 945 946 // Okay we are now ready to call into the served view and have it 947 // do its stuff. 948 // Life is good: let's hook everything up! 949 EditorInfo tba = new EditorInfo(); 950 tba.packageName = view.getContext().getPackageName(); 951 tba.fieldId = view.getId(); 952 InputConnection ic = view.onCreateInputConnection(tba); 953 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); 954 955 synchronized (mH) { 956 // Now that we are locked again, validate that our state hasn't 957 // changed. 958 if (mServedView != view || !mServedConnecting) { 959 // Something else happened, so abort. 960 if (DEBUG) Log.v(TAG, 961 "Starting input: finished by someone else (view=" 962 + mServedView + " conn=" + mServedConnecting + ")"); 963 return; 964 } 965 966 // If we already have a text box, then this view is already 967 // connected so we want to restart it. 968 final boolean initial = mCurrentTextBoxAttribute == null; 969 970 // Hook 'em up and let 'er rip. 971 mCurrentTextBoxAttribute = tba; 972 mServedConnecting = false; 973 mServedInputConnection = ic; 974 IInputContext servedContext; 975 if (ic != null) { 976 mCursorSelStart = tba.initialSelStart; 977 mCursorSelEnd = tba.initialSelEnd; 978 mCursorCandStart = -1; 979 mCursorCandEnd = -1; 980 mCursorRect.setEmpty(); 981 servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic); 982 } else { 983 servedContext = null; 984 } 985 986 try { 987 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" 988 + ic + " tba=" + tba + " initial=" + initial); 989 InputBindResult res = mService.startInput(mClient, 990 servedContext, tba, initial, mCurMethod == null); 991 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); 992 if (res != null) { 993 if (res.id != null) { 994 mBindSequence = res.sequence; 995 mCurMethod = res.method; 996 } else { 997 // This means there is no input method available. 998 if (DEBUG) Log.v(TAG, "ABORT input: no input method!"); 999 return; 1000 } 1001 } 1002 if (mCurMethod != null && mCompletions != null) { 1003 try { 1004 mCurMethod.displayCompletions(mCompletions); 1005 } catch (RemoteException e) { 1006 } 1007 } 1008 } catch (RemoteException e) { 1009 Log.w(TAG, "IME died: " + mCurId, e); 1010 } 1011 } 1012 } 1013 1014 /** 1015 * When the focused window is dismissed, this method is called to finish the 1016 * input method started before. 1017 * @hide 1018 */ 1019 public void windowDismissed(IBinder appWindowToken) { 1020 checkFocus(); 1021 synchronized (mH) { 1022 if (mServedView != null && 1023 mServedView.getWindowToken() == appWindowToken) { 1024 finishInputLocked(); 1025 } 1026 } 1027 } 1028 1029 /** 1030 * Call this when a view receives focus. 1031 * @hide 1032 */ 1033 public void focusIn(View view) { 1034 synchronized (mH) { 1035 focusInLocked(view); 1036 } 1037 } 1038 1039 void focusInLocked(View view) { 1040 if (DEBUG) Log.v(TAG, "focusIn: " + view); 1041 1042 if (mCurRootView != view.getRootView()) { 1043 // This is a request from a window that isn't in the window with 1044 // IME focus, so ignore it. 1045 if (DEBUG) Log.v(TAG, "Not IME target window, ignoring"); 1046 return; 1047 } 1048 1049 mNextServedView = view; 1050 scheduleCheckFocusLocked(view); 1051 } 1052 1053 /** 1054 * Call this when a view loses focus. 1055 * @hide 1056 */ 1057 public void focusOut(View view) { 1058 synchronized (mH) { 1059 if (DEBUG) Log.v(TAG, "focusOut: " + view 1060 + " mServedView=" + mServedView 1061 + " winFocus=" + view.hasWindowFocus()); 1062 if (mServedView != view) { 1063 // The following code would auto-hide the IME if we end up 1064 // with no more views with focus. This can happen, however, 1065 // whenever we go into touch mode, so it ends up hiding 1066 // at times when we don't really want it to. For now it 1067 // seems better to just turn it all off. 1068 if (false && view.hasWindowFocus()) { 1069 mNextServedView = null; 1070 scheduleCheckFocusLocked(view); 1071 } 1072 } 1073 } 1074 } 1075 1076 void scheduleCheckFocusLocked(View view) { 1077 Handler vh = view.getHandler(); 1078 if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) { 1079 // This will result in a call to checkFocus() below. 1080 vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS)); 1081 } 1082 } 1083 1084 /** 1085 * @hide 1086 */ 1087 public void checkFocus() { 1088 // This is called a lot, so short-circuit before locking. 1089 if (mServedView == mNextServedView && !mNextServedNeedsStart) { 1090 return; 1091 } 1092 1093 InputConnection ic = null; 1094 synchronized (mH) { 1095 if (mServedView == mNextServedView && !mNextServedNeedsStart) { 1096 return; 1097 } 1098 if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView 1099 + " next=" + mNextServedView 1100 + " restart=" + mNextServedNeedsStart); 1101 1102 mNextServedNeedsStart = false; 1103 if (mNextServedView == null) { 1104 finishInputLocked(); 1105 // In this case, we used to have a focused view on the window, 1106 // but no longer do. We should make sure the input method is 1107 // no longer shown, since it serves no purpose. 1108 closeCurrentInput(); 1109 return; 1110 } 1111 1112 ic = mServedInputConnection; 1113 1114 mServedView = mNextServedView; 1115 mCurrentTextBoxAttribute = null; 1116 mCompletions = null; 1117 mServedConnecting = true; 1118 } 1119 1120 if (ic != null) { 1121 ic.finishComposingText(); 1122 } 1123 1124 startInputInner(); 1125 } 1126 1127 void closeCurrentInput() { 1128 try { 1129 mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null); 1130 } catch (RemoteException e) { 1131 } 1132 } 1133 1134 /** 1135 * Called by ViewRoot when its window gets input focus. 1136 * @hide 1137 */ 1138 public void onWindowFocus(View rootView, View focusedView, int softInputMode, 1139 boolean first, int windowFlags) { 1140 synchronized (mH) { 1141 if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView 1142 + " softInputMode=" + softInputMode 1143 + " first=" + first + " flags=#" 1144 + Integer.toHexString(windowFlags)); 1145 if (mHasBeenInactive) { 1146 if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh"); 1147 mHasBeenInactive = false; 1148 mNextServedNeedsStart = true; 1149 } 1150 focusInLocked(focusedView != null ? focusedView : rootView); 1151 } 1152 1153 checkFocus(); 1154 1155 synchronized (mH) { 1156 try { 1157 final boolean isTextEditor = focusedView != null && 1158 focusedView.onCheckIsTextEditor(); 1159 mService.windowGainedFocus(mClient, rootView.getWindowToken(), 1160 focusedView != null, isTextEditor, softInputMode, first, 1161 windowFlags); 1162 } catch (RemoteException e) { 1163 } 1164 } 1165 } 1166 1167 /** @hide */ 1168 public void startGettingWindowFocus(View rootView) { 1169 synchronized (mH) { 1170 mCurRootView = rootView; 1171 } 1172 } 1173 1174 /** 1175 * Report the current selection range. 1176 */ 1177 public void updateSelection(View view, int selStart, int selEnd, 1178 int candidatesStart, int candidatesEnd) { 1179 checkFocus(); 1180 synchronized (mH) { 1181 if ((mServedView != view && (mServedView == null 1182 || !mServedView.checkInputConnectionProxy(view))) 1183 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1184 return; 1185 } 1186 1187 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd 1188 || mCursorCandStart != candidatesStart 1189 || mCursorCandEnd != candidatesEnd) { 1190 if (DEBUG) Log.d(TAG, "updateSelection"); 1191 1192 try { 1193 if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod); 1194 mCurMethod.updateSelection(mCursorSelStart, mCursorSelEnd, 1195 selStart, selEnd, candidatesStart, candidatesEnd); 1196 mCursorSelStart = selStart; 1197 mCursorSelEnd = selEnd; 1198 mCursorCandStart = candidatesStart; 1199 mCursorCandEnd = candidatesEnd; 1200 } catch (RemoteException e) { 1201 Log.w(TAG, "IME died: " + mCurId, e); 1202 } 1203 } 1204 } 1205 } 1206 1207 /** 1208 * Returns true if the current input method wants to watch the location 1209 * of the input editor's cursor in its window. 1210 */ 1211 public boolean isWatchingCursor(View view) { 1212 return false; 1213 } 1214 1215 /** 1216 * Report the current cursor location in its window. 1217 */ 1218 public void updateCursor(View view, int left, int top, int right, int bottom) { 1219 checkFocus(); 1220 synchronized (mH) { 1221 if ((mServedView != view && (mServedView == null 1222 || !mServedView.checkInputConnectionProxy(view))) 1223 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1224 return; 1225 } 1226 1227 mTmpCursorRect.set(left, top, right, bottom); 1228 if (!mCursorRect.equals(mTmpCursorRect)) { 1229 if (DEBUG) Log.d(TAG, "updateCursor"); 1230 1231 try { 1232 if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod); 1233 mCurMethod.updateCursor(mTmpCursorRect); 1234 mCursorRect.set(mTmpCursorRect); 1235 } catch (RemoteException e) { 1236 Log.w(TAG, "IME died: " + mCurId, e); 1237 } 1238 } 1239 } 1240 } 1241 1242 /** 1243 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) 1244 * InputMethodSession.appPrivateCommand()} on the current Input Method. 1245 * @param view Optional View that is sending the command, or null if 1246 * you want to send the command regardless of the view that is attached 1247 * to the input method. 1248 * @param action Name of the command to be performed. This <em>must</em> 1249 * be a scoped name, i.e. prefixed with a package name you own, so that 1250 * different developers will not create conflicting commands. 1251 * @param data Any data to include with the command. 1252 */ 1253 public void sendAppPrivateCommand(View view, String action, Bundle data) { 1254 checkFocus(); 1255 synchronized (mH) { 1256 if ((mServedView != view && (mServedView == null 1257 || !mServedView.checkInputConnectionProxy(view))) 1258 || mCurrentTextBoxAttribute == null || mCurMethod == null) { 1259 return; 1260 } 1261 try { 1262 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data); 1263 mCurMethod.appPrivateCommand(action, data); 1264 } catch (RemoteException e) { 1265 Log.w(TAG, "IME died: " + mCurId, e); 1266 } 1267 } 1268 } 1269 1270 /** 1271 * Force switch to a new input method component. This can only be called 1272 * from the currently active input method, as validated by the given token. 1273 * @param token Supplies the identifying token given to an input method 1274 * when it was started, which allows it to perform this operation on 1275 * itself. 1276 * @param id The unique identifier for the new input method to be switched to. 1277 */ 1278 public void setInputMethod(IBinder token, String id) { 1279 try { 1280 mService.setInputMethod(token, id); 1281 } catch (RemoteException e) { 1282 throw new RuntimeException(e); 1283 } 1284 } 1285 1286 /** 1287 * Close/hide the input method's soft input area, so the user no longer 1288 * sees it or can interact with it. This can only be called 1289 * from the currently active input method, as validated by the given token. 1290 * 1291 * @param token Supplies the identifying token given to an input method 1292 * when it was started, which allows it to perform this operation on 1293 * itself. 1294 * @param flags Provides additional operating flags. Currently may be 1295 * 0 or have the {@link #HIDE_IMPLICIT_ONLY}, 1296 * {@link #HIDE_NOT_ALWAYS} bit set. 1297 */ 1298 public void hideSoftInputFromInputMethod(IBinder token, int flags) { 1299 try { 1300 mService.hideMySoftInput(token, flags); 1301 } catch (RemoteException e) { 1302 throw new RuntimeException(e); 1303 } 1304 } 1305 1306 /** 1307 * Show the input method's soft input area, so the user 1308 * sees the input method window and can interact with it. 1309 * This can only be called from the currently active input method, 1310 * as validated by the given token. 1311 * 1312 * @param token Supplies the identifying token given to an input method 1313 * when it was started, which allows it to perform this operation on 1314 * itself. 1315 * @param flags Provides additional operating flags. Currently may be 1316 * 0 or have the {@link #SHOW_IMPLICIT} or 1317 * {@link #SHOW_FORCED} bit set. 1318 */ 1319 public void showSoftInputFromInputMethod(IBinder token, int flags) { 1320 try { 1321 mService.showMySoftInput(token, flags); 1322 } catch (RemoteException e) { 1323 throw new RuntimeException(e); 1324 } 1325 } 1326 1327 /** 1328 * @hide 1329 */ 1330 public void dispatchKeyEvent(Context context, int seq, KeyEvent key, 1331 IInputMethodCallback callback) { 1332 synchronized (mH) { 1333 if (DEBUG) Log.d(TAG, "dispatchKeyEvent"); 1334 1335 if (mCurMethod == null) { 1336 try { 1337 callback.finishedEvent(seq, false); 1338 } catch (RemoteException e) { 1339 } 1340 return; 1341 } 1342 1343 if (key.getAction() == KeyEvent.ACTION_DOWN 1344 && key.getKeyCode() == KeyEvent.KEYCODE_SYM) { 1345 showInputMethodPicker(); 1346 try { 1347 callback.finishedEvent(seq, true); 1348 } catch (RemoteException e) { 1349 } 1350 return; 1351 } 1352 try { 1353 if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod); 1354 mCurMethod.dispatchKeyEvent(seq, key, callback); 1355 } catch (RemoteException e) { 1356 Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e); 1357 try { 1358 callback.finishedEvent(seq, false); 1359 } catch (RemoteException ex) { 1360 } 1361 } 1362 } 1363 } 1364 1365 /** 1366 * @hide 1367 */ 1368 void dispatchTrackballEvent(Context context, int seq, MotionEvent motion, 1369 IInputMethodCallback callback) { 1370 synchronized (mH) { 1371 if (DEBUG) Log.d(TAG, "dispatchTrackballEvent"); 1372 1373 if (mCurMethod == null || mCurrentTextBoxAttribute == null) { 1374 try { 1375 callback.finishedEvent(seq, false); 1376 } catch (RemoteException e) { 1377 } 1378 return; 1379 } 1380 1381 try { 1382 if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod); 1383 mCurMethod.dispatchTrackballEvent(seq, motion, callback); 1384 } catch (RemoteException e) { 1385 Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e); 1386 try { 1387 callback.finishedEvent(seq, false); 1388 } catch (RemoteException ex) { 1389 } 1390 } 1391 } 1392 } 1393 1394 public void showInputMethodPicker() { 1395 synchronized (mH) { 1396 try { 1397 mService.showInputMethodPickerFromClient(mClient); 1398 } catch (RemoteException e) { 1399 Log.w(TAG, "IME died: " + mCurId, e); 1400 } 1401 } 1402 } 1403 1404 public void showInputMethodSubtypePicker() { 1405 synchronized (mH) { 1406 try { 1407 mService.showInputMethodSubtypePickerFromClient(mClient); 1408 } catch (RemoteException e) { 1409 Log.w(TAG, "IME died: " + mCurId, e); 1410 } 1411 } 1412 } 1413 1414 public void showInputMethodAndSubtypeEnabler(String topId) { 1415 synchronized (mH) { 1416 try { 1417 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, topId); 1418 } catch (RemoteException e) { 1419 Log.w(TAG, "IME died: " + mCurId, e); 1420 } 1421 } 1422 } 1423 1424 public InputMethodSubtype getCurrentInputMethodSubtype() { 1425 synchronized (mH) { 1426 try { 1427 return mService.getCurrentInputMethodSubtype(); 1428 } catch (RemoteException e) { 1429 Log.w(TAG, "IME died: " + mCurId, e); 1430 return null; 1431 } 1432 } 1433 } 1434 1435 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { 1436 final Printer p = new PrintWriterPrinter(fout); 1437 p.println("Input method client state for " + this + ":"); 1438 1439 p.println(" mService=" + mService); 1440 p.println(" mMainLooper=" + mMainLooper); 1441 p.println(" mIInputContext=" + mIInputContext); 1442 p.println(" mActive=" + mActive 1443 + " mHasBeenInactive=" + mHasBeenInactive 1444 + " mBindSequence=" + mBindSequence 1445 + " mCurId=" + mCurId); 1446 p.println(" mCurMethod=" + mCurMethod); 1447 p.println(" mCurRootView=" + mCurRootView); 1448 p.println(" mServedView=" + mServedView); 1449 p.println(" mNextServedNeedsStart=" + mNextServedNeedsStart 1450 + " mNextServedView=" + mNextServedView); 1451 p.println(" mServedConnecting=" + mServedConnecting); 1452 if (mCurrentTextBoxAttribute != null) { 1453 p.println(" mCurrentTextBoxAttribute:"); 1454 mCurrentTextBoxAttribute.dump(p, " "); 1455 } else { 1456 p.println(" mCurrentTextBoxAttribute: null"); 1457 } 1458 p.println(" mServedInputConnection=" + mServedInputConnection); 1459 p.println(" mCompletions=" + mCompletions); 1460 p.println(" mCursorRect=" + mCursorRect); 1461 p.println(" mCursorSelStart=" + mCursorSelStart 1462 + " mCursorSelEnd=" + mCursorSelEnd 1463 + " mCursorCandStart=" + mCursorCandStart 1464 + " mCursorCandEnd=" + mCursorCandEnd); 1465 } 1466} 1467