InputMethodService.java revision 4df2423a947bcd3f024cc3d3a1a315a8dc428598
1/*
2 * Copyright (C) 2007-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package android.inputmethodservice;
18
19import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
20import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
21
22import android.app.Dialog;
23import android.content.Context;
24import android.content.res.Configuration;
25import android.graphics.Rect;
26import android.graphics.drawable.Drawable;
27import android.os.Bundle;
28import android.os.IBinder;
29import android.os.ResultReceiver;
30import android.os.SystemClock;
31import android.provider.Settings;
32import android.text.InputType;
33import android.text.Layout;
34import android.text.Spannable;
35import android.text.method.MovementMethod;
36import android.util.Log;
37import android.util.PrintWriterPrinter;
38import android.util.Printer;
39import android.view.KeyEvent;
40import android.view.LayoutInflater;
41import android.view.MotionEvent;
42import android.view.View;
43import android.view.ViewGroup;
44import android.view.ViewTreeObserver;
45import android.view.Window;
46import android.view.WindowManager;
47import android.view.inputmethod.CompletionInfo;
48import android.view.inputmethod.ExtractedText;
49import android.view.inputmethod.ExtractedTextRequest;
50import android.view.inputmethod.InputBinding;
51import android.view.inputmethod.InputConnection;
52import android.view.inputmethod.InputMethod;
53import android.view.inputmethod.InputMethodManager;
54import android.view.inputmethod.EditorInfo;
55import android.widget.Button;
56import android.widget.FrameLayout;
57import java.io.FileDescriptor;
58import java.io.PrintWriter;
59
60/**
61 * InputMethodService provides a standard implementation of an InputMethod,
62 * which final implementations can derive from and customize.  See the
63 * base class {@link AbstractInputMethodService} and the {@link InputMethod}
64 * interface for more information on the basics of writing input methods.
65 *
66 * <p>In addition to the normal Service lifecycle methods, this class
67 * introduces some new specific callbacks that most subclasses will want
68 * to make use of:</p>
69 * <ul>
70 * <li> {@link #onInitializeInterface()} for user-interface initialization,
71 * in particular to deal with configuration changes while the service is
72 * running.
73 * <li> {@link #onBindInput} to find out about switching to a new client.
74 * <li> {@link #onStartInput} to deal with an input session starting with
75 * the client.
76 * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
77 * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
78 * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
79 * starting within the input area of the IME.
80 * </ul>
81 *
82 * <p>An input method has significant discretion in how it goes about its
83 * work: the {@link android.inputmethodservice.InputMethodService} provides
84 * a basic framework for standard UI elements (input view, candidates view,
85 * and running in fullscreen mode), but it is up to a particular implementor
86 * to decide how to use them.  For example, one input method could implement
87 * an input area with a keyboard, another could allow the user to draw text,
88 * while a third could have no input area (and thus not be visible to the
89 * user) but instead listen to audio and perform text to speech conversion.</p>
90 *
91 * <p>In the implementation provided here, all of these elements are placed
92 * together in a single window managed by the InputMethodService.  It will
93 * execute callbacks as it needs information about them, and provides APIs for
94 * programmatic control over them.  They layout of these elements is explicitly
95 * defined:</p>
96 *
97 * <ul>
98 * <li>The soft input view, if available, is placed at the bottom of the
99 * screen.
100 * <li>The candidates view, if currently shown, is placed above the soft
101 * input view.
102 * <li>If not running fullscreen, the application is moved or resized to be
103 * above these views; if running fullscreen, the window will completely cover
104 * the application and its top part will contain the extract text of what is
105 * currently being edited by the application.
106 * </ul>
107 *
108 *
109 * <a name="SoftInputView"></a>
110 * <h3>Soft Input View</h3>
111 *
112 * <p>Central to most input methods is the soft input view.  This is where most
113 * user interaction occurs: pressing on soft keys, drawing characters, or
114 * however else your input method wants to generate text.  Most implementations
115 * will simply have their own view doing all of this work, and return a new
116 * instance of it when {@link #onCreateInputView()} is called.  At that point,
117 * as long as the input view is visible, you will see user interaction in
118 * that view and can call back on the InputMethodService to interact with the
119 * application as appropriate.</p>
120 *
121 * <p>There are some situations where you want to decide whether or not your
122 * soft input view should be shown to the user.  This is done by implementing
123 * the {@link #onEvaluateInputViewShown()} to return true or false based on
124 * whether it should be shown in the current environment.  If any of your
125 * state has changed that may impact this, call
126 * {@link #updateInputViewShown()} to have it re-evaluated.  The default
127 * implementation always shows the input view unless there is a hard
128 * keyboard available, which is the appropriate behavior for most input
129 * methods.</p>
130 *
131 *
132 * <a name="CandidatesView"></a>
133 * <h3>Candidates View</h3>
134 *
135 * <p>Often while the user is generating raw text, an input method wants to
136 * provide them with a list of possible interpretations of that text that can
137 * be selected for use.  This is accomplished with the candidates view, and
138 * like the soft input view you implement {@link #onCreateCandidatesView()}
139 * to instantiate your own view implementing your candidates UI.</p>
140 *
141 * <p>Management of the candidates view is a little different than the input
142 * view, because the candidates view tends to be more transient, being shown
143 * only when there are possible candidates for the current text being entered
144 * by the user.  To control whether the candidates view is shown, you use
145 * {@link #setCandidatesViewShown(boolean)}.  Note that because the candidate
146 * view tends to be shown and hidden a lot, it does not impact the application
147 * UI in the same way as the soft input view: it will never cause application
148 * windows to resize, only cause them to be panned if needed for the user to
149 * see the current focus.</p>
150 *
151 *
152 * <a name="FullscreenMode"></a>
153 * <h3>Fullscreen Mode</h3>
154 *
155 * <p>Sometimes your input method UI is too large to integrate with the
156 * application UI, so you just want to take over the screen.  This is
157 * accomplished by switching to full-screen mode, causing the input method
158 * window to fill the entire screen and add its own "extracted text" editor
159 * showing the user the text that is being typed.  Unlike the other UI elements,
160 * there is a standard implementation for the extract editor that you should
161 * not need to change.  The editor is placed at the top of the IME, above the
162 * input and candidates views.</p>
163 *
164 * <p>Similar to the input view, you control whether the IME is running in
165 * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
166 * to return true or false based on
167 * whether it should be fullscreen in the current environment.  If any of your
168 * state has changed that may impact this, call
169 * {@link #updateFullscreenMode()} to have it re-evaluated.  The default
170 * implementation selects fullscreen mode when the screen is in a landscape
171 * orientation, which is appropriate behavior for most input methods that have
172 * a significant input area.</p>
173 *
174 * <p>When in fullscreen mode, you have some special requirements because the
175 * user can not see the application UI.  In particular, you should implement
176 * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
177 * generated by your application, typically in your candidates view like you
178 * would normally show candidates.
179 *
180 *
181 * <a name="GeneratingText"></a>
182 * <h3>Generating Text</h3>
183 *
184 * <p>The key part of an IME is of course generating text for the application.
185 * This is done through calls to the
186 * {@link android.view.inputmethod.InputConnection} interface to the
187 * application, which can be retrieved from {@link #getCurrentInputConnection()}.
188 * This interface allows you to generate raw key events or, if the target
189 * supports it, directly edit in strings of candidates and committed text.</p>
190 *
191 * <p>Information about what the target is expected and supports can be found
192 * through the {@link android.view.inputmethod.EditorInfo} class, which is
193 * retrieved with {@link #getCurrentInputEditorInfo()} method.  The most
194 * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
195 * EditorInfo.inputType}; in particular, if this is
196 * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
197 * then the target does not support complex edits and you need to only deliver
198 * raw key events to it.  An input method will also want to look at other
199 * values here, to for example detect password mode, auto complete text views,
200 * phone number entry, etc.</p>
201 *
202 * <p>When the user switches between input targets, you will receive calls to
203 * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
204 * You can use these to reset and initialize your input state for the current
205 * target.  For example, you will often want to clear any input state, and
206 * update a soft keyboard to be appropriate for the new inputType.</p>
207 */
208public class InputMethodService extends AbstractInputMethodService {
209    static final String TAG = "InputMethodService";
210    static final boolean DEBUG = false;
211
212    InputMethodManager mImm;
213
214    LayoutInflater mInflater;
215    View mRootView;
216    SoftInputWindow mWindow;
217    boolean mInitialized;
218    boolean mWindowCreated;
219    boolean mWindowAdded;
220    boolean mWindowVisible;
221    FrameLayout mExtractFrame;
222    FrameLayout mCandidatesFrame;
223    FrameLayout mInputFrame;
224
225    IBinder mToken;
226
227    InputBinding mInputBinding;
228    InputConnection mInputConnection;
229    boolean mInputStarted;
230    boolean mInputViewStarted;
231    boolean mCandidatesViewStarted;
232    InputConnection mStartedInputConnection;
233    EditorInfo mInputEditorInfo;
234
235    int mShowInputFlags;
236    boolean mShowInputRequested;
237    boolean mLastShowInputRequested;
238    int mCandidatesVisibility;
239    CompletionInfo[] mCurCompletions;
240
241    boolean mShowInputForced;
242
243    boolean mFullscreenApplied;
244    boolean mIsFullscreen;
245    View mExtractView;
246    ExtractEditText mExtractEditText;
247    ViewGroup mExtractAccessories;
248    Button mExtractAction;
249    ExtractedText mExtractedText;
250    int mExtractedToken;
251
252    View mInputView;
253    boolean mIsInputViewShown;
254
255    int mStatusIcon;
256
257    final Insets mTmpInsets = new Insets();
258    final int[] mTmpLocation = new int[2];
259
260    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
261            new ViewTreeObserver.OnComputeInternalInsetsListener() {
262        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
263            if (isFullscreenMode()) {
264                // In fullscreen mode, we just say the window isn't covering
265                // any content so we don't impact whatever is behind.
266                View decor = getWindow().getWindow().getDecorView();
267                info.contentInsets.top = info.visibleInsets.top
268                        = decor.getHeight();
269                info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
270            } else {
271                onComputeInsets(mTmpInsets);
272                info.contentInsets.top = mTmpInsets.contentTopInsets;
273                info.visibleInsets.top = mTmpInsets.visibleTopInsets;
274                info.setTouchableInsets(mTmpInsets.touchableInsets);
275            }
276        }
277    };
278
279    final View.OnClickListener mActionClickListener = new View.OnClickListener() {
280        public void onClick(View v) {
281            final EditorInfo ei = getCurrentInputEditorInfo();
282            final InputConnection ic = getCurrentInputConnection();
283            if (ei != null && ic != null) {
284                if (ei.actionId != 0) {
285                    ic.performEditorAction(ei.actionId);
286                } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION)
287                        != EditorInfo.IME_ACTION_NONE) {
288                    ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
289                }
290            }
291        }
292    };
293
294    /**
295     * Concrete implementation of
296     * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
297     * all of the standard behavior for an input method.
298     */
299    public class InputMethodImpl extends AbstractInputMethodImpl {
300        /**
301         * Take care of attaching the given window token provided by the system.
302         */
303        public void attachToken(IBinder token) {
304            if (mToken == null) {
305                mToken = token;
306                mWindow.setToken(token);
307            }
308        }
309
310        /**
311         * Handle a new input binding, calling
312         * {@link InputMethodService#onBindInput InputMethodService.onBindInput()}
313         * when done.
314         */
315        public void bindInput(InputBinding binding) {
316            mInputBinding = binding;
317            mInputConnection = binding.getConnection();
318            if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
319                    + " ic=" + mInputConnection);
320            InputConnection ic = getCurrentInputConnection();
321            if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
322            initialize();
323            onBindInput();
324        }
325
326        /**
327         * Clear the current input binding.
328         */
329        public void unbindInput() {
330            if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
331                    + " ic=" + mInputConnection);
332            onUnbindInput();
333            mInputStarted = false;
334            mInputBinding = null;
335            mInputConnection = null;
336        }
337
338        public void startInput(InputConnection ic, EditorInfo attribute) {
339            if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
340            doStartInput(ic, attribute, false);
341        }
342
343        public void restartInput(InputConnection ic, EditorInfo attribute) {
344            if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
345            doStartInput(ic, attribute, true);
346        }
347
348        /**
349         * Handle a request by the system to hide the soft input area.
350         */
351        public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
352            if (DEBUG) Log.v(TAG, "hideSoftInput()");
353            boolean wasVis = isInputViewShown();
354            mShowInputFlags = 0;
355            mShowInputRequested = false;
356            mShowInputForced = false;
357            hideWindow();
358            if (resultReceiver != null) {
359                resultReceiver.send(wasVis != isInputViewShown()
360                        ? InputMethodManager.RESULT_HIDDEN
361                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
362                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
363            }
364        }
365
366        /**
367         * Handle a request by the system to show the soft input area.
368         */
369        public void showSoftInput(int flags, ResultReceiver resultReceiver) {
370            if (DEBUG) Log.v(TAG, "showSoftInput()");
371            boolean wasVis = isInputViewShown();
372            mShowInputFlags = 0;
373            if (onShowInputRequested(flags, false)) {
374                showWindow(true);
375            }
376            if (resultReceiver != null) {
377                resultReceiver.send(wasVis != isInputViewShown()
378                        ? InputMethodManager.RESULT_SHOWN
379                        : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
380                                : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
381            }
382        }
383    }
384
385    /**
386     * Concrete implementation of
387     * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
388     * all of the standard behavior for an input method session.
389     */
390    public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
391        public void finishInput() {
392            if (!isEnabled()) {
393                return;
394            }
395            if (DEBUG) Log.v(TAG, "finishInput() in " + this);
396            doFinishInput();
397        }
398
399        /**
400         * Call {@link InputMethodService#onDisplayCompletions
401         * InputMethodService.onDisplayCompletions()}.
402         */
403        public void displayCompletions(CompletionInfo[] completions) {
404            if (!isEnabled()) {
405                return;
406            }
407            mCurCompletions = completions;
408            onDisplayCompletions(completions);
409        }
410
411        /**
412         * Call {@link InputMethodService#onUpdateExtractedText
413         * InputMethodService.onUpdateExtractedText()}.
414         */
415        public void updateExtractedText(int token, ExtractedText text) {
416            if (!isEnabled()) {
417                return;
418            }
419            onUpdateExtractedText(token, text);
420        }
421
422        /**
423         * Call {@link InputMethodService#onUpdateSelection
424         * InputMethodService.onUpdateSelection()}.
425         */
426        public void updateSelection(int oldSelStart, int oldSelEnd,
427                int newSelStart, int newSelEnd,
428                int candidatesStart, int candidatesEnd) {
429            if (!isEnabled()) {
430                return;
431            }
432            InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
433                    newSelStart, newSelEnd, candidatesStart, candidatesEnd);
434        }
435
436        /**
437         * Call {@link InputMethodService#onUpdateCursor
438         * InputMethodService.onUpdateCursor()}.
439         */
440        public void updateCursor(Rect newCursor) {
441            if (!isEnabled()) {
442                return;
443            }
444            InputMethodService.this.onUpdateCursor(newCursor);
445        }
446
447        /**
448         * Call {@link InputMethodService#onAppPrivateCommand
449         * InputMethodService.onAppPrivateCommand()}.
450         */
451        public void appPrivateCommand(String action, Bundle data) {
452            if (!isEnabled()) {
453                return;
454            }
455            InputMethodService.this.onAppPrivateCommand(action, data);
456        }
457
458        /**
459         *
460         */
461        public void toggleSoftInput(int showFlags, int hideFlags) {
462            InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
463        }
464    }
465
466    /**
467     * Information about where interesting parts of the input method UI appear.
468     */
469    public static final class Insets {
470        /**
471         * This is the top part of the UI that is the main content.  It is
472         * used to determine the basic space needed, to resize/pan the
473         * application behind.  It is assumed that this inset does not
474         * change very much, since any change will cause a full resize/pan
475         * of the application behind.  This value is relative to the top edge
476         * of the input method window.
477         */
478        public int contentTopInsets;
479
480        /**
481         * This is the top part of the UI that is visibly covering the
482         * application behind it.  This provides finer-grained control over
483         * visibility, allowing you to change it relatively frequently (such
484         * as hiding or showing candidates) without disrupting the underlying
485         * UI too much.  For example, this will never resize the application
486         * UI, will only pan if needed to make the current focus visible, and
487         * will not aggressively move the pan position when this changes unless
488         * needed to make the focus visible.  This value is relative to the top edge
489         * of the input method window.
490         */
491        public int visibleTopInsets;
492
493        /**
494         * Option for {@link #touchableInsets}: the entire window frame
495         * can be touched.
496         */
497        public static final int TOUCHABLE_INSETS_FRAME
498                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
499
500        /**
501         * Option for {@link #touchableInsets}: the area inside of
502         * the content insets can be touched.
503         */
504        public static final int TOUCHABLE_INSETS_CONTENT
505                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
506
507        /**
508         * Option for {@link #touchableInsets}: the area inside of
509         * the visible insets can be touched.
510         */
511        public static final int TOUCHABLE_INSETS_VISIBLE
512                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
513
514        /**
515         * Determine which area of the window is touchable by the user.  May
516         * be one of: {@link #TOUCHABLE_INSETS_FRAME},
517         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}.
518         */
519        public int touchableInsets;
520    }
521
522    @Override public void onCreate() {
523        super.onCreate();
524        mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
525        mInflater = (LayoutInflater)getSystemService(
526                Context.LAYOUT_INFLATER_SERVICE);
527        mWindow = new SoftInputWindow(this);
528        initViews();
529        mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
530    }
531
532    /**
533     * This is a hook that subclasses can use to perform initialization of
534     * their interface.  It is called for you prior to any of your UI objects
535     * being created, both after the service is first created and after a
536     * configuration change happens.
537     */
538    public void onInitializeInterface() {
539    }
540
541    void initialize() {
542        if (!mInitialized) {
543            mInitialized = true;
544            onInitializeInterface();
545        }
546    }
547
548    void initViews() {
549        mInitialized = false;
550        mWindowCreated = false;
551        mShowInputRequested = false;
552        mShowInputForced = false;
553
554        mRootView = mInflater.inflate(
555                com.android.internal.R.layout.input_method, null);
556        mWindow.setContentView(mRootView);
557        mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
558        if (Settings.System.getInt(getContentResolver(),
559                Settings.System.FANCY_IME_ANIMATIONS, 0) != 0) {
560            mWindow.getWindow().setWindowAnimations(
561                    com.android.internal.R.style.Animation_InputMethodFancy);
562        }
563        mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
564        mExtractView = null;
565        mExtractEditText = null;
566        mExtractAccessories = null;
567        mExtractAction = null;
568        mFullscreenApplied = false;
569
570        mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
571        mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea);
572        mInputView = null;
573        mIsInputViewShown = false;
574
575        mExtractFrame.setVisibility(View.GONE);
576        mCandidatesVisibility = getCandidatesHiddenVisibility();
577        mCandidatesFrame.setVisibility(mCandidatesVisibility);
578        mInputFrame.setVisibility(View.GONE);
579    }
580
581    @Override public void onDestroy() {
582        super.onDestroy();
583        mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
584                mInsetsComputer);
585        if (mWindowAdded) {
586            mWindow.dismiss();
587        }
588    }
589
590    /**
591     * Take care of handling configuration changes.  Subclasses of
592     * InputMethodService generally don't need to deal directly with
593     * this on their own; the standard implementation here takes care of
594     * regenerating the input method UI as a result of the configuration
595     * change, so you can rely on your {@link #onCreateInputView} and
596     * other methods being called as appropriate due to a configuration change.
597     *
598     * <p>When a configuration change does happen,
599     * {@link #onInitializeInterface()} is guaranteed to be called the next
600     * time prior to any of the other input or UI creation callbacks.  The
601     * following will be called immediately depending if appropriate for current
602     * state: {@link #onStartInput} if input is active, and
603     * {@link #onCreateInputView} and {@link #onStartInputView} and related
604     * appropriate functions if the UI is displayed.
605     */
606    @Override public void onConfigurationChanged(Configuration newConfig) {
607        super.onConfigurationChanged(newConfig);
608
609        boolean visible = mWindowVisible;
610        int showFlags = mShowInputFlags;
611        boolean showingInput = mShowInputRequested;
612        CompletionInfo[] completions = mCurCompletions;
613        initViews();
614        mInputViewStarted = false;
615        mCandidatesViewStarted = false;
616        if (mInputStarted) {
617            doStartInput(getCurrentInputConnection(),
618                    getCurrentInputEditorInfo(), true);
619        }
620        if (visible) {
621            if (showingInput) {
622                // If we were last showing the soft keyboard, try to do so again.
623                if (onShowInputRequested(showFlags, true)) {
624                    showWindow(true);
625                    if (completions != null) {
626                        mCurCompletions = completions;
627                        onDisplayCompletions(completions);
628                    }
629                } else {
630                    hideWindow();
631                }
632            } else if (mCandidatesVisibility == View.VISIBLE) {
633                // If the candidates are currently visible, make sure the
634                // window is shown for them.
635                showWindow(false);
636            } else {
637                // Otherwise hide the window.
638                hideWindow();
639            }
640        }
641    }
642
643    /**
644     * Implement to return our standard {@link InputMethodImpl}.  Subclasses
645     * can override to provide their own customized version.
646     */
647    public AbstractInputMethodImpl onCreateInputMethodInterface() {
648        return new InputMethodImpl();
649    }
650
651    /**
652     * Implement to return our standard {@link InputMethodSessionImpl}.  Subclasses
653     * can override to provide their own customized version.
654     */
655    public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
656        return new InputMethodSessionImpl();
657    }
658
659    public LayoutInflater getLayoutInflater() {
660        return mInflater;
661    }
662
663    public Dialog getWindow() {
664        return mWindow;
665    }
666
667    /**
668     * Return the maximum width, in pixels, available the input method.
669     * Input methods are positioned at the bottom of the screen and, unless
670     * running in fullscreen, will generally want to be as short as possible
671     * so should compute their height based on their contents.  However, they
672     * can stretch as much as needed horizontally.  The function returns to
673     * you the maximum amount of space available horizontally, which you can
674     * use if needed for UI placement.
675     *
676     * <p>In many cases this is not needed, you can just rely on the normal
677     * view layout mechanisms to position your views within the full horizontal
678     * space given to the input method.
679     *
680     * <p>Note that this value can change dynamically, in particular when the
681     * screen orientation changes.
682     */
683    public int getMaxWidth() {
684        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
685        return wm.getDefaultDisplay().getWidth();
686    }
687
688    /**
689     * Return the currently active InputBinding for the input method, or
690     * null if there is none.
691     */
692    public InputBinding getCurrentInputBinding() {
693        return mInputBinding;
694    }
695
696    /**
697     * Retrieve the currently active InputConnection that is bound to
698     * the input method, or null if there is none.
699     */
700    public InputConnection getCurrentInputConnection() {
701        InputConnection ic = mStartedInputConnection;
702        if (ic != null) {
703            return ic;
704        }
705        return mInputConnection;
706    }
707
708    public boolean getCurrentInputStarted() {
709        return mInputStarted;
710    }
711
712    public EditorInfo getCurrentInputEditorInfo() {
713        return mInputEditorInfo;
714    }
715
716    /**
717     * Re-evaluate whether the input method should be running in fullscreen
718     * mode, and update its UI if this has changed since the last time it
719     * was evaluated.  This will call {@link #onEvaluateFullscreenMode()} to
720     * determine whether it should currently run in fullscreen mode.  You
721     * can use {@link #isFullscreenMode()} to determine if the input method
722     * is currently running in fullscreen mode.
723     */
724    public void updateFullscreenMode() {
725        boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
726        boolean changed = mLastShowInputRequested != mShowInputRequested;
727        if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
728            changed = true;
729            mIsFullscreen = isFullscreen;
730            InputConnection ic = getCurrentInputConnection();
731            if (ic != null) ic.reportFullscreenMode(isFullscreen);
732            mFullscreenApplied = true;
733            initialize();
734            Drawable bg = onCreateBackgroundDrawable();
735            if (bg == null) {
736                // We need to give the window a real drawable, so that it
737                // correctly sets its mode.
738                bg = getResources().getDrawable(android.R.color.transparent);
739            }
740            mWindow.getWindow().setBackgroundDrawable(bg);
741            mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
742            if (isFullscreen) {
743                if (mExtractView == null) {
744                    View v = onCreateExtractTextView();
745                    if (v != null) {
746                        setExtractView(v);
747                    }
748                }
749                startExtractingText(false);
750            }
751        }
752
753        if (changed) {
754            onConfigureWindow(mWindow.getWindow(), isFullscreen,
755                    !mShowInputRequested);
756            mLastShowInputRequested = mShowInputRequested;
757        }
758    }
759
760    /**
761     * Update the given window's parameters for the given mode.  This is called
762     * when the window is first displayed and each time the fullscreen or
763     * candidates only mode changes.
764     *
765     * <p>The default implementation makes the layout for the window
766     * FILL_PARENT x FILL_PARENT when in fullscreen mode, and
767     * FILL_PARENT x WRAP_CONTENT when in non-fullscreen mode.
768     *
769     * @param win The input method's window.
770     * @param isFullscreen If true, the window is running in fullscreen mode
771     * and intended to cover the entire application display.
772     * @param isCandidatesOnly If true, the window is only showing the
773     * candidates view and none of the rest of its UI.  This is mutually
774     * exclusive with fullscreen mode.
775     */
776    public void onConfigureWindow(Window win, boolean isFullscreen,
777            boolean isCandidatesOnly) {
778        if (isFullscreen) {
779            mWindow.getWindow().setLayout(FILL_PARENT, FILL_PARENT);
780        } else {
781            mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
782        }
783    }
784
785    /**
786     * Return whether the input method is <em>currently</em> running in
787     * fullscreen mode.  This is the mode that was last determined and
788     * applied by {@link #updateFullscreenMode()}.
789     */
790    public boolean isFullscreenMode() {
791        return mIsFullscreen;
792    }
793
794    /**
795     * Override this to control when the input method should run in
796     * fullscreen mode.  The default implementation runs in fullsceen only
797     * when the screen is in landscape mode.  If you change what
798     * this returns, you will need to call {@link #updateFullscreenMode()}
799     * yourself whenever the returned value may have changed to have it
800     * re-evaluated and applied.
801     */
802    public boolean onEvaluateFullscreenMode() {
803        Configuration config = getResources().getConfiguration();
804        return config.orientation == Configuration.ORIENTATION_LANDSCAPE;
805    }
806
807    /**
808     * Compute the interesting insets into your UI.  The default implementation
809     * uses the top of the candidates frame for the visible insets, and the
810     * top of the input frame for the content insets.  The default touchable
811     * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
812     *
813     * <p>Note that this method is not called when in fullscreen mode, since
814     * in that case the application is left as-is behind the input method and
815     * not impacted by anything in its UI.
816     *
817     * @param outInsets Fill in with the current UI insets.
818     */
819    public void onComputeInsets(Insets outInsets) {
820        int[] loc = mTmpLocation;
821        if (mInputFrame.getVisibility() == View.VISIBLE) {
822            mInputFrame.getLocationInWindow(loc);
823        } else {
824            loc[1] = 0;
825        }
826        outInsets.contentTopInsets = loc[1];
827        if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
828            mCandidatesFrame.getLocationInWindow(loc);
829        }
830        outInsets.visibleTopInsets = loc[1];
831        outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
832    }
833
834    /**
835     * Re-evaluate whether the soft input area should currently be shown, and
836     * update its UI if this has changed since the last time it
837     * was evaluated.  This will call {@link #onEvaluateInputViewShown()} to
838     * determine whether the input view should currently be shown.  You
839     * can use {@link #isInputViewShown()} to determine if the input view
840     * is currently shown.
841     */
842    public void updateInputViewShown() {
843        boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
844        if (mIsInputViewShown != isShown && mWindowVisible) {
845            mIsInputViewShown = isShown;
846            mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
847            if (mInputView == null) {
848                initialize();
849                View v = onCreateInputView();
850                if (v != null) {
851                    setInputView(v);
852                }
853            }
854        }
855    }
856
857    /**
858     * Returns true if we have been asked to show our input view.
859     */
860    public boolean isShowInputRequested() {
861        return mShowInputRequested;
862    }
863
864    /**
865     * Return whether the soft input view is <em>currently</em> shown to the
866     * user.  This is the state that was last determined and
867     * applied by {@link #updateInputViewShown()}.
868     */
869    public boolean isInputViewShown() {
870        return mIsInputViewShown && mWindowVisible;
871    }
872
873    /**
874     * Override this to control when the soft input area should be shown to
875     * the user.  The default implementation only shows the input view when
876     * there is no hard keyboard or the keyboard is hidden.  If you change what
877     * this returns, you will need to call {@link #updateInputViewShown()}
878     * yourself whenever the returned value may have changed to have it
879     * re-evalauted and applied.
880     */
881    public boolean onEvaluateInputViewShown() {
882        Configuration config = getResources().getConfiguration();
883        return config.keyboard == Configuration.KEYBOARD_NOKEYS
884                || config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES;
885    }
886
887    /**
888     * Controls the visibility of the candidates display area.  By default
889     * it is hidden.
890     */
891    public void setCandidatesViewShown(boolean shown) {
892        int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
893        if (mCandidatesVisibility != vis) {
894            mCandidatesFrame.setVisibility(vis);
895            mCandidatesVisibility = vis;
896        }
897        if (!mShowInputRequested && mWindowVisible != shown) {
898            // If we are being asked to show the candidates view while the app
899            // has not asked for the input view to be shown, then we need
900            // to update whether the window is shown.
901            if (shown) {
902                showWindow(false);
903            } else {
904                hideWindow();
905            }
906        }
907    }
908
909    /**
910     * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
911     * or {@link View#GONE View.GONE}) of the candidates view when it is not
912     * shown.  The default implementation returns GONE when in fullscreen mode,
913     * otherwise VISIBLE.  Be careful if you change this to return GONE in
914     * other situations -- if showing or hiding the candidates view causes
915     * your window to resize, this can cause temporary drawing artifacts as
916     * the resize takes place.
917     */
918    public int getCandidatesHiddenVisibility() {
919        return isFullscreenMode() ? View.GONE : View.INVISIBLE;
920    }
921
922    public void showStatusIcon(int iconResId) {
923        mStatusIcon = iconResId;
924        mImm.showStatusIcon(mToken, getPackageName(), iconResId);
925    }
926
927    public void hideStatusIcon() {
928        mStatusIcon = 0;
929        mImm.hideStatusIcon(mToken);
930    }
931
932    /**
933     * Force switch to a new input method, as identified by <var>id</var>.  This
934     * input method will be destroyed, and the requested one started on the
935     * current input field.
936     *
937     * @param id Unique identifier of the new input method ot start.
938     */
939    public void switchInputMethod(String id) {
940        mImm.setInputMethod(mToken, id);
941    }
942
943    public void setExtractView(View view) {
944        mExtractFrame.removeAllViews();
945        mExtractFrame.addView(view, new FrameLayout.LayoutParams(
946                ViewGroup.LayoutParams.FILL_PARENT,
947                ViewGroup.LayoutParams.FILL_PARENT));
948        mExtractView = view;
949        if (view != null) {
950            mExtractEditText = (ExtractEditText)view.findViewById(
951                    com.android.internal.R.id.inputExtractEditText);
952            mExtractEditText.setIME(this);
953            mExtractAction = (Button)view.findViewById(
954                    com.android.internal.R.id.inputExtractAction);
955            if (mExtractAction != null) {
956                mExtractAccessories = (ViewGroup)view.findViewById(
957                        com.android.internal.R.id.inputExtractAccessories);
958            }
959            startExtractingText(false);
960        } else {
961            mExtractEditText = null;
962            mExtractAccessories = null;
963            mExtractAction = null;
964        }
965    }
966
967    /**
968     * Replaces the current candidates view with a new one.  You only need to
969     * call this when dynamically changing the view; normally, you should
970     * implement {@link #onCreateCandidatesView()} and create your view when
971     * first needed by the input method.
972     */
973    public void setCandidatesView(View view) {
974        mCandidatesFrame.removeAllViews();
975        mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
976                ViewGroup.LayoutParams.FILL_PARENT,
977                ViewGroup.LayoutParams.WRAP_CONTENT));
978    }
979
980    /**
981     * Replaces the current input view with a new one.  You only need to
982     * call this when dynamically changing the view; normally, you should
983     * implement {@link #onCreateInputView()} and create your view when
984     * first needed by the input method.
985     */
986    public void setInputView(View view) {
987        mInputFrame.removeAllViews();
988        mInputFrame.addView(view, new FrameLayout.LayoutParams(
989                ViewGroup.LayoutParams.FILL_PARENT,
990                ViewGroup.LayoutParams.WRAP_CONTENT));
991        mInputView = view;
992    }
993
994    /**
995     * Called by the framework to create a Drawable for the background of
996     * the input method window.  May return null for no background.  The default
997     * implementation returns a non-null standard background only when in
998     * fullscreen mode.  This is called each time the fullscreen mode changes.
999     */
1000    public Drawable onCreateBackgroundDrawable() {
1001        if (isFullscreenMode()) {
1002            return getResources().getDrawable(
1003                    com.android.internal.R.drawable.input_method_fullscreen_background);
1004        }
1005        return null;
1006    }
1007
1008    /**
1009     * Called by the framework to create the layout for showing extacted text.
1010     * Only called when in fullscreen mode.  The returned view hierarchy must
1011     * have an {@link ExtractEditText} whose ID is
1012     * {@link android.R.id#inputExtractEditText}.
1013     */
1014    public View onCreateExtractTextView() {
1015        return mInflater.inflate(
1016                com.android.internal.R.layout.input_method_extract_view, null);
1017    }
1018
1019    /**
1020     * Create and return the view hierarchy used to show candidates.  This will
1021     * be called once, when the candidates are first displayed.  You can return
1022     * null to have no candidates view; the default implementation returns null.
1023     *
1024     * <p>To control when the candidates view is displayed, use
1025     * {@link #setCandidatesViewShown(boolean)}.
1026     * To change the candidates view after the first one is created by this
1027     * function, use {@link #setCandidatesView(View)}.
1028     */
1029    public View onCreateCandidatesView() {
1030        return null;
1031    }
1032
1033    /**
1034     * Create and return the view hierarchy used for the input area (such as
1035     * a soft keyboard).  This will be called once, when the input area is
1036     * first displayed.  You can return null to have no input area; the default
1037     * implementation returns null.
1038     *
1039     * <p>To control when the input view is displayed, implement
1040     * {@link #onEvaluateInputViewShown()}.
1041     * To change the input view after the first one is created by this
1042     * function, use {@link #setInputView(View)}.
1043     */
1044    public View onCreateInputView() {
1045        return null;
1046    }
1047
1048    /**
1049     * Called when the input view is being shown and input has started on
1050     * a new editor.  This will always be called after {@link #onStartInput},
1051     * allowing you to do your general setup there and just view-specific
1052     * setup here.  You are guaranteed that {@link #onCreateInputView()} will
1053     * have been called some time before this function is called.
1054     *
1055     * @param info Description of the type of text being edited.
1056     * @param restarting Set to true if we are restarting input on the
1057     * same text field as before.
1058     */
1059    public void onStartInputView(EditorInfo info, boolean restarting) {
1060    }
1061
1062    /**
1063     * Called when the input view is being hidden from the user.  This will
1064     * be called either prior to hiding the window, or prior to switching to
1065     * another target for editing.
1066     *
1067     * <p>The default
1068     * implementation uses the InputConnection to clear any active composing
1069     * text; you can override this (not calling the base class implementation)
1070     * to perform whatever behavior you would like.
1071     *
1072     * @param finishingInput If true, {@link #onFinishInput} will be
1073     * called immediately after.
1074     */
1075    public void onFinishInputView(boolean finishingInput) {
1076        if (!finishingInput) {
1077            InputConnection ic = getCurrentInputConnection();
1078            if (ic != null) {
1079                ic.finishComposingText();
1080            }
1081        }
1082    }
1083
1084    /**
1085     * Called when only the candidates view has been shown for showing
1086     * processing as the user enters text through a hard keyboard.
1087     * This will always be called after {@link #onStartInput},
1088     * allowing you to do your general setup there and just view-specific
1089     * setup here.  You are guaranteed that {@link #onCreateCandidatesView()}
1090     * will have been called some time before this function is called.
1091     *
1092     * <p>Note that this will <em>not</em> be called when the input method
1093     * is running in full editing mode, and thus receiving
1094     * {@link #onStartInputView} to initiate that operation.  This is only
1095     * for the case when candidates are being shown while the input method
1096     * editor is hidden but wants to show its candidates UI as text is
1097     * entered through some other mechanism.
1098     *
1099     * @param info Description of the type of text being edited.
1100     * @param restarting Set to true if we are restarting input on the
1101     * same text field as before.
1102     */
1103    public void onStartCandidatesView(EditorInfo info, boolean restarting) {
1104    }
1105
1106    /**
1107     * Called when the candidates view is being hidden from the user.  This will
1108     * be called either prior to hiding the window, or prior to switching to
1109     * another target for editing.
1110     *
1111     * <p>The default
1112     * implementation uses the InputConnection to clear any active composing
1113     * text; you can override this (not calling the base class implementation)
1114     * to perform whatever behavior you would like.
1115     *
1116     * @param finishingInput If true, {@link #onFinishInput} will be
1117     * called immediately after.
1118     */
1119    public void onFinishCandidatesView(boolean finishingInput) {
1120        if (!finishingInput) {
1121            InputConnection ic = getCurrentInputConnection();
1122            if (ic != null) {
1123                ic.finishComposingText();
1124            }
1125        }
1126    }
1127
1128    /**
1129     * The system has decided that it may be time to show your input method.
1130     * This is called due to a corresponding call to your
1131     * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
1132     * method.  The default implementation uses
1133     * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
1134     * and the current configuration to decide whether the input view should
1135     * be shown at this point.
1136     *
1137     * @param flags Provides additional information about the show request,
1138     * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
1139     * @param configChange This is true if we are re-showing due to a
1140     * configuration change.
1141     * @return Returns true to indicate that the window should be shown.
1142     */
1143    public boolean onShowInputRequested(int flags, boolean configChange) {
1144        if (!onEvaluateInputViewShown()) {
1145            return false;
1146        }
1147        if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
1148            if (!configChange && onEvaluateFullscreenMode()) {
1149                // Don't show if this is not explicitly requested by the user and
1150                // the input method is fullscreen.  That would be too disruptive.
1151                // However, we skip this change for a config change, since if
1152                // the IME is already shown we do want to go into fullscreen
1153                // mode at this point.
1154                return false;
1155            }
1156            Configuration config = getResources().getConfiguration();
1157            if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {
1158                // And if the device has a hard keyboard, even if it is
1159                // currently hidden, don't show the input method implicitly.
1160                // These kinds of devices don't need it that much.
1161                return false;
1162            }
1163        }
1164        if ((flags&InputMethod.SHOW_FORCED) != 0) {
1165            mShowInputForced = true;
1166        }
1167        return true;
1168    }
1169
1170    public void showWindow(boolean showInput) {
1171        if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
1172                + " mShowInputRequested=" + mShowInputRequested
1173                + " mWindowAdded=" + mWindowAdded
1174                + " mWindowCreated=" + mWindowCreated
1175                + " mWindowVisible=" + mWindowVisible
1176                + " mInputStarted=" + mInputStarted);
1177        boolean doShowInput = false;
1178        boolean wasVisible = mWindowVisible;
1179        mWindowVisible = true;
1180        if (!mShowInputRequested) {
1181            if (mInputStarted) {
1182                if (showInput) {
1183                    doShowInput = true;
1184                    mShowInputRequested = true;
1185                }
1186            }
1187        } else {
1188            showInput = true;
1189        }
1190
1191        if (DEBUG) Log.v(TAG, "showWindow: updating UI");
1192        initialize();
1193        updateFullscreenMode();
1194        updateInputViewShown();
1195
1196        if (!mWindowAdded || !mWindowCreated) {
1197            mWindowAdded = true;
1198            mWindowCreated = true;
1199            initialize();
1200            if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
1201            View v = onCreateCandidatesView();
1202            if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
1203            if (v != null) {
1204                setCandidatesView(v);
1205            }
1206        }
1207        if (mShowInputRequested) {
1208            if (!mInputViewStarted) {
1209                if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1210                mInputViewStarted = true;
1211                onStartInputView(mInputEditorInfo, false);
1212            }
1213        } else if (!mCandidatesViewStarted) {
1214            if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1215            mCandidatesViewStarted = true;
1216            onStartCandidatesView(mInputEditorInfo, false);
1217        }
1218
1219        if (doShowInput) {
1220            startExtractingText(false);
1221        }
1222
1223        if (!wasVisible) {
1224            if (DEBUG) Log.v(TAG, "showWindow: showing!");
1225            onWindowShown();
1226            mWindow.show();
1227        }
1228    }
1229
1230    public void hideWindow() {
1231        if (mInputViewStarted) {
1232            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1233            onFinishInputView(false);
1234        } else if (mCandidatesViewStarted) {
1235            if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1236            onFinishCandidatesView(false);
1237        }
1238        mInputViewStarted = false;
1239        mCandidatesViewStarted = false;
1240        if (mWindowVisible) {
1241            mWindow.hide();
1242            mWindowVisible = false;
1243            onWindowHidden();
1244        }
1245    }
1246
1247    /**
1248     * Called when the input method window has been shown to the user, after
1249     * previously not being visible.  This is done after all of the UI setup
1250     * for the window has occurred (creating its views etc).
1251     */
1252    public void onWindowShown() {
1253    }
1254
1255    /**
1256     * Called when the input method window has been hidden from the user,
1257     * after previously being visible.
1258     */
1259    public void onWindowHidden() {
1260    }
1261
1262    /**
1263     * Called when a new client has bound to the input method.  This
1264     * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
1265     * and {@link #onFinishInput()} calls as the user navigates through its
1266     * UI.  Upon this call you know that {@link #getCurrentInputBinding}
1267     * and {@link #getCurrentInputConnection} return valid objects.
1268     */
1269    public void onBindInput() {
1270    }
1271
1272    /**
1273     * Called when the previous bound client is no longer associated
1274     * with the input method.  After returning {@link #getCurrentInputBinding}
1275     * and {@link #getCurrentInputConnection} will no longer return
1276     * valid objects.
1277     */
1278    public void onUnbindInput() {
1279    }
1280
1281    /**
1282     * Called to inform the input method that text input has started in an
1283     * editor.  You should use this callback to initialize the state of your
1284     * input to match the state of the editor given to it.
1285     *
1286     * @param attribute The attributes of the editor that input is starting
1287     * in.
1288     * @param restarting Set to true if input is restarting in the same
1289     * editor such as because the application has changed the text in
1290     * the editor.  Otherwise will be false, indicating this is a new
1291     * session with the editor.
1292     */
1293    public void onStartInput(EditorInfo attribute, boolean restarting) {
1294    }
1295
1296    void doFinishInput() {
1297        if (mInputViewStarted) {
1298            if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1299            onFinishInputView(true);
1300        } else if (mCandidatesViewStarted) {
1301            if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1302            onFinishCandidatesView(true);
1303        }
1304        mInputViewStarted = false;
1305        mCandidatesViewStarted = false;
1306        if (mInputStarted) {
1307            if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
1308            onFinishInput();
1309        }
1310        mInputStarted = false;
1311        mStartedInputConnection = null;
1312        mCurCompletions = null;
1313    }
1314
1315    void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
1316        if (!restarting) {
1317            doFinishInput();
1318        }
1319        mInputStarted = true;
1320        mStartedInputConnection = ic;
1321        mInputEditorInfo = attribute;
1322        initialize();
1323        if (DEBUG) Log.v(TAG, "CALL: onStartInput");
1324        onStartInput(attribute, restarting);
1325        if (mWindowVisible) {
1326            if (mShowInputRequested) {
1327                if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1328                mInputViewStarted = true;
1329                onStartInputView(mInputEditorInfo, restarting);
1330                startExtractingText(true);
1331            } else if (mCandidatesVisibility == View.VISIBLE) {
1332                if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1333                mCandidatesViewStarted = true;
1334                onStartCandidatesView(mInputEditorInfo, restarting);
1335            }
1336        }
1337    }
1338
1339    /**
1340     * Called to inform the input method that text input has finished in
1341     * the last editor.  At this point there may be a call to
1342     * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
1343     * new editor, or the input method may be left idle.  This method is
1344     * <em>not</em> called when input restarts in the same editor.
1345     *
1346     * <p>The default
1347     * implementation uses the InputConnection to clear any active composing
1348     * text; you can override this (not calling the base class implementation)
1349     * to perform whatever behavior you would like.
1350     */
1351    public void onFinishInput() {
1352        InputConnection ic = getCurrentInputConnection();
1353        if (ic != null) {
1354            ic.finishComposingText();
1355        }
1356    }
1357
1358    /**
1359     * Called when the application has reported auto-completion candidates that
1360     * it would like to have the input method displayed.  Typically these are
1361     * only used when an input method is running in full-screen mode, since
1362     * otherwise the user can see and interact with the pop-up window of
1363     * completions shown by the application.
1364     *
1365     * <p>The default implementation here does nothing.
1366     */
1367    public void onDisplayCompletions(CompletionInfo[] completions) {
1368    }
1369
1370    /**
1371     * Called when the application has reported new extracted text to be shown
1372     * due to changes in its current text state.  The default implementation
1373     * here places the new text in the extract edit text, when the input
1374     * method is running in fullscreen mode.
1375     */
1376    public void onUpdateExtractedText(int token, ExtractedText text) {
1377        if (mExtractedToken != token) {
1378            return;
1379        }
1380        if (mExtractEditText != null && text != null) {
1381            mExtractedText = text;
1382            mExtractEditText.setExtractedText(text);
1383        }
1384    }
1385
1386    /**
1387     * Called when the application has reported a new selection region of
1388     * the text.  This is called whether or not the input method has requested
1389     * extracted text updates, although if so it will not receive this call
1390     * if the extracted text has changed as well.
1391     *
1392     * <p>The default implementation takes care of updating the cursor in
1393     * the extract text, if it is being shown.
1394     */
1395    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
1396            int newSelStart, int newSelEnd,
1397            int candidatesStart, int candidatesEnd) {
1398        final ExtractEditText eet = mExtractEditText;
1399        if (eet != null && mExtractedText != null) {
1400            final int off = mExtractedText.startOffset;
1401            eet.startInternalChanges();
1402            eet.setSelection(newSelStart-off, newSelEnd-off);
1403            eet.finishInternalChanges();
1404        }
1405    }
1406
1407    /**
1408     * Called when the application has reported a new location of its text
1409     * cursor.  This is only called if explicitly requested by the input method.
1410     * The default implementation does nothing.
1411     */
1412    public void onUpdateCursor(Rect newCursor) {
1413    }
1414
1415    /**
1416     * Close this input method's soft input area, removing it from the display.
1417     * The input method will continue running, but the user can no longer use
1418     * it to generate input by touching the screen.
1419     * @param flags Provides additional operating flags.  Currently may be
1420     * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY
1421     * InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
1422     */
1423    public void requestHideSelf(int flags) {
1424        mImm.hideSoftInputFromInputMethod(mToken, flags);
1425    }
1426
1427    /**
1428     * Show the input method. This is a call back to the
1429     * IMF to handle showing the input method.
1430     * Close this input method's soft input area, removing it from the display.
1431     * The input method will continue running, but the user can no longer use
1432     * it to generate input by touching the screen.
1433     * @param flags Provides additional operating flags.  Currently may be
1434     * 0 or have the {@link InputMethodManager#SHOW_FORCED
1435     * InputMethodManager.} bit set.
1436     */
1437    private void requestShowSelf(int flags) {
1438        mImm.showSoftInputFromInputMethod(mToken, flags);
1439    }
1440
1441    /**
1442     * Override this to intercept key down events before they are processed by the
1443     * application.  If you return true, the application will not itself
1444     * process the event.  If you return true, the normal application processing
1445     * will occur as if the IME had not seen the event at all.
1446     *
1447     * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
1448     * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown.  In
1449     * additional, in fullscreen mode only, it will consume DPAD movement
1450     * events to move the cursor in the extracted text view, not allowing
1451     * them to perform navigation in the underlying application.
1452     */
1453    public boolean onKeyDown(int keyCode, KeyEvent event) {
1454        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
1455                && event.getRepeatCount() == 0) {
1456            if (mShowInputRequested) {
1457                // If the soft input area is shown, back closes it and we
1458                // consume the back key.
1459                requestHideSelf(0);
1460                return true;
1461            } else if (mWindowVisible) {
1462                if (mCandidatesVisibility == View.VISIBLE) {
1463                    // If we are showing candidates even if no input area, then
1464                    // hide them.
1465                    setCandidatesViewShown(false);
1466                    return true;
1467                } else {
1468                    // If we have the window visible for some other reason --
1469                    // most likely to show candidates -- then just get rid
1470                    // of it.  This really shouldn't happen, but just in case...
1471                    hideWindow();
1472                    return true;
1473                }
1474            }
1475        }
1476        return doMovementKey(keyCode, event, MOVEMENT_DOWN);
1477    }
1478
1479    /**
1480     * Override this to intercept special key multiple events before they are
1481     * processed by the
1482     * application.  If you return true, the application will not itself
1483     * process the event.  If you return true, the normal application processing
1484     * will occur as if the IME had not seen the event at all.
1485     *
1486     * <p>The default implementation always returns false, except when
1487     * in fullscreen mode, where it will consume DPAD movement
1488     * events to move the cursor in the extracted text view, not allowing
1489     * them to perform navigation in the underlying application.
1490     */
1491    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
1492        return doMovementKey(keyCode, event, count);
1493    }
1494
1495    /**
1496     * Override this to intercept key up events before they are processed by the
1497     * application.  If you return true, the application will not itself
1498     * process the event.  If you return true, the normal application processing
1499     * will occur as if the IME had not seen the event at all.
1500     *
1501     * <p>The default implementation always returns false, except when
1502     * in fullscreen mode, where it will consume DPAD movement
1503     * events to move the cursor in the extracted text view, not allowing
1504     * them to perform navigation in the underlying application.
1505     */
1506    public boolean onKeyUp(int keyCode, KeyEvent event) {
1507        return doMovementKey(keyCode, event, MOVEMENT_UP);
1508    }
1509
1510    public boolean onTrackballEvent(MotionEvent event) {
1511        return false;
1512    }
1513
1514    public void onAppPrivateCommand(String action, Bundle data) {
1515    }
1516
1517    /**
1518     * Handle a request by the system to toggle the soft input area.
1519     */
1520    private void onToggleSoftInput(int showFlags, int hideFlags) {
1521        if (DEBUG) Log.v(TAG, "toggleSoftInput()");
1522        if (isInputViewShown()) {
1523            requestHideSelf(hideFlags);
1524        } else {
1525            requestShowSelf(showFlags);
1526        }
1527    }
1528
1529    static final int MOVEMENT_DOWN = -1;
1530    static final int MOVEMENT_UP = -2;
1531
1532    void reportExtractedMovement(int keyCode, int count) {
1533        int dx = 0, dy = 0;
1534        switch (keyCode) {
1535            case KeyEvent.KEYCODE_DPAD_LEFT:
1536                dx = -count;
1537                break;
1538            case KeyEvent.KEYCODE_DPAD_RIGHT:
1539                dx = count;
1540                break;
1541            case KeyEvent.KEYCODE_DPAD_UP:
1542                dy = -count;
1543                break;
1544            case KeyEvent.KEYCODE_DPAD_DOWN:
1545                dy = count;
1546                break;
1547        }
1548        onExtractedCursorMovement(dx, dy);
1549    }
1550
1551    boolean doMovementKey(int keyCode, KeyEvent event, int count) {
1552        final ExtractEditText eet = mExtractEditText;
1553        if (isFullscreenMode() && isInputViewShown() && eet != null) {
1554            // If we are in fullscreen mode, the cursor will move around
1555            // the extract edit text, but should NOT cause focus to move
1556            // to other fields.
1557            MovementMethod movement = eet.getMovementMethod();
1558            Layout layout = eet.getLayout();
1559            if (movement != null && layout != null) {
1560                // We want our own movement method to handle the key, so the
1561                // cursor will properly move in our own word wrapping.
1562                if (count == MOVEMENT_DOWN) {
1563                    if (movement.onKeyDown(eet,
1564                            (Spannable)eet.getText(), keyCode, event)) {
1565                        reportExtractedMovement(keyCode, 1);
1566                        return true;
1567                    }
1568                } else if (count == MOVEMENT_UP) {
1569                    if (movement.onKeyUp(eet,
1570                            (Spannable)eet.getText(), keyCode, event)) {
1571                        return true;
1572                    }
1573                } else {
1574                    if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
1575                        reportExtractedMovement(keyCode, count);
1576                    } else {
1577                        KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
1578                        if (movement.onKeyDown(eet,
1579                                (Spannable)eet.getText(), keyCode, down)) {
1580                            KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
1581                            movement.onKeyUp(eet,
1582                                    (Spannable)eet.getText(), keyCode, up);
1583                            while (--count > 0) {
1584                                movement.onKeyDown(eet,
1585                                        (Spannable)eet.getText(), keyCode, down);
1586                                movement.onKeyUp(eet,
1587                                        (Spannable)eet.getText(), keyCode, up);
1588                            }
1589                            reportExtractedMovement(keyCode, count);
1590                        }
1591                    }
1592                }
1593            }
1594            // Regardless of whether the movement method handled the key,
1595            // we never allow DPAD navigation to the application.
1596            switch (keyCode) {
1597                case KeyEvent.KEYCODE_DPAD_LEFT:
1598                case KeyEvent.KEYCODE_DPAD_RIGHT:
1599                case KeyEvent.KEYCODE_DPAD_UP:
1600                case KeyEvent.KEYCODE_DPAD_DOWN:
1601                    return true;
1602            }
1603        }
1604
1605        return false;
1606    }
1607
1608    /**
1609     * Send the given key event code (as defined by {@link KeyEvent}) to the
1610     * current input connection is a key down + key up event pair.  The sent
1611     * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
1612     * set, so that the recipient can identify them as coming from a software
1613     * input method, and
1614     * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
1615     * that they don't impact the current touch mode of the UI.
1616     *
1617     * @param keyEventCode The raw key code to send, as defined by
1618     * {@link KeyEvent}.
1619     */
1620    public void sendDownUpKeyEvents(int keyEventCode) {
1621        InputConnection ic = getCurrentInputConnection();
1622        if (ic == null) return;
1623        long eventTime = SystemClock.uptimeMillis();
1624        ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
1625                KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
1626                KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
1627        ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
1628                KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
1629                KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
1630    }
1631
1632    /**
1633     * Ask the input target to execute its default action via
1634     * {@link InputConnection#performEditorAction
1635     * InputConnection.performEditorAction()}.
1636     *
1637     * @param fromEnterKey If true, this will be executed as if the user had
1638     * pressed an enter key on the keyboard, that is it will <em>not</em>
1639     * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
1640     * EditorInfo.IME_FLAG_NO_ENTER_ACTION}.  If false, the action will be
1641     * sent regardless of how the editor has set that flag.
1642     *
1643     * @return Returns a boolean indicating whether an action has been sent.
1644     * If false, either the editor did not specify a default action or it
1645     * does not want an action from the enter key.  If true, the action was
1646     * sent (or there was no input connection at all).
1647     */
1648    public boolean sendDefaultEditorAction(boolean fromEnterKey) {
1649        EditorInfo ei = getCurrentInputEditorInfo();
1650        if (ei != null &&
1651                (!fromEnterKey || (ei.imeOptions &
1652                        EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
1653                (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
1654                    EditorInfo.IME_ACTION_NONE) {
1655            // If the enter key was pressed, and the editor has a default
1656            // action associated with pressing enter, then send it that
1657            // explicit action instead of the key event.
1658            InputConnection ic = getCurrentInputConnection();
1659            if (ic != null) {
1660                ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
1661            }
1662            return true;
1663        }
1664
1665        return false;
1666    }
1667
1668    /**
1669     * Send the given UTF-16 character to the current input connection.  Most
1670     * characters will be delivered simply by calling
1671     * {@link InputConnection#commitText InputConnection.commitText()} with
1672     * the character; some, however, may be handled different.  In particular,
1673     * the enter character ('\n') will either be delivered as an action code
1674     * or a raw key event, as appropriate.
1675     *
1676     * @param charCode The UTF-16 character code to send.
1677     */
1678    public void sendKeyChar(char charCode) {
1679        switch (charCode) {
1680            case '\n': // Apps may be listening to an enter key to perform an action
1681                if (!sendDefaultEditorAction(true)) {
1682                    sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
1683                }
1684                break;
1685            default:
1686                // Make sure that digits go through any text watcher on the client side.
1687                if (charCode >= '0' && charCode <= '9') {
1688                    sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
1689                } else {
1690                    InputConnection ic = getCurrentInputConnection();
1691                    if (ic != null) {
1692                        ic.commitText(String.valueOf((char) charCode), 1);
1693                    }
1694                }
1695                break;
1696        }
1697    }
1698
1699    /**
1700     * This is called when the user has moved the cursor in the extracted
1701     * text view, when running in fullsreen mode.  The default implementation
1702     * performs the corresponding selection change on the underlying text
1703     * editor.
1704     */
1705    public void onExtractedSelectionChanged(int start, int end) {
1706        InputConnection conn = getCurrentInputConnection();
1707        if (conn != null) {
1708            conn.setSelection(start, end);
1709        }
1710    }
1711
1712    /**
1713     * This is called when the user has clicked on the extracted text view,
1714     * when running in fullscreen mode.  The default implementation hides
1715     * the candidates view when this happens, but only if the extracted text
1716     * editor has a vertical scroll bar because its text doesn't fit.
1717     * Re-implement this to provide whatever behavior you want.
1718     */
1719    public void onExtractedTextClicked() {
1720        if (mExtractEditText == null) {
1721            return;
1722        }
1723        if (mExtractEditText.hasVerticalScrollBar()) {
1724            setCandidatesViewShown(false);
1725        }
1726    }
1727
1728    /**
1729     * This is called when the user has performed a cursor movement in the
1730     * extracted text view, when it is running in fullscreen mode.  The default
1731     * implementation hides the candidates view when a vertical movement
1732     * happens, but only if the extracted text editor has a vertical scroll bar
1733     * because its text doesn't fit.
1734     * Re-implement this to provide whatever behavior you want.
1735     * @param dx The amount of cursor movement in the x dimension.
1736     * @param dy The amount of cursor movement in the y dimension.
1737     */
1738    public void onExtractedCursorMovement(int dx, int dy) {
1739        if (mExtractEditText == null || dy == 0) {
1740            return;
1741        }
1742        if (mExtractEditText.hasVerticalScrollBar()) {
1743            setCandidatesViewShown(false);
1744        }
1745    }
1746
1747    /**
1748     * This is called when the user has selected a context menu item from the
1749     * extracted text view, when running in fullscreen mode.  The default
1750     * implementation sends this action to the current InputConnection's
1751     * {@link InputConnection#performContextMenuAction(int)}, for it
1752     * to be processed in underlying "real" editor.  Re-implement this to
1753     * provide whatever behavior you want.
1754     */
1755    public boolean onExtractTextContextMenuItem(int id) {
1756        InputConnection ic = getCurrentInputConnection();
1757        if (ic != null) {
1758            ic.performContextMenuAction(id);
1759        }
1760        return true;
1761    }
1762
1763    /**
1764     * Return text that can be used as a button label for the given
1765     * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.  Returns null
1766     * if there is no action requested.  Note that there is no guarantee that
1767     * the returned text will be relatively short, so you probably do not
1768     * want to use it as text on a soft keyboard key label.
1769     *
1770     * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
1771     *
1772     * @return Returns a label to use, or null if there is no action.
1773     */
1774    public CharSequence getTextForImeAction(int imeOptions) {
1775        switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
1776            case EditorInfo.IME_ACTION_NONE:
1777                return null;
1778            case EditorInfo.IME_ACTION_GO:
1779                return getText(com.android.internal.R.string.ime_action_go);
1780            case EditorInfo.IME_ACTION_SEARCH:
1781                return getText(com.android.internal.R.string.ime_action_search);
1782            case EditorInfo.IME_ACTION_SEND:
1783                return getText(com.android.internal.R.string.ime_action_send);
1784            case EditorInfo.IME_ACTION_NEXT:
1785                return getText(com.android.internal.R.string.ime_action_next);
1786            case EditorInfo.IME_ACTION_DONE:
1787                return getText(com.android.internal.R.string.ime_action_done);
1788            default:
1789                return getText(com.android.internal.R.string.ime_action_default);
1790        }
1791    }
1792
1793    /**
1794     * Called when it is time to update the actions available from a full-screen
1795     * IME.  You do not need to deal with this if you are using the standard
1796     * full screen extract UI.  If replacing it, you will need to re-implement
1797     * this to put the action in your own UI and handle it.
1798     */
1799    public void onUpdateExtractingAccessories(EditorInfo ei) {
1800        if (mExtractAccessories == null) {
1801            return;
1802        }
1803        final boolean hasAction = ei.actionLabel != null || (
1804                (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
1805                (ei.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0);
1806        if (hasAction) {
1807            mExtractAccessories.setVisibility(View.VISIBLE);
1808            if (ei.actionLabel != null) {
1809                mExtractAction.setText(ei.actionLabel);
1810            } else {
1811                mExtractAction.setText(getTextForImeAction(ei.imeOptions));
1812            }
1813            mExtractAction.setOnClickListener(mActionClickListener);
1814        } else {
1815            mExtractAccessories.setVisibility(View.GONE);
1816            mExtractAction.setOnClickListener(null);
1817        }
1818    }
1819
1820    /**
1821     * This is called when, while currently displayed in extract mode, the
1822     * current input target changes.  The default implementation will
1823     * auto-hide the IME if the new target is not a full editor, since this
1824     * can be an confusing experience for the user.
1825     */
1826    public void onExtractingInputChanged(EditorInfo ei) {
1827        if (ei.inputType == InputType.TYPE_NULL) {
1828            requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
1829        }
1830    }
1831
1832    void startExtractingText(boolean inputChanged) {
1833        final ExtractEditText eet = mExtractEditText;
1834        if (eet != null && getCurrentInputStarted()
1835                && isFullscreenMode()) {
1836            mExtractedToken++;
1837            ExtractedTextRequest req = new ExtractedTextRequest();
1838            req.token = mExtractedToken;
1839            req.flags = InputConnection.GET_TEXT_WITH_STYLES;
1840            req.hintMaxLines = 10;
1841            req.hintMaxChars = 10000;
1842            mExtractedText = getCurrentInputConnection().getExtractedText(req,
1843                    InputConnection.GET_EXTRACTED_TEXT_MONITOR);
1844
1845            final EditorInfo ei = getCurrentInputEditorInfo();
1846
1847            try {
1848                eet.startInternalChanges();
1849                onUpdateExtractingAccessories(ei);
1850                int inputType = ei.inputType;
1851                if ((inputType&EditorInfo.TYPE_MASK_CLASS)
1852                        == EditorInfo.TYPE_CLASS_TEXT) {
1853                    if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
1854                        inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
1855                    }
1856                }
1857                eet.setInputType(inputType);
1858                eet.setHint(ei.hintText);
1859                if (mExtractedText != null) {
1860                    eet.setEnabled(true);
1861                    eet.setExtractedText(mExtractedText);
1862                } else {
1863                    eet.setEnabled(false);
1864                    eet.setText("");
1865                }
1866            } finally {
1867                eet.finishInternalChanges();
1868            }
1869
1870            if (inputChanged) {
1871                onExtractingInputChanged(ei);
1872            }
1873        }
1874    }
1875
1876    /**
1877     * Performs a dump of the InputMethodService's internal state.  Override
1878     * to add your own information to the dump.
1879     */
1880    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1881        final Printer p = new PrintWriterPrinter(fout);
1882        p.println("Input method service state for " + this + ":");
1883        p.println("  mWindowCreated=" + mWindowCreated
1884                + " mWindowAdded=" + mWindowAdded
1885                + " mWindowVisible=" + mWindowVisible);
1886        p.println("  Configuration=" + getResources().getConfiguration());
1887        p.println("  mToken=" + mToken);
1888        p.println("  mInputBinding=" + mInputBinding);
1889        p.println("  mInputConnection=" + mInputConnection);
1890        p.println("  mStartedInputConnection=" + mStartedInputConnection);
1891        p.println("  mInputStarted=" + mInputStarted
1892                + " mInputViewStarted=" + mInputViewStarted
1893                + " mCandidatesViewStarted=" + mCandidatesViewStarted);
1894
1895        if (mInputEditorInfo != null) {
1896            p.println("  mInputEditorInfo:");
1897            mInputEditorInfo.dump(p, "    ");
1898        } else {
1899            p.println("  mInputEditorInfo: null");
1900        }
1901
1902        p.println("  mShowInputRequested=" + mShowInputRequested
1903                + " mLastShowInputRequested=" + mLastShowInputRequested
1904                + " mShowInputForced=" + mShowInputForced
1905                + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
1906        p.println("  mCandidatesVisibility=" + mCandidatesVisibility
1907                + " mFullscreenApplied=" + mFullscreenApplied
1908                + " mIsFullscreen=" + mIsFullscreen);
1909
1910        if (mExtractedText != null) {
1911            p.println("  mExtractedText:");
1912            p.println("    text=" + mExtractedText.text.length() + " chars"
1913                    + " startOffset=" + mExtractedText.startOffset);
1914            p.println("    selectionStart=" + mExtractedText.selectionStart
1915                    + " selectionEnd=" + mExtractedText.selectionEnd
1916                    + " flags=0x" + Integer.toHexString(mExtractedText.flags));
1917        } else {
1918            p.println("  mExtractedText: null");
1919        }
1920        p.println("  mExtractedToken=" + mExtractedToken);
1921        p.println("  mIsInputViewShown=" + mIsInputViewShown
1922                + " mStatusIcon=" + mStatusIcon);
1923        p.println("Last computed insets:");
1924        p.println("  contentTopInsets=" + mTmpInsets.contentTopInsets
1925                + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
1926                + " touchableInsets=" + mTmpInsets.touchableInsets);
1927    }
1928}
1929