Home | History | Annotate | Download | only in inputmethodservice
      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.inputmethodservice;
     18 
     19 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     20 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
     21 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
     22 
     23 import static java.lang.annotation.RetentionPolicy.SOURCE;
     24 
     25 import android.annotation.CallSuper;
     26 import android.annotation.DrawableRes;
     27 import android.annotation.IntDef;
     28 import android.annotation.MainThread;
     29 import android.annotation.NonNull;
     30 import android.annotation.Nullable;
     31 import android.app.ActivityManager;
     32 import android.app.Dialog;
     33 import android.content.Context;
     34 import android.content.res.Configuration;
     35 import android.content.res.Resources;
     36 import android.content.res.TypedArray;
     37 import android.database.ContentObserver;
     38 import android.graphics.Rect;
     39 import android.graphics.Region;
     40 import android.net.Uri;
     41 import android.os.Bundle;
     42 import android.os.Handler;
     43 import android.os.IBinder;
     44 import android.os.ResultReceiver;
     45 import android.os.SystemClock;
     46 import android.provider.Settings;
     47 import android.text.InputType;
     48 import android.text.Layout;
     49 import android.text.Spannable;
     50 import android.text.method.MovementMethod;
     51 import android.util.Log;
     52 import android.util.PrintWriterPrinter;
     53 import android.util.Printer;
     54 import android.view.Gravity;
     55 import android.view.KeyCharacterMap;
     56 import android.view.KeyEvent;
     57 import android.view.LayoutInflater;
     58 import android.view.MotionEvent;
     59 import android.view.View;
     60 import android.view.ViewGroup;
     61 import android.view.ViewTreeObserver;
     62 import android.view.Window;
     63 import android.view.WindowManager;
     64 import android.view.WindowManager.BadTokenException;
     65 import android.view.animation.AnimationUtils;
     66 import android.view.inputmethod.CompletionInfo;
     67 import android.view.inputmethod.CursorAnchorInfo;
     68 import android.view.inputmethod.EditorInfo;
     69 import android.view.inputmethod.ExtractedText;
     70 import android.view.inputmethod.ExtractedTextRequest;
     71 import android.view.inputmethod.InputBinding;
     72 import android.view.inputmethod.InputConnection;
     73 import android.view.inputmethod.InputContentInfo;
     74 import android.view.inputmethod.InputMethod;
     75 import android.view.inputmethod.InputMethodManager;
     76 import android.view.inputmethod.InputMethodSubtype;
     77 import android.widget.FrameLayout;
     78 import android.widget.ImageButton;
     79 import android.widget.LinearLayout;
     80 import android.widget.TextView;
     81 
     82 import java.io.FileDescriptor;
     83 import java.io.PrintWriter;
     84 import java.lang.annotation.Retention;
     85 import java.lang.annotation.RetentionPolicy;
     86 
     87 /**
     88  * InputMethodService provides a standard implementation of an InputMethod,
     89  * which final implementations can derive from and customize.  See the
     90  * base class {@link AbstractInputMethodService} and the {@link InputMethod}
     91  * interface for more information on the basics of writing input methods.
     92  *
     93  * <p>In addition to the normal Service lifecycle methods, this class
     94  * introduces some new specific callbacks that most subclasses will want
     95  * to make use of:</p>
     96  * <ul>
     97  * <li> {@link #onInitializeInterface()} for user-interface initialization,
     98  * in particular to deal with configuration changes while the service is
     99  * running.
    100  * <li> {@link #onBindInput} to find out about switching to a new client.
    101  * <li> {@link #onStartInput} to deal with an input session starting with
    102  * the client.
    103  * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
    104  * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
    105  * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
    106  * starting within the input area of the IME.
    107  * </ul>
    108  *
    109  * <p>An input method has significant discretion in how it goes about its
    110  * work: the {@link android.inputmethodservice.InputMethodService} provides
    111  * a basic framework for standard UI elements (input view, candidates view,
    112  * and running in fullscreen mode), but it is up to a particular implementor
    113  * to decide how to use them.  For example, one input method could implement
    114  * an input area with a keyboard, another could allow the user to draw text,
    115  * while a third could have no input area (and thus not be visible to the
    116  * user) but instead listen to audio and perform text to speech conversion.</p>
    117  *
    118  * <p>In the implementation provided here, all of these elements are placed
    119  * together in a single window managed by the InputMethodService.  It will
    120  * execute callbacks as it needs information about them, and provides APIs for
    121  * programmatic control over them.  They layout of these elements is explicitly
    122  * defined:</p>
    123  *
    124  * <ul>
    125  * <li>The soft input view, if available, is placed at the bottom of the
    126  * screen.
    127  * <li>The candidates view, if currently shown, is placed above the soft
    128  * input view.
    129  * <li>If not running fullscreen, the application is moved or resized to be
    130  * above these views; if running fullscreen, the window will completely cover
    131  * the application and its top part will contain the extract text of what is
    132  * currently being edited by the application.
    133  * </ul>
    134  *
    135  *
    136  * <a name="SoftInputView"></a>
    137  * <h3>Soft Input View</h3>
    138  *
    139  * <p>Central to most input methods is the soft input view.  This is where most
    140  * user interaction occurs: pressing on soft keys, drawing characters, or
    141  * however else your input method wants to generate text.  Most implementations
    142  * will simply have their own view doing all of this work, and return a new
    143  * instance of it when {@link #onCreateInputView()} is called.  At that point,
    144  * as long as the input view is visible, you will see user interaction in
    145  * that view and can call back on the InputMethodService to interact with the
    146  * application as appropriate.</p>
    147  *
    148  * <p>There are some situations where you want to decide whether or not your
    149  * soft input view should be shown to the user.  This is done by implementing
    150  * the {@link #onEvaluateInputViewShown()} to return true or false based on
    151  * whether it should be shown in the current environment.  If any of your
    152  * state has changed that may impact this, call
    153  * {@link #updateInputViewShown()} to have it re-evaluated.  The default
    154  * implementation always shows the input view unless there is a hard
    155  * keyboard available, which is the appropriate behavior for most input
    156  * methods.</p>
    157  *
    158  *
    159  * <a name="CandidatesView"></a>
    160  * <h3>Candidates View</h3>
    161  *
    162  * <p>Often while the user is generating raw text, an input method wants to
    163  * provide them with a list of possible interpretations of that text that can
    164  * be selected for use.  This is accomplished with the candidates view, and
    165  * like the soft input view you implement {@link #onCreateCandidatesView()}
    166  * to instantiate your own view implementing your candidates UI.</p>
    167  *
    168  * <p>Management of the candidates view is a little different than the input
    169  * view, because the candidates view tends to be more transient, being shown
    170  * only when there are possible candidates for the current text being entered
    171  * by the user.  To control whether the candidates view is shown, you use
    172  * {@link #setCandidatesViewShown(boolean)}.  Note that because the candidate
    173  * view tends to be shown and hidden a lot, it does not impact the application
    174  * UI in the same way as the soft input view: it will never cause application
    175  * windows to resize, only cause them to be panned if needed for the user to
    176  * see the current focus.</p>
    177  *
    178  *
    179  * <a name="FullscreenMode"></a>
    180  * <h3>Fullscreen Mode</h3>
    181  *
    182  * <p>Sometimes your input method UI is too large to integrate with the
    183  * application UI, so you just want to take over the screen.  This is
    184  * accomplished by switching to full-screen mode, causing the input method
    185  * window to fill the entire screen and add its own "extracted text" editor
    186  * showing the user the text that is being typed.  Unlike the other UI elements,
    187  * there is a standard implementation for the extract editor that you should
    188  * not need to change.  The editor is placed at the top of the IME, above the
    189  * input and candidates views.</p>
    190  *
    191  * <p>Similar to the input view, you control whether the IME is running in
    192  * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
    193  * to return true or false based on
    194  * whether it should be fullscreen in the current environment.  If any of your
    195  * state has changed that may impact this, call
    196  * {@link #updateFullscreenMode()} to have it re-evaluated.  The default
    197  * implementation selects fullscreen mode when the screen is in a landscape
    198  * orientation, which is appropriate behavior for most input methods that have
    199  * a significant input area.</p>
    200  *
    201  * <p>When in fullscreen mode, you have some special requirements because the
    202  * user can not see the application UI.  In particular, you should implement
    203  * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
    204  * generated by your application, typically in your candidates view like you
    205  * would normally show candidates.
    206  *
    207  *
    208  * <a name="GeneratingText"></a>
    209  * <h3>Generating Text</h3>
    210  *
    211  * <p>The key part of an IME is of course generating text for the application.
    212  * This is done through calls to the
    213  * {@link android.view.inputmethod.InputConnection} interface to the
    214  * application, which can be retrieved from {@link #getCurrentInputConnection()}.
    215  * This interface allows you to generate raw key events or, if the target
    216  * supports it, directly edit in strings of candidates and committed text.</p>
    217  *
    218  * <p>Information about what the target is expected and supports can be found
    219  * through the {@link android.view.inputmethod.EditorInfo} class, which is
    220  * retrieved with {@link #getCurrentInputEditorInfo()} method.  The most
    221  * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
    222  * EditorInfo.inputType}; in particular, if this is
    223  * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
    224  * then the target does not support complex edits and you need to only deliver
    225  * raw key events to it.  An input method will also want to look at other
    226  * values here, to for example detect password mode, auto complete text views,
    227  * phone number entry, etc.</p>
    228  *
    229  * <p>When the user switches between input targets, you will receive calls to
    230  * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
    231  * You can use these to reset and initialize your input state for the current
    232  * target.  For example, you will often want to clear any input state, and
    233  * update a soft keyboard to be appropriate for the new inputType.</p>
    234  *
    235  * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground
    236  * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
    237  * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
    238  */
    239 public class InputMethodService extends AbstractInputMethodService {
    240     static final String TAG = "InputMethodService";
    241     static final boolean DEBUG = false;
    242 
    243     /**
    244      * Allows the system to optimize the back button affordance based on the presence of software
    245      * keyboard.
    246      *
    247      * <p>For instance, on devices that have navigation bar and software-rendered back button, the
    248      * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
    249      * indicate that the back button has "dismiss" affordance.</p>
    250      *
    251      * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
    252      * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
    253      * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
    254      * not take this mode into account.</p>
    255      *
    256      * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
    257      * only mode you can safely specify without worrying about the compatibility.</p>
    258      *
    259      * @see #setBackDisposition(int)
    260      */
    261     public static final int BACK_DISPOSITION_DEFAULT = 0;
    262 
    263     /**
    264      * Deprecated flag.
    265      *
    266      * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
    267      *
    268      * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
    269      *             handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
    270      *             {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
    271      *             of this mode had not been well defined. Most likely the end result would be the
    272      *             same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
    273      *             use this mode
    274      * @see #setBackDisposition(int)
    275      */
    276     @Deprecated
    277     public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;
    278 
    279     /**
    280      * Deprecated flag.
    281      *
    282      * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
    283      *
    284      * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
    285      *             handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
    286      *             {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
    287      *             of this mode had not been well defined. In AOSP implementation running on devices
    288      *             that have navigation bar, specifying this flag could change the software back
    289      *             button to "Dismiss" icon no matter whether the software keyboard is shown or not,
    290      *             but there would be no easy way to restore the icon state even after IME lost the
    291      *             connection to the application. To avoid user confusions, do not specify this mode
    292      *             anyway
    293      * @see #setBackDisposition(int)
    294      */
    295     @Deprecated
    296     public static final int BACK_DISPOSITION_WILL_DISMISS = 2;
    297 
    298     /**
    299      * Asks the system to not adjust the back button affordance even when the software keyboard is
    300      * shown.
    301      *
    302      * <p>This mode is useful for UI modes where IME's main soft input window is used for some
    303      * supplemental UI, such as floating candidate window for languages such as Chinese and
    304      * Japanese, where users expect the back button is, or at least looks to be, handled by the
    305      * target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
    306      * returns {@code true}.</p>
    307      *
    308      * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
    309      * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
    310      * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
    311      * not take this mode into account.</p>
    312      *
    313      * @see #setBackDisposition(int)
    314      */
    315     public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
    316 
    317     /**
    318      * Enum flag to be used for {@link #setBackDisposition(int)}.
    319      *
    320      * @hide
    321      */
    322     @Retention(SOURCE)
    323     @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
    324             BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
    325             prefix = "BACK_DISPOSITION_")
    326     public @interface BackDispositionMode {}
    327 
    328     /**
    329      * @hide
    330      * The IME is active.  It may or may not be visible.
    331      */
    332     public static final int IME_ACTIVE = 0x1;
    333 
    334     /**
    335      * @hide
    336      * The IME is visible.
    337      */
    338     public static final int IME_VISIBLE = 0x2;
    339 
    340     // Min and max values for back disposition.
    341     private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
    342     private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
    343 
    344     InputMethodManager mImm;
    345 
    346     int mTheme = 0;
    347 
    348     LayoutInflater mInflater;
    349     TypedArray mThemeAttrs;
    350     View mRootView;
    351     SoftInputWindow mWindow;
    352     boolean mInitialized;
    353     boolean mWindowCreated;
    354     boolean mWindowAdded;
    355     boolean mWindowVisible;
    356     boolean mWindowWasVisible;
    357     boolean mInShowWindow;
    358     ViewGroup mFullscreenArea;
    359     FrameLayout mExtractFrame;
    360     FrameLayout mCandidatesFrame;
    361     FrameLayout mInputFrame;
    362 
    363     IBinder mToken;
    364 
    365     InputBinding mInputBinding;
    366     InputConnection mInputConnection;
    367     boolean mInputStarted;
    368     boolean mInputViewStarted;
    369     boolean mCandidatesViewStarted;
    370     InputConnection mStartedInputConnection;
    371     EditorInfo mInputEditorInfo;
    372 
    373     /**
    374      * A token to keep tracking the last IPC that triggered
    375      * {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If
    376      * {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from
    377      * {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged.
    378      *
    379      * <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to
    380      * disentangle event flows for various purposes such as better window animation and providing
    381      * fine-grained debugging information.</p>
    382      */
    383     @Nullable
    384     private IBinder mStartInputToken;
    385 
    386     int mShowInputFlags;
    387     boolean mShowInputRequested;
    388     boolean mLastShowInputRequested;
    389     int mCandidatesVisibility;
    390     CompletionInfo[] mCurCompletions;
    391 
    392     boolean mFullscreenApplied;
    393     boolean mIsFullscreen;
    394     View mExtractView;
    395     boolean mExtractViewHidden;
    396     ExtractEditText mExtractEditText;
    397     ViewGroup mExtractAccessories;
    398     View mExtractAction;
    399     ExtractedText mExtractedText;
    400     int mExtractedToken;
    401 
    402     View mInputView;
    403     boolean mIsInputViewShown;
    404 
    405     int mStatusIcon;
    406 
    407     @BackDispositionMode
    408     int mBackDisposition;
    409 
    410     /**
    411      * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
    412      * have not shown our own window yet.  In this situation, the previous inset continues to be
    413      * shown as an empty region until it is explicitly updated. Basically we can trigger the update
    414      * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}.
    415      */
    416     boolean mShouldClearInsetOfPreviousIme;
    417 
    418     final Insets mTmpInsets = new Insets();
    419     final int[] mTmpLocation = new int[2];
    420 
    421     final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
    422         if (isExtractViewShown()) {
    423             // In true fullscreen mode, we just say the window isn't covering
    424             // any content so we don't impact whatever is behind.
    425             View decor = getWindow().getWindow().getDecorView();
    426             info.contentInsets.top = info.visibleInsets.top = decor.getHeight();
    427             info.touchableRegion.setEmpty();
    428             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
    429         } else {
    430             onComputeInsets(mTmpInsets);
    431             info.contentInsets.top = mTmpInsets.contentTopInsets;
    432             info.visibleInsets.top = mTmpInsets.visibleTopInsets;
    433             info.touchableRegion.set(mTmpInsets.touchableRegion);
    434             info.setTouchableInsets(mTmpInsets.touchableInsets);
    435         }
    436     };
    437 
    438     final View.OnClickListener mActionClickListener = v -> {
    439         final EditorInfo ei = getCurrentInputEditorInfo();
    440         final InputConnection ic = getCurrentInputConnection();
    441         if (ei != null && ic != null) {
    442             if (ei.actionId != 0) {
    443                 ic.performEditorAction(ei.actionId);
    444             } else if ((ei.imeOptions & EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE) {
    445                 ic.performEditorAction(ei.imeOptions & EditorInfo.IME_MASK_ACTION);
    446             }
    447         }
    448     };
    449 
    450     /**
    451      * Concrete implementation of
    452      * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
    453      * all of the standard behavior for an input method.
    454      */
    455     public class InputMethodImpl extends AbstractInputMethodImpl {
    456         /**
    457          * {@inheritDoc}
    458          */
    459         @MainThread
    460         @Override
    461         public void attachToken(IBinder token) {
    462             if (mToken == null) {
    463                 mToken = token;
    464                 mWindow.setToken(token);
    465             }
    466         }
    467 
    468         /**
    469          * {@inheritDoc}
    470          *
    471          * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
    472          */
    473         @MainThread
    474         @Override
    475         public void bindInput(InputBinding binding) {
    476             mInputBinding = binding;
    477             mInputConnection = binding.getConnection();
    478             if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
    479                     + " ic=" + mInputConnection);
    480             if (mImm != null && mToken != null) {
    481                 mImm.reportFullscreenMode(mToken, mIsFullscreen);
    482             }
    483             initialize();
    484             onBindInput();
    485         }
    486 
    487         /**
    488          * {@inheritDoc}
    489          *
    490          * <p>Calls {@link InputMethodService#onUnbindInput()} when done.</p>
    491          */
    492         @MainThread
    493         @Override
    494         public void unbindInput() {
    495             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
    496                     + " ic=" + mInputConnection);
    497             onUnbindInput();
    498             mInputBinding = null;
    499             mInputConnection = null;
    500         }
    501 
    502         /**
    503          * {@inheritDoc}
    504          */
    505         @MainThread
    506         @Override
    507         public void startInput(InputConnection ic, EditorInfo attribute) {
    508             if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
    509             doStartInput(ic, attribute, false);
    510         }
    511 
    512         /**
    513          * {@inheritDoc}
    514          */
    515         @MainThread
    516         @Override
    517         public void restartInput(InputConnection ic, EditorInfo attribute) {
    518             if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
    519             doStartInput(ic, attribute, true);
    520         }
    521 
    522         /**
    523          * {@inheritDoc}
    524          * @hide
    525          */
    526         @MainThread
    527         @Override
    528         public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
    529                 @NonNull EditorInfo editorInfo, boolean restarting,
    530                 @NonNull IBinder startInputToken) {
    531             mStartInputToken = startInputToken;
    532 
    533             // This needs to be dispatched to interface methods rather than doStartInput().
    534             // Otherwise IME developers who have overridden those interface methods will lose
    535             // notifications.
    536             super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting,
    537                     startInputToken);
    538         }
    539 
    540         /**
    541          * {@inheritDoc}
    542          */
    543         @MainThread
    544         @Override
    545         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
    546             if (DEBUG) Log.v(TAG, "hideSoftInput()");
    547             boolean wasVis = isInputViewShown();
    548             mShowInputFlags = 0;
    549             mShowInputRequested = false;
    550             doHideWindow();
    551             clearInsetOfPreviousIme();
    552             if (resultReceiver != null) {
    553                 resultReceiver.send(wasVis != isInputViewShown()
    554                         ? InputMethodManager.RESULT_HIDDEN
    555                         : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
    556                                 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
    557             }
    558         }
    559 
    560         /**
    561          * {@inheritDoc}
    562          */
    563         @MainThread
    564         @Override
    565         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
    566             if (DEBUG) Log.v(TAG, "showSoftInput()");
    567             boolean wasVis = isInputViewShown();
    568             if (dispatchOnShowInputRequested(flags, false)) {
    569                 try {
    570                     showWindow(true);
    571                 } catch (BadTokenException e) {
    572                     // We have ignored BadTokenException here since Jelly Bean MR-2 (API Level 18).
    573                     // We could ignore BadTokenException in InputMethodService#showWindow() instead,
    574                     // but it may break assumptions for those who override #showWindow() that we can
    575                     // detect errors in #showWindow() by checking BadTokenException.
    576                     // TODO: Investigate its feasibility.  Update JavaDoc of #showWindow() of
    577                     // whether it's OK to override #showWindow() or not.
    578                 }
    579             }
    580             clearInsetOfPreviousIme();
    581             // If user uses hard keyboard, IME button should always be shown.
    582             mImm.setImeWindowStatus(mToken, mStartInputToken,
    583                     mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
    584             if (resultReceiver != null) {
    585                 resultReceiver.send(wasVis != isInputViewShown()
    586                         ? InputMethodManager.RESULT_SHOWN
    587                         : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
    588                                 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
    589             }
    590         }
    591 
    592         /**
    593          * {@inheritDoc}
    594          */
    595         @MainThread
    596         @Override
    597         public void changeInputMethodSubtype(InputMethodSubtype subtype) {
    598             onCurrentInputMethodSubtypeChanged(subtype);
    599         }
    600     }
    601 
    602     /**
    603      * Concrete implementation of
    604      * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
    605      * all of the standard behavior for an input method session.
    606      */
    607     public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
    608         public void finishInput() {
    609             if (!isEnabled()) {
    610                 return;
    611             }
    612             if (DEBUG) Log.v(TAG, "finishInput() in " + this);
    613             doFinishInput();
    614         }
    615 
    616         /**
    617          * Call {@link InputMethodService#onDisplayCompletions
    618          * InputMethodService.onDisplayCompletions()}.
    619          */
    620         public void displayCompletions(CompletionInfo[] completions) {
    621             if (!isEnabled()) {
    622                 return;
    623             }
    624             mCurCompletions = completions;
    625             onDisplayCompletions(completions);
    626         }
    627 
    628         /**
    629          * Call {@link InputMethodService#onUpdateExtractedText
    630          * InputMethodService.onUpdateExtractedText()}.
    631          */
    632         public void updateExtractedText(int token, ExtractedText text) {
    633             if (!isEnabled()) {
    634                 return;
    635             }
    636             onUpdateExtractedText(token, text);
    637         }
    638 
    639         /**
    640          * Call {@link InputMethodService#onUpdateSelection
    641          * InputMethodService.onUpdateSelection()}.
    642          */
    643         public void updateSelection(int oldSelStart, int oldSelEnd,
    644                 int newSelStart, int newSelEnd,
    645                 int candidatesStart, int candidatesEnd) {
    646             if (!isEnabled()) {
    647                 return;
    648             }
    649             InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
    650                     newSelStart, newSelEnd, candidatesStart, candidatesEnd);
    651         }
    652 
    653         @Override
    654         public void viewClicked(boolean focusChanged) {
    655             if (!isEnabled()) {
    656                 return;
    657             }
    658             InputMethodService.this.onViewClicked(focusChanged);
    659         }
    660 
    661         /**
    662          * Call {@link InputMethodService#onUpdateCursor
    663          * InputMethodService.onUpdateCursor()}.
    664          */
    665         public void updateCursor(Rect newCursor) {
    666             if (!isEnabled()) {
    667                 return;
    668             }
    669             InputMethodService.this.onUpdateCursor(newCursor);
    670         }
    671 
    672         /**
    673          * Call {@link InputMethodService#onAppPrivateCommand
    674          * InputMethodService.onAppPrivateCommand()}.
    675          */
    676         public void appPrivateCommand(String action, Bundle data) {
    677             if (!isEnabled()) {
    678                 return;
    679             }
    680             InputMethodService.this.onAppPrivateCommand(action, data);
    681         }
    682 
    683         /**
    684          *
    685          */
    686         public void toggleSoftInput(int showFlags, int hideFlags) {
    687             InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
    688         }
    689 
    690         /**
    691          * Call {@link InputMethodService#onUpdateCursorAnchorInfo
    692          * InputMethodService.onUpdateCursorAnchorInfo()}.
    693          */
    694         public void updateCursorAnchorInfo(CursorAnchorInfo info) {
    695             if (!isEnabled()) {
    696                 return;
    697             }
    698             InputMethodService.this.onUpdateCursorAnchorInfo(info);
    699         }
    700     }
    701 
    702     /**
    703      * Information about where interesting parts of the input method UI appear.
    704      */
    705     public static final class Insets {
    706         /**
    707          * This is the top part of the UI that is the main content.  It is
    708          * used to determine the basic space needed, to resize/pan the
    709          * application behind.  It is assumed that this inset does not
    710          * change very much, since any change will cause a full resize/pan
    711          * of the application behind.  This value is relative to the top edge
    712          * of the input method window.
    713          */
    714         public int contentTopInsets;
    715 
    716         /**
    717          * This is the top part of the UI that is visibly covering the
    718          * application behind it.  This provides finer-grained control over
    719          * visibility, allowing you to change it relatively frequently (such
    720          * as hiding or showing candidates) without disrupting the underlying
    721          * UI too much.  For example, this will never resize the application
    722          * UI, will only pan if needed to make the current focus visible, and
    723          * will not aggressively move the pan position when this changes unless
    724          * needed to make the focus visible.  This value is relative to the top edge
    725          * of the input method window.
    726          */
    727         public int visibleTopInsets;
    728 
    729         /**
    730          * This is the region of the UI that is touchable.  It is used when
    731          * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
    732          * The region should be specified relative to the origin of the window frame.
    733          */
    734         public final Region touchableRegion = new Region();
    735 
    736         /**
    737          * Option for {@link #touchableInsets}: the entire window frame
    738          * can be touched.
    739          */
    740         public static final int TOUCHABLE_INSETS_FRAME
    741                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
    742 
    743         /**
    744          * Option for {@link #touchableInsets}: the area inside of
    745          * the content insets can be touched.
    746          */
    747         public static final int TOUCHABLE_INSETS_CONTENT
    748                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
    749 
    750         /**
    751          * Option for {@link #touchableInsets}: the area inside of
    752          * the visible insets can be touched.
    753          */
    754         public static final int TOUCHABLE_INSETS_VISIBLE
    755                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
    756 
    757         /**
    758          * Option for {@link #touchableInsets}: the region specified by
    759          * {@link #touchableRegion} can be touched.
    760          */
    761         public static final int TOUCHABLE_INSETS_REGION
    762                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
    763 
    764         /**
    765          * Determine which area of the window is touchable by the user.  May
    766          * be one of: {@link #TOUCHABLE_INSETS_FRAME},
    767          * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
    768          * or {@link #TOUCHABLE_INSETS_REGION}.
    769          */
    770         public int touchableInsets;
    771     }
    772 
    773     /**
    774      * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
    775      *
    776      * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
    777      * Basically this functionality still needs to be considered as implementation details.</p>
    778      */
    779     @MainThread
    780     private static final class SettingsObserver extends ContentObserver {
    781         @Retention(RetentionPolicy.SOURCE)
    782         @IntDef({
    783                 ShowImeWithHardKeyboardType.UNKNOWN,
    784                 ShowImeWithHardKeyboardType.FALSE,
    785                 ShowImeWithHardKeyboardType.TRUE,
    786         })
    787         private @interface ShowImeWithHardKeyboardType {
    788             int UNKNOWN = 0;
    789             int FALSE = 1;
    790             int TRUE = 2;
    791         }
    792         @ShowImeWithHardKeyboardType
    793         private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
    794 
    795         private final InputMethodService mService;
    796 
    797         private SettingsObserver(InputMethodService service) {
    798             super(new Handler(service.getMainLooper()));
    799             mService = service;
    800         }
    801 
    802         /**
    803          * A factory method that internally enforces two-phase initialization to make sure that the
    804          * object reference will not be escaped until the object is properly constructed.
    805          *
    806          * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread.  Hence
    807          * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
    808          *
    809          * @param service {@link InputMethodService} that needs to receive the callback.
    810          * @return {@link SettingsObserver} that is already registered to
    811          * {@link android.content.ContentResolver}. The caller must call
    812          * {@link SettingsObserver#unregister()}.
    813          */
    814         public static SettingsObserver createAndRegister(InputMethodService service) {
    815             final SettingsObserver observer = new SettingsObserver(service);
    816             // The observer is properly constructed. Let's start accepting the event.
    817             service.getContentResolver().registerContentObserver(
    818                     Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
    819                     false, observer);
    820             return observer;
    821         }
    822 
    823         void unregister() {
    824             mService.getContentResolver().unregisterContentObserver(this);
    825         }
    826 
    827         private boolean shouldShowImeWithHardKeyboard() {
    828             // Lazily initialize as needed.
    829             if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
    830                 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
    831                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
    832                         ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
    833             }
    834             switch (mShowImeWithHardKeyboard) {
    835                 case ShowImeWithHardKeyboardType.TRUE:
    836                     return true;
    837                 case ShowImeWithHardKeyboardType.FALSE:
    838                     return false;
    839                 default:
    840                     Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
    841                     return false;
    842             }
    843         }
    844 
    845         @Override
    846         public void onChange(boolean selfChange, Uri uri) {
    847             final Uri showImeWithHardKeyboardUri =
    848                     Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
    849             if (showImeWithHardKeyboardUri.equals(uri)) {
    850                 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
    851                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
    852                         ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
    853                 // In Android M and prior, state change of
    854                 // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
    855                 // #onConfigurationChanged().  For compatibility reasons, we reset the internal
    856                 // state as if configuration was changed.
    857                 mService.resetStateForNewConfiguration();
    858             }
    859         }
    860 
    861         @Override
    862         public String toString() {
    863             return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard  + "}";
    864         }
    865     }
    866     private SettingsObserver mSettingsObserver;
    867 
    868     /**
    869      * You can call this to customize the theme used by your IME's window.
    870      * This theme should typically be one that derives from
    871      * {@link android.R.style#Theme_InputMethod}, which is the default theme
    872      * you will get.  This must be set before {@link #onCreate}, so you
    873      * will typically call it in your constructor with the resource ID
    874      * of your custom theme.
    875      */
    876     @Override
    877     public void setTheme(int theme) {
    878         if (mWindow != null) {
    879             throw new IllegalStateException("Must be called before onCreate()");
    880         }
    881         mTheme = theme;
    882     }
    883 
    884     /**
    885      * You can call this to try to enable accelerated drawing for your IME. This must be set before
    886      * {@link #onCreate()}, so you will typically call it in your constructor.  It is not always
    887      * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
    888      * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
    889      * {@code false} if you will need to draw in software.  You must be able to handle either case.
    890      *
    891      * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
    892      * IME on capable devices even if this method is not explicitly called. Make sure that your IME
    893      * is able to handle either case.</p>
    894      *
    895      * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
    896      *         On API 21 and later devices the return value is basically just a hint and your IME
    897      *         does not need to change the behavior based on the it
    898      * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
    899      */
    900     @Deprecated
    901     public boolean enableHardwareAcceleration() {
    902         if (mWindow != null) {
    903             throw new IllegalStateException("Must be called before onCreate()");
    904         }
    905         return ActivityManager.isHighEndGfx();
    906     }
    907 
    908     @Override public void onCreate() {
    909         mTheme = Resources.selectSystemTheme(mTheme,
    910                 getApplicationInfo().targetSdkVersion,
    911                 android.R.style.Theme_InputMethod,
    912                 android.R.style.Theme_Holo_InputMethod,
    913                 android.R.style.Theme_DeviceDefault_InputMethod,
    914                 android.R.style.Theme_DeviceDefault_InputMethod);
    915         super.setTheme(mTheme);
    916         super.onCreate();
    917         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
    918         mSettingsObserver = SettingsObserver.createAndRegister(this);
    919         // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
    920         // we continue to use the same size of the inset or update it
    921         mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
    922         mInflater = (LayoutInflater)getSystemService(
    923                 Context.LAYOUT_INFLATER_SERVICE);
    924         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
    925                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
    926         // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
    927         // by default (but IME developers can opt this out later if they want a new behavior).
    928         mWindow.getWindow().setFlags(
    929                 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    930 
    931         initViews();
    932         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
    933     }
    934 
    935     /**
    936      * This is a hook that subclasses can use to perform initialization of
    937      * their interface.  It is called for you prior to any of your UI objects
    938      * being created, both after the service is first created and after a
    939      * configuration change happens.
    940      */
    941     public void onInitializeInterface() {
    942         // Intentionally empty
    943     }
    944 
    945     void initialize() {
    946         if (!mInitialized) {
    947             mInitialized = true;
    948             onInitializeInterface();
    949         }
    950     }
    951 
    952     void initViews() {
    953         mInitialized = false;
    954         mWindowCreated = false;
    955         mShowInputRequested = false;
    956         mShowInputFlags = 0;
    957 
    958         mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
    959         mRootView = mInflater.inflate(
    960                 com.android.internal.R.layout.input_method, null);
    961         mWindow.setContentView(mRootView);
    962         mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
    963         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
    964         if (Settings.Global.getInt(getContentResolver(),
    965                 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
    966             mWindow.getWindow().setWindowAnimations(
    967                     com.android.internal.R.style.Animation_InputMethodFancy);
    968         }
    969         mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
    970         mExtractViewHidden = false;
    971         mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
    972         mExtractView = null;
    973         mExtractEditText = null;
    974         mExtractAccessories = null;
    975         mExtractAction = null;
    976         mFullscreenApplied = false;
    977 
    978         mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
    979         mInputFrame = mRootView.findViewById(android.R.id.inputArea);
    980         mInputView = null;
    981         mIsInputViewShown = false;
    982 
    983         mExtractFrame.setVisibility(View.GONE);
    984         mCandidatesVisibility = getCandidatesHiddenVisibility();
    985         mCandidatesFrame.setVisibility(mCandidatesVisibility);
    986         mInputFrame.setVisibility(View.GONE);
    987     }
    988 
    989     @Override public void onDestroy() {
    990         super.onDestroy();
    991         mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
    992                 mInsetsComputer);
    993         doFinishInput();
    994         if (mWindowAdded) {
    995             // Disable exit animation for the current IME window
    996             // to avoid the race condition between the exit and enter animations
    997             // when the current IME is being switched to another one.
    998             mWindow.getWindow().setWindowAnimations(0);
    999             mWindow.dismiss();
   1000         }
   1001         if (mSettingsObserver != null) {
   1002             mSettingsObserver.unregister();
   1003             mSettingsObserver = null;
   1004         }
   1005     }
   1006 
   1007     /**
   1008      * Take care of handling configuration changes.  Subclasses of
   1009      * InputMethodService generally don't need to deal directly with
   1010      * this on their own; the standard implementation here takes care of
   1011      * regenerating the input method UI as a result of the configuration
   1012      * change, so you can rely on your {@link #onCreateInputView} and
   1013      * other methods being called as appropriate due to a configuration change.
   1014      *
   1015      * <p>When a configuration change does happen,
   1016      * {@link #onInitializeInterface()} is guaranteed to be called the next
   1017      * time prior to any of the other input or UI creation callbacks.  The
   1018      * following will be called immediately depending if appropriate for current
   1019      * state: {@link #onStartInput} if input is active, and
   1020      * {@link #onCreateInputView} and {@link #onStartInputView} and related
   1021      * appropriate functions if the UI is displayed.
   1022      */
   1023     @Override public void onConfigurationChanged(Configuration newConfig) {
   1024         super.onConfigurationChanged(newConfig);
   1025         resetStateForNewConfiguration();
   1026     }
   1027 
   1028     private void resetStateForNewConfiguration() {
   1029         boolean visible = mWindowVisible;
   1030         int showFlags = mShowInputFlags;
   1031         boolean showingInput = mShowInputRequested;
   1032         CompletionInfo[] completions = mCurCompletions;
   1033         initViews();
   1034         mInputViewStarted = false;
   1035         mCandidatesViewStarted = false;
   1036         if (mInputStarted) {
   1037             doStartInput(getCurrentInputConnection(),
   1038                     getCurrentInputEditorInfo(), true);
   1039         }
   1040         if (visible) {
   1041             if (showingInput) {
   1042                 // If we were last showing the soft keyboard, try to do so again.
   1043                 if (dispatchOnShowInputRequested(showFlags, true)) {
   1044                     showWindow(true);
   1045                     if (completions != null) {
   1046                         mCurCompletions = completions;
   1047                         onDisplayCompletions(completions);
   1048                     }
   1049                 } else {
   1050                     doHideWindow();
   1051                 }
   1052             } else if (mCandidatesVisibility == View.VISIBLE) {
   1053                 // If the candidates are currently visible, make sure the
   1054                 // window is shown for them.
   1055                 showWindow(false);
   1056             } else {
   1057                 // Otherwise hide the window.
   1058                 doHideWindow();
   1059             }
   1060             // If user uses hard keyboard, IME button should always be shown.
   1061             boolean showing = onEvaluateInputViewShown();
   1062             mImm.setImeWindowStatus(mToken, mStartInputToken,
   1063                     IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
   1064         }
   1065     }
   1066 
   1067     /**
   1068      * Implement to return our standard {@link InputMethodImpl}.  Subclasses
   1069      * can override to provide their own customized version.
   1070      */
   1071     @Override
   1072     public AbstractInputMethodImpl onCreateInputMethodInterface() {
   1073         return new InputMethodImpl();
   1074     }
   1075 
   1076     /**
   1077      * Implement to return our standard {@link InputMethodSessionImpl}.  Subclasses
   1078      * can override to provide their own customized version.
   1079      */
   1080     @Override
   1081     public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
   1082         return new InputMethodSessionImpl();
   1083     }
   1084 
   1085     public LayoutInflater getLayoutInflater() {
   1086         return mInflater;
   1087     }
   1088 
   1089     public Dialog getWindow() {
   1090         return mWindow;
   1091     }
   1092 
   1093     /**
   1094      * Sets the disposition mode that indicates the expected affordance for the back button.
   1095      *
   1096      * <p>Keep in mind that specifying this flag does not change the the default behavior of
   1097      * {@link #onKeyDown(int, KeyEvent)}.  It is IME developers' responsibility for making sure that
   1098      * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
   1099      * specified to this API.</p>
   1100      *
   1101      * @see #getBackDisposition()
   1102      * @param disposition disposition mode to be set
   1103      */
   1104     public void setBackDisposition(@BackDispositionMode int disposition) {
   1105         if (disposition == mBackDisposition) {
   1106             return;
   1107         }
   1108         if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
   1109             Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
   1110             return;
   1111         }
   1112         mBackDisposition = disposition;
   1113         mImm.setImeWindowStatus(mToken, mStartInputToken, mapToImeWindowStatus(isInputViewShown()),
   1114                 mBackDisposition);
   1115     }
   1116 
   1117     /**
   1118      * Retrieves the current disposition mode that indicates the expected back button affordance.
   1119      *
   1120      * @see #setBackDisposition(int)
   1121      * @return currently selected disposition mode
   1122      */
   1123     @BackDispositionMode
   1124     public int getBackDisposition() {
   1125         return mBackDisposition;
   1126     }
   1127 
   1128     /**
   1129      * Return the maximum width, in pixels, available the input method.
   1130      * Input methods are positioned at the bottom of the screen and, unless
   1131      * running in fullscreen, will generally want to be as short as possible
   1132      * so should compute their height based on their contents.  However, they
   1133      * can stretch as much as needed horizontally.  The function returns to
   1134      * you the maximum amount of space available horizontally, which you can
   1135      * use if needed for UI placement.
   1136      *
   1137      * <p>In many cases this is not needed, you can just rely on the normal
   1138      * view layout mechanisms to position your views within the full horizontal
   1139      * space given to the input method.
   1140      *
   1141      * <p>Note that this value can change dynamically, in particular when the
   1142      * screen orientation changes.
   1143      */
   1144     public int getMaxWidth() {
   1145         WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
   1146         return wm.getDefaultDisplay().getWidth();
   1147     }
   1148 
   1149     /**
   1150      * Return the currently active InputBinding for the input method, or
   1151      * null if there is none.
   1152      */
   1153     public InputBinding getCurrentInputBinding() {
   1154         return mInputBinding;
   1155     }
   1156 
   1157     /**
   1158      * Retrieve the currently active InputConnection that is bound to
   1159      * the input method, or null if there is none.
   1160      */
   1161     public InputConnection getCurrentInputConnection() {
   1162         InputConnection ic = mStartedInputConnection;
   1163         if (ic != null) {
   1164             return ic;
   1165         }
   1166         return mInputConnection;
   1167     }
   1168 
   1169     /**
   1170      * Force switch to the last used input method and subtype. If the last input method didn't have
   1171      * any subtypes, the framework will simply switch to the last input method with no subtype
   1172      * specified.
   1173      * @return true if the current input method and subtype was successfully switched to the last
   1174      * used input method and subtype.
   1175      */
   1176     public final boolean switchToPreviousInputMethod() {
   1177         return mImm.switchToPreviousInputMethodInternal(mToken);
   1178     }
   1179 
   1180     /**
   1181      * Force switch to the next input method and subtype. If there is no IME enabled except
   1182      * current IME and subtype, do nothing.
   1183      * @param onlyCurrentIme if true, the framework will find the next subtype which
   1184      * belongs to the current IME
   1185      * @return true if the current input method and subtype was successfully switched to the next
   1186      * input method and subtype.
   1187      */
   1188     public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
   1189         return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
   1190     }
   1191 
   1192     /**
   1193      * Returns true if the current IME needs to offer the users ways to switch to a next input
   1194      * method (e.g. a globe key.).
   1195      * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
   1196      * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
   1197      * <p> Note that the system determines the most appropriate next input method
   1198      * and subtype in order to provide the consistent user experience in switching
   1199      * between IMEs and subtypes.
   1200      */
   1201     public final boolean shouldOfferSwitchingToNextInputMethod() {
   1202         return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
   1203     }
   1204 
   1205     public boolean getCurrentInputStarted() {
   1206         return mInputStarted;
   1207     }
   1208 
   1209     public EditorInfo getCurrentInputEditorInfo() {
   1210         return mInputEditorInfo;
   1211     }
   1212 
   1213     /**
   1214      * Re-evaluate whether the input method should be running in fullscreen
   1215      * mode, and update its UI if this has changed since the last time it
   1216      * was evaluated.  This will call {@link #onEvaluateFullscreenMode()} to
   1217      * determine whether it should currently run in fullscreen mode.  You
   1218      * can use {@link #isFullscreenMode()} to determine if the input method
   1219      * is currently running in fullscreen mode.
   1220      */
   1221     public void updateFullscreenMode() {
   1222         boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
   1223         boolean changed = mLastShowInputRequested != mShowInputRequested;
   1224         if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
   1225             changed = true;
   1226             mIsFullscreen = isFullscreen;
   1227             if (mImm != null && mToken != null) {
   1228                 mImm.reportFullscreenMode(mToken, mIsFullscreen);
   1229             }
   1230             mFullscreenApplied = true;
   1231             initialize();
   1232             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
   1233                     mFullscreenArea.getLayoutParams();
   1234             if (isFullscreen) {
   1235                 mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
   1236                         com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
   1237                 lp.height = 0;
   1238                 lp.weight = 1;
   1239             } else {
   1240                 mFullscreenArea.setBackgroundDrawable(null);
   1241                 lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
   1242                 lp.weight = 0;
   1243             }
   1244             ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
   1245                     mFullscreenArea, lp);
   1246             if (isFullscreen) {
   1247                 if (mExtractView == null) {
   1248                     View v = onCreateExtractTextView();
   1249                     if (v != null) {
   1250                         setExtractView(v);
   1251                     }
   1252                 }
   1253                 startExtractingText(false);
   1254             }
   1255             updateExtractFrameVisibility();
   1256         }
   1257 
   1258         if (changed) {
   1259             onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
   1260             mLastShowInputRequested = mShowInputRequested;
   1261         }
   1262     }
   1263 
   1264     /**
   1265      * Update the given window's parameters for the given mode.  This is called
   1266      * when the window is first displayed and each time the fullscreen or
   1267      * candidates only mode changes.
   1268      *
   1269      * <p>The default implementation makes the layout for the window
   1270      * MATCH_PARENT x MATCH_PARENT when in fullscreen mode, and
   1271      * MATCH_PARENT x WRAP_CONTENT when in non-fullscreen mode.
   1272      *
   1273      * @param win The input method's window.
   1274      * @param isFullscreen If true, the window is running in fullscreen mode
   1275      * and intended to cover the entire application display.
   1276      * @param isCandidatesOnly If true, the window is only showing the
   1277      * candidates view and none of the rest of its UI.  This is mutually
   1278      * exclusive with fullscreen mode.
   1279      */
   1280     public void onConfigureWindow(Window win, boolean isFullscreen,
   1281             boolean isCandidatesOnly) {
   1282         final int currentHeight = mWindow.getWindow().getAttributes().height;
   1283         final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
   1284         if (mIsInputViewShown && currentHeight != newHeight) {
   1285             if (DEBUG) {
   1286                 Log.w(TAG,"Window size has been changed. This may cause jankiness of resizing "
   1287                         + "window: " + currentHeight + " -> " + newHeight);
   1288             }
   1289         }
   1290         mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
   1291     }
   1292 
   1293     /**
   1294      * Return whether the input method is <em>currently</em> running in
   1295      * fullscreen mode.  This is the mode that was last determined and
   1296      * applied by {@link #updateFullscreenMode()}.
   1297      */
   1298     public boolean isFullscreenMode() {
   1299         return mIsFullscreen;
   1300     }
   1301 
   1302     /**
   1303      * Override this to control when the input method should run in
   1304      * fullscreen mode.  The default implementation runs in fullsceen only
   1305      * when the screen is in landscape mode.  If you change what
   1306      * this returns, you will need to call {@link #updateFullscreenMode()}
   1307      * yourself whenever the returned value may have changed to have it
   1308      * re-evaluated and applied.
   1309      */
   1310     public boolean onEvaluateFullscreenMode() {
   1311         Configuration config = getResources().getConfiguration();
   1312         if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
   1313             return false;
   1314         }
   1315         if (mInputEditorInfo != null
   1316                 && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
   1317             return false;
   1318         }
   1319         return true;
   1320     }
   1321 
   1322     /**
   1323      * Controls the visibility of the extracted text area.  This only applies
   1324      * when the input method is in fullscreen mode, and thus showing extracted
   1325      * text.  When false, the extracted text will not be shown, allowing some
   1326      * of the application to be seen behind.  This is normally set for you
   1327      * by {@link #onUpdateExtractingVisibility}.  This controls the visibility
   1328      * of both the extracted text and candidate view; the latter since it is
   1329      * not useful if there is no text to see.
   1330      */
   1331     public void setExtractViewShown(boolean shown) {
   1332         if (mExtractViewHidden == shown) {
   1333             mExtractViewHidden = !shown;
   1334             updateExtractFrameVisibility();
   1335         }
   1336     }
   1337 
   1338     /**
   1339      * Return whether the fullscreen extract view is shown.  This will only
   1340      * return true if {@link #isFullscreenMode()} returns true, and in that
   1341      * case its value depends on the last call to
   1342      * {@link #setExtractViewShown(boolean)}.  This effectively lets you
   1343      * determine if the application window is entirely covered (when this
   1344      * returns true) or if some part of it may be shown (if this returns
   1345      * false, though if {@link #isFullscreenMode()} returns true in that case
   1346      * then it is probably only a sliver of the application).
   1347      */
   1348     public boolean isExtractViewShown() {
   1349         return mIsFullscreen && !mExtractViewHidden;
   1350     }
   1351 
   1352     void updateExtractFrameVisibility() {
   1353         final int vis;
   1354         if (isFullscreenMode()) {
   1355             vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
   1356             // "vis" should be applied for the extract frame as well in the fullscreen mode.
   1357             mExtractFrame.setVisibility(vis);
   1358         } else {
   1359             vis = View.VISIBLE;
   1360             mExtractFrame.setVisibility(View.GONE);
   1361         }
   1362         updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
   1363         if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
   1364             int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
   1365                     ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
   1366                     : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
   1367                     0);
   1368             if (animRes != 0) {
   1369                 mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
   1370                         this, animRes));
   1371             }
   1372         }
   1373         mFullscreenArea.setVisibility(vis);
   1374     }
   1375 
   1376     /**
   1377      * Compute the interesting insets into your UI.  The default implementation
   1378      * uses the top of the candidates frame for the visible insets, and the
   1379      * top of the input frame for the content insets.  The default touchable
   1380      * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
   1381      *
   1382      * <p>Note that this method is not called when
   1383      * {@link #isExtractViewShown} returns true, since
   1384      * in that case the application is left as-is behind the input method and
   1385      * not impacted by anything in its UI.
   1386      *
   1387      * @param outInsets Fill in with the current UI insets.
   1388      */
   1389     public void onComputeInsets(Insets outInsets) {
   1390         int[] loc = mTmpLocation;
   1391         if (mInputFrame.getVisibility() == View.VISIBLE) {
   1392             mInputFrame.getLocationInWindow(loc);
   1393         } else {
   1394             View decor = getWindow().getWindow().getDecorView();
   1395             loc[1] = decor.getHeight();
   1396         }
   1397         if (isFullscreenMode()) {
   1398             // In fullscreen mode, we never resize the underlying window.
   1399             View decor = getWindow().getWindow().getDecorView();
   1400             outInsets.contentTopInsets = decor.getHeight();
   1401         } else {
   1402             outInsets.contentTopInsets = loc[1];
   1403         }
   1404         if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
   1405             mCandidatesFrame.getLocationInWindow(loc);
   1406         }
   1407         outInsets.visibleTopInsets = loc[1];
   1408         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
   1409         outInsets.touchableRegion.setEmpty();
   1410     }
   1411 
   1412     /**
   1413      * Re-evaluate whether the soft input area should currently be shown, and
   1414      * update its UI if this has changed since the last time it
   1415      * was evaluated.  This will call {@link #onEvaluateInputViewShown()} to
   1416      * determine whether the input view should currently be shown.  You
   1417      * can use {@link #isInputViewShown()} to determine if the input view
   1418      * is currently shown.
   1419      */
   1420     public void updateInputViewShown() {
   1421         boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
   1422         if (mIsInputViewShown != isShown && mWindowVisible) {
   1423             mIsInputViewShown = isShown;
   1424             mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
   1425             if (mInputView == null) {
   1426                 initialize();
   1427                 View v = onCreateInputView();
   1428                 if (v != null) {
   1429                     setInputView(v);
   1430                 }
   1431             }
   1432         }
   1433     }
   1434 
   1435     /**
   1436      * Returns true if we have been asked to show our input view.
   1437      */
   1438     public boolean isShowInputRequested() {
   1439         return mShowInputRequested;
   1440     }
   1441 
   1442     /**
   1443      * Return whether the soft input view is <em>currently</em> shown to the
   1444      * user.  This is the state that was last determined and
   1445      * applied by {@link #updateInputViewShown()}.
   1446      */
   1447     public boolean isInputViewShown() {
   1448         return mIsInputViewShown && mWindowVisible;
   1449     }
   1450 
   1451     /**
   1452      * Override this to control when the soft input area should be shown to the user.  The default
   1453      * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
   1454      * unless the user shows an intention to use software keyboard.  If you change what this
   1455      * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
   1456      * value may have changed to have it re-evaluated and applied.
   1457      *
   1458      * <p>When you override this method, it is recommended to call
   1459      * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
   1460      * returned.</p>
   1461      */
   1462     @CallSuper
   1463     public boolean onEvaluateInputViewShown() {
   1464         if (mSettingsObserver == null) {
   1465             Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
   1466             return false;
   1467         }
   1468         if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
   1469             return true;
   1470         }
   1471         Configuration config = getResources().getConfiguration();
   1472         return config.keyboard == Configuration.KEYBOARD_NOKEYS
   1473                 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
   1474     }
   1475 
   1476     /**
   1477      * Controls the visibility of the candidates display area.  By default
   1478      * it is hidden.
   1479      */
   1480     public void setCandidatesViewShown(boolean shown) {
   1481         updateCandidatesVisibility(shown);
   1482         if (!mShowInputRequested && mWindowVisible != shown) {
   1483             // If we are being asked to show the candidates view while the app
   1484             // has not asked for the input view to be shown, then we need
   1485             // to update whether the window is shown.
   1486             if (shown) {
   1487                 showWindow(false);
   1488             } else {
   1489                 doHideWindow();
   1490             }
   1491         }
   1492     }
   1493 
   1494     void updateCandidatesVisibility(boolean shown) {
   1495         int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
   1496         if (mCandidatesVisibility != vis) {
   1497             mCandidatesFrame.setVisibility(vis);
   1498             mCandidatesVisibility = vis;
   1499         }
   1500     }
   1501 
   1502     /**
   1503      * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
   1504      * or {@link View#GONE View.GONE}) of the candidates view when it is not
   1505      * shown.  The default implementation returns GONE when
   1506      * {@link #isExtractViewShown} returns true,
   1507      * otherwise VISIBLE.  Be careful if you change this to return GONE in
   1508      * other situations -- if showing or hiding the candidates view causes
   1509      * your window to resize, this can cause temporary drawing artifacts as
   1510      * the resize takes place.
   1511      */
   1512     public int getCandidatesHiddenVisibility() {
   1513         return isExtractViewShown() ? View.GONE : View.INVISIBLE;
   1514     }
   1515 
   1516     public void showStatusIcon(@DrawableRes int iconResId) {
   1517         mStatusIcon = iconResId;
   1518         mImm.showStatusIconInternal(mToken, getPackageName(), iconResId);
   1519     }
   1520 
   1521     public void hideStatusIcon() {
   1522         mStatusIcon = 0;
   1523         mImm.hideStatusIconInternal(mToken);
   1524     }
   1525 
   1526     /**
   1527      * Force switch to a new input method, as identified by <var>id</var>.  This
   1528      * input method will be destroyed, and the requested one started on the
   1529      * current input field.
   1530      *
   1531      * @param id Unique identifier of the new input method to start.
   1532      */
   1533     public void switchInputMethod(String id) {
   1534         mImm.setInputMethodInternal(mToken, id);
   1535     }
   1536 
   1537     /**
   1538      * Force switch to a new input method, as identified by {@code id}.  This
   1539      * input method will be destroyed, and the requested one started on the
   1540      * current input field.
   1541      *
   1542      * @param id Unique identifier of the new input method to start.
   1543      * @param subtype The new subtype of the new input method to be switched to.
   1544      */
   1545     public final void switchInputMethod(String id, InputMethodSubtype subtype) {
   1546         mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
   1547     }
   1548 
   1549     public void setExtractView(View view) {
   1550         mExtractFrame.removeAllViews();
   1551         mExtractFrame.addView(view, new FrameLayout.LayoutParams(
   1552                 ViewGroup.LayoutParams.MATCH_PARENT,
   1553                 ViewGroup.LayoutParams.MATCH_PARENT));
   1554         mExtractView = view;
   1555         if (view != null) {
   1556             mExtractEditText = view.findViewById(
   1557                     com.android.internal.R.id.inputExtractEditText);
   1558             mExtractEditText.setIME(this);
   1559             mExtractAction = view.findViewById(
   1560                     com.android.internal.R.id.inputExtractAction);
   1561             if (mExtractAction != null) {
   1562                 mExtractAccessories = view.findViewById(
   1563                         com.android.internal.R.id.inputExtractAccessories);
   1564             }
   1565             startExtractingText(false);
   1566         } else {
   1567             mExtractEditText = null;
   1568             mExtractAccessories = null;
   1569             mExtractAction = null;
   1570         }
   1571     }
   1572 
   1573     /**
   1574      * Replaces the current candidates view with a new one.  You only need to
   1575      * call this when dynamically changing the view; normally, you should
   1576      * implement {@link #onCreateCandidatesView()} and create your view when
   1577      * first needed by the input method.
   1578      */
   1579     public void setCandidatesView(View view) {
   1580         mCandidatesFrame.removeAllViews();
   1581         mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
   1582                 ViewGroup.LayoutParams.MATCH_PARENT,
   1583                 ViewGroup.LayoutParams.WRAP_CONTENT));
   1584     }
   1585 
   1586     /**
   1587      * Replaces the current input view with a new one.  You only need to
   1588      * call this when dynamically changing the view; normally, you should
   1589      * implement {@link #onCreateInputView()} and create your view when
   1590      * first needed by the input method.
   1591      */
   1592     public void setInputView(View view) {
   1593         mInputFrame.removeAllViews();
   1594         mInputFrame.addView(view, new FrameLayout.LayoutParams(
   1595                 ViewGroup.LayoutParams.MATCH_PARENT,
   1596                 ViewGroup.LayoutParams.WRAP_CONTENT));
   1597         mInputView = view;
   1598     }
   1599 
   1600     /**
   1601      * Called by the framework to create the layout for showing extacted text.
   1602      * Only called when in fullscreen mode.  The returned view hierarchy must
   1603      * have an {@link ExtractEditText} whose ID is
   1604      * {@link android.R.id#inputExtractEditText}.
   1605      */
   1606     public View onCreateExtractTextView() {
   1607         return mInflater.inflate(
   1608                 com.android.internal.R.layout.input_method_extract_view, null);
   1609     }
   1610 
   1611     /**
   1612      * Create and return the view hierarchy used to show candidates.  This will
   1613      * be called once, when the candidates are first displayed.  You can return
   1614      * null to have no candidates view; the default implementation returns null.
   1615      *
   1616      * <p>To control when the candidates view is displayed, use
   1617      * {@link #setCandidatesViewShown(boolean)}.
   1618      * To change the candidates view after the first one is created by this
   1619      * function, use {@link #setCandidatesView(View)}.
   1620      */
   1621     public View onCreateCandidatesView() {
   1622         return null;
   1623     }
   1624 
   1625     /**
   1626      * Create and return the view hierarchy used for the input area (such as
   1627      * a soft keyboard).  This will be called once, when the input area is
   1628      * first displayed.  You can return null to have no input area; the default
   1629      * implementation returns null.
   1630      *
   1631      * <p>To control when the input view is displayed, implement
   1632      * {@link #onEvaluateInputViewShown()}.
   1633      * To change the input view after the first one is created by this
   1634      * function, use {@link #setInputView(View)}.
   1635      */
   1636     public View onCreateInputView() {
   1637         return null;
   1638     }
   1639 
   1640     /**
   1641      * Called when the input view is being shown and input has started on
   1642      * a new editor.  This will always be called after {@link #onStartInput},
   1643      * allowing you to do your general setup there and just view-specific
   1644      * setup here.  You are guaranteed that {@link #onCreateInputView()} will
   1645      * have been called some time before this function is called.
   1646      *
   1647      * @param info Description of the type of text being edited.
   1648      * @param restarting Set to true if we are restarting input on the
   1649      * same text field as before.
   1650      */
   1651     public void onStartInputView(EditorInfo info, boolean restarting) {
   1652         // Intentionally empty
   1653     }
   1654 
   1655     /**
   1656      * Called when the input view is being hidden from the user.  This will
   1657      * be called either prior to hiding the window, or prior to switching to
   1658      * another target for editing.
   1659      *
   1660      * <p>The default
   1661      * implementation uses the InputConnection to clear any active composing
   1662      * text; you can override this (not calling the base class implementation)
   1663      * to perform whatever behavior you would like.
   1664      *
   1665      * @param finishingInput If true, {@link #onFinishInput} will be
   1666      * called immediately after.
   1667      */
   1668     public void onFinishInputView(boolean finishingInput) {
   1669         if (!finishingInput) {
   1670             InputConnection ic = getCurrentInputConnection();
   1671             if (ic != null) {
   1672                 ic.finishComposingText();
   1673             }
   1674         }
   1675     }
   1676 
   1677     /**
   1678      * Called when only the candidates view has been shown for showing
   1679      * processing as the user enters text through a hard keyboard.
   1680      * This will always be called after {@link #onStartInput},
   1681      * allowing you to do your general setup there and just view-specific
   1682      * setup here.  You are guaranteed that {@link #onCreateCandidatesView()}
   1683      * will have been called some time before this function is called.
   1684      *
   1685      * <p>Note that this will <em>not</em> be called when the input method
   1686      * is running in full editing mode, and thus receiving
   1687      * {@link #onStartInputView} to initiate that operation.  This is only
   1688      * for the case when candidates are being shown while the input method
   1689      * editor is hidden but wants to show its candidates UI as text is
   1690      * entered through some other mechanism.
   1691      *
   1692      * @param info Description of the type of text being edited.
   1693      * @param restarting Set to true if we are restarting input on the
   1694      * same text field as before.
   1695      */
   1696     public void onStartCandidatesView(EditorInfo info, boolean restarting) {
   1697         // Intentionally empty
   1698     }
   1699 
   1700     /**
   1701      * Called when the candidates view is being hidden from the user.  This will
   1702      * be called either prior to hiding the window, or prior to switching to
   1703      * another target for editing.
   1704      *
   1705      * <p>The default
   1706      * implementation uses the InputConnection to clear any active composing
   1707      * text; you can override this (not calling the base class implementation)
   1708      * to perform whatever behavior you would like.
   1709      *
   1710      * @param finishingInput If true, {@link #onFinishInput} will be
   1711      * called immediately after.
   1712      */
   1713     public void onFinishCandidatesView(boolean finishingInput) {
   1714         if (!finishingInput) {
   1715             InputConnection ic = getCurrentInputConnection();
   1716             if (ic != null) {
   1717                 ic.finishComposingText();
   1718             }
   1719         }
   1720     }
   1721 
   1722     /**
   1723      * The system has decided that it may be time to show your input method.
   1724      * This is called due to a corresponding call to your
   1725      * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
   1726      * method.  The default implementation uses
   1727      * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
   1728      * and the current configuration to decide whether the input view should
   1729      * be shown at this point.
   1730      *
   1731      * @param flags Provides additional information about the show request,
   1732      * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
   1733      * @param configChange This is true if we are re-showing due to a
   1734      * configuration change.
   1735      * @return Returns true to indicate that the window should be shown.
   1736      */
   1737     public boolean onShowInputRequested(int flags, boolean configChange) {
   1738         if (!onEvaluateInputViewShown()) {
   1739             return false;
   1740         }
   1741         if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
   1742             if (!configChange && onEvaluateFullscreenMode()) {
   1743                 // Don't show if this is not explicitly requested by the user and
   1744                 // the input method is fullscreen.  That would be too disruptive.
   1745                 // However, we skip this change for a config change, since if
   1746                 // the IME is already shown we do want to go into fullscreen
   1747                 // mode at this point.
   1748                 return false;
   1749             }
   1750             if (!mSettingsObserver.shouldShowImeWithHardKeyboard() &&
   1751                     getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS) {
   1752                 // And if the device has a hard keyboard, even if it is
   1753                 // currently hidden, don't show the input method implicitly.
   1754                 // These kinds of devices don't need it that much.
   1755                 return false;
   1756             }
   1757         }
   1758         return true;
   1759     }
   1760 
   1761     /**
   1762      * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
   1763      * states depending on its result.  Since {@link #onShowInputRequested(int, boolean)} is
   1764      * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
   1765      * to have this method to ensure that those internal states are always updated no matter how
   1766      * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
   1767      * @param flags Provides additional information about the show request,
   1768      * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
   1769      * @param configChange This is true if we are re-showing due to a
   1770      * configuration change.
   1771      * @return Returns true to indicate that the window should be shown.
   1772      * @see #onShowInputRequested(int, boolean)
   1773      */
   1774     private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
   1775         final boolean result = onShowInputRequested(flags, configChange);
   1776         if (result) {
   1777             mShowInputFlags = flags;
   1778         } else {
   1779             mShowInputFlags = 0;
   1780         }
   1781         return result;
   1782     }
   1783 
   1784     public void showWindow(boolean showInput) {
   1785         if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
   1786                 + " mShowInputRequested=" + mShowInputRequested
   1787                 + " mWindowAdded=" + mWindowAdded
   1788                 + " mWindowCreated=" + mWindowCreated
   1789                 + " mWindowVisible=" + mWindowVisible
   1790                 + " mInputStarted=" + mInputStarted
   1791                 + " mShowInputFlags=" + mShowInputFlags);
   1792 
   1793         if (mInShowWindow) {
   1794             Log.w(TAG, "Re-entrance in to showWindow");
   1795             return;
   1796         }
   1797 
   1798         try {
   1799             mWindowWasVisible = mWindowVisible;
   1800             mInShowWindow = true;
   1801             showWindowInner(showInput);
   1802         } catch (BadTokenException e) {
   1803             // BadTokenException is a normal consequence in certain situations, e.g., swapping IMEs
   1804             // while there is a DO_SHOW_SOFT_INPUT message in the IIMethodWrapper queue.
   1805             if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
   1806             mWindowVisible = false;
   1807             mWindowAdded = false;
   1808             // Rethrow the exception to preserve the existing behavior.  Some IMEs may have directly
   1809             // called this method and relied on this exception for some clean-up tasks.
   1810             // TODO: Give developers a clear guideline of whether it's OK to call this method or
   1811             // InputMethodService#requestShowSelf(int) should always be used instead.
   1812             throw e;
   1813         } finally {
   1814             // TODO: Is it OK to set true when we get BadTokenException?
   1815             mWindowWasVisible = true;
   1816             mInShowWindow = false;
   1817         }
   1818     }
   1819 
   1820     void showWindowInner(boolean showInput) {
   1821         boolean doShowInput = false;
   1822         final int previousImeWindowStatus =
   1823                 (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
   1824         mWindowVisible = true;
   1825         if (!mShowInputRequested && mInputStarted && showInput) {
   1826             doShowInput = true;
   1827             mShowInputRequested = true;
   1828         }
   1829 
   1830         if (DEBUG) Log.v(TAG, "showWindow: updating UI");
   1831         initialize();
   1832         updateFullscreenMode();
   1833         updateInputViewShown();
   1834 
   1835         if (!mWindowAdded || !mWindowCreated) {
   1836             mWindowAdded = true;
   1837             mWindowCreated = true;
   1838             initialize();
   1839             if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
   1840             View v = onCreateCandidatesView();
   1841             if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
   1842             if (v != null) {
   1843                 setCandidatesView(v);
   1844             }
   1845         }
   1846         if (mShowInputRequested) {
   1847             if (!mInputViewStarted) {
   1848                 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
   1849                 mInputViewStarted = true;
   1850                 onStartInputView(mInputEditorInfo, false);
   1851             }
   1852         } else if (!mCandidatesViewStarted) {
   1853             if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
   1854             mCandidatesViewStarted = true;
   1855             onStartCandidatesView(mInputEditorInfo, false);
   1856         }
   1857 
   1858         if (doShowInput) {
   1859             startExtractingText(false);
   1860         }
   1861 
   1862         final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
   1863         if (previousImeWindowStatus != nextImeWindowStatus) {
   1864             mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,
   1865                     mBackDisposition);
   1866         }
   1867         if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
   1868             if (DEBUG) Log.v(TAG, "showWindow: showing!");
   1869             onWindowShown();
   1870             mWindow.show();
   1871             // Put here rather than in onWindowShown() in case people forget to call
   1872             // super.onWindowShown().
   1873             mShouldClearInsetOfPreviousIme = false;
   1874         }
   1875     }
   1876 
   1877     private void finishViews() {
   1878         if (mInputViewStarted) {
   1879             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
   1880             onFinishInputView(false);
   1881         } else if (mCandidatesViewStarted) {
   1882             if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
   1883             onFinishCandidatesView(false);
   1884         }
   1885         mInputViewStarted = false;
   1886         mCandidatesViewStarted = false;
   1887     }
   1888 
   1889     private void doHideWindow() {
   1890         mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition);
   1891         hideWindow();
   1892     }
   1893 
   1894     public void hideWindow() {
   1895         finishViews();
   1896         if (mWindowVisible) {
   1897             mWindow.hide();
   1898             mWindowVisible = false;
   1899             onWindowHidden();
   1900             mWindowWasVisible = false;
   1901         }
   1902         updateFullscreenMode();
   1903     }
   1904 
   1905     /**
   1906      * Called immediately before the input method window is shown to the user.
   1907      * You could override this to prepare for the window to be shown
   1908      * (update view structure etc).
   1909      */
   1910     public void onWindowShown() {
   1911         // Intentionally empty
   1912     }
   1913 
   1914     /**
   1915      * Called when the input method window has been hidden from the user,
   1916      * after previously being visible.
   1917      */
   1918     public void onWindowHidden() {
   1919         // Intentionally empty
   1920     }
   1921 
   1922     /**
   1923      * Reset the inset occupied the previous IME when and only when
   1924      * {@link #mShouldClearInsetOfPreviousIme} is {@code true}.
   1925      */
   1926     private void clearInsetOfPreviousIme() {
   1927         if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() "
   1928                 + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
   1929         if (!mShouldClearInsetOfPreviousIme) return;
   1930 
   1931         mImm.clearLastInputMethodWindowForTransition(mToken);
   1932         mShouldClearInsetOfPreviousIme = false;
   1933     }
   1934 
   1935     /**
   1936      * Called when a new client has bound to the input method.  This
   1937      * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
   1938      * and {@link #onFinishInput()} calls as the user navigates through its
   1939      * UI.  Upon this call you know that {@link #getCurrentInputBinding}
   1940      * and {@link #getCurrentInputConnection} return valid objects.
   1941      */
   1942     public void onBindInput() {
   1943         // Intentionally empty
   1944     }
   1945 
   1946     /**
   1947      * Called when the previous bound client is no longer associated
   1948      * with the input method.  After returning {@link #getCurrentInputBinding}
   1949      * and {@link #getCurrentInputConnection} will no longer return
   1950      * valid objects.
   1951      */
   1952     public void onUnbindInput() {
   1953         // Intentionally empty
   1954     }
   1955 
   1956     /**
   1957      * Called to inform the input method that text input has started in an
   1958      * editor.  You should use this callback to initialize the state of your
   1959      * input to match the state of the editor given to it.
   1960      *
   1961      * @param attribute The attributes of the editor that input is starting
   1962      * in.
   1963      * @param restarting Set to true if input is restarting in the same
   1964      * editor such as because the application has changed the text in
   1965      * the editor.  Otherwise will be false, indicating this is a new
   1966      * session with the editor.
   1967      */
   1968     public void onStartInput(EditorInfo attribute, boolean restarting) {
   1969         // Intentionally empty
   1970     }
   1971 
   1972     void doFinishInput() {
   1973         if (mInputViewStarted) {
   1974             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
   1975             onFinishInputView(true);
   1976         } else if (mCandidatesViewStarted) {
   1977             if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
   1978             onFinishCandidatesView(true);
   1979         }
   1980         mInputViewStarted = false;
   1981         mCandidatesViewStarted = false;
   1982         if (mInputStarted) {
   1983             if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
   1984             onFinishInput();
   1985         }
   1986         mInputStarted = false;
   1987         mStartedInputConnection = null;
   1988         mCurCompletions = null;
   1989     }
   1990 
   1991     void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
   1992         if (!restarting) {
   1993             doFinishInput();
   1994         }
   1995         mInputStarted = true;
   1996         mStartedInputConnection = ic;
   1997         mInputEditorInfo = attribute;
   1998         initialize();
   1999         if (DEBUG) Log.v(TAG, "CALL: onStartInput");
   2000         onStartInput(attribute, restarting);
   2001         if (mWindowVisible) {
   2002             if (mShowInputRequested) {
   2003                 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
   2004                 mInputViewStarted = true;
   2005                 onStartInputView(mInputEditorInfo, restarting);
   2006                 startExtractingText(true);
   2007             } else if (mCandidatesVisibility == View.VISIBLE) {
   2008                 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
   2009                 mCandidatesViewStarted = true;
   2010                 onStartCandidatesView(mInputEditorInfo, restarting);
   2011             }
   2012         }
   2013     }
   2014 
   2015     /**
   2016      * Called to inform the input method that text input has finished in
   2017      * the last editor.  At this point there may be a call to
   2018      * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
   2019      * new editor, or the input method may be left idle.  This method is
   2020      * <em>not</em> called when input restarts in the same editor.
   2021      *
   2022      * <p>The default
   2023      * implementation uses the InputConnection to clear any active composing
   2024      * text; you can override this (not calling the base class implementation)
   2025      * to perform whatever behavior you would like.
   2026      */
   2027     public void onFinishInput() {
   2028         InputConnection ic = getCurrentInputConnection();
   2029         if (ic != null) {
   2030             ic.finishComposingText();
   2031         }
   2032     }
   2033 
   2034     /**
   2035      * Called when the application has reported auto-completion candidates that
   2036      * it would like to have the input method displayed.  Typically these are
   2037      * only used when an input method is running in full-screen mode, since
   2038      * otherwise the user can see and interact with the pop-up window of
   2039      * completions shown by the application.
   2040      *
   2041      * <p>The default implementation here does nothing.
   2042      */
   2043     public void onDisplayCompletions(CompletionInfo[] completions) {
   2044         // Intentionally empty
   2045     }
   2046 
   2047     /**
   2048      * Called when the application has reported new extracted text to be shown
   2049      * due to changes in its current text state.  The default implementation
   2050      * here places the new text in the extract edit text, when the input
   2051      * method is running in fullscreen mode.
   2052      */
   2053     public void onUpdateExtractedText(int token, ExtractedText text) {
   2054         if (mExtractedToken != token) {
   2055             return;
   2056         }
   2057         if (text != null) {
   2058             if (mExtractEditText != null) {
   2059                 mExtractedText = text;
   2060                 mExtractEditText.setExtractedText(text);
   2061             }
   2062         }
   2063     }
   2064 
   2065     /**
   2066      * Called when the application has reported a new selection region of
   2067      * the text.  This is called whether or not the input method has requested
   2068      * extracted text updates, although if so it will not receive this call
   2069      * if the extracted text has changed as well.
   2070      *
   2071      * <p>Be careful about changing the text in reaction to this call with
   2072      * methods such as setComposingText, commitText or
   2073      * deleteSurroundingText. If the cursor moves as a result, this method
   2074      * will be called again, which may result in an infinite loop.
   2075      *
   2076      * <p>The default implementation takes care of updating the cursor in
   2077      * the extract text, if it is being shown.
   2078      */
   2079     public void onUpdateSelection(int oldSelStart, int oldSelEnd,
   2080             int newSelStart, int newSelEnd,
   2081             int candidatesStart, int candidatesEnd) {
   2082         final ExtractEditText eet = mExtractEditText;
   2083         if (eet != null && isFullscreenMode() && mExtractedText != null) {
   2084             final int off = mExtractedText.startOffset;
   2085             eet.startInternalChanges();
   2086             newSelStart -= off;
   2087             newSelEnd -= off;
   2088             final int len = eet.getText().length();
   2089             if (newSelStart < 0) newSelStart = 0;
   2090             else if (newSelStart > len) newSelStart = len;
   2091             if (newSelEnd < 0) newSelEnd = 0;
   2092             else if (newSelEnd > len) newSelEnd = len;
   2093             eet.setSelection(newSelStart, newSelEnd);
   2094             eet.finishInternalChanges();
   2095         }
   2096     }
   2097 
   2098     /**
   2099      * Called when the user tapped or clicked a text view.
   2100      * IMEs can't rely on this method being called because this was not part of the original IME
   2101      * protocol, so applications with custom text editing written before this method appeared will
   2102      * not call to inform the IME of this interaction.
   2103      * @param focusChanged true if the user changed the focused view by this click.
   2104      */
   2105     public void onViewClicked(boolean focusChanged) {
   2106         // Intentionally empty
   2107     }
   2108 
   2109     /**
   2110      * Called when the application has reported a new location of its text
   2111      * cursor.  This is only called if explicitly requested by the input method.
   2112      * The default implementation does nothing.
   2113      * @deprecated Use {#link onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
   2114      */
   2115     @Deprecated
   2116     public void onUpdateCursor(Rect newCursor) {
   2117         // Intentionally empty
   2118     }
   2119 
   2120     /**
   2121      * Called when the application has reported a new location of its text insertion point and
   2122      * characters in the composition string.  This is only called if explicitly requested by the
   2123      * input method. The default implementation does nothing.
   2124      * @param cursorAnchorInfo The positional information of the text insertion point and the
   2125      * composition string.
   2126      */
   2127     public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
   2128         // Intentionally empty
   2129     }
   2130 
   2131     /**
   2132      * Close this input method's soft input area, removing it from the display.
   2133      *
   2134      * The input method will continue running, but the user can no longer use it to generate input
   2135      * by touching the screen.
   2136      *
   2137      * @see InputMethodManager#HIDE_IMPLICIT_ONLY
   2138      * @see InputMethodManager#HIDE_NOT_ALWAYS
   2139      * @param flags Provides additional operating flags.
   2140      */
   2141     public void requestHideSelf(int flags) {
   2142         mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
   2143     }
   2144 
   2145     /**
   2146      * Show the input method's soft input area, so the user sees the input method window and can
   2147      * interact with it.
   2148      *
   2149      * @see InputMethodManager#SHOW_IMPLICIT
   2150      * @see InputMethodManager#SHOW_FORCED
   2151      * @param flags Provides additional operating flags.
   2152      */
   2153     public final void requestShowSelf(int flags) {
   2154         mImm.showSoftInputFromInputMethodInternal(mToken, flags);
   2155     }
   2156 
   2157     private boolean handleBack(boolean doIt) {
   2158         if (mShowInputRequested) {
   2159             // If the soft input area is shown, back closes it and we
   2160             // consume the back key.
   2161             if (doIt) requestHideSelf(0);
   2162             return true;
   2163         } else if (mWindowVisible) {
   2164             if (mCandidatesVisibility == View.VISIBLE) {
   2165                 // If we are showing candidates even if no input area, then
   2166                 // hide them.
   2167                 if (doIt) setCandidatesViewShown(false);
   2168             } else {
   2169                 // If we have the window visible for some other reason --
   2170                 // most likely to show candidates -- then just get rid
   2171                 // of it.  This really shouldn't happen, but just in case...
   2172                 if (doIt) doHideWindow();
   2173             }
   2174             return true;
   2175         }
   2176         return false;
   2177     }
   2178 
   2179     /**
   2180      * @return {#link ExtractEditText} if it is considered to be visible and active. Otherwise
   2181      * {@code null} is returned.
   2182      */
   2183     private ExtractEditText getExtractEditTextIfVisible() {
   2184         if (!isExtractViewShown() || !isInputViewShown()) {
   2185             return null;
   2186         }
   2187         return mExtractEditText;
   2188     }
   2189 
   2190 
   2191     /**
   2192      * Called back when a {@link KeyEvent} is forwarded from the target application.
   2193      *
   2194      * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
   2195      * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
   2196      * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
   2197      * in the extracted text view, not allowing them to perform navigation in the underlying
   2198      * application.</p>
   2199      *
   2200      * <p>The default implementation does not take flags specified to
   2201      * {@link #setBackDisposition(int)} into account, even on API version
   2202      * {@link android.os.Build.VERSION_CODES#P} and later devices.  IME developers are responsible
   2203      * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
   2204      * with the flag they specified to {@link #setBackDisposition(int)}.</p>
   2205      *
   2206      * @param keyCode The value in {@code event.getKeyCode()}
   2207      * @param event Description of the key event
   2208      *
   2209      * @return {@code true} if the event is consumed by the IME and the application no longer needs
   2210      *         to consume it.  Return {@code false} when the event should be handled as if the IME
   2211      *         had not seen the event at all.
   2212      */
   2213     public boolean onKeyDown(int keyCode, KeyEvent event) {
   2214         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
   2215             final ExtractEditText eet = getExtractEditTextIfVisible();
   2216             if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
   2217                 return true;
   2218             }
   2219             if (handleBack(false)) {
   2220                 event.startTracking();
   2221                 return true;
   2222             }
   2223             return false;
   2224         }
   2225         return doMovementKey(keyCode, event, MOVEMENT_DOWN);
   2226     }
   2227 
   2228     /**
   2229      * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
   2230      * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
   2231      * the event).
   2232      */
   2233     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
   2234         return false;
   2235     }
   2236 
   2237     /**
   2238      * Override this to intercept special key multiple events before they are
   2239      * processed by the
   2240      * application.  If you return true, the application will not itself
   2241      * process the event.  If you return false, the normal application processing
   2242      * will occur as if the IME had not seen the event at all.
   2243      *
   2244      * <p>The default implementation always returns false, except when
   2245      * in fullscreen mode, where it will consume DPAD movement
   2246      * events to move the cursor in the extracted text view, not allowing
   2247      * them to perform navigation in the underlying application.
   2248      */
   2249     public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
   2250         return doMovementKey(keyCode, event, count);
   2251     }
   2252 
   2253     /**
   2254      * Override this to intercept key up events before they are processed by the
   2255      * application.  If you return true, the application will not itself
   2256      * process the event.  If you return false, the normal application processing
   2257      * will occur as if the IME had not seen the event at all.
   2258      *
   2259      * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
   2260      * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown.  In
   2261      * addition, in fullscreen mode only, it will consume DPAD movement
   2262      * events to move the cursor in the extracted text view, not allowing
   2263      * them to perform navigation in the underlying application.
   2264      */
   2265     public boolean onKeyUp(int keyCode, KeyEvent event) {
   2266         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
   2267             final ExtractEditText eet = getExtractEditTextIfVisible();
   2268             if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
   2269                 return true;
   2270             }
   2271             if (event.isTracking() && !event.isCanceled()) {
   2272                 return handleBack(true);
   2273             }
   2274         }
   2275         return doMovementKey(keyCode, event, MOVEMENT_UP);
   2276     }
   2277 
   2278     /**
   2279      * Override this to intercept trackball motion events before they are
   2280      * processed by the application.
   2281      * If you return true, the application will not itself process the event.
   2282      * If you return false, the normal application processing will occur as if
   2283      * the IME had not seen the event at all.
   2284      */
   2285     @Override
   2286     public boolean onTrackballEvent(MotionEvent event) {
   2287         if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
   2288         return false;
   2289     }
   2290 
   2291     /**
   2292      * Override this to intercept generic motion events before they are
   2293      * processed by the application.
   2294      * If you return true, the application will not itself process the event.
   2295      * If you return false, the normal application processing will occur as if
   2296      * the IME had not seen the event at all.
   2297      */
   2298     @Override
   2299     public boolean onGenericMotionEvent(MotionEvent event) {
   2300         if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
   2301         return false;
   2302     }
   2303 
   2304     public void onAppPrivateCommand(String action, Bundle data) {
   2305     }
   2306 
   2307     /**
   2308      * Handle a request by the system to toggle the soft input area.
   2309      */
   2310     private void onToggleSoftInput(int showFlags, int hideFlags) {
   2311         if (DEBUG) Log.v(TAG, "toggleSoftInput()");
   2312         if (isInputViewShown()) {
   2313             requestHideSelf(hideFlags);
   2314         } else {
   2315             requestShowSelf(showFlags);
   2316         }
   2317     }
   2318 
   2319     static final int MOVEMENT_DOWN = -1;
   2320     static final int MOVEMENT_UP = -2;
   2321 
   2322     void reportExtractedMovement(int keyCode, int count) {
   2323         int dx = 0, dy = 0;
   2324         switch (keyCode) {
   2325             case KeyEvent.KEYCODE_DPAD_LEFT:
   2326                 dx = -count;
   2327                 break;
   2328             case KeyEvent.KEYCODE_DPAD_RIGHT:
   2329                 dx = count;
   2330                 break;
   2331             case KeyEvent.KEYCODE_DPAD_UP:
   2332                 dy = -count;
   2333                 break;
   2334             case KeyEvent.KEYCODE_DPAD_DOWN:
   2335                 dy = count;
   2336                 break;
   2337         }
   2338         onExtractedCursorMovement(dx, dy);
   2339     }
   2340 
   2341     boolean doMovementKey(int keyCode, KeyEvent event, int count) {
   2342         final ExtractEditText eet = getExtractEditTextIfVisible();
   2343         if (eet != null) {
   2344             // If we are in fullscreen mode, the cursor will move around
   2345             // the extract edit text, but should NOT cause focus to move
   2346             // to other fields.
   2347             MovementMethod movement = eet.getMovementMethod();
   2348             Layout layout = eet.getLayout();
   2349             if (movement != null && layout != null) {
   2350                 // We want our own movement method to handle the key, so the
   2351                 // cursor will properly move in our own word wrapping.
   2352                 if (count == MOVEMENT_DOWN) {
   2353                     if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
   2354                         reportExtractedMovement(keyCode, 1);
   2355                         return true;
   2356                     }
   2357                 } else if (count == MOVEMENT_UP) {
   2358                     if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
   2359                         return true;
   2360                     }
   2361                 } else {
   2362                     if (movement.onKeyOther(eet, eet.getText(), event)) {
   2363                         reportExtractedMovement(keyCode, count);
   2364                     } else {
   2365                         KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
   2366                         if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
   2367                             KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
   2368                             movement.onKeyUp(eet, eet.getText(), keyCode, up);
   2369                             while (--count > 0) {
   2370                                 movement.onKeyDown(eet, eet.getText(), keyCode, down);
   2371                                 movement.onKeyUp(eet, eet.getText(), keyCode, up);
   2372                             }
   2373                             reportExtractedMovement(keyCode, count);
   2374                         }
   2375                     }
   2376                 }
   2377             }
   2378             // Regardless of whether the movement method handled the key,
   2379             // we never allow DPAD navigation to the application.
   2380             switch (keyCode) {
   2381                 case KeyEvent.KEYCODE_DPAD_LEFT:
   2382                 case KeyEvent.KEYCODE_DPAD_RIGHT:
   2383                 case KeyEvent.KEYCODE_DPAD_UP:
   2384                 case KeyEvent.KEYCODE_DPAD_DOWN:
   2385                     return true;
   2386             }
   2387         }
   2388 
   2389         return false;
   2390     }
   2391 
   2392     /**
   2393      * Send the given key event code (as defined by {@link KeyEvent}) to the
   2394      * current input connection is a key down + key up event pair.  The sent
   2395      * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
   2396      * set, so that the recipient can identify them as coming from a software
   2397      * input method, and
   2398      * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
   2399      * that they don't impact the current touch mode of the UI.
   2400      *
   2401      * <p>Note that it's discouraged to send such key events in normal operation;
   2402      * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
   2403      * text fields, or for non-rich input methods. A reasonably capable software
   2404      * input method should use the
   2405      * {@link android.view.inputmethod.InputConnection#commitText} family of methods
   2406      * to send text to an application, rather than sending key events.</p>
   2407      *
   2408      * @param keyEventCode The raw key code to send, as defined by
   2409      * {@link KeyEvent}.
   2410      */
   2411     public void sendDownUpKeyEvents(int keyEventCode) {
   2412         InputConnection ic = getCurrentInputConnection();
   2413         if (ic == null) return;
   2414         long eventTime = SystemClock.uptimeMillis();
   2415         ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
   2416                 KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
   2417                 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
   2418         ic.sendKeyEvent(new KeyEvent(eventTime, SystemClock.uptimeMillis(),
   2419                 KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
   2420                 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
   2421     }
   2422 
   2423     /**
   2424      * Ask the input target to execute its default action via
   2425      * {@link InputConnection#performEditorAction
   2426      * InputConnection.performEditorAction()}.
   2427      *
   2428      * @param fromEnterKey If true, this will be executed as if the user had
   2429      * pressed an enter key on the keyboard, that is it will <em>not</em>
   2430      * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
   2431      * EditorInfo.IME_FLAG_NO_ENTER_ACTION}.  If false, the action will be
   2432      * sent regardless of how the editor has set that flag.
   2433      *
   2434      * @return Returns a boolean indicating whether an action has been sent.
   2435      * If false, either the editor did not specify a default action or it
   2436      * does not want an action from the enter key.  If true, the action was
   2437      * sent (or there was no input connection at all).
   2438      */
   2439     public boolean sendDefaultEditorAction(boolean fromEnterKey) {
   2440         EditorInfo ei = getCurrentInputEditorInfo();
   2441         if (ei != null &&
   2442                 (!fromEnterKey || (ei.imeOptions &
   2443                         EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
   2444                 (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
   2445                     EditorInfo.IME_ACTION_NONE) {
   2446             // If the enter key was pressed, and the editor has a default
   2447             // action associated with pressing enter, then send it that
   2448             // explicit action instead of the key event.
   2449             InputConnection ic = getCurrentInputConnection();
   2450             if (ic != null) {
   2451                 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
   2452             }
   2453             return true;
   2454         }
   2455 
   2456         return false;
   2457     }
   2458 
   2459     /**
   2460      * Send the given UTF-16 character to the current input connection.  Most
   2461      * characters will be delivered simply by calling
   2462      * {@link InputConnection#commitText InputConnection.commitText()} with
   2463      * the character; some, however, may be handled different.  In particular,
   2464      * the enter character ('\n') will either be delivered as an action code
   2465      * or a raw key event, as appropriate.  Consider this as a convenience
   2466      * method for IMEs that do not have a full implementation of actions; a
   2467      * fully complying IME will decide of the right action for each event and
   2468      * will likely never call this method except maybe to handle events coming
   2469      * from an actual hardware keyboard.
   2470      *
   2471      * @param charCode The UTF-16 character code to send.
   2472      */
   2473     public void sendKeyChar(char charCode) {
   2474         switch (charCode) {
   2475             case '\n': // Apps may be listening to an enter key to perform an action
   2476                 if (!sendDefaultEditorAction(true)) {
   2477                     sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
   2478                 }
   2479                 break;
   2480             default:
   2481                 // Make sure that digits go through any text watcher on the client side.
   2482                 if (charCode >= '0' && charCode <= '9') {
   2483                     sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
   2484                 } else {
   2485                     InputConnection ic = getCurrentInputConnection();
   2486                     if (ic != null) {
   2487                         ic.commitText(String.valueOf(charCode), 1);
   2488                     }
   2489                 }
   2490                 break;
   2491         }
   2492     }
   2493 
   2494     /**
   2495      * This is called when the user has moved the cursor in the extracted
   2496      * text view, when running in fullsreen mode.  The default implementation
   2497      * performs the corresponding selection change on the underlying text
   2498      * editor.
   2499      */
   2500     public void onExtractedSelectionChanged(int start, int end) {
   2501         InputConnection conn = getCurrentInputConnection();
   2502         if (conn != null) {
   2503             conn.setSelection(start, end);
   2504         }
   2505     }
   2506 
   2507     /**
   2508      * @hide
   2509      */
   2510     public void onExtractedDeleteText(int start, int end) {
   2511         InputConnection conn = getCurrentInputConnection();
   2512         if (conn != null) {
   2513             conn.finishComposingText();
   2514             conn.setSelection(start, start);
   2515             conn.deleteSurroundingText(0, end - start);
   2516         }
   2517     }
   2518 
   2519     /**
   2520      * @hide
   2521      */
   2522     public void onExtractedReplaceText(int start, int end, CharSequence text) {
   2523         InputConnection conn = getCurrentInputConnection();
   2524         if (conn != null) {
   2525             conn.setComposingRegion(start, end);
   2526             conn.commitText(text, 1);
   2527         }
   2528     }
   2529 
   2530     /**
   2531      * @hide
   2532      */
   2533     public void onExtractedSetSpan(Object span, int start, int end, int flags) {
   2534         InputConnection conn = getCurrentInputConnection();
   2535         if (conn != null) {
   2536             if (!conn.setSelection(start, end)) return;
   2537             CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
   2538             if (text instanceof Spannable) {
   2539                 ((Spannable) text).setSpan(span, 0, text.length(), flags);
   2540                 conn.setComposingRegion(start, end);
   2541                 conn.commitText(text, 1);
   2542             }
   2543         }
   2544     }
   2545 
   2546     /**
   2547      * This is called when the user has clicked on the extracted text view,
   2548      * when running in fullscreen mode.  The default implementation hides
   2549      * the candidates view when this happens, but only if the extracted text
   2550      * editor has a vertical scroll bar because its text doesn't fit.
   2551      * Re-implement this to provide whatever behavior you want.
   2552      */
   2553     public void onExtractedTextClicked() {
   2554         if (mExtractEditText == null) {
   2555             return;
   2556         }
   2557         if (mExtractEditText.hasVerticalScrollBar()) {
   2558             setCandidatesViewShown(false);
   2559         }
   2560     }
   2561 
   2562     /**
   2563      * This is called when the user has performed a cursor movement in the
   2564      * extracted text view, when it is running in fullscreen mode.  The default
   2565      * implementation hides the candidates view when a vertical movement
   2566      * happens, but only if the extracted text editor has a vertical scroll bar
   2567      * because its text doesn't fit.
   2568      * Re-implement this to provide whatever behavior you want.
   2569      * @param dx The amount of cursor movement in the x dimension.
   2570      * @param dy The amount of cursor movement in the y dimension.
   2571      */
   2572     public void onExtractedCursorMovement(int dx, int dy) {
   2573         if (mExtractEditText == null || dy == 0) {
   2574             return;
   2575         }
   2576         if (mExtractEditText.hasVerticalScrollBar()) {
   2577             setCandidatesViewShown(false);
   2578         }
   2579     }
   2580 
   2581     /**
   2582      * This is called when the user has selected a context menu item from the
   2583      * extracted text view, when running in fullscreen mode.  The default
   2584      * implementation sends this action to the current InputConnection's
   2585      * {@link InputConnection#performContextMenuAction(int)}, for it
   2586      * to be processed in underlying "real" editor.  Re-implement this to
   2587      * provide whatever behavior you want.
   2588      */
   2589     public boolean onExtractTextContextMenuItem(int id) {
   2590         InputConnection ic = getCurrentInputConnection();
   2591         if (ic != null) {
   2592             ic.performContextMenuAction(id);
   2593         }
   2594         return true;
   2595     }
   2596 
   2597     /**
   2598      * Return text that can be used as a button label for the given
   2599      * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.  Returns null
   2600      * if there is no action requested.  Note that there is no guarantee that
   2601      * the returned text will be relatively short, so you probably do not
   2602      * want to use it as text on a soft keyboard key label.
   2603      *
   2604      * @param imeOptions The value from {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
   2605      *
   2606      * @return Returns a label to use, or null if there is no action.
   2607      */
   2608     public CharSequence getTextForImeAction(int imeOptions) {
   2609         switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
   2610             case EditorInfo.IME_ACTION_NONE:
   2611                 return null;
   2612             case EditorInfo.IME_ACTION_GO:
   2613                 return getText(com.android.internal.R.string.ime_action_go);
   2614             case EditorInfo.IME_ACTION_SEARCH:
   2615                 return getText(com.android.internal.R.string.ime_action_search);
   2616             case EditorInfo.IME_ACTION_SEND:
   2617                 return getText(com.android.internal.R.string.ime_action_send);
   2618             case EditorInfo.IME_ACTION_NEXT:
   2619                 return getText(com.android.internal.R.string.ime_action_next);
   2620             case EditorInfo.IME_ACTION_DONE:
   2621                 return getText(com.android.internal.R.string.ime_action_done);
   2622             case EditorInfo.IME_ACTION_PREVIOUS:
   2623                 return getText(com.android.internal.R.string.ime_action_previous);
   2624             default:
   2625                 return getText(com.android.internal.R.string.ime_action_default);
   2626         }
   2627     }
   2628 
   2629     /**
   2630      * Return a drawable resource id that can be used as a button icon for the given
   2631      * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
   2632      *
   2633      * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
   2634      *
   2635      * @return Returns a drawable resource id to use.
   2636      */
   2637     @DrawableRes
   2638     private int getIconForImeAction(int imeOptions) {
   2639         switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
   2640             case EditorInfo.IME_ACTION_GO:
   2641                 return com.android.internal.R.drawable.ic_input_extract_action_go;
   2642             case EditorInfo.IME_ACTION_SEARCH:
   2643                 return com.android.internal.R.drawable.ic_input_extract_action_search;
   2644             case EditorInfo.IME_ACTION_SEND:
   2645                 return com.android.internal.R.drawable.ic_input_extract_action_send;
   2646             case EditorInfo.IME_ACTION_NEXT:
   2647                 return com.android.internal.R.drawable.ic_input_extract_action_next;
   2648             case EditorInfo.IME_ACTION_DONE:
   2649                 return com.android.internal.R.drawable.ic_input_extract_action_done;
   2650             case EditorInfo.IME_ACTION_PREVIOUS:
   2651                 return com.android.internal.R.drawable.ic_input_extract_action_previous;
   2652             default:
   2653                 return com.android.internal.R.drawable.ic_input_extract_action_return;
   2654         }
   2655     }
   2656 
   2657     /**
   2658      * Called when the fullscreen-mode extracting editor info has changed,
   2659      * to determine whether the extracting (extract text and candidates) portion
   2660      * of the UI should be shown.  The standard implementation hides or shows
   2661      * the extract area depending on whether it makes sense for the
   2662      * current editor.  In particular, a {@link InputType#TYPE_NULL}
   2663      * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
   2664      * turn off the extract area since there is no text to be shown.
   2665      */
   2666     public void onUpdateExtractingVisibility(EditorInfo ei) {
   2667         if (ei.inputType == InputType.TYPE_NULL ||
   2668                 (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
   2669             // No reason to show extract UI!
   2670             setExtractViewShown(false);
   2671             return;
   2672         }
   2673 
   2674         setExtractViewShown(true);
   2675     }
   2676 
   2677     /**
   2678      * Called when the fullscreen-mode extracting editor info has changed,
   2679      * to update the state of its UI such as the action buttons shown.
   2680      * You do not need to deal with this if you are using the standard
   2681      * full screen extract UI.  If replacing it, you will need to re-implement
   2682      * this to put the appropriate action button in your own UI and handle it,
   2683      * and perform any other changes.
   2684      *
   2685      * <p>The standard implementation turns on or off its accessory area
   2686      * depending on whether there is an action button, and hides or shows
   2687      * the entire extract area depending on whether it makes sense for the
   2688      * current editor.  In particular, a {@link InputType#TYPE_NULL} or
   2689      * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
   2690      * extract area since there is no text to be shown.
   2691      */
   2692     public void onUpdateExtractingViews(EditorInfo ei) {
   2693         if (!isExtractViewShown()) {
   2694             return;
   2695         }
   2696 
   2697         if (mExtractAccessories == null) {
   2698             return;
   2699         }
   2700         final boolean hasAction = ei.actionLabel != null || (
   2701                 (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
   2702                 (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
   2703                 ei.inputType != InputType.TYPE_NULL);
   2704         if (hasAction) {
   2705             mExtractAccessories.setVisibility(View.VISIBLE);
   2706             if (mExtractAction != null) {
   2707                 if (mExtractAction instanceof ImageButton) {
   2708                     ((ImageButton) mExtractAction)
   2709                             .setImageResource(getIconForImeAction(ei.imeOptions));
   2710                     if (ei.actionLabel != null) {
   2711                         mExtractAction.setContentDescription(ei.actionLabel);
   2712                     } else {
   2713                         mExtractAction.setContentDescription(getTextForImeAction(ei.imeOptions));
   2714                     }
   2715                 } else {
   2716                     if (ei.actionLabel != null) {
   2717                         ((TextView) mExtractAction).setText(ei.actionLabel);
   2718                     } else {
   2719                         ((TextView) mExtractAction).setText(getTextForImeAction(ei.imeOptions));
   2720                     }
   2721                 }
   2722                 mExtractAction.setOnClickListener(mActionClickListener);
   2723             }
   2724         } else {
   2725             mExtractAccessories.setVisibility(View.GONE);
   2726             if (mExtractAction != null) {
   2727                 mExtractAction.setOnClickListener(null);
   2728             }
   2729         }
   2730     }
   2731 
   2732     /**
   2733      * This is called when, while currently displayed in extract mode, the
   2734      * current input target changes.  The default implementation will
   2735      * auto-hide the IME if the new target is not a full editor, since this
   2736      * can be a confusing experience for the user.
   2737      */
   2738     public void onExtractingInputChanged(EditorInfo ei) {
   2739         if (ei.inputType == InputType.TYPE_NULL) {
   2740             requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
   2741         }
   2742     }
   2743 
   2744     void startExtractingText(boolean inputChanged) {
   2745         final ExtractEditText eet = mExtractEditText;
   2746         if (eet != null && getCurrentInputStarted()
   2747                 && isFullscreenMode()) {
   2748             mExtractedToken++;
   2749             ExtractedTextRequest req = new ExtractedTextRequest();
   2750             req.token = mExtractedToken;
   2751             req.flags = InputConnection.GET_TEXT_WITH_STYLES;
   2752             req.hintMaxLines = 10;
   2753             req.hintMaxChars = 10000;
   2754             InputConnection ic = getCurrentInputConnection();
   2755             mExtractedText = ic == null? null
   2756                     : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
   2757             if (mExtractedText == null || ic == null) {
   2758                 Log.e(TAG, "Unexpected null in startExtractingText : mExtractedText = "
   2759                         + mExtractedText + ", input connection = " + ic);
   2760             }
   2761             final EditorInfo ei = getCurrentInputEditorInfo();
   2762 
   2763             try {
   2764                 eet.startInternalChanges();
   2765                 onUpdateExtractingVisibility(ei);
   2766                 onUpdateExtractingViews(ei);
   2767                 int inputType = ei.inputType;
   2768                 if ((inputType&EditorInfo.TYPE_MASK_CLASS)
   2769                         == EditorInfo.TYPE_CLASS_TEXT) {
   2770                     if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
   2771                         inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
   2772                     }
   2773                 }
   2774                 eet.setInputType(inputType);
   2775                 eet.setHint(ei.hintText);
   2776                 if (mExtractedText != null) {
   2777                     eet.setEnabled(true);
   2778                     eet.setExtractedText(mExtractedText);
   2779                 } else {
   2780                     eet.setEnabled(false);
   2781                     eet.setText("");
   2782                 }
   2783             } finally {
   2784                 eet.finishInternalChanges();
   2785             }
   2786 
   2787             if (inputChanged) {
   2788                 onExtractingInputChanged(ei);
   2789             }
   2790         }
   2791     }
   2792 
   2793     // TODO: Handle the subtype change event
   2794     /**
   2795      * Called when the subtype was changed.
   2796      * @param newSubtype the subtype which is being changed to.
   2797      */
   2798     protected void onCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
   2799         if (DEBUG) {
   2800             int nameResId = newSubtype.getNameResId();
   2801             String mode = newSubtype.getMode();
   2802             String output = "changeInputMethodSubtype:"
   2803                 + (nameResId == 0 ? "<none>" : getString(nameResId)) + ","
   2804                 + mode + ","
   2805                 + newSubtype.getLocale() + "," + newSubtype.getExtraValue();
   2806             Log.v(TAG, "--- " + output);
   2807         }
   2808     }
   2809 
   2810     /**
   2811      * @return The recommended height of the input method window.
   2812      * An IME author can get the last input method's height as the recommended height
   2813      * by calling this in
   2814      * {@link android.inputmethodservice.InputMethodService#onStartInputView(EditorInfo, boolean)}.
   2815      * If you don't need to use a predefined fixed height, you can avoid the window-resizing of IME
   2816      * switching by using this value as a visible inset height. It's efficient for the smooth
   2817      * transition between different IMEs. However, note that this may return 0 (or possibly
   2818      * unexpectedly low height). You should thus avoid relying on the return value of this method
   2819      * all the time. Please make sure to use a reasonable height for the IME.
   2820      */
   2821     public int getInputMethodWindowRecommendedHeight() {
   2822         return mImm.getInputMethodWindowVisibleHeight();
   2823     }
   2824 
   2825     /**
   2826      * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
   2827      * permission to the content.
   2828      *
   2829      * @param inputContentInfo Content to be temporarily exposed from the input method to the
   2830      * application.
   2831      * This cannot be {@code null}.
   2832      * @param inputConnection {@link InputConnection} with which
   2833      * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
   2834      * @hide
   2835      */
   2836     @Override
   2837     public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
   2838             @NonNull InputConnection inputConnection) {
   2839         if (inputConnection == null) {
   2840             return;
   2841         }
   2842         if (getCurrentInputConnection() != inputConnection) {
   2843             return;
   2844         }
   2845         mImm.exposeContent(mToken, inputContentInfo, getCurrentInputEditorInfo());
   2846     }
   2847 
   2848     private static int mapToImeWindowStatus(boolean isInputViewShown) {
   2849         return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
   2850     }
   2851 
   2852     /**
   2853      * Performs a dump of the InputMethodService's internal state.  Override
   2854      * to add your own information to the dump.
   2855      */
   2856     @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
   2857         final Printer p = new PrintWriterPrinter(fout);
   2858         p.println("Input method service state for " + this + ":");
   2859         p.println("  mWindowCreated=" + mWindowCreated
   2860                 + " mWindowAdded=" + mWindowAdded);
   2861         p.println("  mWindowVisible=" + mWindowVisible
   2862                 + " mWindowWasVisible=" + mWindowWasVisible
   2863                 + " mInShowWindow=" + mInShowWindow);
   2864         p.println("  Configuration=" + getResources().getConfiguration());
   2865         p.println("  mToken=" + mToken);
   2866         p.println("  mInputBinding=" + mInputBinding);
   2867         p.println("  mInputConnection=" + mInputConnection);
   2868         p.println("  mStartedInputConnection=" + mStartedInputConnection);
   2869         p.println("  mInputStarted=" + mInputStarted
   2870                 + " mInputViewStarted=" + mInputViewStarted
   2871                 + " mCandidatesViewStarted=" + mCandidatesViewStarted);
   2872         p.println("  mStartInputToken=" + mStartInputToken);
   2873 
   2874         if (mInputEditorInfo != null) {
   2875             p.println("  mInputEditorInfo:");
   2876             mInputEditorInfo.dump(p, "    ");
   2877         } else {
   2878             p.println("  mInputEditorInfo: null");
   2879         }
   2880 
   2881         p.println("  mShowInputRequested=" + mShowInputRequested
   2882                 + " mLastShowInputRequested=" + mLastShowInputRequested
   2883                 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
   2884         p.println("  mCandidatesVisibility=" + mCandidatesVisibility
   2885                 + " mFullscreenApplied=" + mFullscreenApplied
   2886                 + " mIsFullscreen=" + mIsFullscreen
   2887                 + " mExtractViewHidden=" + mExtractViewHidden);
   2888 
   2889         if (mExtractedText != null) {
   2890             p.println("  mExtractedText:");
   2891             p.println("    text=" + mExtractedText.text.length() + " chars"
   2892                     + " startOffset=" + mExtractedText.startOffset);
   2893             p.println("    selectionStart=" + mExtractedText.selectionStart
   2894                     + " selectionEnd=" + mExtractedText.selectionEnd
   2895                     + " flags=0x" + Integer.toHexString(mExtractedText.flags));
   2896         } else {
   2897             p.println("  mExtractedText: null");
   2898         }
   2899         p.println("  mExtractedToken=" + mExtractedToken);
   2900         p.println("  mIsInputViewShown=" + mIsInputViewShown
   2901                 + " mStatusIcon=" + mStatusIcon);
   2902         p.println("Last computed insets:");
   2903         p.println("  contentTopInsets=" + mTmpInsets.contentTopInsets
   2904                 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
   2905                 + " touchableInsets=" + mTmpInsets.touchableInsets
   2906                 + " touchableRegion=" + mTmpInsets.touchableRegion);
   2907         p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
   2908         p.println(" mSettingsObserver=" + mSettingsObserver);
   2909     }
   2910 }
   2911