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