blob: f07002e88bbeefca0efebc2a867744476ab1cfdc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Romain Guy980a9382010-01-08 15:06:28 -080019import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
21
Dianne Hackborn836531b2012-08-01 19:00:38 -070022import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.app.Dialog;
24import android.content.Context;
25import android.content.res.Configuration;
Dianne Hackbornd922ae02011-01-14 11:43:24 -080026import android.content.res.Resources;
The Android Open Source Project10592532009-03-18 17:39:46 -070027import android.content.res.TypedArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.graphics.Rect;
Jeff Brownfbf09772011-01-16 14:06:57 -080029import android.graphics.Region;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.Bundle;
31import android.os.IBinder;
The Android Open Source Project4df24232009-03-05 14:34:35 -080032import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.SystemClock;
34import android.provider.Settings;
35import android.text.InputType;
36import android.text.Layout;
37import android.text.Spannable;
38import android.text.method.MovementMethod;
39import android.util.Log;
40import android.util.PrintWriterPrinter;
41import android.util.Printer;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080042import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.view.KeyEvent;
44import android.view.LayoutInflater;
45import android.view.MotionEvent;
46import android.view.View;
47import android.view.ViewGroup;
48import android.view.ViewTreeObserver;
49import android.view.Window;
50import android.view.WindowManager;
The Android Open Source Project10592532009-03-18 17:39:46 -070051import android.view.animation.AnimationUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.view.inputmethod.CompletionInfo;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080053import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.view.inputmethod.ExtractedText;
55import android.view.inputmethod.ExtractedTextRequest;
56import android.view.inputmethod.InputBinding;
57import android.view.inputmethod.InputConnection;
58import android.view.inputmethod.InputMethod;
59import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +090060import android.view.inputmethod.InputMethodSubtype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.widget.Button;
62import android.widget.FrameLayout;
The Android Open Source Project10592532009-03-18 17:39:46 -070063import android.widget.LinearLayout;
64
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import java.io.FileDescriptor;
66import java.io.PrintWriter;
67
68/**
69 * InputMethodService provides a standard implementation of an InputMethod,
70 * which final implementations can derive from and customize. See the
71 * base class {@link AbstractInputMethodService} and the {@link InputMethod}
72 * interface for more information on the basics of writing input methods.
73 *
74 * <p>In addition to the normal Service lifecycle methods, this class
75 * introduces some new specific callbacks that most subclasses will want
76 * to make use of:</p>
77 * <ul>
78 * <li> {@link #onInitializeInterface()} for user-interface initialization,
79 * in particular to deal with configuration changes while the service is
80 * running.
81 * <li> {@link #onBindInput} to find out about switching to a new client.
82 * <li> {@link #onStartInput} to deal with an input session starting with
83 * the client.
84 * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
85 * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
86 * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
87 * starting within the input area of the IME.
88 * </ul>
89 *
90 * <p>An input method has significant discretion in how it goes about its
91 * work: the {@link android.inputmethodservice.InputMethodService} provides
92 * a basic framework for standard UI elements (input view, candidates view,
93 * and running in fullscreen mode), but it is up to a particular implementor
94 * to decide how to use them. For example, one input method could implement
95 * an input area with a keyboard, another could allow the user to draw text,
96 * while a third could have no input area (and thus not be visible to the
97 * user) but instead listen to audio and perform text to speech conversion.</p>
98 *
99 * <p>In the implementation provided here, all of these elements are placed
100 * together in a single window managed by the InputMethodService. It will
101 * execute callbacks as it needs information about them, and provides APIs for
102 * programmatic control over them. They layout of these elements is explicitly
103 * defined:</p>
104 *
105 * <ul>
106 * <li>The soft input view, if available, is placed at the bottom of the
107 * screen.
108 * <li>The candidates view, if currently shown, is placed above the soft
109 * input view.
110 * <li>If not running fullscreen, the application is moved or resized to be
111 * above these views; if running fullscreen, the window will completely cover
112 * the application and its top part will contain the extract text of what is
113 * currently being edited by the application.
114 * </ul>
115 *
116 *
117 * <a name="SoftInputView"></a>
118 * <h3>Soft Input View</h3>
119 *
120 * <p>Central to most input methods is the soft input view. This is where most
121 * user interaction occurs: pressing on soft keys, drawing characters, or
122 * however else your input method wants to generate text. Most implementations
123 * will simply have their own view doing all of this work, and return a new
124 * instance of it when {@link #onCreateInputView()} is called. At that point,
125 * as long as the input view is visible, you will see user interaction in
126 * that view and can call back on the InputMethodService to interact with the
127 * application as appropriate.</p>
128 *
129 * <p>There are some situations where you want to decide whether or not your
130 * soft input view should be shown to the user. This is done by implementing
131 * the {@link #onEvaluateInputViewShown()} to return true or false based on
132 * whether it should be shown in the current environment. If any of your
133 * state has changed that may impact this, call
134 * {@link #updateInputViewShown()} to have it re-evaluated. The default
135 * implementation always shows the input view unless there is a hard
136 * keyboard available, which is the appropriate behavior for most input
137 * methods.</p>
138 *
139 *
140 * <a name="CandidatesView"></a>
141 * <h3>Candidates View</h3>
142 *
143 * <p>Often while the user is generating raw text, an input method wants to
144 * provide them with a list of possible interpretations of that text that can
145 * be selected for use. This is accomplished with the candidates view, and
146 * like the soft input view you implement {@link #onCreateCandidatesView()}
147 * to instantiate your own view implementing your candidates UI.</p>
148 *
149 * <p>Management of the candidates view is a little different than the input
150 * view, because the candidates view tends to be more transient, being shown
151 * only when there are possible candidates for the current text being entered
152 * by the user. To control whether the candidates view is shown, you use
153 * {@link #setCandidatesViewShown(boolean)}. Note that because the candidate
154 * view tends to be shown and hidden a lot, it does not impact the application
155 * UI in the same way as the soft input view: it will never cause application
156 * windows to resize, only cause them to be panned if needed for the user to
157 * see the current focus.</p>
158 *
159 *
160 * <a name="FullscreenMode"></a>
161 * <h3>Fullscreen Mode</h3>
162 *
163 * <p>Sometimes your input method UI is too large to integrate with the
164 * application UI, so you just want to take over the screen. This is
165 * accomplished by switching to full-screen mode, causing the input method
166 * window to fill the entire screen and add its own "extracted text" editor
167 * showing the user the text that is being typed. Unlike the other UI elements,
168 * there is a standard implementation for the extract editor that you should
169 * not need to change. The editor is placed at the top of the IME, above the
170 * input and candidates views.</p>
171 *
172 * <p>Similar to the input view, you control whether the IME is running in
173 * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
174 * to return true or false based on
175 * whether it should be fullscreen in the current environment. If any of your
176 * state has changed that may impact this, call
177 * {@link #updateFullscreenMode()} to have it re-evaluated. The default
178 * implementation selects fullscreen mode when the screen is in a landscape
179 * orientation, which is appropriate behavior for most input methods that have
180 * a significant input area.</p>
181 *
182 * <p>When in fullscreen mode, you have some special requirements because the
183 * user can not see the application UI. In particular, you should implement
184 * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
185 * generated by your application, typically in your candidates view like you
186 * would normally show candidates.
187 *
188 *
189 * <a name="GeneratingText"></a>
190 * <h3>Generating Text</h3>
191 *
192 * <p>The key part of an IME is of course generating text for the application.
193 * This is done through calls to the
194 * {@link android.view.inputmethod.InputConnection} interface to the
195 * application, which can be retrieved from {@link #getCurrentInputConnection()}.
196 * This interface allows you to generate raw key events or, if the target
197 * supports it, directly edit in strings of candidates and committed text.</p>
198 *
199 * <p>Information about what the target is expected and supports can be found
200 * through the {@link android.view.inputmethod.EditorInfo} class, which is
201 * retrieved with {@link #getCurrentInputEditorInfo()} method. The most
202 * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
203 * EditorInfo.inputType}; in particular, if this is
204 * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
205 * then the target does not support complex edits and you need to only deliver
206 * raw key events to it. An input method will also want to look at other
207 * values here, to for example detect password mode, auto complete text views,
208 * phone number entry, etc.</p>
209 *
210 * <p>When the user switches between input targets, you will receive calls to
211 * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
212 * You can use these to reset and initialize your input state for the current
213 * target. For example, you will often want to clear any input state, and
214 * update a soft keyboard to be appropriate for the new inputType.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700215 *
216 * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground
217 * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
218 * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 */
220public class InputMethodService extends AbstractInputMethodService {
221 static final String TAG = "InputMethodService";
222 static final boolean DEBUG = false;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800223
224 /**
225 * The back button will close the input window.
226 */
227 public static final int BACK_DISPOSITION_DEFAULT = 0; // based on window
228
229 /**
230 * This input method will not consume the back key.
231 */
232 public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back
233
234 /**
235 * This input method will consume the back key.
236 */
237 public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down
238
239 /**
240 * @hide
241 * The IME is active. It may or may not be visible.
242 */
243 public static final int IME_ACTIVE = 0x1;
244
245 /**
246 * @hide
247 * The IME is visible.
248 */
249 public static final int IME_VISIBLE = 0x2;
250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 InputMethodManager mImm;
252
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800253 int mTheme = 0;
Dianne Hackborn836531b2012-08-01 19:00:38 -0700254 boolean mHardwareAccelerated = false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 LayoutInflater mInflater;
The Android Open Source Project10592532009-03-18 17:39:46 -0700257 TypedArray mThemeAttrs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 View mRootView;
259 SoftInputWindow mWindow;
260 boolean mInitialized;
261 boolean mWindowCreated;
262 boolean mWindowAdded;
263 boolean mWindowVisible;
The Android Open Source Project10592532009-03-18 17:39:46 -0700264 boolean mWindowWasVisible;
265 boolean mInShowWindow;
266 ViewGroup mFullscreenArea;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 FrameLayout mExtractFrame;
268 FrameLayout mCandidatesFrame;
269 FrameLayout mInputFrame;
270
271 IBinder mToken;
272
273 InputBinding mInputBinding;
274 InputConnection mInputConnection;
275 boolean mInputStarted;
276 boolean mInputViewStarted;
277 boolean mCandidatesViewStarted;
278 InputConnection mStartedInputConnection;
279 EditorInfo mInputEditorInfo;
280
281 int mShowInputFlags;
282 boolean mShowInputRequested;
283 boolean mLastShowInputRequested;
284 int mCandidatesVisibility;
285 CompletionInfo[] mCurCompletions;
286
287 boolean mShowInputForced;
288
289 boolean mFullscreenApplied;
290 boolean mIsFullscreen;
291 View mExtractView;
The Android Open Source Project10592532009-03-18 17:39:46 -0700292 boolean mExtractViewHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 ExtractEditText mExtractEditText;
294 ViewGroup mExtractAccessories;
295 Button mExtractAction;
296 ExtractedText mExtractedText;
297 int mExtractedToken;
298
299 View mInputView;
300 boolean mIsInputViewShown;
301
302 int mStatusIcon;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800303 int mBackDisposition;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304
305 final Insets mTmpInsets = new Insets();
306 final int[] mTmpLocation = new int[2];
satokab751aa2010-09-14 19:17:36 +0900307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
309 new ViewTreeObserver.OnComputeInternalInsetsListener() {
310 public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700311 if (isExtractViewShown()) {
312 // In true fullscreen mode, we just say the window isn't covering
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 // any content so we don't impact whatever is behind.
314 View decor = getWindow().getWindow().getDecorView();
315 info.contentInsets.top = info.visibleInsets.top
316 = decor.getHeight();
Jeff Brownfbf09772011-01-16 14:06:57 -0800317 info.touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
319 } else {
320 onComputeInsets(mTmpInsets);
321 info.contentInsets.top = mTmpInsets.contentTopInsets;
322 info.visibleInsets.top = mTmpInsets.visibleTopInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -0800323 info.touchableRegion.set(mTmpInsets.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 info.setTouchableInsets(mTmpInsets.touchableInsets);
325 }
326 }
327 };
328
329 final View.OnClickListener mActionClickListener = new View.OnClickListener() {
330 public void onClick(View v) {
331 final EditorInfo ei = getCurrentInputEditorInfo();
332 final InputConnection ic = getCurrentInputConnection();
333 if (ei != null && ic != null) {
334 if (ei.actionId != 0) {
335 ic.performEditorAction(ei.actionId);
336 } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION)
337 != EditorInfo.IME_ACTION_NONE) {
338 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
339 }
340 }
341 }
342 };
343
344 /**
345 * Concrete implementation of
346 * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
347 * all of the standard behavior for an input method.
348 */
349 public class InputMethodImpl extends AbstractInputMethodImpl {
350 /**
351 * Take care of attaching the given window token provided by the system.
352 */
353 public void attachToken(IBinder token) {
354 if (mToken == null) {
355 mToken = token;
356 mWindow.setToken(token);
357 }
358 }
359
360 /**
361 * Handle a new input binding, calling
362 * {@link InputMethodService#onBindInput InputMethodService.onBindInput()}
363 * when done.
364 */
365 public void bindInput(InputBinding binding) {
366 mInputBinding = binding;
367 mInputConnection = binding.getConnection();
368 if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
369 + " ic=" + mInputConnection);
370 InputConnection ic = getCurrentInputConnection();
371 if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
372 initialize();
373 onBindInput();
374 }
375
376 /**
377 * Clear the current input binding.
378 */
379 public void unbindInput() {
380 if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
381 + " ic=" + mInputConnection);
382 onUnbindInput();
383 mInputStarted = false;
384 mInputBinding = null;
385 mInputConnection = null;
386 }
387
388 public void startInput(InputConnection ic, EditorInfo attribute) {
389 if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
390 doStartInput(ic, attribute, false);
391 }
392
393 public void restartInput(InputConnection ic, EditorInfo attribute) {
394 if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
395 doStartInput(ic, attribute, true);
396 }
397
398 /**
399 * Handle a request by the system to hide the soft input area.
400 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800401 public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 if (DEBUG) Log.v(TAG, "hideSoftInput()");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800403 boolean wasVis = isInputViewShown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 mShowInputFlags = 0;
405 mShowInputRequested = false;
406 mShowInputForced = false;
satok2f913d92012-05-10 01:48:03 +0900407 doHideWindow();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800408 if (resultReceiver != null) {
409 resultReceiver.send(wasVis != isInputViewShown()
410 ? InputMethodManager.RESULT_HIDDEN
411 : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
412 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415
416 /**
417 * Handle a request by the system to show the soft input area.
418 */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800419 public void showSoftInput(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 if (DEBUG) Log.v(TAG, "showSoftInput()");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800421 boolean wasVis = isInputViewShown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 mShowInputFlags = 0;
423 if (onShowInputRequested(flags, false)) {
424 showWindow(true);
425 }
satok865b9772011-01-21 02:45:06 +0900426 // If user uses hard keyboard, IME button should always be shown.
Joe Onorato857fd9b2011-01-27 15:08:35 -0800427 boolean showing = onEvaluateInputViewShown();
428 mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
429 mBackDisposition);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800430 if (resultReceiver != null) {
431 resultReceiver.send(wasVis != isInputViewShown()
432 ? InputMethodManager.RESULT_SHOWN
433 : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
434 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
satokab751aa2010-09-14 19:17:36 +0900437
438 public void changeInputMethodSubtype(InputMethodSubtype subtype) {
439 onCurrentInputMethodSubtypeChanged(subtype);
440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 }
satokab751aa2010-09-14 19:17:36 +0900442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 /**
444 * Concrete implementation of
445 * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
446 * all of the standard behavior for an input method session.
447 */
448 public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
449 public void finishInput() {
450 if (!isEnabled()) {
451 return;
452 }
453 if (DEBUG) Log.v(TAG, "finishInput() in " + this);
454 doFinishInput();
455 }
456
457 /**
458 * Call {@link InputMethodService#onDisplayCompletions
459 * InputMethodService.onDisplayCompletions()}.
460 */
461 public void displayCompletions(CompletionInfo[] completions) {
462 if (!isEnabled()) {
463 return;
464 }
465 mCurCompletions = completions;
466 onDisplayCompletions(completions);
467 }
468
469 /**
470 * Call {@link InputMethodService#onUpdateExtractedText
471 * InputMethodService.onUpdateExtractedText()}.
472 */
473 public void updateExtractedText(int token, ExtractedText text) {
474 if (!isEnabled()) {
475 return;
476 }
477 onUpdateExtractedText(token, text);
478 }
479
480 /**
481 * Call {@link InputMethodService#onUpdateSelection
482 * InputMethodService.onUpdateSelection()}.
483 */
484 public void updateSelection(int oldSelStart, int oldSelEnd,
485 int newSelStart, int newSelEnd,
486 int candidatesStart, int candidatesEnd) {
487 if (!isEnabled()) {
488 return;
489 }
490 InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
491 newSelStart, newSelEnd, candidatesStart, candidatesEnd);
492 }
satok863fcd62011-06-21 17:38:02 +0900493
494 @Override
495 public void viewClicked(boolean focusChanged) {
496 if (!isEnabled()) {
497 return;
498 }
499 InputMethodService.this.onViewClicked(focusChanged);
500 }
501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 /**
503 * Call {@link InputMethodService#onUpdateCursor
504 * InputMethodService.onUpdateCursor()}.
505 */
506 public void updateCursor(Rect newCursor) {
507 if (!isEnabled()) {
508 return;
509 }
510 InputMethodService.this.onUpdateCursor(newCursor);
511 }
512
513 /**
514 * Call {@link InputMethodService#onAppPrivateCommand
515 * InputMethodService.onAppPrivateCommand()}.
516 */
517 public void appPrivateCommand(String action, Bundle data) {
518 if (!isEnabled()) {
519 return;
520 }
521 InputMethodService.this.onAppPrivateCommand(action, data);
522 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800523
524 /**
525 *
526 */
527 public void toggleSoftInput(int showFlags, int hideFlags) {
528 InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 }
531
532 /**
533 * Information about where interesting parts of the input method UI appear.
534 */
535 public static final class Insets {
536 /**
537 * This is the top part of the UI that is the main content. It is
538 * used to determine the basic space needed, to resize/pan the
539 * application behind. It is assumed that this inset does not
540 * change very much, since any change will cause a full resize/pan
541 * of the application behind. This value is relative to the top edge
542 * of the input method window.
543 */
544 public int contentTopInsets;
545
546 /**
547 * This is the top part of the UI that is visibly covering the
548 * application behind it. This provides finer-grained control over
549 * visibility, allowing you to change it relatively frequently (such
550 * as hiding or showing candidates) without disrupting the underlying
551 * UI too much. For example, this will never resize the application
552 * UI, will only pan if needed to make the current focus visible, and
553 * will not aggressively move the pan position when this changes unless
554 * needed to make the focus visible. This value is relative to the top edge
555 * of the input method window.
556 */
557 public int visibleTopInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -0800558
559 /**
560 * This is the region of the UI that is touchable. It is used when
561 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
562 * The region should be specified relative to the origin of the window frame.
563 */
564 public final Region touchableRegion = new Region();
565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 /**
567 * Option for {@link #touchableInsets}: the entire window frame
568 * can be touched.
569 */
570 public static final int TOUCHABLE_INSETS_FRAME
571 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
572
573 /**
574 * Option for {@link #touchableInsets}: the area inside of
575 * the content insets can be touched.
576 */
577 public static final int TOUCHABLE_INSETS_CONTENT
578 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
579
580 /**
581 * Option for {@link #touchableInsets}: the area inside of
582 * the visible insets can be touched.
583 */
584 public static final int TOUCHABLE_INSETS_VISIBLE
585 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -0800586
587 /**
588 * Option for {@link #touchableInsets}: the region specified by
589 * {@link #touchableRegion} can be touched.
590 */
591 public static final int TOUCHABLE_INSETS_REGION
592 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 /**
595 * Determine which area of the window is touchable by the user. May
596 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
Jeff Brownfbf09772011-01-16 14:06:57 -0800597 * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
598 * or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 */
600 public int touchableInsets;
601 }
satok865b9772011-01-21 02:45:06 +0900602
The Android Open Source Project10592532009-03-18 17:39:46 -0700603 /**
604 * You can call this to customize the theme used by your IME's window.
605 * This theme should typically be one that derives from
606 * {@link android.R.style#Theme_InputMethod}, which is the default theme
607 * you will get. This must be set before {@link #onCreate}, so you
608 * will typically call it in your constructor with the resource ID
609 * of your custom theme.
610 */
satokab751aa2010-09-14 19:17:36 +0900611 @Override
The Android Open Source Project10592532009-03-18 17:39:46 -0700612 public void setTheme(int theme) {
613 if (mWindow != null) {
614 throw new IllegalStateException("Must be called before onCreate()");
615 }
616 mTheme = theme;
617 }
satok865b9772011-01-21 02:45:06 +0900618
Dianne Hackborn836531b2012-08-01 19:00:38 -0700619 /**
620 * You can call this to try to enable hardware accelerated drawing for
621 * your IME. This must be set before {@link #onCreate}, so you
622 * will typically call it in your constructor. It is not always possible
623 * to use hardware acclerated drawing in an IME (for example on low-end
624 * devices that do not have the resources to support this), so the call
625 * returns true if it succeeds otherwise false if you will need to draw
626 * in software. You must be able to handle either case.
627 */
628 public boolean enableHardwareAcceleration() {
629 if (mWindow != null) {
630 throw new IllegalStateException("Must be called before onCreate()");
631 }
Jeff Brown98365d72012-08-19 20:30:52 -0700632 if (ActivityManager.isHighEndGfx()) {
Dianne Hackborn836531b2012-08-01 19:00:38 -0700633 mHardwareAccelerated = true;
634 return true;
635 }
636 return false;
637 }
638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 @Override public void onCreate() {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800640 mTheme = Resources.selectSystemTheme(mTheme,
641 getApplicationInfo().targetSdkVersion,
Adam Powell6e90a362011-08-14 16:48:32 -0700642 android.R.style.Theme_InputMethod,
Adam Powell36a97e402011-09-07 11:27:49 -0700643 android.R.style.Theme_Holo_InputMethod,
Adam Powell6e90a362011-08-14 16:48:32 -0700644 android.R.style.Theme_DeviceDefault_InputMethod);
The Android Open Source Project10592532009-03-18 17:39:46 -0700645 super.setTheme(mTheme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 super.onCreate();
647 mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
648 mInflater = (LayoutInflater)getSystemService(
649 Context.LAYOUT_INFLATER_SERVICE);
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700650 mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
Dianne Hackborn836531b2012-08-01 19:00:38 -0700651 if (mHardwareAccelerated) {
652 mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 initViews();
Romain Guy980a9382010-01-08 15:06:28 -0800655 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
satokab751aa2010-09-14 19:17:36 +0900657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 /**
659 * This is a hook that subclasses can use to perform initialization of
660 * their interface. It is called for you prior to any of your UI objects
661 * being created, both after the service is first created and after a
662 * configuration change happens.
663 */
664 public void onInitializeInterface() {
Gilles Debunne34703b62011-09-08 11:16:25 -0700665 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 }
satokab751aa2010-09-14 19:17:36 +0900667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 void initialize() {
669 if (!mInitialized) {
670 mInitialized = true;
671 onInitializeInterface();
672 }
673 }
satokab751aa2010-09-14 19:17:36 +0900674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 void initViews() {
676 mInitialized = false;
677 mWindowCreated = false;
678 mShowInputRequested = false;
679 mShowInputForced = false;
680
The Android Open Source Project10592532009-03-18 17:39:46 -0700681 mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 mRootView = mInflater.inflate(
683 com.android.internal.R.layout.input_method, null);
684 mWindow.setContentView(mRootView);
685 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
Jeff Sharkey6e2bee72012-10-01 13:39:08 -0700686 if (Settings.Global.getInt(getContentResolver(),
687 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 mWindow.getWindow().setWindowAnimations(
689 com.android.internal.R.style.Animation_InputMethodFancy);
690 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700691 mFullscreenArea = (ViewGroup)mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
692 mExtractViewHidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
694 mExtractView = null;
695 mExtractEditText = null;
696 mExtractAccessories = null;
697 mExtractAction = null;
698 mFullscreenApplied = false;
699
700 mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
701 mInputFrame = (FrameLayout)mRootView.findViewById(android.R.id.inputArea);
702 mInputView = null;
703 mIsInputViewShown = false;
704
705 mExtractFrame.setVisibility(View.GONE);
706 mCandidatesVisibility = getCandidatesHiddenVisibility();
707 mCandidatesFrame.setVisibility(mCandidatesVisibility);
708 mInputFrame.setVisibility(View.GONE);
709 }
satokab751aa2010-09-14 19:17:36 +0900710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 @Override public void onDestroy() {
712 super.onDestroy();
713 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
714 mInsetsComputer);
satokf17db9f2011-09-14 18:55:58 +0900715 finishViews();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 if (mWindowAdded) {
satokc0c87652011-09-12 12:08:05 +0900717 // Disable exit animation for the current IME window
718 // to avoid the race condition between the exit and enter animations
719 // when the current IME is being switched to another one.
720 mWindow.getWindow().setWindowAnimations(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 mWindow.dismiss();
722 }
723 }
satokf17db9f2011-09-14 18:55:58 +0900724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 /**
726 * Take care of handling configuration changes. Subclasses of
727 * InputMethodService generally don't need to deal directly with
728 * this on their own; the standard implementation here takes care of
729 * regenerating the input method UI as a result of the configuration
730 * change, so you can rely on your {@link #onCreateInputView} and
731 * other methods being called as appropriate due to a configuration change.
732 *
733 * <p>When a configuration change does happen,
734 * {@link #onInitializeInterface()} is guaranteed to be called the next
735 * time prior to any of the other input or UI creation callbacks. The
736 * following will be called immediately depending if appropriate for current
737 * state: {@link #onStartInput} if input is active, and
738 * {@link #onCreateInputView} and {@link #onStartInputView} and related
739 * appropriate functions if the UI is displayed.
740 */
741 @Override public void onConfigurationChanged(Configuration newConfig) {
742 super.onConfigurationChanged(newConfig);
743
744 boolean visible = mWindowVisible;
745 int showFlags = mShowInputFlags;
746 boolean showingInput = mShowInputRequested;
747 CompletionInfo[] completions = mCurCompletions;
748 initViews();
749 mInputViewStarted = false;
750 mCandidatesViewStarted = false;
751 if (mInputStarted) {
752 doStartInput(getCurrentInputConnection(),
753 getCurrentInputEditorInfo(), true);
754 }
755 if (visible) {
756 if (showingInput) {
757 // If we were last showing the soft keyboard, try to do so again.
758 if (onShowInputRequested(showFlags, true)) {
759 showWindow(true);
760 if (completions != null) {
761 mCurCompletions = completions;
762 onDisplayCompletions(completions);
763 }
764 } else {
satok2f913d92012-05-10 01:48:03 +0900765 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 } else if (mCandidatesVisibility == View.VISIBLE) {
768 // If the candidates are currently visible, make sure the
769 // window is shown for them.
770 showWindow(false);
771 } else {
772 // Otherwise hide the window.
satok2f913d92012-05-10 01:48:03 +0900773 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 }
satok865b9772011-01-21 02:45:06 +0900775 // If user uses hard keyboard, IME button should always be shown.
Joe Onorato857fd9b2011-01-27 15:08:35 -0800776 boolean showing = onEvaluateInputViewShown();
777 mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
778 mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 }
780 }
781
782 /**
783 * Implement to return our standard {@link InputMethodImpl}. Subclasses
784 * can override to provide their own customized version.
785 */
satokab751aa2010-09-14 19:17:36 +0900786 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 public AbstractInputMethodImpl onCreateInputMethodInterface() {
788 return new InputMethodImpl();
789 }
790
791 /**
792 * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses
793 * can override to provide their own customized version.
794 */
satokab751aa2010-09-14 19:17:36 +0900795 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
797 return new InputMethodSessionImpl();
798 }
799
800 public LayoutInflater getLayoutInflater() {
801 return mInflater;
802 }
803
804 public Dialog getWindow() {
805 return mWindow;
806 }
807
Joe Onorato857fd9b2011-01-27 15:08:35 -0800808 public void setBackDisposition(int disposition) {
809 mBackDisposition = disposition;
810 }
811
812 public int getBackDisposition() {
813 return mBackDisposition;
814 }
815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 /**
817 * Return the maximum width, in pixels, available the input method.
818 * Input methods are positioned at the bottom of the screen and, unless
819 * running in fullscreen, will generally want to be as short as possible
820 * so should compute their height based on their contents. However, they
821 * can stretch as much as needed horizontally. The function returns to
822 * you the maximum amount of space available horizontally, which you can
823 * use if needed for UI placement.
824 *
825 * <p>In many cases this is not needed, you can just rely on the normal
826 * view layout mechanisms to position your views within the full horizontal
827 * space given to the input method.
828 *
829 * <p>Note that this value can change dynamically, in particular when the
830 * screen orientation changes.
831 */
832 public int getMaxWidth() {
833 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
834 return wm.getDefaultDisplay().getWidth();
835 }
836
837 /**
838 * Return the currently active InputBinding for the input method, or
839 * null if there is none.
840 */
841 public InputBinding getCurrentInputBinding() {
842 return mInputBinding;
843 }
844
845 /**
846 * Retrieve the currently active InputConnection that is bound to
847 * the input method, or null if there is none.
848 */
849 public InputConnection getCurrentInputConnection() {
850 InputConnection ic = mStartedInputConnection;
851 if (ic != null) {
852 return ic;
853 }
854 return mInputConnection;
855 }
856
857 public boolean getCurrentInputStarted() {
858 return mInputStarted;
859 }
860
861 public EditorInfo getCurrentInputEditorInfo() {
862 return mInputEditorInfo;
863 }
864
865 /**
866 * Re-evaluate whether the input method should be running in fullscreen
867 * mode, and update its UI if this has changed since the last time it
868 * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to
869 * determine whether it should currently run in fullscreen mode. You
870 * can use {@link #isFullscreenMode()} to determine if the input method
871 * is currently running in fullscreen mode.
872 */
873 public void updateFullscreenMode() {
874 boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
875 boolean changed = mLastShowInputRequested != mShowInputRequested;
876 if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
877 changed = true;
878 mIsFullscreen = isFullscreen;
879 InputConnection ic = getCurrentInputConnection();
880 if (ic != null) ic.reportFullscreenMode(isFullscreen);
881 mFullscreenApplied = true;
882 initialize();
The Android Open Source Project10592532009-03-18 17:39:46 -0700883 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
884 mFullscreenArea.getLayoutParams();
885 if (isFullscreen) {
886 mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
887 com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
888 lp.height = 0;
889 lp.weight = 1;
890 } else {
891 mFullscreenArea.setBackgroundDrawable(null);
892 lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
893 lp.weight = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700895 ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
896 mFullscreenArea, lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 if (isFullscreen) {
898 if (mExtractView == null) {
899 View v = onCreateExtractTextView();
900 if (v != null) {
901 setExtractView(v);
902 }
903 }
904 startExtractingText(false);
905 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700906 updateExtractFrameVisibility();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 }
908
909 if (changed) {
Gilles Debunne34703b62011-09-08 11:16:25 -0700910 onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 mLastShowInputRequested = mShowInputRequested;
912 }
913 }
914
915 /**
916 * Update the given window's parameters for the given mode. This is called
917 * when the window is first displayed and each time the fullscreen or
918 * candidates only mode changes.
919 *
920 * <p>The default implementation makes the layout for the window
Romain Guy980a9382010-01-08 15:06:28 -0800921 * MATCH_PARENT x MATCH_PARENT when in fullscreen mode, and
922 * MATCH_PARENT x WRAP_CONTENT when in non-fullscreen mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 *
924 * @param win The input method's window.
925 * @param isFullscreen If true, the window is running in fullscreen mode
926 * and intended to cover the entire application display.
927 * @param isCandidatesOnly If true, the window is only showing the
928 * candidates view and none of the rest of its UI. This is mutually
929 * exclusive with fullscreen mode.
930 */
931 public void onConfigureWindow(Window win, boolean isFullscreen,
932 boolean isCandidatesOnly) {
933 if (isFullscreen) {
Romain Guy980a9382010-01-08 15:06:28 -0800934 mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 } else {
Romain Guy980a9382010-01-08 15:06:28 -0800936 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
938 }
939
940 /**
941 * Return whether the input method is <em>currently</em> running in
942 * fullscreen mode. This is the mode that was last determined and
943 * applied by {@link #updateFullscreenMode()}.
944 */
945 public boolean isFullscreenMode() {
946 return mIsFullscreen;
947 }
948
949 /**
950 * Override this to control when the input method should run in
951 * fullscreen mode. The default implementation runs in fullsceen only
952 * when the screen is in landscape mode. If you change what
953 * this returns, you will need to call {@link #updateFullscreenMode()}
954 * yourself whenever the returned value may have changed to have it
955 * re-evaluated and applied.
956 */
957 public boolean onEvaluateFullscreenMode() {
958 Configuration config = getResources().getConfiguration();
Leon Scroggins2edd6822010-01-12 11:36:13 -0500959 if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
960 return false;
961 }
962 if (mInputEditorInfo != null
963 && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
964 return false;
965 }
966 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
Gilles Debunne34703b62011-09-08 11:16:25 -0700968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700970 * Controls the visibility of the extracted text area. This only applies
971 * when the input method is in fullscreen mode, and thus showing extracted
972 * text. When false, the extracted text will not be shown, allowing some
973 * of the application to be seen behind. This is normally set for you
974 * by {@link #onUpdateExtractingVisibility}. This controls the visibility
975 * of both the extracted text and candidate view; the latter since it is
976 * not useful if there is no text to see.
977 */
978 public void setExtractViewShown(boolean shown) {
979 if (mExtractViewHidden == shown) {
980 mExtractViewHidden = !shown;
981 updateExtractFrameVisibility();
982 }
983 }
984
985 /**
986 * Return whether the fullscreen extract view is shown. This will only
987 * return true if {@link #isFullscreenMode()} returns true, and in that
988 * case its value depends on the last call to
989 * {@link #setExtractViewShown(boolean)}. This effectively lets you
990 * determine if the application window is entirely covered (when this
991 * returns true) or if some part of it may be shown (if this returns
992 * false, though if {@link #isFullscreenMode()} returns true in that case
993 * then it is probably only a sliver of the application).
994 */
995 public boolean isExtractViewShown() {
996 return mIsFullscreen && !mExtractViewHidden;
997 }
998
999 void updateExtractFrameVisibility() {
1000 int vis;
1001 if (isFullscreenMode()) {
1002 vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
1003 mExtractFrame.setVisibility(View.VISIBLE);
1004 } else {
1005 vis = View.VISIBLE;
1006 mExtractFrame.setVisibility(View.GONE);
1007 }
1008 updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
1009 if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
1010 int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
1011 ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
1012 : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
1013 0);
1014 if (animRes != 0) {
1015 mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
1016 this, animRes));
1017 }
1018 }
1019 mFullscreenArea.setVisibility(vis);
1020 }
1021
1022 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 * Compute the interesting insets into your UI. The default implementation
1024 * uses the top of the candidates frame for the visible insets, and the
1025 * top of the input frame for the content insets. The default touchable
1026 * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
1027 *
The Android Open Source Project10592532009-03-18 17:39:46 -07001028 * <p>Note that this method is not called when
1029 * {@link #isExtractViewShown} returns true, since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 * in that case the application is left as-is behind the input method and
1031 * not impacted by anything in its UI.
1032 *
1033 * @param outInsets Fill in with the current UI insets.
1034 */
1035 public void onComputeInsets(Insets outInsets) {
1036 int[] loc = mTmpLocation;
1037 if (mInputFrame.getVisibility() == View.VISIBLE) {
1038 mInputFrame.getLocationInWindow(loc);
1039 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001040 View decor = getWindow().getWindow().getDecorView();
1041 loc[1] = decor.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001043 if (isFullscreenMode()) {
1044 // In fullscreen mode, we never resize the underlying window.
1045 View decor = getWindow().getWindow().getDecorView();
1046 outInsets.contentTopInsets = decor.getHeight();
1047 } else {
1048 outInsets.contentTopInsets = loc[1];
1049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
1051 mCandidatesFrame.getLocationInWindow(loc);
1052 }
1053 outInsets.visibleTopInsets = loc[1];
1054 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -08001055 outInsets.touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
1057
1058 /**
1059 * Re-evaluate whether the soft input area should currently be shown, and
1060 * update its UI if this has changed since the last time it
1061 * was evaluated. This will call {@link #onEvaluateInputViewShown()} to
1062 * determine whether the input view should currently be shown. You
1063 * can use {@link #isInputViewShown()} to determine if the input view
1064 * is currently shown.
1065 */
1066 public void updateInputViewShown() {
1067 boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
1068 if (mIsInputViewShown != isShown && mWindowVisible) {
1069 mIsInputViewShown = isShown;
1070 mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
1071 if (mInputView == null) {
1072 initialize();
1073 View v = onCreateInputView();
1074 if (v != null) {
1075 setInputView(v);
1076 }
1077 }
1078 }
1079 }
1080
1081 /**
1082 * Returns true if we have been asked to show our input view.
1083 */
1084 public boolean isShowInputRequested() {
1085 return mShowInputRequested;
1086 }
1087
1088 /**
1089 * Return whether the soft input view is <em>currently</em> shown to the
1090 * user. This is the state that was last determined and
1091 * applied by {@link #updateInputViewShown()}.
1092 */
1093 public boolean isInputViewShown() {
1094 return mIsInputViewShown && mWindowVisible;
1095 }
1096
1097 /**
1098 * Override this to control when the soft input area should be shown to
1099 * the user. The default implementation only shows the input view when
1100 * there is no hard keyboard or the keyboard is hidden. If you change what
1101 * this returns, you will need to call {@link #updateInputViewShown()}
1102 * yourself whenever the returned value may have changed to have it
Gilles Debunne8cbb4c62011-01-24 12:33:56 -08001103 * re-evaluated and applied.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 */
1105 public boolean onEvaluateInputViewShown() {
1106 Configuration config = getResources().getConfiguration();
1107 return config.keyboard == Configuration.KEYBOARD_NOKEYS
Ken Wakasa8710e762011-01-30 11:02:09 +09001108 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 }
1110
1111 /**
1112 * Controls the visibility of the candidates display area. By default
1113 * it is hidden.
1114 */
1115 public void setCandidatesViewShown(boolean shown) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001116 updateCandidatesVisibility(shown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 if (!mShowInputRequested && mWindowVisible != shown) {
1118 // If we are being asked to show the candidates view while the app
1119 // has not asked for the input view to be shown, then we need
1120 // to update whether the window is shown.
1121 if (shown) {
1122 showWindow(false);
1123 } else {
satok2f913d92012-05-10 01:48:03 +09001124 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 }
1126 }
1127 }
1128
The Android Open Source Project10592532009-03-18 17:39:46 -07001129 void updateCandidatesVisibility(boolean shown) {
1130 int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
1131 if (mCandidatesVisibility != vis) {
1132 mCandidatesFrame.setVisibility(vis);
1133 mCandidatesVisibility = vis;
1134 }
1135 }
1136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 /**
1138 * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
1139 * or {@link View#GONE View.GONE}) of the candidates view when it is not
The Android Open Source Project10592532009-03-18 17:39:46 -07001140 * shown. The default implementation returns GONE when
1141 * {@link #isExtractViewShown} returns true,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 * otherwise VISIBLE. Be careful if you change this to return GONE in
1143 * other situations -- if showing or hiding the candidates view causes
1144 * your window to resize, this can cause temporary drawing artifacts as
1145 * the resize takes place.
1146 */
1147 public int getCandidatesHiddenVisibility() {
The Android Open Source Project10592532009-03-18 17:39:46 -07001148 return isExtractViewShown() ? View.GONE : View.INVISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 }
1150
1151 public void showStatusIcon(int iconResId) {
1152 mStatusIcon = iconResId;
1153 mImm.showStatusIcon(mToken, getPackageName(), iconResId);
1154 }
1155
1156 public void hideStatusIcon() {
1157 mStatusIcon = 0;
1158 mImm.hideStatusIcon(mToken);
1159 }
1160
1161 /**
1162 * Force switch to a new input method, as identified by <var>id</var>. This
1163 * input method will be destroyed, and the requested one started on the
1164 * current input field.
1165 *
1166 * @param id Unique identifier of the new input method ot start.
1167 */
1168 public void switchInputMethod(String id) {
1169 mImm.setInputMethod(mToken, id);
1170 }
1171
1172 public void setExtractView(View view) {
1173 mExtractFrame.removeAllViews();
1174 mExtractFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001175 ViewGroup.LayoutParams.MATCH_PARENT,
1176 ViewGroup.LayoutParams.MATCH_PARENT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 mExtractView = view;
1178 if (view != null) {
1179 mExtractEditText = (ExtractEditText)view.findViewById(
1180 com.android.internal.R.id.inputExtractEditText);
1181 mExtractEditText.setIME(this);
1182 mExtractAction = (Button)view.findViewById(
1183 com.android.internal.R.id.inputExtractAction);
1184 if (mExtractAction != null) {
1185 mExtractAccessories = (ViewGroup)view.findViewById(
1186 com.android.internal.R.id.inputExtractAccessories);
1187 }
1188 startExtractingText(false);
1189 } else {
1190 mExtractEditText = null;
1191 mExtractAccessories = null;
1192 mExtractAction = null;
1193 }
1194 }
1195
1196 /**
1197 * Replaces the current candidates view with a new one. You only need to
1198 * call this when dynamically changing the view; normally, you should
1199 * implement {@link #onCreateCandidatesView()} and create your view when
1200 * first needed by the input method.
1201 */
1202 public void setCandidatesView(View view) {
1203 mCandidatesFrame.removeAllViews();
1204 mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001205 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 ViewGroup.LayoutParams.WRAP_CONTENT));
1207 }
1208
1209 /**
1210 * Replaces the current input view with a new one. You only need to
1211 * call this when dynamically changing the view; normally, you should
1212 * implement {@link #onCreateInputView()} and create your view when
1213 * first needed by the input method.
1214 */
1215 public void setInputView(View view) {
1216 mInputFrame.removeAllViews();
1217 mInputFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001218 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 ViewGroup.LayoutParams.WRAP_CONTENT));
1220 mInputView = view;
1221 }
1222
1223 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 * Called by the framework to create the layout for showing extacted text.
1225 * Only called when in fullscreen mode. The returned view hierarchy must
1226 * have an {@link ExtractEditText} whose ID is
1227 * {@link android.R.id#inputExtractEditText}.
1228 */
1229 public View onCreateExtractTextView() {
1230 return mInflater.inflate(
1231 com.android.internal.R.layout.input_method_extract_view, null);
1232 }
1233
1234 /**
1235 * Create and return the view hierarchy used to show candidates. This will
1236 * be called once, when the candidates are first displayed. You can return
1237 * null to have no candidates view; the default implementation returns null.
1238 *
1239 * <p>To control when the candidates view is displayed, use
1240 * {@link #setCandidatesViewShown(boolean)}.
1241 * To change the candidates view after the first one is created by this
1242 * function, use {@link #setCandidatesView(View)}.
1243 */
1244 public View onCreateCandidatesView() {
1245 return null;
1246 }
1247
1248 /**
1249 * Create and return the view hierarchy used for the input area (such as
1250 * a soft keyboard). This will be called once, when the input area is
1251 * first displayed. You can return null to have no input area; the default
1252 * implementation returns null.
1253 *
1254 * <p>To control when the input view is displayed, implement
1255 * {@link #onEvaluateInputViewShown()}.
1256 * To change the input view after the first one is created by this
1257 * function, use {@link #setInputView(View)}.
1258 */
1259 public View onCreateInputView() {
1260 return null;
1261 }
1262
1263 /**
1264 * Called when the input view is being shown and input has started on
1265 * a new editor. This will always be called after {@link #onStartInput},
1266 * allowing you to do your general setup there and just view-specific
1267 * setup here. You are guaranteed that {@link #onCreateInputView()} will
1268 * have been called some time before this function is called.
1269 *
1270 * @param info Description of the type of text being edited.
1271 * @param restarting Set to true if we are restarting input on the
1272 * same text field as before.
1273 */
1274 public void onStartInputView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001275 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
1277
1278 /**
1279 * Called when the input view is being hidden from the user. This will
1280 * be called either prior to hiding the window, or prior to switching to
1281 * another target for editing.
1282 *
1283 * <p>The default
1284 * implementation uses the InputConnection to clear any active composing
1285 * text; you can override this (not calling the base class implementation)
1286 * to perform whatever behavior you would like.
1287 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001288 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 * called immediately after.
1290 */
1291 public void onFinishInputView(boolean finishingInput) {
1292 if (!finishingInput) {
1293 InputConnection ic = getCurrentInputConnection();
1294 if (ic != null) {
1295 ic.finishComposingText();
1296 }
1297 }
1298 }
1299
1300 /**
1301 * Called when only the candidates view has been shown for showing
1302 * processing as the user enters text through a hard keyboard.
1303 * This will always be called after {@link #onStartInput},
1304 * allowing you to do your general setup there and just view-specific
1305 * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
1306 * will have been called some time before this function is called.
1307 *
1308 * <p>Note that this will <em>not</em> be called when the input method
1309 * is running in full editing mode, and thus receiving
1310 * {@link #onStartInputView} to initiate that operation. This is only
1311 * for the case when candidates are being shown while the input method
1312 * editor is hidden but wants to show its candidates UI as text is
1313 * entered through some other mechanism.
1314 *
1315 * @param info Description of the type of text being edited.
1316 * @param restarting Set to true if we are restarting input on the
1317 * same text field as before.
1318 */
1319 public void onStartCandidatesView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001320 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 }
1322
1323 /**
1324 * Called when the candidates view is being hidden from the user. This will
1325 * be called either prior to hiding the window, or prior to switching to
1326 * another target for editing.
1327 *
1328 * <p>The default
1329 * implementation uses the InputConnection to clear any active composing
1330 * text; you can override this (not calling the base class implementation)
1331 * to perform whatever behavior you would like.
1332 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001333 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 * called immediately after.
1335 */
1336 public void onFinishCandidatesView(boolean finishingInput) {
1337 if (!finishingInput) {
1338 InputConnection ic = getCurrentInputConnection();
1339 if (ic != null) {
1340 ic.finishComposingText();
1341 }
1342 }
1343 }
1344
1345 /**
1346 * The system has decided that it may be time to show your input method.
1347 * This is called due to a corresponding call to your
The Android Open Source Project4df24232009-03-05 14:34:35 -08001348 * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 * method. The default implementation uses
1350 * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
1351 * and the current configuration to decide whether the input view should
1352 * be shown at this point.
1353 *
1354 * @param flags Provides additional information about the show request,
The Android Open Source Project4df24232009-03-05 14:34:35 -08001355 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 * @param configChange This is true if we are re-showing due to a
1357 * configuration change.
1358 * @return Returns true to indicate that the window should be shown.
1359 */
1360 public boolean onShowInputRequested(int flags, boolean configChange) {
1361 if (!onEvaluateInputViewShown()) {
1362 return false;
1363 }
1364 if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
1365 if (!configChange && onEvaluateFullscreenMode()) {
1366 // Don't show if this is not explicitly requested by the user and
1367 // the input method is fullscreen. That would be too disruptive.
1368 // However, we skip this change for a config change, since if
1369 // the IME is already shown we do want to go into fullscreen
1370 // mode at this point.
1371 return false;
1372 }
1373 Configuration config = getResources().getConfiguration();
1374 if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {
1375 // And if the device has a hard keyboard, even if it is
1376 // currently hidden, don't show the input method implicitly.
1377 // These kinds of devices don't need it that much.
1378 return false;
1379 }
1380 }
1381 if ((flags&InputMethod.SHOW_FORCED) != 0) {
1382 mShowInputForced = true;
1383 }
1384 return true;
1385 }
1386
1387 public void showWindow(boolean showInput) {
1388 if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
1389 + " mShowInputRequested=" + mShowInputRequested
1390 + " mWindowAdded=" + mWindowAdded
1391 + " mWindowCreated=" + mWindowCreated
1392 + " mWindowVisible=" + mWindowVisible
1393 + " mInputStarted=" + mInputStarted);
The Android Open Source Project10592532009-03-18 17:39:46 -07001394
1395 if (mInShowWindow) {
1396 Log.w(TAG, "Re-entrance in to showWindow");
1397 return;
1398 }
1399
1400 try {
1401 mWindowWasVisible = mWindowVisible;
1402 mInShowWindow = true;
1403 showWindowInner(showInput);
1404 } finally {
1405 mWindowWasVisible = true;
1406 mInShowWindow = false;
1407 }
1408 }
satok06487a52010-10-29 11:37:18 +09001409
The Android Open Source Project10592532009-03-18 17:39:46 -07001410 void showWindowInner(boolean showInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 boolean doShowInput = false;
1412 boolean wasVisible = mWindowVisible;
1413 mWindowVisible = true;
1414 if (!mShowInputRequested) {
1415 if (mInputStarted) {
1416 if (showInput) {
1417 doShowInput = true;
1418 mShowInputRequested = true;
1419 }
1420 }
1421 } else {
1422 showInput = true;
1423 }
satok06487a52010-10-29 11:37:18 +09001424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 if (DEBUG) Log.v(TAG, "showWindow: updating UI");
1426 initialize();
1427 updateFullscreenMode();
1428 updateInputViewShown();
1429
1430 if (!mWindowAdded || !mWindowCreated) {
1431 mWindowAdded = true;
1432 mWindowCreated = true;
1433 initialize();
1434 if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
1435 View v = onCreateCandidatesView();
1436 if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
1437 if (v != null) {
1438 setCandidatesView(v);
1439 }
1440 }
1441 if (mShowInputRequested) {
1442 if (!mInputViewStarted) {
1443 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1444 mInputViewStarted = true;
1445 onStartInputView(mInputEditorInfo, false);
1446 }
1447 } else if (!mCandidatesViewStarted) {
1448 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1449 mCandidatesViewStarted = true;
1450 onStartCandidatesView(mInputEditorInfo, false);
1451 }
1452
1453 if (doShowInput) {
1454 startExtractingText(false);
1455 }
satok06487a52010-10-29 11:37:18 +09001456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 if (!wasVisible) {
1458 if (DEBUG) Log.v(TAG, "showWindow: showing!");
Joe Onorato857fd9b2011-01-27 15:08:35 -08001459 mImm.setImeWindowStatus(mToken, IME_ACTIVE, mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 onWindowShown();
1461 mWindow.show();
1462 }
1463 }
satok06487a52010-10-29 11:37:18 +09001464
satokf17db9f2011-09-14 18:55:58 +09001465 private void finishViews() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 if (mInputViewStarted) {
1467 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1468 onFinishInputView(false);
1469 } else if (mCandidatesViewStarted) {
1470 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1471 onFinishCandidatesView(false);
1472 }
1473 mInputViewStarted = false;
1474 mCandidatesViewStarted = false;
satokf17db9f2011-09-14 18:55:58 +09001475 }
1476
satok2f913d92012-05-10 01:48:03 +09001477 private void doHideWindow() {
1478 mImm.setImeWindowStatus(mToken, 0, mBackDisposition);
1479 hideWindow();
1480 }
1481
satokf17db9f2011-09-14 18:55:58 +09001482 public void hideWindow() {
1483 finishViews();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 if (mWindowVisible) {
1485 mWindow.hide();
1486 mWindowVisible = false;
1487 onWindowHidden();
The Android Open Source Project10592532009-03-18 17:39:46 -07001488 mWindowWasVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490 }
satok06487a52010-10-29 11:37:18 +09001491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 /**
1493 * Called when the input method window has been shown to the user, after
1494 * previously not being visible. This is done after all of the UI setup
1495 * for the window has occurred (creating its views etc).
1496 */
1497 public void onWindowShown() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001498 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 }
1500
1501 /**
1502 * Called when the input method window has been hidden from the user,
1503 * after previously being visible.
1504 */
1505 public void onWindowHidden() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001506 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 }
1508
1509 /**
1510 * Called when a new client has bound to the input method. This
1511 * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
1512 * and {@link #onFinishInput()} calls as the user navigates through its
1513 * UI. Upon this call you know that {@link #getCurrentInputBinding}
1514 * and {@link #getCurrentInputConnection} return valid objects.
1515 */
1516 public void onBindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001517 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 }
1519
1520 /**
1521 * Called when the previous bound client is no longer associated
1522 * with the input method. After returning {@link #getCurrentInputBinding}
1523 * and {@link #getCurrentInputConnection} will no longer return
1524 * valid objects.
1525 */
1526 public void onUnbindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001527 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
1529
1530 /**
1531 * Called to inform the input method that text input has started in an
1532 * editor. You should use this callback to initialize the state of your
1533 * input to match the state of the editor given to it.
1534 *
1535 * @param attribute The attributes of the editor that input is starting
1536 * in.
1537 * @param restarting Set to true if input is restarting in the same
1538 * editor such as because the application has changed the text in
1539 * the editor. Otherwise will be false, indicating this is a new
1540 * session with the editor.
1541 */
1542 public void onStartInput(EditorInfo attribute, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001543 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 }
1545
1546 void doFinishInput() {
1547 if (mInputViewStarted) {
1548 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1549 onFinishInputView(true);
1550 } else if (mCandidatesViewStarted) {
1551 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1552 onFinishCandidatesView(true);
1553 }
1554 mInputViewStarted = false;
1555 mCandidatesViewStarted = false;
1556 if (mInputStarted) {
1557 if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
1558 onFinishInput();
1559 }
1560 mInputStarted = false;
1561 mStartedInputConnection = null;
1562 mCurCompletions = null;
1563 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
1566 if (!restarting) {
1567 doFinishInput();
1568 }
1569 mInputStarted = true;
1570 mStartedInputConnection = ic;
1571 mInputEditorInfo = attribute;
1572 initialize();
1573 if (DEBUG) Log.v(TAG, "CALL: onStartInput");
1574 onStartInput(attribute, restarting);
1575 if (mWindowVisible) {
1576 if (mShowInputRequested) {
1577 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1578 mInputViewStarted = true;
1579 onStartInputView(mInputEditorInfo, restarting);
1580 startExtractingText(true);
1581 } else if (mCandidatesVisibility == View.VISIBLE) {
1582 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1583 mCandidatesViewStarted = true;
1584 onStartCandidatesView(mInputEditorInfo, restarting);
1585 }
1586 }
1587 }
1588
1589 /**
1590 * Called to inform the input method that text input has finished in
1591 * the last editor. At this point there may be a call to
1592 * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
1593 * new editor, or the input method may be left idle. This method is
1594 * <em>not</em> called when input restarts in the same editor.
1595 *
1596 * <p>The default
1597 * implementation uses the InputConnection to clear any active composing
1598 * text; you can override this (not calling the base class implementation)
1599 * to perform whatever behavior you would like.
1600 */
1601 public void onFinishInput() {
1602 InputConnection ic = getCurrentInputConnection();
1603 if (ic != null) {
1604 ic.finishComposingText();
1605 }
1606 }
1607
1608 /**
1609 * Called when the application has reported auto-completion candidates that
1610 * it would like to have the input method displayed. Typically these are
1611 * only used when an input method is running in full-screen mode, since
1612 * otherwise the user can see and interact with the pop-up window of
1613 * completions shown by the application.
1614 *
1615 * <p>The default implementation here does nothing.
1616 */
1617 public void onDisplayCompletions(CompletionInfo[] completions) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001618 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 }
1620
1621 /**
1622 * Called when the application has reported new extracted text to be shown
1623 * due to changes in its current text state. The default implementation
1624 * here places the new text in the extract edit text, when the input
1625 * method is running in fullscreen mode.
1626 */
1627 public void onUpdateExtractedText(int token, ExtractedText text) {
1628 if (mExtractedToken != token) {
1629 return;
1630 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001631 if (text != null) {
1632 if (mExtractEditText != null) {
1633 mExtractedText = text;
1634 mExtractEditText.setExtractedText(text);
1635 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 }
1637 }
1638
1639 /**
1640 * Called when the application has reported a new selection region of
1641 * the text. This is called whether or not the input method has requested
1642 * extracted text updates, although if so it will not receive this call
1643 * if the extracted text has changed as well.
1644 *
1645 * <p>The default implementation takes care of updating the cursor in
1646 * the extract text, if it is being shown.
1647 */
1648 public void onUpdateSelection(int oldSelStart, int oldSelEnd,
1649 int newSelStart, int newSelEnd,
1650 int candidatesStart, int candidatesEnd) {
1651 final ExtractEditText eet = mExtractEditText;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001652 if (eet != null && isFullscreenMode() && mExtractedText != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 final int off = mExtractedText.startOffset;
1654 eet.startInternalChanges();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001655 newSelStart -= off;
1656 newSelEnd -= off;
1657 final int len = eet.getText().length();
1658 if (newSelStart < 0) newSelStart = 0;
1659 else if (newSelStart > len) newSelStart = len;
1660 if (newSelEnd < 0) newSelEnd = 0;
1661 else if (newSelEnd > len) newSelEnd = len;
1662 eet.setSelection(newSelStart, newSelEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 eet.finishInternalChanges();
1664 }
1665 }
1666
1667 /**
satok863fcd62011-06-21 17:38:02 +09001668 * Called when the user tapped or clicked a text view.
1669 * IMEs can't rely on this method being called because this was not part of the original IME
1670 * protocol, so applications with custom text editing written before this method appeared will
1671 * not call to inform the IME of this interaction.
1672 * @param focusChanged true if the user changed the focused view by this click.
1673 */
1674 public void onViewClicked(boolean focusChanged) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001675 // Intentionally empty
satok863fcd62011-06-21 17:38:02 +09001676 }
1677
1678 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 * Called when the application has reported a new location of its text
1680 * cursor. This is only called if explicitly requested by the input method.
1681 * The default implementation does nothing.
1682 */
1683 public void onUpdateCursor(Rect newCursor) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001684 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 }
1686
1687 /**
1688 * Close this input method's soft input area, removing it from the display.
1689 * The input method will continue running, but the user can no longer use
1690 * it to generate input by touching the screen.
1691 * @param flags Provides additional operating flags. Currently may be
1692 * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY
1693 * InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
1694 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001695 public void requestHideSelf(int flags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 mImm.hideSoftInputFromInputMethod(mToken, flags);
1697 }
1698
1699 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -08001700 * Show the input method. This is a call back to the
1701 * IMF to handle showing the input method.
The Android Open Source Project4df24232009-03-05 14:34:35 -08001702 * @param flags Provides additional operating flags. Currently may be
1703 * 0 or have the {@link InputMethodManager#SHOW_FORCED
1704 * InputMethodManager.} bit set.
1705 */
1706 private void requestShowSelf(int flags) {
1707 mImm.showSoftInputFromInputMethod(mToken, flags);
1708 }
1709
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001710 private boolean handleBack(boolean doIt) {
1711 if (mShowInputRequested) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001712 if (isExtractViewShown() && mExtractView instanceof ExtractEditLayout) {
1713 ExtractEditLayout extractEditLayout = (ExtractEditLayout) mExtractView;
1714 if (extractEditLayout.isActionModeStarted()) {
1715 if (doIt) extractEditLayout.finishActionMode();
1716 return true;
1717 }
1718 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001719 // If the soft input area is shown, back closes it and we
1720 // consume the back key.
1721 if (doIt) requestHideSelf(0);
1722 return true;
1723 } else if (mWindowVisible) {
1724 if (mCandidatesVisibility == View.VISIBLE) {
1725 // If we are showing candidates even if no input area, then
1726 // hide them.
1727 if (doIt) setCandidatesViewShown(false);
1728 } else {
1729 // If we have the window visible for some other reason --
1730 // most likely to show candidates -- then just get rid
1731 // of it. This really shouldn't happen, but just in case...
satok2f913d92012-05-10 01:48:03 +09001732 if (doIt) doHideWindow();
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001733 }
1734 return true;
1735 }
1736 return false;
1737 }
1738
The Android Open Source Project4df24232009-03-05 14:34:35 -08001739 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 * Override this to intercept key down events before they are processed by the
Quddus Chongee71b1f2012-04-12 11:49:37 -07001741 * application. If you return true, the application will not
1742 * process the event itself. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 * will occur as if the IME had not seen the event at all.
1744 *
1745 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001746 * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
1747 * possibly hide it when the key goes up (if not canceled or long pressed). In
1748 * addition, in fullscreen mode only, it will consume DPAD movement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 * events to move the cursor in the extracted text view, not allowing
1750 * them to perform navigation in the underlying application.
1751 */
1752 public boolean onKeyDown(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001753 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
1754 if (handleBack(false)) {
1755 event.startTracking();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001758 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 return doMovementKey(keyCode, event, MOVEMENT_DOWN);
1761 }
1762
1763 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001764 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
1765 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
1766 * the event).
1767 */
1768 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1769 return false;
1770 }
1771
1772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 * Override this to intercept special key multiple events before they are
1774 * processed by the
1775 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07001776 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 * will occur as if the IME had not seen the event at all.
1778 *
1779 * <p>The default implementation always returns false, except when
1780 * in fullscreen mode, where it will consume DPAD movement
1781 * events to move the cursor in the extracted text view, not allowing
1782 * them to perform navigation in the underlying application.
1783 */
1784 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
1785 return doMovementKey(keyCode, event, count);
1786 }
1787
1788 /**
1789 * Override this to intercept key up events before they are processed by the
1790 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07001791 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 * will occur as if the IME had not seen the event at all.
1793 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001794 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
1795 * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
1796 * addition, in fullscreen mode only, it will consume DPAD movement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 * events to move the cursor in the extracted text view, not allowing
1798 * them to perform navigation in the underlying application.
1799 */
1800 public boolean onKeyUp(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001801 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isTracking()
1802 && !event.isCanceled()) {
1803 return handleBack(true);
1804 }
1805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 return doMovementKey(keyCode, event, MOVEMENT_UP);
1807 }
1808
Victoria Leaseb38070c2012-08-24 13:46:02 -07001809 /**
1810 * Override this to intercept trackball motion events before they are
1811 * processed by the application.
1812 * If you return true, the application will not itself process the event.
1813 * If you return false, the normal application processing will occur as if
1814 * the IME had not seen the event at all.
1815 */
satokab751aa2010-09-14 19:17:36 +09001816 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 public boolean onTrackballEvent(MotionEvent event) {
Victoria Leaseb38070c2012-08-24 13:46:02 -07001818 if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
1819 return false;
1820 }
1821
1822 /**
1823 * Override this to intercept generic motion events before they are
1824 * processed by the application.
1825 * If you return true, the application will not itself process the event.
1826 * If you return false, the normal application processing will occur as if
1827 * the IME had not seen the event at all.
1828 */
1829 @Override
1830 public boolean onGenericMotionEvent(MotionEvent event) {
1831 if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 return false;
1833 }
1834
1835 public void onAppPrivateCommand(String action, Bundle data) {
1836 }
1837
The Android Open Source Project4df24232009-03-05 14:34:35 -08001838 /**
1839 * Handle a request by the system to toggle the soft input area.
1840 */
1841 private void onToggleSoftInput(int showFlags, int hideFlags) {
1842 if (DEBUG) Log.v(TAG, "toggleSoftInput()");
1843 if (isInputViewShown()) {
1844 requestHideSelf(hideFlags);
1845 } else {
1846 requestShowSelf(showFlags);
1847 }
1848 }
1849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 static final int MOVEMENT_DOWN = -1;
1851 static final int MOVEMENT_UP = -2;
1852
1853 void reportExtractedMovement(int keyCode, int count) {
1854 int dx = 0, dy = 0;
1855 switch (keyCode) {
1856 case KeyEvent.KEYCODE_DPAD_LEFT:
1857 dx = -count;
1858 break;
1859 case KeyEvent.KEYCODE_DPAD_RIGHT:
1860 dx = count;
1861 break;
1862 case KeyEvent.KEYCODE_DPAD_UP:
1863 dy = -count;
1864 break;
1865 case KeyEvent.KEYCODE_DPAD_DOWN:
1866 dy = count;
1867 break;
1868 }
satokab751aa2010-09-14 19:17:36 +09001869 onExtractedCursorMovement(dx, dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 }
1871
1872 boolean doMovementKey(int keyCode, KeyEvent event, int count) {
1873 final ExtractEditText eet = mExtractEditText;
The Android Open Source Project10592532009-03-18 17:39:46 -07001874 if (isExtractViewShown() && isInputViewShown() && eet != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 // If we are in fullscreen mode, the cursor will move around
1876 // the extract edit text, but should NOT cause focus to move
1877 // to other fields.
1878 MovementMethod movement = eet.getMovementMethod();
1879 Layout layout = eet.getLayout();
1880 if (movement != null && layout != null) {
1881 // We want our own movement method to handle the key, so the
1882 // cursor will properly move in our own word wrapping.
1883 if (count == MOVEMENT_DOWN) {
1884 if (movement.onKeyDown(eet,
1885 (Spannable)eet.getText(), keyCode, event)) {
1886 reportExtractedMovement(keyCode, 1);
1887 return true;
1888 }
1889 } else if (count == MOVEMENT_UP) {
1890 if (movement.onKeyUp(eet,
1891 (Spannable)eet.getText(), keyCode, event)) {
1892 return true;
1893 }
1894 } else {
1895 if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
1896 reportExtractedMovement(keyCode, count);
1897 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001898 KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 if (movement.onKeyDown(eet,
1900 (Spannable)eet.getText(), keyCode, down)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001901 KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 movement.onKeyUp(eet,
1903 (Spannable)eet.getText(), keyCode, up);
1904 while (--count > 0) {
1905 movement.onKeyDown(eet,
1906 (Spannable)eet.getText(), keyCode, down);
1907 movement.onKeyUp(eet,
1908 (Spannable)eet.getText(), keyCode, up);
1909 }
1910 reportExtractedMovement(keyCode, count);
1911 }
1912 }
1913 }
1914 }
1915 // Regardless of whether the movement method handled the key,
1916 // we never allow DPAD navigation to the application.
1917 switch (keyCode) {
1918 case KeyEvent.KEYCODE_DPAD_LEFT:
1919 case KeyEvent.KEYCODE_DPAD_RIGHT:
1920 case KeyEvent.KEYCODE_DPAD_UP:
1921 case KeyEvent.KEYCODE_DPAD_DOWN:
1922 return true;
1923 }
1924 }
1925
1926 return false;
1927 }
1928
1929 /**
1930 * Send the given key event code (as defined by {@link KeyEvent}) to the
1931 * current input connection is a key down + key up event pair. The sent
1932 * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
1933 * set, so that the recipient can identify them as coming from a software
1934 * input method, and
1935 * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
1936 * that they don't impact the current touch mode of the UI.
1937 *
Jean Chalard405bc512012-05-29 19:12:34 +09001938 * <p>Note that it's discouraged to send such key events in normal operation;
1939 * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
1940 * text fields, or for non-rich input methods. A reasonably capable software
1941 * input method should use the
1942 * {@link android.view.inputmethod.InputConnection#commitText} family of methods
1943 * to send text to an application, rather than sending key events.</p>
1944 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 * @param keyEventCode The raw key code to send, as defined by
1946 * {@link KeyEvent}.
1947 */
1948 public void sendDownUpKeyEvents(int keyEventCode) {
1949 InputConnection ic = getCurrentInputConnection();
1950 if (ic == null) return;
1951 long eventTime = SystemClock.uptimeMillis();
1952 ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001953 KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
1955 ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001956 KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
1958 }
1959
1960 /**
1961 * Ask the input target to execute its default action via
1962 * {@link InputConnection#performEditorAction
1963 * InputConnection.performEditorAction()}.
1964 *
1965 * @param fromEnterKey If true, this will be executed as if the user had
1966 * pressed an enter key on the keyboard, that is it will <em>not</em>
1967 * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
1968 * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
1969 * sent regardless of how the editor has set that flag.
1970 *
1971 * @return Returns a boolean indicating whether an action has been sent.
1972 * If false, either the editor did not specify a default action or it
1973 * does not want an action from the enter key. If true, the action was
1974 * sent (or there was no input connection at all).
1975 */
1976 public boolean sendDefaultEditorAction(boolean fromEnterKey) {
1977 EditorInfo ei = getCurrentInputEditorInfo();
1978 if (ei != null &&
1979 (!fromEnterKey || (ei.imeOptions &
1980 EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
1981 (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
1982 EditorInfo.IME_ACTION_NONE) {
1983 // If the enter key was pressed, and the editor has a default
1984 // action associated with pressing enter, then send it that
1985 // explicit action instead of the key event.
1986 InputConnection ic = getCurrentInputConnection();
1987 if (ic != null) {
1988 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
1989 }
1990 return true;
1991 }
1992
1993 return false;
1994 }
1995
1996 /**
1997 * Send the given UTF-16 character to the current input connection. Most
1998 * characters will be delivered simply by calling
1999 * {@link InputConnection#commitText InputConnection.commitText()} with
2000 * the character; some, however, may be handled different. In particular,
2001 * the enter character ('\n') will either be delivered as an action code
Jean Chalard405bc512012-05-29 19:12:34 +09002002 * or a raw key event, as appropriate. Consider this as a convenience
2003 * method for IMEs that do not have a full implementation of actions; a
2004 * fully complying IME will decide of the right action for each event and
2005 * will likely never call this method except maybe to handle events coming
2006 * from an actual hardware keyboard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 *
2008 * @param charCode The UTF-16 character code to send.
2009 */
2010 public void sendKeyChar(char charCode) {
2011 switch (charCode) {
2012 case '\n': // Apps may be listening to an enter key to perform an action
2013 if (!sendDefaultEditorAction(true)) {
2014 sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
2015 }
2016 break;
2017 default:
2018 // Make sure that digits go through any text watcher on the client side.
2019 if (charCode >= '0' && charCode <= '9') {
2020 sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
2021 } else {
2022 InputConnection ic = getCurrentInputConnection();
2023 if (ic != null) {
2024 ic.commitText(String.valueOf((char) charCode), 1);
2025 }
2026 }
2027 break;
2028 }
2029 }
2030
2031 /**
2032 * This is called when the user has moved the cursor in the extracted
2033 * text view, when running in fullsreen mode. The default implementation
2034 * performs the corresponding selection change on the underlying text
2035 * editor.
2036 */
2037 public void onExtractedSelectionChanged(int start, int end) {
2038 InputConnection conn = getCurrentInputConnection();
2039 if (conn != null) {
2040 conn.setSelection(start, end);
2041 }
2042 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002043
2044 /**
2045 * @hide
2046 */
2047 public void onExtractedDeleteText(int start, int end) {
2048 InputConnection conn = getCurrentInputConnection();
2049 if (conn != null) {
2050 conn.setSelection(start, start);
2051 conn.deleteSurroundingText(0, end-start);
2052 }
2053 }
2054
2055 /**
2056 * @hide
2057 */
2058 public void onExtractedReplaceText(int start, int end, CharSequence text) {
2059 InputConnection conn = getCurrentInputConnection();
2060 if (conn != null) {
2061 conn.setComposingRegion(start, end);
2062 conn.commitText(text, 1);
2063 }
2064 }
2065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 /**
Gilles Debunnee300be92011-12-06 10:15:56 -08002067 * @hide
2068 */
2069 public void onExtractedSetSpan(Object span, int start, int end, int flags) {
2070 InputConnection conn = getCurrentInputConnection();
2071 if (conn != null) {
2072 if (!conn.setSelection(start, end)) return;
2073 CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
2074 if (text instanceof Spannable) {
2075 ((Spannable) text).setSpan(span, 0, text.length(), flags);
2076 conn.setComposingRegion(start, end);
2077 conn.commitText(text, 1);
2078 }
2079 }
2080 }
2081
2082 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 * This is called when the user has clicked on the extracted text view,
2084 * when running in fullscreen mode. The default implementation hides
2085 * the candidates view when this happens, but only if the extracted text
2086 * editor has a vertical scroll bar because its text doesn't fit.
2087 * Re-implement this to provide whatever behavior you want.
2088 */
2089 public void onExtractedTextClicked() {
2090 if (mExtractEditText == null) {
2091 return;
2092 }
2093 if (mExtractEditText.hasVerticalScrollBar()) {
2094 setCandidatesViewShown(false);
2095 }
2096 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 /**
2099 * This is called when the user has performed a cursor movement in the
2100 * extracted text view, when it is running in fullscreen mode. The default
2101 * implementation hides the candidates view when a vertical movement
2102 * happens, but only if the extracted text editor has a vertical scroll bar
2103 * because its text doesn't fit.
2104 * Re-implement this to provide whatever behavior you want.
2105 * @param dx The amount of cursor movement in the x dimension.
2106 * @param dy The amount of cursor movement in the y dimension.
2107 */
2108 public void onExtractedCursorMovement(int dx, int dy) {
2109 if (mExtractEditText == null || dy == 0) {
2110 return;
2111 }
2112 if (mExtractEditText.hasVerticalScrollBar()) {
2113 setCandidatesViewShown(false);
2114 }
2115 }
2116
2117 /**
2118 * This is called when the user has selected a context menu item from the
2119 * extracted text view, when running in fullscreen mode. The default
2120 * implementation sends this action to the current InputConnection's
2121 * {@link InputConnection#performContextMenuAction(int)}, for it
2122 * to be processed in underlying "real" editor. Re-implement this to
2123 * provide whatever behavior you want.
2124 */
2125 public boolean onExtractTextContextMenuItem(int id) {
2126 InputConnection ic = getCurrentInputConnection();
2127 if (ic != null) {
2128 ic.performContextMenuAction(id);
2129 }
2130 return true;
2131 }
2132
2133 /**
2134 * Return text that can be used as a button label for the given
2135 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
2136 * if there is no action requested. Note that there is no guarantee that
2137 * the returned text will be relatively short, so you probably do not
2138 * want to use it as text on a soft keyboard key label.
2139 *
2140 * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
2141 *
2142 * @return Returns a label to use, or null if there is no action.
2143 */
2144 public CharSequence getTextForImeAction(int imeOptions) {
2145 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2146 case EditorInfo.IME_ACTION_NONE:
2147 return null;
2148 case EditorInfo.IME_ACTION_GO:
2149 return getText(com.android.internal.R.string.ime_action_go);
2150 case EditorInfo.IME_ACTION_SEARCH:
2151 return getText(com.android.internal.R.string.ime_action_search);
2152 case EditorInfo.IME_ACTION_SEND:
2153 return getText(com.android.internal.R.string.ime_action_send);
2154 case EditorInfo.IME_ACTION_NEXT:
2155 return getText(com.android.internal.R.string.ime_action_next);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002156 case EditorInfo.IME_ACTION_DONE:
2157 return getText(com.android.internal.R.string.ime_action_done);
Dianne Hackborndea3ef72010-10-28 14:24:22 -07002158 case EditorInfo.IME_ACTION_PREVIOUS:
2159 return getText(com.android.internal.R.string.ime_action_previous);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 default:
2161 return getText(com.android.internal.R.string.ime_action_default);
2162 }
2163 }
2164
2165 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07002166 * Called when the fullscreen-mode extracting editor info has changed,
2167 * to determine whether the extracting (extract text and candidates) portion
2168 * of the UI should be shown. The standard implementation hides or shows
2169 * the extract area depending on whether it makes sense for the
2170 * current editor. In particular, a {@link InputType#TYPE_NULL}
2171 * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
2172 * turn off the extract area since there is no text to be shown.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 */
The Android Open Source Project10592532009-03-18 17:39:46 -07002174 public void onUpdateExtractingVisibility(EditorInfo ei) {
2175 if (ei.inputType == InputType.TYPE_NULL ||
2176 (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
2177 // No reason to show extract UI!
2178 setExtractViewShown(false);
2179 return;
2180 }
2181
2182 setExtractViewShown(true);
2183 }
2184
2185 /**
2186 * Called when the fullscreen-mode extracting editor info has changed,
2187 * to update the state of its UI such as the action buttons shown.
2188 * You do not need to deal with this if you are using the standard
2189 * full screen extract UI. If replacing it, you will need to re-implement
2190 * this to put the appropriate action button in your own UI and handle it,
2191 * and perform any other changes.
2192 *
2193 * <p>The standard implementation turns on or off its accessory area
2194 * depending on whether there is an action button, and hides or shows
2195 * the entire extract area depending on whether it makes sense for the
2196 * current editor. In particular, a {@link InputType#TYPE_NULL} or
2197 * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
2198 * extract area since there is no text to be shown.
2199 */
2200 public void onUpdateExtractingViews(EditorInfo ei) {
2201 if (!isExtractViewShown()) {
2202 return;
2203 }
2204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 if (mExtractAccessories == null) {
2206 return;
2207 }
2208 final boolean hasAction = ei.actionLabel != null || (
2209 (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
The Android Open Source Project10592532009-03-18 17:39:46 -07002210 (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
2211 ei.inputType != InputType.TYPE_NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 if (hasAction) {
2213 mExtractAccessories.setVisibility(View.VISIBLE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002214 if (mExtractAction != null) {
2215 if (ei.actionLabel != null) {
2216 mExtractAction.setText(ei.actionLabel);
2217 } else {
2218 mExtractAction.setText(getTextForImeAction(ei.imeOptions));
2219 }
2220 mExtractAction.setOnClickListener(mActionClickListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 } else {
2223 mExtractAccessories.setVisibility(View.GONE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002224 if (mExtractAction != null) {
2225 mExtractAction.setOnClickListener(null);
2226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228 }
2229
2230 /**
2231 * This is called when, while currently displayed in extract mode, the
2232 * current input target changes. The default implementation will
2233 * auto-hide the IME if the new target is not a full editor, since this
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002234 * can be a confusing experience for the user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 */
2236 public void onExtractingInputChanged(EditorInfo ei) {
2237 if (ei.inputType == InputType.TYPE_NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002238 requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 }
2240 }
2241
2242 void startExtractingText(boolean inputChanged) {
2243 final ExtractEditText eet = mExtractEditText;
2244 if (eet != null && getCurrentInputStarted()
2245 && isFullscreenMode()) {
2246 mExtractedToken++;
2247 ExtractedTextRequest req = new ExtractedTextRequest();
2248 req.token = mExtractedToken;
2249 req.flags = InputConnection.GET_TEXT_WITH_STYLES;
2250 req.hintMaxLines = 10;
2251 req.hintMaxChars = 10000;
Amith Yamasaniba4d93f2009-08-19 18:27:56 -07002252 InputConnection ic = getCurrentInputConnection();
2253 mExtractedText = ic == null? null
2254 : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
Amith Yamasania8b00c82010-03-05 15:41:31 -08002255 if (mExtractedText == null || ic == null) {
2256 Log.e(TAG, "Unexpected null in startExtractingText : mExtractedText = "
2257 + mExtractedText + ", input connection = " + ic);
2258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 final EditorInfo ei = getCurrentInputEditorInfo();
2260
2261 try {
2262 eet.startInternalChanges();
The Android Open Source Project10592532009-03-18 17:39:46 -07002263 onUpdateExtractingVisibility(ei);
2264 onUpdateExtractingViews(ei);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 int inputType = ei.inputType;
2266 if ((inputType&EditorInfo.TYPE_MASK_CLASS)
2267 == EditorInfo.TYPE_CLASS_TEXT) {
2268 if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
2269 inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
2270 }
2271 }
2272 eet.setInputType(inputType);
2273 eet.setHint(ei.hintText);
2274 if (mExtractedText != null) {
2275 eet.setEnabled(true);
2276 eet.setExtractedText(mExtractedText);
2277 } else {
2278 eet.setEnabled(false);
2279 eet.setText("");
2280 }
2281 } finally {
2282 eet.finishInternalChanges();
2283 }
2284
2285 if (inputChanged) {
2286 onExtractingInputChanged(ei);
2287 }
2288 }
2289 }
satokab751aa2010-09-14 19:17:36 +09002290
2291 // TODO: Handle the subtype change event
2292 /**
2293 * Called when the subtype was changed.
2294 * @param newSubtype the subtype which is being changed to.
2295 */
2296 protected void onCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2297 if (DEBUG) {
2298 int nameResId = newSubtype.getNameResId();
satok9ef02832010-11-04 21:17:48 +09002299 String mode = newSubtype.getMode();
satokab751aa2010-09-14 19:17:36 +09002300 String output = "changeInputMethodSubtype:"
2301 + (nameResId == 0 ? "<none>" : getString(nameResId)) + ","
satok9ef02832010-11-04 21:17:48 +09002302 + mode + ","
satokab751aa2010-09-14 19:17:36 +09002303 + newSubtype.getLocale() + "," + newSubtype.getExtraValue();
2304 Log.v(TAG, "--- " + output);
2305 }
2306 }
2307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 /**
2309 * Performs a dump of the InputMethodService's internal state. Override
2310 * to add your own information to the dump.
2311 */
2312 @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2313 final Printer p = new PrintWriterPrinter(fout);
2314 p.println("Input method service state for " + this + ":");
2315 p.println(" mWindowCreated=" + mWindowCreated
The Android Open Source Project10592532009-03-18 17:39:46 -07002316 + " mWindowAdded=" + mWindowAdded);
2317 p.println(" mWindowVisible=" + mWindowVisible
2318 + " mWindowWasVisible=" + mWindowWasVisible
2319 + " mInShowWindow=" + mInShowWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002320 p.println(" Configuration=" + getResources().getConfiguration());
2321 p.println(" mToken=" + mToken);
2322 p.println(" mInputBinding=" + mInputBinding);
2323 p.println(" mInputConnection=" + mInputConnection);
2324 p.println(" mStartedInputConnection=" + mStartedInputConnection);
2325 p.println(" mInputStarted=" + mInputStarted
2326 + " mInputViewStarted=" + mInputViewStarted
2327 + " mCandidatesViewStarted=" + mCandidatesViewStarted);
2328
2329 if (mInputEditorInfo != null) {
2330 p.println(" mInputEditorInfo:");
2331 mInputEditorInfo.dump(p, " ");
2332 } else {
2333 p.println(" mInputEditorInfo: null");
2334 }
2335
2336 p.println(" mShowInputRequested=" + mShowInputRequested
2337 + " mLastShowInputRequested=" + mLastShowInputRequested
2338 + " mShowInputForced=" + mShowInputForced
2339 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
2340 p.println(" mCandidatesVisibility=" + mCandidatesVisibility
2341 + " mFullscreenApplied=" + mFullscreenApplied
The Android Open Source Project10592532009-03-18 17:39:46 -07002342 + " mIsFullscreen=" + mIsFullscreen
2343 + " mExtractViewHidden=" + mExtractViewHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344
2345 if (mExtractedText != null) {
2346 p.println(" mExtractedText:");
2347 p.println(" text=" + mExtractedText.text.length() + " chars"
2348 + " startOffset=" + mExtractedText.startOffset);
2349 p.println(" selectionStart=" + mExtractedText.selectionStart
2350 + " selectionEnd=" + mExtractedText.selectionEnd
2351 + " flags=0x" + Integer.toHexString(mExtractedText.flags));
2352 } else {
2353 p.println(" mExtractedText: null");
2354 }
2355 p.println(" mExtractedToken=" + mExtractedToken);
2356 p.println(" mIsInputViewShown=" + mIsInputViewShown
2357 + " mStatusIcon=" + mStatusIcon);
2358 p.println("Last computed insets:");
2359 p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
2360 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
Jeff Brownfbf09772011-01-16 14:06:57 -08002361 + " touchableInsets=" + mTmpInsets.touchableInsets
2362 + " touchableRegion=" + mTmpInsets.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 }
2364}