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