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