blob: 364962612e71589099e9869cd772d986a7664d96 [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;
Yohei Yukawa8f162c62018-01-10 13:18:09 -080021import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
Yohei Yukawa386f50e2018-03-14 13:03:42 -070023import static java.lang.annotation.RetentionPolicy.SOURCE;
24
Yohei Yukawa7b739a82015-12-21 13:30:44 -080025import android.annotation.CallSuper;
Tor Norbye7b9c9122013-05-30 16:48:33 -070026import android.annotation.DrawableRes;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080027import android.annotation.IntDef;
28import android.annotation.MainThread;
Yohei Yukawa25e08132016-06-22 16:31:41 -070029import android.annotation.NonNull;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -080030import android.annotation.Nullable;
Mathew Inwood6be79492018-07-31 14:49:38 +010031import android.annotation.UnsupportedAppUsage;
Dianne Hackborn836531b2012-08-01 19:00:38 -070032import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.app.Dialog;
34import android.content.Context;
35import android.content.res.Configuration;
Dianne Hackbornd922ae02011-01-14 11:43:24 -080036import android.content.res.Resources;
The Android Open Source Project10592532009-03-18 17:39:46 -070037import android.content.res.TypedArray;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080038import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.graphics.Rect;
Jeff Brownfbf09772011-01-16 14:06:57 -080040import android.graphics.Region;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080041import android.net.Uri;
Mathew Inwood55418ea2018-12-20 15:30:45 +000042import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Bundle;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080044import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.IBinder;
The Android Open Source Project4df24232009-03-05 14:34:35 -080046import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.SystemClock;
48import android.provider.Settings;
49import android.text.InputType;
50import android.text.Layout;
51import android.text.Spannable;
52import android.text.method.MovementMethod;
53import android.util.Log;
54import android.util.PrintWriterPrinter;
55import android.util.Printer;
Dianne Hackborne30e02f2014-05-27 18:24:45 -070056import android.view.Gravity;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080057import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.view.KeyEvent;
59import android.view.LayoutInflater;
60import android.view.MotionEvent;
61import android.view.View;
62import android.view.ViewGroup;
63import android.view.ViewTreeObserver;
64import android.view.Window;
65import android.view.WindowManager;
The Android Open Source Project10592532009-03-18 17:39:46 -070066import android.view.animation.AnimationUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.view.inputmethod.CompletionInfo;
Yohei Yukawac2ddd602014-05-06 21:22:49 +090068import android.view.inputmethod.CursorAnchorInfo;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080069import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.view.inputmethod.ExtractedText;
71import android.view.inputmethod.ExtractedTextRequest;
72import android.view.inputmethod.InputBinding;
73import android.view.inputmethod.InputConnection;
Yohei Yukawa25e08132016-06-22 16:31:41 -070074import android.view.inputmethod.InputContentInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.view.inputmethod.InputMethod;
76import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +090077import android.view.inputmethod.InputMethodSubtype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.widget.FrameLayout;
Mark Renouf91eb2652016-04-11 16:03:26 -040079import android.widget.ImageButton;
The Android Open Source Project10592532009-03-18 17:39:46 -070080import android.widget.LinearLayout;
Mark Renouf91eb2652016-04-11 16:03:26 -040081import android.widget.TextView;
The Android Open Source Project10592532009-03-18 17:39:46 -070082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import java.io.FileDescriptor;
84import java.io.PrintWriter;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080085import java.lang.annotation.Retention;
86import java.lang.annotation.RetentionPolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
88/**
89 * InputMethodService provides a standard implementation of an InputMethod,
90 * which final implementations can derive from and customize. See the
91 * base class {@link AbstractInputMethodService} and the {@link InputMethod}
92 * interface for more information on the basics of writing input methods.
93 *
94 * <p>In addition to the normal Service lifecycle methods, this class
95 * introduces some new specific callbacks that most subclasses will want
96 * to make use of:</p>
97 * <ul>
98 * <li> {@link #onInitializeInterface()} for user-interface initialization,
99 * in particular to deal with configuration changes while the service is
100 * running.
101 * <li> {@link #onBindInput} to find out about switching to a new client.
102 * <li> {@link #onStartInput} to deal with an input session starting with
103 * the client.
104 * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
105 * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
106 * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
107 * starting within the input area of the IME.
108 * </ul>
109 *
110 * <p>An input method has significant discretion in how it goes about its
111 * work: the {@link android.inputmethodservice.InputMethodService} provides
112 * a basic framework for standard UI elements (input view, candidates view,
113 * and running in fullscreen mode), but it is up to a particular implementor
114 * to decide how to use them. For example, one input method could implement
115 * an input area with a keyboard, another could allow the user to draw text,
116 * while a third could have no input area (and thus not be visible to the
117 * user) but instead listen to audio and perform text to speech conversion.</p>
118 *
119 * <p>In the implementation provided here, all of these elements are placed
120 * together in a single window managed by the InputMethodService. It will
121 * execute callbacks as it needs information about them, and provides APIs for
122 * programmatic control over them. They layout of these elements is explicitly
123 * defined:</p>
124 *
125 * <ul>
126 * <li>The soft input view, if available, is placed at the bottom of the
127 * screen.
128 * <li>The candidates view, if currently shown, is placed above the soft
129 * input view.
130 * <li>If not running fullscreen, the application is moved or resized to be
131 * above these views; if running fullscreen, the window will completely cover
132 * the application and its top part will contain the extract text of what is
133 * currently being edited by the application.
134 * </ul>
135 *
136 *
137 * <a name="SoftInputView"></a>
138 * <h3>Soft Input View</h3>
139 *
140 * <p>Central to most input methods is the soft input view. This is where most
141 * user interaction occurs: pressing on soft keys, drawing characters, or
142 * however else your input method wants to generate text. Most implementations
143 * will simply have their own view doing all of this work, and return a new
144 * instance of it when {@link #onCreateInputView()} is called. At that point,
145 * as long as the input view is visible, you will see user interaction in
146 * that view and can call back on the InputMethodService to interact with the
147 * application as appropriate.</p>
148 *
149 * <p>There are some situations where you want to decide whether or not your
150 * soft input view should be shown to the user. This is done by implementing
151 * the {@link #onEvaluateInputViewShown()} to return true or false based on
152 * whether it should be shown in the current environment. If any of your
153 * state has changed that may impact this, call
154 * {@link #updateInputViewShown()} to have it re-evaluated. The default
155 * implementation always shows the input view unless there is a hard
156 * keyboard available, which is the appropriate behavior for most input
157 * methods.</p>
158 *
159 *
160 * <a name="CandidatesView"></a>
161 * <h3>Candidates View</h3>
162 *
163 * <p>Often while the user is generating raw text, an input method wants to
164 * provide them with a list of possible interpretations of that text that can
165 * be selected for use. This is accomplished with the candidates view, and
166 * like the soft input view you implement {@link #onCreateCandidatesView()}
167 * to instantiate your own view implementing your candidates UI.</p>
168 *
169 * <p>Management of the candidates view is a little different than the input
170 * view, because the candidates view tends to be more transient, being shown
171 * only when there are possible candidates for the current text being entered
172 * by the user. To control whether the candidates view is shown, you use
173 * {@link #setCandidatesViewShown(boolean)}. Note that because the candidate
174 * view tends to be shown and hidden a lot, it does not impact the application
175 * UI in the same way as the soft input view: it will never cause application
176 * windows to resize, only cause them to be panned if needed for the user to
177 * see the current focus.</p>
178 *
179 *
180 * <a name="FullscreenMode"></a>
181 * <h3>Fullscreen Mode</h3>
182 *
183 * <p>Sometimes your input method UI is too large to integrate with the
184 * application UI, so you just want to take over the screen. This is
185 * accomplished by switching to full-screen mode, causing the input method
186 * window to fill the entire screen and add its own "extracted text" editor
187 * showing the user the text that is being typed. Unlike the other UI elements,
188 * there is a standard implementation for the extract editor that you should
189 * not need to change. The editor is placed at the top of the IME, above the
190 * input and candidates views.</p>
191 *
192 * <p>Similar to the input view, you control whether the IME is running in
193 * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
194 * to return true or false based on
195 * whether it should be fullscreen in the current environment. If any of your
196 * state has changed that may impact this, call
197 * {@link #updateFullscreenMode()} to have it re-evaluated. The default
198 * implementation selects fullscreen mode when the screen is in a landscape
199 * orientation, which is appropriate behavior for most input methods that have
200 * a significant input area.</p>
201 *
202 * <p>When in fullscreen mode, you have some special requirements because the
203 * user can not see the application UI. In particular, you should implement
204 * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
205 * generated by your application, typically in your candidates view like you
206 * would normally show candidates.
207 *
208 *
209 * <a name="GeneratingText"></a>
210 * <h3>Generating Text</h3>
211 *
212 * <p>The key part of an IME is of course generating text for the application.
213 * This is done through calls to the
214 * {@link android.view.inputmethod.InputConnection} interface to the
215 * application, which can be retrieved from {@link #getCurrentInputConnection()}.
216 * This interface allows you to generate raw key events or, if the target
217 * supports it, directly edit in strings of candidates and committed text.</p>
218 *
219 * <p>Information about what the target is expected and supports can be found
220 * through the {@link android.view.inputmethod.EditorInfo} class, which is
221 * retrieved with {@link #getCurrentInputEditorInfo()} method. The most
222 * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
223 * EditorInfo.inputType}; in particular, if this is
224 * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
225 * then the target does not support complex edits and you need to only deliver
226 * raw key events to it. An input method will also want to look at other
227 * values here, to for example detect password mode, auto complete text views,
228 * phone number entry, etc.</p>
229 *
230 * <p>When the user switches between input targets, you will receive calls to
231 * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
232 * You can use these to reset and initialize your input state for the current
233 * target. For example, you will often want to clear any input state, and
234 * update a soft keyboard to be appropriate for the new inputType.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700235 *
236 * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground
237 * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
238 * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 */
240public class InputMethodService extends AbstractInputMethodService {
241 static final String TAG = "InputMethodService";
242 static final boolean DEBUG = false;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800243
244 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700245 * Allows the system to optimize the back button affordance based on the presence of software
246 * keyboard.
247 *
248 * <p>For instance, on devices that have navigation bar and software-rendered back button, the
249 * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
250 * indicate that the back button has "dismiss" affordance.</p>
251 *
252 * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
253 * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
254 * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
255 * not take this mode into account.</p>
256 *
257 * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
258 * only mode you can safely specify without worrying about the compatibility.</p>
259 *
260 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800261 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700262 public static final int BACK_DISPOSITION_DEFAULT = 0;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800263
264 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700265 * Deprecated flag.
266 *
267 * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
268 *
269 * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
270 * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
271 * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
272 * of this mode had not been well defined. Most likely the end result would be the
273 * same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
274 * use this mode
275 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800276 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700277 @Deprecated
278 public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800279
280 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700281 * Deprecated flag.
282 *
283 * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
284 *
285 * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
286 * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
287 * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
288 * of this mode had not been well defined. In AOSP implementation running on devices
289 * that have navigation bar, specifying this flag could change the software back
290 * button to "Dismiss" icon no matter whether the software keyboard is shown or not,
291 * but there would be no easy way to restore the icon state even after IME lost the
292 * connection to the application. To avoid user confusions, do not specify this mode
293 * anyway
294 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800295 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700296 @Deprecated
297 public static final int BACK_DISPOSITION_WILL_DISMISS = 2;
298
299 /**
300 * Asks the system to not adjust the back button affordance even when the software keyboard is
301 * shown.
302 *
303 * <p>This mode is useful for UI modes where IME's main soft input window is used for some
304 * supplemental UI, such as floating candidate window for languages such as Chinese and
305 * Japanese, where users expect the back button is, or at least looks to be, handled by the
306 * target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
307 * returns {@code true}.</p>
308 *
309 * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
310 * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
311 * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
312 * not take this mode into account.</p>
313 *
314 * @see #setBackDisposition(int)
315 */
316 public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
317
318 /**
319 * Enum flag to be used for {@link #setBackDisposition(int)}.
320 *
321 * @hide
322 */
323 @Retention(SOURCE)
324 @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
325 BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
326 prefix = "BACK_DISPOSITION_")
327 public @interface BackDispositionMode {}
Joe Onorato857fd9b2011-01-27 15:08:35 -0800328
329 /**
330 * @hide
331 * The IME is active. It may or may not be visible.
332 */
333 public static final int IME_ACTIVE = 0x1;
334
335 /**
336 * @hide
337 * The IME is visible.
338 */
339 public static final int IME_VISIBLE = 0x2;
340
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800341 // Min and max values for back disposition.
342 private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700343 private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 InputMethodManager mImm;
346
Mathew Inwood55418ea2018-12-20 15:30:45 +0000347 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800348 int mTheme = 0;
The Android Open Source Project10592532009-03-18 17:39:46 -0700349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 LayoutInflater mInflater;
The Android Open Source Project10592532009-03-18 17:39:46 -0700351 TypedArray mThemeAttrs;
Mathew Inwood6be79492018-07-31 14:49:38 +0100352 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 View mRootView;
354 SoftInputWindow mWindow;
355 boolean mInitialized;
356 boolean mWindowCreated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 boolean mWindowVisible;
The Android Open Source Project10592532009-03-18 17:39:46 -0700358 boolean mWindowWasVisible;
359 boolean mInShowWindow;
360 ViewGroup mFullscreenArea;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 FrameLayout mExtractFrame;
362 FrameLayout mCandidatesFrame;
363 FrameLayout mInputFrame;
364
365 IBinder mToken;
366
367 InputBinding mInputBinding;
368 InputConnection mInputConnection;
369 boolean mInputStarted;
370 boolean mInputViewStarted;
371 boolean mCandidatesViewStarted;
372 InputConnection mStartedInputConnection;
373 EditorInfo mInputEditorInfo;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800374
375 /**
376 * A token to keep tracking the last IPC that triggered
377 * {@link #doStartInput(InputConnection, EditorInfo, boolean)}. If
378 * {@link #doStartInput(InputConnection, EditorInfo, boolean)} was not caused by IPCs from
379 * {@link com.android.server.InputMethodManagerService}, this needs to remain unchanged.
380 *
381 * <p>Some IPCs to {@link com.android.server.InputMethodManagerService} require this token to
382 * disentangle event flows for various purposes such as better window animation and providing
383 * fine-grained debugging information.</p>
384 */
385 @Nullable
386 private IBinder mStartInputToken;
387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 int mShowInputFlags;
389 boolean mShowInputRequested;
390 boolean mLastShowInputRequested;
391 int mCandidatesVisibility;
392 CompletionInfo[] mCurCompletions;
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 boolean mFullscreenApplied;
395 boolean mIsFullscreen;
Mathew Inwood6be79492018-07-31 14:49:38 +0100396 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 View mExtractView;
The Android Open Source Project10592532009-03-18 17:39:46 -0700398 boolean mExtractViewHidden;
Mathew Inwood6be79492018-07-31 14:49:38 +0100399 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 ExtractEditText mExtractEditText;
401 ViewGroup mExtractAccessories;
Mark Renouf91eb2652016-04-11 16:03:26 -0400402 View mExtractAction;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 ExtractedText mExtractedText;
404 int mExtractedToken;
405
406 View mInputView;
407 boolean mIsInputViewShown;
408
409 int mStatusIcon;
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700410
411 @BackDispositionMode
Joe Onorato857fd9b2011-01-27 15:08:35 -0800412 int mBackDisposition;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413
Yohei Yukawa2977eb72015-05-27 18:54:18 -0700414 /**
415 * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
416 * have not shown our own window yet. In this situation, the previous inset continues to be
417 * shown as an empty region until it is explicitly updated. Basically we can trigger the update
418 * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}.
419 */
420 boolean mShouldClearInsetOfPreviousIme;
421
Mathew Inwood55418ea2018-12-20 15:30:45 +0000422 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 final Insets mTmpInsets = new Insets();
424 final int[] mTmpLocation = new int[2];
satokab751aa2010-09-14 19:17:36 +0900425
Yohei Yukawa623e94b2018-01-14 16:30:59 -0800426 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
427 if (isExtractViewShown()) {
428 // In true fullscreen mode, we just say the window isn't covering
429 // any content so we don't impact whatever is behind.
430 View decor = getWindow().getWindow().getDecorView();
431 info.contentInsets.top = info.visibleInsets.top = decor.getHeight();
432 info.touchableRegion.setEmpty();
433 info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
434 } else {
435 onComputeInsets(mTmpInsets);
436 info.contentInsets.top = mTmpInsets.contentTopInsets;
437 info.visibleInsets.top = mTmpInsets.visibleTopInsets;
438 info.touchableRegion.set(mTmpInsets.touchableRegion);
439 info.setTouchableInsets(mTmpInsets.touchableInsets);
440 }
441 };
442
443 final View.OnClickListener mActionClickListener = v -> {
444 final EditorInfo ei = getCurrentInputEditorInfo();
445 final InputConnection ic = getCurrentInputConnection();
446 if (ei != null && ic != null) {
447 if (ei.actionId != 0) {
448 ic.performEditorAction(ei.actionId);
449 } else if ((ei.imeOptions & EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE) {
450 ic.performEditorAction(ei.imeOptions & EditorInfo.IME_MASK_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
452 }
453 };
454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 /**
456 * Concrete implementation of
457 * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
458 * all of the standard behavior for an input method.
459 */
460 public class InputMethodImpl extends AbstractInputMethodImpl {
461 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700462 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700464 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700465 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 public void attachToken(IBinder token) {
467 if (mToken == null) {
468 mToken = token;
469 mWindow.setToken(token);
470 }
471 }
Tarandeep Singhd8d03a82017-11-28 13:35:32 -0800472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700474 * {@inheritDoc}
475 *
476 * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700478 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700479 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 public void bindInput(InputBinding binding) {
481 mInputBinding = binding;
482 mInputConnection = binding.getConnection();
483 if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
484 + " ic=" + mInputConnection);
Yohei Yukawa2bc66172017-02-08 11:13:25 -0800485 if (mImm != null && mToken != null) {
486 mImm.reportFullscreenMode(mToken, mIsFullscreen);
487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 initialize();
489 onBindInput();
490 }
491
492 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700493 * {@inheritDoc}
494 *
495 * <p>Calls {@link InputMethodService#onUnbindInput()} when done.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700497 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700498 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 public void unbindInput() {
500 if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
501 + " ic=" + mInputConnection);
502 onUnbindInput();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 mInputBinding = null;
504 mInputConnection = null;
505 }
506
Yohei Yukawa16f04072017-10-18 20:19:43 -0700507 /**
508 * {@inheritDoc}
509 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700510 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700511 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 public void startInput(InputConnection ic, EditorInfo attribute) {
513 if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
514 doStartInput(ic, attribute, false);
515 }
516
Yohei Yukawa16f04072017-10-18 20:19:43 -0700517 /**
518 * {@inheritDoc}
519 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700520 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700521 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 public void restartInput(InputConnection ic, EditorInfo attribute) {
523 if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
524 doStartInput(ic, attribute, true);
525 }
526
527 /**
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800528 * {@inheritDoc}
529 * @hide
530 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700531 @MainThread
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800532 @Override
533 public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
534 @NonNull EditorInfo editorInfo, boolean restarting,
535 @NonNull IBinder startInputToken) {
536 mStartInputToken = startInputToken;
537
538 // This needs to be dispatched to interface methods rather than doStartInput().
539 // Otherwise IME developers who have overridden those interface methods will lose
540 // notifications.
541 super.dispatchStartInputWithToken(inputConnection, editorInfo, restarting,
542 startInputToken);
543 }
544
545 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700546 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700548 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700549 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800550 public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 if (DEBUG) Log.v(TAG, "hideSoftInput()");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800552 boolean wasVis = isInputViewShown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 mShowInputFlags = 0;
554 mShowInputRequested = false;
satok2f913d92012-05-10 01:48:03 +0900555 doHideWindow();
Yohei Yukawa2977eb72015-05-27 18:54:18 -0700556 clearInsetOfPreviousIme();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800557 if (resultReceiver != null) {
558 resultReceiver.send(wasVis != isInputViewShown()
559 ? InputMethodManager.RESULT_HIDDEN
560 : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
561 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 }
564
565 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700566 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700568 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700569 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800570 public void showSoftInput(int flags, ResultReceiver resultReceiver) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -0700571 if (DEBUG) Log.v(TAG, "showSoftInput()");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800572 boolean wasVis = isInputViewShown();
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700573 if (dispatchOnShowInputRequested(flags, false)) {
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -0700574 showWindow(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
Yohei Yukawa2977eb72015-05-27 18:54:18 -0700576 clearInsetOfPreviousIme();
satok865b9772011-01-21 02:45:06 +0900577 // If user uses hard keyboard, IME button should always be shown.
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800578 mImm.setImeWindowStatus(mToken, mStartInputToken,
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800579 mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800580 if (resultReceiver != null) {
581 resultReceiver.send(wasVis != isInputViewShown()
582 ? InputMethodManager.RESULT_SHOWN
583 : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
584 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
satokab751aa2010-09-14 19:17:36 +0900587
Yohei Yukawa16f04072017-10-18 20:19:43 -0700588 /**
589 * {@inheritDoc}
590 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700591 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700592 @Override
satokab751aa2010-09-14 19:17:36 +0900593 public void changeInputMethodSubtype(InputMethodSubtype subtype) {
594 onCurrentInputMethodSubtypeChanged(subtype);
595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
satokab751aa2010-09-14 19:17:36 +0900597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 /**
599 * Concrete implementation of
600 * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
601 * all of the standard behavior for an input method session.
602 */
603 public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
604 public void finishInput() {
605 if (!isEnabled()) {
606 return;
607 }
608 if (DEBUG) Log.v(TAG, "finishInput() in " + this);
609 doFinishInput();
610 }
611
612 /**
613 * Call {@link InputMethodService#onDisplayCompletions
614 * InputMethodService.onDisplayCompletions()}.
615 */
616 public void displayCompletions(CompletionInfo[] completions) {
617 if (!isEnabled()) {
618 return;
619 }
620 mCurCompletions = completions;
621 onDisplayCompletions(completions);
622 }
623
624 /**
625 * Call {@link InputMethodService#onUpdateExtractedText
626 * InputMethodService.onUpdateExtractedText()}.
627 */
628 public void updateExtractedText(int token, ExtractedText text) {
629 if (!isEnabled()) {
630 return;
631 }
632 onUpdateExtractedText(token, text);
633 }
634
635 /**
636 * Call {@link InputMethodService#onUpdateSelection
637 * InputMethodService.onUpdateSelection()}.
638 */
639 public void updateSelection(int oldSelStart, int oldSelEnd,
640 int newSelStart, int newSelEnd,
641 int candidatesStart, int candidatesEnd) {
642 if (!isEnabled()) {
643 return;
644 }
645 InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
646 newSelStart, newSelEnd, candidatesStart, candidatesEnd);
647 }
satok863fcd62011-06-21 17:38:02 +0900648
649 @Override
650 public void viewClicked(boolean focusChanged) {
651 if (!isEnabled()) {
652 return;
653 }
654 InputMethodService.this.onViewClicked(focusChanged);
655 }
656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 /**
658 * Call {@link InputMethodService#onUpdateCursor
659 * InputMethodService.onUpdateCursor()}.
660 */
661 public void updateCursor(Rect newCursor) {
662 if (!isEnabled()) {
663 return;
664 }
665 InputMethodService.this.onUpdateCursor(newCursor);
666 }
667
668 /**
669 * Call {@link InputMethodService#onAppPrivateCommand
670 * InputMethodService.onAppPrivateCommand()}.
671 */
672 public void appPrivateCommand(String action, Bundle data) {
673 if (!isEnabled()) {
674 return;
675 }
676 InputMethodService.this.onAppPrivateCommand(action, data);
677 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800678
679 /**
680 *
681 */
682 public void toggleSoftInput(int showFlags, int hideFlags) {
683 InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
684 }
Yohei Yukawac2ddd602014-05-06 21:22:49 +0900685
686 /**
687 * Call {@link InputMethodService#onUpdateCursorAnchorInfo
688 * InputMethodService.onUpdateCursorAnchorInfo()}.
689 */
690 public void updateCursorAnchorInfo(CursorAnchorInfo info) {
691 if (!isEnabled()) {
692 return;
693 }
694 InputMethodService.this.onUpdateCursorAnchorInfo(info);
695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 }
697
698 /**
699 * Information about where interesting parts of the input method UI appear.
700 */
701 public static final class Insets {
702 /**
703 * This is the top part of the UI that is the main content. It is
704 * used to determine the basic space needed, to resize/pan the
705 * application behind. It is assumed that this inset does not
706 * change very much, since any change will cause a full resize/pan
707 * of the application behind. This value is relative to the top edge
708 * of the input method window.
709 */
710 public int contentTopInsets;
711
712 /**
713 * This is the top part of the UI that is visibly covering the
714 * application behind it. This provides finer-grained control over
715 * visibility, allowing you to change it relatively frequently (such
716 * as hiding or showing candidates) without disrupting the underlying
717 * UI too much. For example, this will never resize the application
718 * UI, will only pan if needed to make the current focus visible, and
719 * will not aggressively move the pan position when this changes unless
720 * needed to make the focus visible. This value is relative to the top edge
721 * of the input method window.
722 */
723 public int visibleTopInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -0800724
725 /**
726 * This is the region of the UI that is touchable. It is used when
727 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
728 * The region should be specified relative to the origin of the window frame.
729 */
730 public final Region touchableRegion = new Region();
731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 /**
733 * Option for {@link #touchableInsets}: the entire window frame
734 * can be touched.
735 */
736 public static final int TOUCHABLE_INSETS_FRAME
737 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
738
739 /**
740 * Option for {@link #touchableInsets}: the area inside of
741 * the content insets can be touched.
742 */
743 public static final int TOUCHABLE_INSETS_CONTENT
744 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
745
746 /**
747 * Option for {@link #touchableInsets}: the area inside of
748 * the visible insets can be touched.
749 */
750 public static final int TOUCHABLE_INSETS_VISIBLE
751 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -0800752
753 /**
754 * Option for {@link #touchableInsets}: the region specified by
755 * {@link #touchableRegion} can be touched.
756 */
757 public static final int TOUCHABLE_INSETS_REGION
758 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 /**
761 * Determine which area of the window is touchable by the user. May
762 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
Jeff Brownfbf09772011-01-16 14:06:57 -0800763 * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
764 * or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 */
766 public int touchableInsets;
767 }
satok865b9772011-01-21 02:45:06 +0900768
The Android Open Source Project10592532009-03-18 17:39:46 -0700769 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800770 * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
771 *
772 * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
773 * Basically this functionality still needs to be considered as implementation details.</p>
774 */
775 @MainThread
776 private static final class SettingsObserver extends ContentObserver {
777 @Retention(RetentionPolicy.SOURCE)
778 @IntDef({
779 ShowImeWithHardKeyboardType.UNKNOWN,
780 ShowImeWithHardKeyboardType.FALSE,
781 ShowImeWithHardKeyboardType.TRUE,
782 })
783 private @interface ShowImeWithHardKeyboardType {
784 int UNKNOWN = 0;
785 int FALSE = 1;
786 int TRUE = 2;
787 }
788 @ShowImeWithHardKeyboardType
789 private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
790
791 private final InputMethodService mService;
792
793 private SettingsObserver(InputMethodService service) {
794 super(new Handler(service.getMainLooper()));
795 mService = service;
796 }
797
798 /**
799 * A factory method that internally enforces two-phase initialization to make sure that the
800 * object reference will not be escaped until the object is properly constructed.
801 *
802 * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence
803 * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
804 *
805 * @param service {@link InputMethodService} that needs to receive the callback.
806 * @return {@link SettingsObserver} that is already registered to
807 * {@link android.content.ContentResolver}. The caller must call
808 * {@link SettingsObserver#unregister()}.
809 */
810 public static SettingsObserver createAndRegister(InputMethodService service) {
811 final SettingsObserver observer = new SettingsObserver(service);
812 // The observer is properly constructed. Let's start accepting the event.
813 service.getContentResolver().registerContentObserver(
814 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
815 false, observer);
816 return observer;
817 }
818
819 void unregister() {
820 mService.getContentResolver().unregisterContentObserver(this);
821 }
822
Mathew Inwood6be79492018-07-31 14:49:38 +0100823 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800824 private boolean shouldShowImeWithHardKeyboard() {
825 // Lazily initialize as needed.
826 if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
827 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
828 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
829 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
830 }
831 switch (mShowImeWithHardKeyboard) {
832 case ShowImeWithHardKeyboardType.TRUE:
833 return true;
834 case ShowImeWithHardKeyboardType.FALSE:
835 return false;
836 default:
837 Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
838 return false;
839 }
840 }
841
842 @Override
843 public void onChange(boolean selfChange, Uri uri) {
844 final Uri showImeWithHardKeyboardUri =
845 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
846 if (showImeWithHardKeyboardUri.equals(uri)) {
847 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
848 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
849 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
Yohei Yukawa2dbc5322016-04-03 22:50:18 -0700850 // In Android M and prior, state change of
851 // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
852 // #onConfigurationChanged(). For compatibility reasons, we reset the internal
853 // state as if configuration was changed.
854 mService.resetStateForNewConfiguration();
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800855 }
856 }
857
858 @Override
859 public String toString() {
860 return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}";
861 }
862 }
Mathew Inwood6be79492018-07-31 14:49:38 +0100863 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800864 private SettingsObserver mSettingsObserver;
865
866 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700867 * You can call this to customize the theme used by your IME's window.
868 * This theme should typically be one that derives from
869 * {@link android.R.style#Theme_InputMethod}, which is the default theme
870 * you will get. This must be set before {@link #onCreate}, so you
871 * will typically call it in your constructor with the resource ID
872 * of your custom theme.
873 */
satokab751aa2010-09-14 19:17:36 +0900874 @Override
The Android Open Source Project10592532009-03-18 17:39:46 -0700875 public void setTheme(int theme) {
876 if (mWindow != null) {
877 throw new IllegalStateException("Must be called before onCreate()");
878 }
879 mTheme = theme;
880 }
satok865b9772011-01-21 02:45:06 +0900881
Dianne Hackborn836531b2012-08-01 19:00:38 -0700882 /**
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700883 * You can call this to try to enable accelerated drawing for your IME. This must be set before
884 * {@link #onCreate()}, so you will typically call it in your constructor. It is not always
885 * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
886 * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
887 * {@code false} if you will need to draw in software. You must be able to handle either case.
Alan Viverettee07b5952014-08-13 19:13:54 -0700888 *
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700889 * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
890 * IME on capable devices even if this method is not explicitly called. Make sure that your IME
891 * is able to handle either case.</p>
892 *
893 * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
894 * On API 21 and later devices the return value is basically just a hint and your IME
895 * does not need to change the behavior based on the it
896 * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
Dianne Hackborn836531b2012-08-01 19:00:38 -0700897 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700898 @Deprecated
Dianne Hackborn836531b2012-08-01 19:00:38 -0700899 public boolean enableHardwareAcceleration() {
900 if (mWindow != null) {
901 throw new IllegalStateException("Must be called before onCreate()");
902 }
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700903 return ActivityManager.isHighEndGfx();
Dianne Hackborn836531b2012-08-01 19:00:38 -0700904 }
905
Alan Viverette5effd7e2014-05-05 12:25:33 -0700906 @Override public void onCreate() {
907 mTheme = Resources.selectSystemTheme(mTheme,
908 getApplicationInfo().targetSdkVersion,
909 android.R.style.Theme_InputMethod,
910 android.R.style.Theme_Holo_InputMethod,
911 android.R.style.Theme_DeviceDefault_InputMethod,
912 android.R.style.Theme_DeviceDefault_InputMethod);
The Android Open Source Project10592532009-03-18 17:39:46 -0700913 super.setTheme(mTheme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 super.onCreate();
915 mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800916 mSettingsObserver = SettingsObserver.createAndRegister(this);
Yohei Yukawa2977eb72015-05-27 18:54:18 -0700917 // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
918 // we continue to use the same size of the inset or update it
919 mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 mInflater = (LayoutInflater)getSystemService(
921 Context.LAYOUT_INFLATER_SERVICE);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700922 mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700923 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
Yohei Yukawa8f162c62018-01-10 13:18:09 -0800924 // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
925 // by default (but IME developers can opt this out later if they want a new behavior).
926 mWindow.getWindow().setFlags(
927 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 initViews();
Romain Guy980a9382010-01-08 15:06:28 -0800930 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 }
satokab751aa2010-09-14 19:17:36 +0900932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 /**
934 * This is a hook that subclasses can use to perform initialization of
935 * their interface. It is called for you prior to any of your UI objects
936 * being created, both after the service is first created and after a
937 * configuration change happens.
938 */
939 public void onInitializeInterface() {
Gilles Debunne34703b62011-09-08 11:16:25 -0700940 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
satokab751aa2010-09-14 19:17:36 +0900942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 void initialize() {
944 if (!mInitialized) {
945 mInitialized = true;
946 onInitializeInterface();
947 }
948 }
satokab751aa2010-09-14 19:17:36 +0900949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 void initViews() {
951 mInitialized = false;
952 mWindowCreated = false;
953 mShowInputRequested = false;
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700954 mShowInputFlags = 0;
955
The Android Open Source Project10592532009-03-18 17:39:46 -0700956 mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 mRootView = mInflater.inflate(
958 com.android.internal.R.layout.input_method, null);
959 mWindow.setContentView(mRootView);
Seonggoo Kang72745ff2014-12-24 13:55:50 +0900960 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
Jeff Sharkey6e2bee72012-10-01 13:39:08 -0700962 if (Settings.Global.getInt(getContentResolver(),
963 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 mWindow.getWindow().setWindowAnimations(
965 com.android.internal.R.style.Animation_InputMethodFancy);
966 }
Yohei Yukawa31a260f2018-01-14 16:24:26 -0800967 mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
The Android Open Source Project10592532009-03-18 17:39:46 -0700968 mExtractViewHidden = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -0800969 mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 mExtractView = null;
971 mExtractEditText = null;
972 mExtractAccessories = null;
973 mExtractAction = null;
974 mFullscreenApplied = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -0800975
976 mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
977 mInputFrame = mRootView.findViewById(android.R.id.inputArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 mInputView = null;
979 mIsInputViewShown = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -0800980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 mExtractFrame.setVisibility(View.GONE);
982 mCandidatesVisibility = getCandidatesHiddenVisibility();
983 mCandidatesFrame.setVisibility(mCandidatesVisibility);
984 mInputFrame.setVisibility(View.GONE);
985 }
satokab751aa2010-09-14 19:17:36 +0900986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 @Override public void onDestroy() {
988 super.onDestroy();
989 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
990 mInsetsComputer);
Satoshi Kataokac56191f2013-05-30 13:14:47 +0900991 doFinishInput();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -0700992 mWindow.dismissForDestroyIfNecessary();
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800993 if (mSettingsObserver != null) {
994 mSettingsObserver.unregister();
995 mSettingsObserver = null;
996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
satokf17db9f2011-09-14 18:55:58 +0900998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 /**
1000 * Take care of handling configuration changes. Subclasses of
1001 * InputMethodService generally don't need to deal directly with
1002 * this on their own; the standard implementation here takes care of
1003 * regenerating the input method UI as a result of the configuration
1004 * change, so you can rely on your {@link #onCreateInputView} and
1005 * other methods being called as appropriate due to a configuration change.
1006 *
1007 * <p>When a configuration change does happen,
1008 * {@link #onInitializeInterface()} is guaranteed to be called the next
1009 * time prior to any of the other input or UI creation callbacks. The
1010 * following will be called immediately depending if appropriate for current
1011 * state: {@link #onStartInput} if input is active, and
1012 * {@link #onCreateInputView} and {@link #onStartInputView} and related
1013 * appropriate functions if the UI is displayed.
1014 */
1015 @Override public void onConfigurationChanged(Configuration newConfig) {
1016 super.onConfigurationChanged(newConfig);
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001017 resetStateForNewConfiguration();
1018 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001019
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001020 private void resetStateForNewConfiguration() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 boolean visible = mWindowVisible;
1022 int showFlags = mShowInputFlags;
1023 boolean showingInput = mShowInputRequested;
1024 CompletionInfo[] completions = mCurCompletions;
1025 initViews();
1026 mInputViewStarted = false;
1027 mCandidatesViewStarted = false;
1028 if (mInputStarted) {
1029 doStartInput(getCurrentInputConnection(),
1030 getCurrentInputEditorInfo(), true);
1031 }
1032 if (visible) {
1033 if (showingInput) {
1034 // If we were last showing the soft keyboard, try to do so again.
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001035 if (dispatchOnShowInputRequested(showFlags, true)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 showWindow(true);
1037 if (completions != null) {
1038 mCurCompletions = completions;
1039 onDisplayCompletions(completions);
1040 }
1041 } else {
satok2f913d92012-05-10 01:48:03 +09001042 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
1044 } else if (mCandidatesVisibility == View.VISIBLE) {
1045 // If the candidates are currently visible, make sure the
1046 // window is shown for them.
1047 showWindow(false);
1048 } else {
1049 // Otherwise hide the window.
satok2f913d92012-05-10 01:48:03 +09001050 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
satok865b9772011-01-21 02:45:06 +09001052 // If user uses hard keyboard, IME button should always be shown.
Joe Onorato857fd9b2011-01-27 15:08:35 -08001053 boolean showing = onEvaluateInputViewShown();
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001054 mImm.setImeWindowStatus(mToken, mStartInputToken,
1055 IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
1057 }
1058
1059 /**
1060 * Implement to return our standard {@link InputMethodImpl}. Subclasses
1061 * can override to provide their own customized version.
1062 */
satokab751aa2010-09-14 19:17:36 +09001063 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 public AbstractInputMethodImpl onCreateInputMethodInterface() {
1065 return new InputMethodImpl();
1066 }
1067
1068 /**
1069 * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses
1070 * can override to provide their own customized version.
1071 */
satokab751aa2010-09-14 19:17:36 +09001072 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
1074 return new InputMethodSessionImpl();
1075 }
1076
1077 public LayoutInflater getLayoutInflater() {
1078 return mInflater;
1079 }
1080
1081 public Dialog getWindow() {
1082 return mWindow;
1083 }
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001084
1085 /**
1086 * Sets the disposition mode that indicates the expected affordance for the back button.
1087 *
1088 * <p>Keep in mind that specifying this flag does not change the the default behavior of
1089 * {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that
1090 * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
1091 * specified to this API.</p>
1092 *
1093 * @see #getBackDisposition()
1094 * @param disposition disposition mode to be set
1095 */
1096 public void setBackDisposition(@BackDispositionMode int disposition) {
Tarandeep Singh3fecef12018-01-22 14:33:33 -08001097 if (disposition == mBackDisposition) {
1098 return;
1099 }
1100 if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
1101 Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
1102 return;
1103 }
Joe Onorato857fd9b2011-01-27 15:08:35 -08001104 mBackDisposition = disposition;
Tarandeep Singh3fecef12018-01-22 14:33:33 -08001105 mImm.setImeWindowStatus(mToken, mStartInputToken, mapToImeWindowStatus(isInputViewShown()),
1106 mBackDisposition);
Joe Onorato857fd9b2011-01-27 15:08:35 -08001107 }
1108
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001109 /**
1110 * Retrieves the current disposition mode that indicates the expected back button affordance.
1111 *
1112 * @see #setBackDisposition(int)
1113 * @return currently selected disposition mode
1114 */
1115 @BackDispositionMode
Joe Onorato857fd9b2011-01-27 15:08:35 -08001116 public int getBackDisposition() {
1117 return mBackDisposition;
1118 }
1119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 /**
1121 * Return the maximum width, in pixels, available the input method.
1122 * Input methods are positioned at the bottom of the screen and, unless
1123 * running in fullscreen, will generally want to be as short as possible
1124 * so should compute their height based on their contents. However, they
1125 * can stretch as much as needed horizontally. The function returns to
1126 * you the maximum amount of space available horizontally, which you can
1127 * use if needed for UI placement.
1128 *
1129 * <p>In many cases this is not needed, you can just rely on the normal
1130 * view layout mechanisms to position your views within the full horizontal
1131 * space given to the input method.
1132 *
1133 * <p>Note that this value can change dynamically, in particular when the
1134 * screen orientation changes.
1135 */
1136 public int getMaxWidth() {
1137 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
1138 return wm.getDefaultDisplay().getWidth();
1139 }
1140
1141 /**
1142 * Return the currently active InputBinding for the input method, or
1143 * null if there is none.
1144 */
1145 public InputBinding getCurrentInputBinding() {
1146 return mInputBinding;
1147 }
1148
1149 /**
1150 * Retrieve the currently active InputConnection that is bound to
1151 * the input method, or null if there is none.
1152 */
1153 public InputConnection getCurrentInputConnection() {
1154 InputConnection ic = mStartedInputConnection;
1155 if (ic != null) {
1156 return ic;
1157 }
1158 return mInputConnection;
1159 }
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001160
1161 /**
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001162 * Force switch to the last used input method and subtype. If the last input method didn't have
1163 * any subtypes, the framework will simply switch to the last input method with no subtype
1164 * specified.
1165 * @return true if the current input method and subtype was successfully switched to the last
1166 * used input method and subtype.
1167 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001168 public final boolean switchToPreviousInputMethod() {
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001169 return mImm.switchToPreviousInputMethodInternal(mToken);
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001170 }
1171
1172 /**
1173 * Force switch to the next input method and subtype. If there is no IME enabled except
1174 * current IME and subtype, do nothing.
1175 * @param onlyCurrentIme if true, the framework will find the next subtype which
1176 * belongs to the current IME
1177 * @return true if the current input method and subtype was successfully switched to the next
1178 * input method and subtype.
1179 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001180 public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001181 return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
1182 }
1183
1184 /**
1185 * Returns true if the current IME needs to offer the users ways to switch to a next input
1186 * method (e.g. a globe key.).
1187 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
1188 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
1189 * <p> Note that the system determines the most appropriate next input method
1190 * and subtype in order to provide the consistent user experience in switching
1191 * between IMEs and subtypes.
1192 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001193 public final boolean shouldOfferSwitchingToNextInputMethod() {
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001194 return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
1195 }
1196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 public boolean getCurrentInputStarted() {
1198 return mInputStarted;
1199 }
1200
1201 public EditorInfo getCurrentInputEditorInfo() {
1202 return mInputEditorInfo;
1203 }
1204
1205 /**
1206 * Re-evaluate whether the input method should be running in fullscreen
1207 * mode, and update its UI if this has changed since the last time it
1208 * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to
1209 * determine whether it should currently run in fullscreen mode. You
1210 * can use {@link #isFullscreenMode()} to determine if the input method
1211 * is currently running in fullscreen mode.
1212 */
1213 public void updateFullscreenMode() {
1214 boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
1215 boolean changed = mLastShowInputRequested != mShowInputRequested;
1216 if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
1217 changed = true;
1218 mIsFullscreen = isFullscreen;
Yohei Yukawa2bc66172017-02-08 11:13:25 -08001219 if (mImm != null && mToken != null) {
1220 mImm.reportFullscreenMode(mToken, mIsFullscreen);
1221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 mFullscreenApplied = true;
1223 initialize();
The Android Open Source Project10592532009-03-18 17:39:46 -07001224 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1225 mFullscreenArea.getLayoutParams();
1226 if (isFullscreen) {
1227 mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
1228 com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
1229 lp.height = 0;
1230 lp.weight = 1;
1231 } else {
1232 mFullscreenArea.setBackgroundDrawable(null);
1233 lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
1234 lp.weight = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001236 ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
1237 mFullscreenArea, lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 if (isFullscreen) {
1239 if (mExtractView == null) {
1240 View v = onCreateExtractTextView();
1241 if (v != null) {
1242 setExtractView(v);
1243 }
1244 }
1245 startExtractingText(false);
1246 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001247 updateExtractFrameVisibility();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249
1250 if (changed) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001251 onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 mLastShowInputRequested = mShowInputRequested;
1253 }
1254 }
1255
1256 /**
1257 * Update the given window's parameters for the given mode. This is called
1258 * when the window is first displayed and each time the fullscreen or
1259 * candidates only mode changes.
1260 *
1261 * <p>The default implementation makes the layout for the window
Romain Guy980a9382010-01-08 15:06:28 -08001262 * MATCH_PARENT x MATCH_PARENT when in fullscreen mode, and
1263 * MATCH_PARENT x WRAP_CONTENT when in non-fullscreen mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 *
1265 * @param win The input method's window.
1266 * @param isFullscreen If true, the window is running in fullscreen mode
1267 * and intended to cover the entire application display.
1268 * @param isCandidatesOnly If true, the window is only showing the
1269 * candidates view and none of the rest of its UI. This is mutually
1270 * exclusive with fullscreen mode.
1271 */
1272 public void onConfigureWindow(Window win, boolean isFullscreen,
1273 boolean isCandidatesOnly) {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001274 final int currentHeight = mWindow.getWindow().getAttributes().height;
1275 final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
1276 if (mIsInputViewShown && currentHeight != newHeight) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001277 if (DEBUG) {
1278 Log.w(TAG,"Window size has been changed. This may cause jankiness of resizing "
1279 + "window: " + currentHeight + " -> " + newHeight);
1280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 }
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001282 mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 }
1284
1285 /**
1286 * Return whether the input method is <em>currently</em> running in
1287 * fullscreen mode. This is the mode that was last determined and
1288 * applied by {@link #updateFullscreenMode()}.
1289 */
1290 public boolean isFullscreenMode() {
1291 return mIsFullscreen;
1292 }
1293
1294 /**
1295 * Override this to control when the input method should run in
1296 * fullscreen mode. The default implementation runs in fullsceen only
1297 * when the screen is in landscape mode. If you change what
1298 * this returns, you will need to call {@link #updateFullscreenMode()}
1299 * yourself whenever the returned value may have changed to have it
1300 * re-evaluated and applied.
1301 */
1302 public boolean onEvaluateFullscreenMode() {
1303 Configuration config = getResources().getConfiguration();
Leon Scroggins2edd6822010-01-12 11:36:13 -05001304 if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
1305 return false;
1306 }
1307 if (mInputEditorInfo != null
1308 && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
1309 return false;
1310 }
1311 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
Gilles Debunne34703b62011-09-08 11:16:25 -07001313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07001315 * Controls the visibility of the extracted text area. This only applies
1316 * when the input method is in fullscreen mode, and thus showing extracted
1317 * text. When false, the extracted text will not be shown, allowing some
1318 * of the application to be seen behind. This is normally set for you
1319 * by {@link #onUpdateExtractingVisibility}. This controls the visibility
1320 * of both the extracted text and candidate view; the latter since it is
1321 * not useful if there is no text to see.
1322 */
1323 public void setExtractViewShown(boolean shown) {
1324 if (mExtractViewHidden == shown) {
1325 mExtractViewHidden = !shown;
1326 updateExtractFrameVisibility();
1327 }
1328 }
1329
1330 /**
1331 * Return whether the fullscreen extract view is shown. This will only
1332 * return true if {@link #isFullscreenMode()} returns true, and in that
1333 * case its value depends on the last call to
1334 * {@link #setExtractViewShown(boolean)}. This effectively lets you
1335 * determine if the application window is entirely covered (when this
1336 * returns true) or if some part of it may be shown (if this returns
1337 * false, though if {@link #isFullscreenMode()} returns true in that case
1338 * then it is probably only a sliver of the application).
1339 */
1340 public boolean isExtractViewShown() {
1341 return mIsFullscreen && !mExtractViewHidden;
1342 }
1343
1344 void updateExtractFrameVisibility() {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001345 final int vis;
The Android Open Source Project10592532009-03-18 17:39:46 -07001346 if (isFullscreenMode()) {
1347 vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001348 // "vis" should be applied for the extract frame as well in the fullscreen mode.
1349 mExtractFrame.setVisibility(vis);
The Android Open Source Project10592532009-03-18 17:39:46 -07001350 } else {
1351 vis = View.VISIBLE;
1352 mExtractFrame.setVisibility(View.GONE);
1353 }
1354 updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
1355 if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
1356 int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
1357 ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
1358 : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
1359 0);
1360 if (animRes != 0) {
1361 mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
1362 this, animRes));
1363 }
1364 }
1365 mFullscreenArea.setVisibility(vis);
1366 }
1367
1368 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 * Compute the interesting insets into your UI. The default implementation
1370 * uses the top of the candidates frame for the visible insets, and the
1371 * top of the input frame for the content insets. The default touchable
1372 * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
1373 *
The Android Open Source Project10592532009-03-18 17:39:46 -07001374 * <p>Note that this method is not called when
1375 * {@link #isExtractViewShown} returns true, since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 * in that case the application is left as-is behind the input method and
1377 * not impacted by anything in its UI.
1378 *
1379 * @param outInsets Fill in with the current UI insets.
1380 */
1381 public void onComputeInsets(Insets outInsets) {
1382 int[] loc = mTmpLocation;
1383 if (mInputFrame.getVisibility() == View.VISIBLE) {
1384 mInputFrame.getLocationInWindow(loc);
1385 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001386 View decor = getWindow().getWindow().getDecorView();
1387 loc[1] = decor.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001389 if (isFullscreenMode()) {
1390 // In fullscreen mode, we never resize the underlying window.
1391 View decor = getWindow().getWindow().getDecorView();
1392 outInsets.contentTopInsets = decor.getHeight();
1393 } else {
1394 outInsets.contentTopInsets = loc[1];
1395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
1397 mCandidatesFrame.getLocationInWindow(loc);
1398 }
1399 outInsets.visibleTopInsets = loc[1];
1400 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -08001401 outInsets.touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 }
1403
1404 /**
1405 * Re-evaluate whether the soft input area should currently be shown, and
1406 * update its UI if this has changed since the last time it
1407 * was evaluated. This will call {@link #onEvaluateInputViewShown()} to
1408 * determine whether the input view should currently be shown. You
1409 * can use {@link #isInputViewShown()} to determine if the input view
1410 * is currently shown.
1411 */
1412 public void updateInputViewShown() {
1413 boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
1414 if (mIsInputViewShown != isShown && mWindowVisible) {
1415 mIsInputViewShown = isShown;
1416 mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
1417 if (mInputView == null) {
1418 initialize();
1419 View v = onCreateInputView();
1420 if (v != null) {
1421 setInputView(v);
1422 }
1423 }
1424 }
1425 }
1426
1427 /**
1428 * Returns true if we have been asked to show our input view.
1429 */
1430 public boolean isShowInputRequested() {
1431 return mShowInputRequested;
1432 }
1433
1434 /**
1435 * Return whether the soft input view is <em>currently</em> shown to the
1436 * user. This is the state that was last determined and
1437 * applied by {@link #updateInputViewShown()}.
1438 */
1439 public boolean isInputViewShown() {
1440 return mIsInputViewShown && mWindowVisible;
1441 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001444 * Override this to control when the soft input area should be shown to the user. The default
1445 * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
1446 * unless the user shows an intention to use software keyboard. If you change what this
1447 * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
1448 * value may have changed to have it re-evaluated and applied.
1449 *
1450 * <p>When you override this method, it is recommended to call
1451 * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
1452 * returned.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 */
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001454 @CallSuper
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 public boolean onEvaluateInputViewShown() {
Yohei Yukawacf8403b2016-01-12 11:54:58 -08001456 if (mSettingsObserver == null) {
1457 Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
1458 return false;
1459 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001460 if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
1461 return true;
1462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 Configuration config = getResources().getConfiguration();
1464 return config.keyboard == Configuration.KEYBOARD_NOKEYS
Ken Wakasa8710e762011-01-30 11:02:09 +09001465 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 /**
1469 * Controls the visibility of the candidates display area. By default
1470 * it is hidden.
1471 */
1472 public void setCandidatesViewShown(boolean shown) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001473 updateCandidatesVisibility(shown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 if (!mShowInputRequested && mWindowVisible != shown) {
1475 // If we are being asked to show the candidates view while the app
1476 // has not asked for the input view to be shown, then we need
1477 // to update whether the window is shown.
1478 if (shown) {
1479 showWindow(false);
1480 } else {
satok2f913d92012-05-10 01:48:03 +09001481 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 }
1483 }
1484 }
1485
The Android Open Source Project10592532009-03-18 17:39:46 -07001486 void updateCandidatesVisibility(boolean shown) {
1487 int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
1488 if (mCandidatesVisibility != vis) {
1489 mCandidatesFrame.setVisibility(vis);
1490 mCandidatesVisibility = vis;
1491 }
1492 }
1493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 /**
1495 * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
1496 * or {@link View#GONE View.GONE}) of the candidates view when it is not
The Android Open Source Project10592532009-03-18 17:39:46 -07001497 * shown. The default implementation returns GONE when
1498 * {@link #isExtractViewShown} returns true,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 * otherwise VISIBLE. Be careful if you change this to return GONE in
1500 * other situations -- if showing or hiding the candidates view causes
1501 * your window to resize, this can cause temporary drawing artifacts as
1502 * the resize takes place.
1503 */
1504 public int getCandidatesHiddenVisibility() {
The Android Open Source Project10592532009-03-18 17:39:46 -07001505 return isExtractViewShown() ? View.GONE : View.INVISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001507
Tor Norbye7b9c9122013-05-30 16:48:33 -07001508 public void showStatusIcon(@DrawableRes int iconResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 mStatusIcon = iconResId;
Yohei Yukawa2b634342018-01-14 16:15:31 -08001510 mImm.showStatusIconInternal(mToken, getPackageName(), iconResId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 public void hideStatusIcon() {
1514 mStatusIcon = 0;
Yohei Yukawa2b634342018-01-14 16:15:31 -08001515 mImm.hideStatusIconInternal(mToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 /**
1519 * Force switch to a new input method, as identified by <var>id</var>. This
1520 * input method will be destroyed, and the requested one started on the
1521 * current input field.
1522 *
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001523 * @param id Unique identifier of the new input method to start.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 */
1525 public void switchInputMethod(String id) {
Yohei Yukawa2b634342018-01-14 16:15:31 -08001526 mImm.setInputMethodInternal(mToken, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001528
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001529 /**
1530 * Force switch to a new input method, as identified by {@code id}. This
1531 * input method will be destroyed, and the requested one started on the
1532 * current input field.
1533 *
1534 * @param id Unique identifier of the new input method to start.
1535 * @param subtype The new subtype of the new input method to be switched to.
1536 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001537 public final void switchInputMethod(String id, InputMethodSubtype subtype) {
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001538 mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
1539 }
1540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 public void setExtractView(View view) {
1542 mExtractFrame.removeAllViews();
1543 mExtractFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001544 ViewGroup.LayoutParams.MATCH_PARENT,
1545 ViewGroup.LayoutParams.MATCH_PARENT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 mExtractView = view;
1547 if (view != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001548 mExtractEditText = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 com.android.internal.R.id.inputExtractEditText);
1550 mExtractEditText.setIME(this);
Mark Renouf91eb2652016-04-11 16:03:26 -04001551 mExtractAction = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 com.android.internal.R.id.inputExtractAction);
1553 if (mExtractAction != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001554 mExtractAccessories = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 com.android.internal.R.id.inputExtractAccessories);
1556 }
1557 startExtractingText(false);
1558 } else {
1559 mExtractEditText = null;
1560 mExtractAccessories = null;
1561 mExtractAction = null;
1562 }
1563 }
1564
1565 /**
1566 * Replaces the current candidates view with a new one. You only need to
1567 * call this when dynamically changing the view; normally, you should
1568 * implement {@link #onCreateCandidatesView()} and create your view when
1569 * first needed by the input method.
1570 */
1571 public void setCandidatesView(View view) {
1572 mCandidatesFrame.removeAllViews();
1573 mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001574 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 ViewGroup.LayoutParams.WRAP_CONTENT));
1576 }
1577
1578 /**
1579 * Replaces the current input view with a new one. You only need to
1580 * call this when dynamically changing the view; normally, you should
1581 * implement {@link #onCreateInputView()} and create your view when
1582 * first needed by the input method.
1583 */
1584 public void setInputView(View view) {
1585 mInputFrame.removeAllViews();
1586 mInputFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001587 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 ViewGroup.LayoutParams.WRAP_CONTENT));
1589 mInputView = view;
1590 }
1591
1592 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 * Called by the framework to create the layout for showing extacted text.
1594 * Only called when in fullscreen mode. The returned view hierarchy must
1595 * have an {@link ExtractEditText} whose ID is
1596 * {@link android.R.id#inputExtractEditText}.
1597 */
1598 public View onCreateExtractTextView() {
1599 return mInflater.inflate(
1600 com.android.internal.R.layout.input_method_extract_view, null);
1601 }
1602
1603 /**
1604 * Create and return the view hierarchy used to show candidates. This will
1605 * be called once, when the candidates are first displayed. You can return
1606 * null to have no candidates view; the default implementation returns null.
1607 *
1608 * <p>To control when the candidates view is displayed, use
1609 * {@link #setCandidatesViewShown(boolean)}.
1610 * To change the candidates view after the first one is created by this
1611 * function, use {@link #setCandidatesView(View)}.
1612 */
1613 public View onCreateCandidatesView() {
1614 return null;
1615 }
1616
1617 /**
1618 * Create and return the view hierarchy used for the input area (such as
1619 * a soft keyboard). This will be called once, when the input area is
1620 * first displayed. You can return null to have no input area; the default
1621 * implementation returns null.
1622 *
1623 * <p>To control when the input view is displayed, implement
1624 * {@link #onEvaluateInputViewShown()}.
1625 * To change the input view after the first one is created by this
1626 * function, use {@link #setInputView(View)}.
1627 */
1628 public View onCreateInputView() {
1629 return null;
1630 }
1631
1632 /**
1633 * Called when the input view is being shown and input has started on
1634 * a new editor. This will always be called after {@link #onStartInput},
1635 * allowing you to do your general setup there and just view-specific
1636 * setup here. You are guaranteed that {@link #onCreateInputView()} will
1637 * have been called some time before this function is called.
1638 *
1639 * @param info Description of the type of text being edited.
1640 * @param restarting Set to true if we are restarting input on the
1641 * same text field as before.
1642 */
1643 public void onStartInputView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001644 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 }
1646
1647 /**
1648 * Called when the input view is being hidden from the user. This will
1649 * be called either prior to hiding the window, or prior to switching to
1650 * another target for editing.
1651 *
1652 * <p>The default
1653 * implementation uses the InputConnection to clear any active composing
1654 * text; you can override this (not calling the base class implementation)
1655 * to perform whatever behavior you would like.
1656 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001657 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 * called immediately after.
1659 */
1660 public void onFinishInputView(boolean finishingInput) {
1661 if (!finishingInput) {
1662 InputConnection ic = getCurrentInputConnection();
1663 if (ic != null) {
1664 ic.finishComposingText();
1665 }
1666 }
1667 }
1668
1669 /**
1670 * Called when only the candidates view has been shown for showing
1671 * processing as the user enters text through a hard keyboard.
1672 * This will always be called after {@link #onStartInput},
1673 * allowing you to do your general setup there and just view-specific
1674 * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
1675 * will have been called some time before this function is called.
1676 *
1677 * <p>Note that this will <em>not</em> be called when the input method
1678 * is running in full editing mode, and thus receiving
1679 * {@link #onStartInputView} to initiate that operation. This is only
1680 * for the case when candidates are being shown while the input method
1681 * editor is hidden but wants to show its candidates UI as text is
1682 * entered through some other mechanism.
1683 *
1684 * @param info Description of the type of text being edited.
1685 * @param restarting Set to true if we are restarting input on the
1686 * same text field as before.
1687 */
1688 public void onStartCandidatesView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001689 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
1691
1692 /**
1693 * Called when the candidates view is being hidden from the user. This will
1694 * be called either prior to hiding the window, or prior to switching to
1695 * another target for editing.
1696 *
1697 * <p>The default
1698 * implementation uses the InputConnection to clear any active composing
1699 * text; you can override this (not calling the base class implementation)
1700 * to perform whatever behavior you would like.
1701 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001702 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 * called immediately after.
1704 */
1705 public void onFinishCandidatesView(boolean finishingInput) {
1706 if (!finishingInput) {
1707 InputConnection ic = getCurrentInputConnection();
1708 if (ic != null) {
1709 ic.finishComposingText();
1710 }
1711 }
1712 }
1713
1714 /**
1715 * The system has decided that it may be time to show your input method.
1716 * This is called due to a corresponding call to your
The Android Open Source Project4df24232009-03-05 14:34:35 -08001717 * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 * method. The default implementation uses
1719 * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
1720 * and the current configuration to decide whether the input view should
1721 * be shown at this point.
1722 *
1723 * @param flags Provides additional information about the show request,
The Android Open Source Project4df24232009-03-05 14:34:35 -08001724 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 * @param configChange This is true if we are re-showing due to a
1726 * configuration change.
1727 * @return Returns true to indicate that the window should be shown.
1728 */
1729 public boolean onShowInputRequested(int flags, boolean configChange) {
1730 if (!onEvaluateInputViewShown()) {
1731 return false;
1732 }
1733 if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
1734 if (!configChange && onEvaluateFullscreenMode()) {
1735 // Don't show if this is not explicitly requested by the user and
1736 // the input method is fullscreen. That would be too disruptive.
1737 // However, we skip this change for a config change, since if
1738 // the IME is already shown we do want to go into fullscreen
1739 // mode at this point.
1740 return false;
1741 }
Yohei Yukawad0d07972016-05-04 11:56:35 -07001742 if (!mSettingsObserver.shouldShowImeWithHardKeyboard() &&
1743 getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 // And if the device has a hard keyboard, even if it is
1745 // currently hidden, don't show the input method implicitly.
1746 // These kinds of devices don't need it that much.
1747 return false;
1748 }
1749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 return true;
1751 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001752
1753 /**
1754 * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
1755 * states depending on its result. Since {@link #onShowInputRequested(int, boolean)} is
1756 * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
1757 * to have this method to ensure that those internal states are always updated no matter how
1758 * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
1759 * @param flags Provides additional information about the show request,
1760 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
1761 * @param configChange This is true if we are re-showing due to a
1762 * configuration change.
1763 * @return Returns true to indicate that the window should be shown.
1764 * @see #onShowInputRequested(int, boolean)
1765 */
1766 private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
1767 final boolean result = onShowInputRequested(flags, configChange);
1768 if (result) {
1769 mShowInputFlags = flags;
1770 } else {
1771 mShowInputFlags = 0;
1772 }
1773 return result;
1774 }
1775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 public void showWindow(boolean showInput) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07001777 if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 + " mShowInputRequested=" + mShowInputRequested
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 + " mWindowCreated=" + mWindowCreated
1780 + " mWindowVisible=" + mWindowVisible
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001781 + " mInputStarted=" + mInputStarted
1782 + " mShowInputFlags=" + mShowInputFlags);
1783
The Android Open Source Project10592532009-03-18 17:39:46 -07001784 if (mInShowWindow) {
1785 Log.w(TAG, "Re-entrance in to showWindow");
1786 return;
1787 }
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001788
1789 mWindowWasVisible = mWindowVisible;
1790 mInShowWindow = true;
1791 showWindowInner(showInput);
1792 mWindowWasVisible = true;
1793 mInShowWindow = false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001794 }
satok06487a52010-10-29 11:37:18 +09001795
The Android Open Source Project10592532009-03-18 17:39:46 -07001796 void showWindowInner(boolean showInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 boolean doShowInput = false;
Seigo Nonaka98d88022015-04-15 18:31:32 +09001798 final int previousImeWindowStatus =
1799 (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 mWindowVisible = true;
Yohei Yukawaac8bdd22015-09-11 18:17:11 -07001801 if (!mShowInputRequested && mInputStarted && showInput) {
1802 doShowInput = true;
1803 mShowInputRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 }
satok06487a52010-10-29 11:37:18 +09001805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 if (DEBUG) Log.v(TAG, "showWindow: updating UI");
1807 initialize();
1808 updateFullscreenMode();
1809 updateInputViewShown();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001810
1811 if (!mWindowCreated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 mWindowCreated = true;
1813 initialize();
1814 if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
1815 View v = onCreateCandidatesView();
1816 if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
1817 if (v != null) {
1818 setCandidatesView(v);
1819 }
1820 }
1821 if (mShowInputRequested) {
1822 if (!mInputViewStarted) {
1823 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1824 mInputViewStarted = true;
1825 onStartInputView(mInputEditorInfo, false);
1826 }
1827 } else if (!mCandidatesViewStarted) {
1828 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1829 mCandidatesViewStarted = true;
1830 onStartCandidatesView(mInputEditorInfo, false);
1831 }
1832
1833 if (doShowInput) {
1834 startExtractingText(false);
1835 }
satok06487a52010-10-29 11:37:18 +09001836
Tarandeep Singh3fecef12018-01-22 14:33:33 -08001837 final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
Seigo Nonaka98d88022015-04-15 18:31:32 +09001838 if (previousImeWindowStatus != nextImeWindowStatus) {
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001839 mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,
1840 mBackDisposition);
Seigo Nonaka98d88022015-04-15 18:31:32 +09001841 }
1842 if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 if (DEBUG) Log.v(TAG, "showWindow: showing!");
1844 onWindowShown();
1845 mWindow.show();
Yohei Yukawa2977eb72015-05-27 18:54:18 -07001846 // Put here rather than in onWindowShown() in case people forget to call
1847 // super.onWindowShown().
1848 mShouldClearInsetOfPreviousIme = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 }
1850 }
satok06487a52010-10-29 11:37:18 +09001851
satokf17db9f2011-09-14 18:55:58 +09001852 private void finishViews() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 if (mInputViewStarted) {
1854 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1855 onFinishInputView(false);
1856 } else if (mCandidatesViewStarted) {
1857 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1858 onFinishCandidatesView(false);
1859 }
1860 mInputViewStarted = false;
1861 mCandidatesViewStarted = false;
satokf17db9f2011-09-14 18:55:58 +09001862 }
1863
satok2f913d92012-05-10 01:48:03 +09001864 private void doHideWindow() {
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08001865 mImm.setImeWindowStatus(mToken, mStartInputToken, 0, mBackDisposition);
satok2f913d92012-05-10 01:48:03 +09001866 hideWindow();
1867 }
1868
satokf17db9f2011-09-14 18:55:58 +09001869 public void hideWindow() {
1870 finishViews();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 if (mWindowVisible) {
1872 mWindow.hide();
1873 mWindowVisible = false;
1874 onWindowHidden();
The Android Open Source Project10592532009-03-18 17:39:46 -07001875 mWindowWasVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
Seigo Nonaka93c47ea2015-07-14 15:05:04 +09001877 updateFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 }
satok06487a52010-10-29 11:37:18 +09001879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 /**
tiansiming [田思明]b9025932018-02-05 18:28:28 +08001881 * Called immediately before the input method window is shown to the user.
1882 * You could override this to prepare for the window to be shown
1883 * (update view structure etc).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 */
1885 public void onWindowShown() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001886 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
1888
1889 /**
1890 * Called when the input method window has been hidden from the user,
1891 * after previously being visible.
1892 */
1893 public void onWindowHidden() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001894 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 }
Yohei Yukawa2977eb72015-05-27 18:54:18 -07001896
1897 /**
1898 * Reset the inset occupied the previous IME when and only when
1899 * {@link #mShouldClearInsetOfPreviousIme} is {@code true}.
1900 */
1901 private void clearInsetOfPreviousIme() {
1902 if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() "
1903 + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
Yohei Yukawa833bdce2016-05-15 20:05:56 -07001904 if (!mShouldClearInsetOfPreviousIme) return;
1905
1906 mImm.clearLastInputMethodWindowForTransition(mToken);
Yohei Yukawa2977eb72015-05-27 18:54:18 -07001907 mShouldClearInsetOfPreviousIme = false;
1908 }
1909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 /**
1911 * Called when a new client has bound to the input method. This
1912 * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
1913 * and {@link #onFinishInput()} calls as the user navigates through its
1914 * UI. Upon this call you know that {@link #getCurrentInputBinding}
1915 * and {@link #getCurrentInputConnection} return valid objects.
1916 */
1917 public void onBindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001918 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 }
1920
1921 /**
1922 * Called when the previous bound client is no longer associated
1923 * with the input method. After returning {@link #getCurrentInputBinding}
1924 * and {@link #getCurrentInputConnection} will no longer return
1925 * valid objects.
1926 */
1927 public void onUnbindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001928 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 }
1930
1931 /**
1932 * Called to inform the input method that text input has started in an
1933 * editor. You should use this callback to initialize the state of your
1934 * input to match the state of the editor given to it.
1935 *
1936 * @param attribute The attributes of the editor that input is starting
1937 * in.
1938 * @param restarting Set to true if input is restarting in the same
1939 * editor such as because the application has changed the text in
1940 * the editor. Otherwise will be false, indicating this is a new
1941 * session with the editor.
1942 */
1943 public void onStartInput(EditorInfo attribute, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001944 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 }
1946
1947 void doFinishInput() {
1948 if (mInputViewStarted) {
1949 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
1950 onFinishInputView(true);
1951 } else if (mCandidatesViewStarted) {
1952 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
1953 onFinishCandidatesView(true);
1954 }
1955 mInputViewStarted = false;
1956 mCandidatesViewStarted = false;
1957 if (mInputStarted) {
1958 if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
1959 onFinishInput();
1960 }
1961 mInputStarted = false;
1962 mStartedInputConnection = null;
1963 mCurCompletions = null;
1964 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
1967 if (!restarting) {
1968 doFinishInput();
1969 }
1970 mInputStarted = true;
1971 mStartedInputConnection = ic;
1972 mInputEditorInfo = attribute;
1973 initialize();
1974 if (DEBUG) Log.v(TAG, "CALL: onStartInput");
1975 onStartInput(attribute, restarting);
1976 if (mWindowVisible) {
1977 if (mShowInputRequested) {
1978 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1979 mInputViewStarted = true;
1980 onStartInputView(mInputEditorInfo, restarting);
1981 startExtractingText(true);
1982 } else if (mCandidatesVisibility == View.VISIBLE) {
1983 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1984 mCandidatesViewStarted = true;
1985 onStartCandidatesView(mInputEditorInfo, restarting);
1986 }
1987 }
1988 }
1989
1990 /**
1991 * Called to inform the input method that text input has finished in
1992 * the last editor. At this point there may be a call to
1993 * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
1994 * new editor, or the input method may be left idle. This method is
1995 * <em>not</em> called when input restarts in the same editor.
1996 *
1997 * <p>The default
1998 * implementation uses the InputConnection to clear any active composing
1999 * text; you can override this (not calling the base class implementation)
2000 * to perform whatever behavior you would like.
2001 */
2002 public void onFinishInput() {
2003 InputConnection ic = getCurrentInputConnection();
2004 if (ic != null) {
2005 ic.finishComposingText();
2006 }
2007 }
2008
2009 /**
2010 * Called when the application has reported auto-completion candidates that
2011 * it would like to have the input method displayed. Typically these are
2012 * only used when an input method is running in full-screen mode, since
2013 * otherwise the user can see and interact with the pop-up window of
2014 * completions shown by the application.
2015 *
2016 * <p>The default implementation here does nothing.
2017 */
2018 public void onDisplayCompletions(CompletionInfo[] completions) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002019 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 }
2021
2022 /**
2023 * Called when the application has reported new extracted text to be shown
2024 * due to changes in its current text state. The default implementation
2025 * here places the new text in the extract edit text, when the input
2026 * method is running in fullscreen mode.
2027 */
2028 public void onUpdateExtractedText(int token, ExtractedText text) {
2029 if (mExtractedToken != token) {
2030 return;
2031 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002032 if (text != null) {
2033 if (mExtractEditText != null) {
2034 mExtractedText = text;
2035 mExtractEditText.setExtractedText(text);
2036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 }
2038 }
2039
2040 /**
2041 * Called when the application has reported a new selection region of
2042 * the text. This is called whether or not the input method has requested
2043 * extracted text updates, although if so it will not receive this call
2044 * if the extracted text has changed as well.
Jean Chalardc743cb92013-09-12 16:28:45 +09002045 *
2046 * <p>Be careful about changing the text in reaction to this call with
2047 * methods such as setComposingText, commitText or
2048 * deleteSurroundingText. If the cursor moves as a result, this method
2049 * will be called again, which may result in an infinite loop.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 *
2051 * <p>The default implementation takes care of updating the cursor in
2052 * the extract text, if it is being shown.
2053 */
2054 public void onUpdateSelection(int oldSelStart, int oldSelEnd,
2055 int newSelStart, int newSelEnd,
2056 int candidatesStart, int candidatesEnd) {
2057 final ExtractEditText eet = mExtractEditText;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002058 if (eet != null && isFullscreenMode() && mExtractedText != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 final int off = mExtractedText.startOffset;
2060 eet.startInternalChanges();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002061 newSelStart -= off;
2062 newSelEnd -= off;
2063 final int len = eet.getText().length();
2064 if (newSelStart < 0) newSelStart = 0;
2065 else if (newSelStart > len) newSelStart = len;
2066 if (newSelEnd < 0) newSelEnd = 0;
2067 else if (newSelEnd > len) newSelEnd = len;
2068 eet.setSelection(newSelStart, newSelEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 eet.finishInternalChanges();
2070 }
2071 }
2072
2073 /**
satok863fcd62011-06-21 17:38:02 +09002074 * Called when the user tapped or clicked a text view.
2075 * IMEs can't rely on this method being called because this was not part of the original IME
2076 * protocol, so applications with custom text editing written before this method appeared will
2077 * not call to inform the IME of this interaction.
2078 * @param focusChanged true if the user changed the focused view by this click.
2079 */
2080 public void onViewClicked(boolean focusChanged) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002081 // Intentionally empty
satok863fcd62011-06-21 17:38:02 +09002082 }
2083
2084 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07002085 * Called when the application has reported a new location of its text
2086 * cursor. This is only called if explicitly requested by the input method.
2087 * The default implementation does nothing.
2088 * @deprecated Use {#link onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07002090 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 public void onUpdateCursor(Rect newCursor) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002092 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 }
2094
2095 /**
Yohei Yukawac2ddd602014-05-06 21:22:49 +09002096 * Called when the application has reported a new location of its text insertion point and
2097 * characters in the composition string. This is only called if explicitly requested by the
2098 * input method. The default implementation does nothing.
2099 * @param cursorAnchorInfo The positional information of the text insertion point and the
2100 * composition string.
2101 */
2102 public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
2103 // Intentionally empty
2104 }
2105
2106 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 * Close this input method's soft input area, removing it from the display.
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002108 *
2109 * The input method will continue running, but the user can no longer use it to generate input
2110 * by touching the screen.
2111 *
2112 * @see InputMethodManager#HIDE_IMPLICIT_ONLY
2113 * @see InputMethodManager#HIDE_NOT_ALWAYS
2114 * @param flags Provides additional operating flags.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08002116 public void requestHideSelf(int flags) {
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002117 mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 /**
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002121 * Show the input method's soft input area, so the user sees the input method window and can
2122 * interact with it.
2123 *
2124 * @see InputMethodManager#SHOW_IMPLICIT
2125 * @see InputMethodManager#SHOW_FORCED
2126 * @param flags Provides additional operating flags.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002127 */
Tarandeep Singh45136992018-03-08 10:52:03 -08002128 public final void requestShowSelf(int flags) {
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002129 mImm.showSoftInputFromInputMethodInternal(mToken, flags);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002130 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002131
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002132 private boolean handleBack(boolean doIt) {
2133 if (mShowInputRequested) {
2134 // If the soft input area is shown, back closes it and we
2135 // consume the back key.
2136 if (doIt) requestHideSelf(0);
2137 return true;
2138 } else if (mWindowVisible) {
2139 if (mCandidatesVisibility == View.VISIBLE) {
2140 // If we are showing candidates even if no input area, then
2141 // hide them.
2142 if (doIt) setCandidatesViewShown(false);
2143 } else {
2144 // If we have the window visible for some other reason --
2145 // most likely to show candidates -- then just get rid
2146 // of it. This really shouldn't happen, but just in case...
satok2f913d92012-05-10 01:48:03 +09002147 if (doIt) doHideWindow();
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002148 }
2149 return true;
2150 }
2151 return false;
2152 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002153
2154 /**
2155 * @return {#link ExtractEditText} if it is considered to be visible and active. Otherwise
2156 * {@code null} is returned.
2157 */
2158 private ExtractEditText getExtractEditTextIfVisible() {
2159 if (!isExtractViewShown() || !isInputViewShown()) {
2160 return null;
2161 }
2162 return mExtractEditText;
2163 }
2164
Yohei Yukawa386f50e2018-03-14 13:03:42 -07002165
The Android Open Source Project4df24232009-03-05 14:34:35 -08002166 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -07002167 * Called back when a {@link KeyEvent} is forwarded from the target application.
2168 *
2169 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
2170 * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
2171 * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
2172 * in the extracted text view, not allowing them to perform navigation in the underlying
2173 * application.</p>
2174 *
2175 * <p>The default implementation does not take flags specified to
2176 * {@link #setBackDisposition(int)} into account, even on API version
2177 * {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible
2178 * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
2179 * with the flag they specified to {@link #setBackDisposition(int)}.</p>
2180 *
2181 * @param keyCode The value in {@code event.getKeyCode()}
2182 * @param event Description of the key event
2183 *
2184 * @return {@code true} if the event is consumed by the IME and the application no longer needs
2185 * to consume it. Return {@code false} when the event should be handled as if the IME
2186 * had not seen the event at all.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 */
2188 public boolean onKeyDown(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002189 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002190 final ExtractEditText eet = getExtractEditTextIfVisible();
2191 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2192 return true;
2193 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002194 if (handleBack(false)) {
2195 event.startTracking();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002198 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 return doMovementKey(keyCode, event, MOVEMENT_DOWN);
2201 }
2202
2203 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002204 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
2205 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
2206 * the event).
2207 */
2208 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
2209 return false;
2210 }
2211
2212 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 * Override this to intercept special key multiple events before they are
2214 * processed by the
2215 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002216 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 * will occur as if the IME had not seen the event at all.
2218 *
2219 * <p>The default implementation always returns false, except when
2220 * in fullscreen mode, where it will consume DPAD movement
2221 * events to move the cursor in the extracted text view, not allowing
2222 * them to perform navigation in the underlying application.
2223 */
2224 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
2225 return doMovementKey(keyCode, event, count);
2226 }
2227
2228 /**
2229 * Override this to intercept key up events before they are processed by the
2230 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002231 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 * will occur as if the IME had not seen the event at all.
2233 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002234 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
2235 * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
2236 * addition, in fullscreen mode only, it will consume DPAD movement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 * events to move the cursor in the extracted text view, not allowing
2238 * them to perform navigation in the underlying application.
2239 */
2240 public boolean onKeyUp(int keyCode, KeyEvent event) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002241 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
2242 final ExtractEditText eet = getExtractEditTextIfVisible();
2243 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2244 return true;
2245 }
2246 if (event.isTracking() && !event.isCanceled()) {
2247 return handleBack(true);
2248 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 return doMovementKey(keyCode, event, MOVEMENT_UP);
2251 }
2252
Victoria Leaseb38070c2012-08-24 13:46:02 -07002253 /**
2254 * Override this to intercept trackball motion events before they are
2255 * processed by the application.
2256 * If you return true, the application will not itself process the event.
2257 * If you return false, the normal application processing will occur as if
2258 * the IME had not seen the event at all.
2259 */
satokab751aa2010-09-14 19:17:36 +09002260 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 public boolean onTrackballEvent(MotionEvent event) {
Victoria Leaseb38070c2012-08-24 13:46:02 -07002262 if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
2263 return false;
2264 }
2265
2266 /**
2267 * Override this to intercept generic motion events before they are
2268 * processed by the application.
2269 * If you return true, the application will not itself process the event.
2270 * If you return false, the normal application processing will occur as if
2271 * the IME had not seen the event at all.
2272 */
2273 @Override
2274 public boolean onGenericMotionEvent(MotionEvent event) {
2275 if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 return false;
2277 }
2278
2279 public void onAppPrivateCommand(String action, Bundle data) {
2280 }
2281
The Android Open Source Project4df24232009-03-05 14:34:35 -08002282 /**
2283 * Handle a request by the system to toggle the soft input area.
2284 */
2285 private void onToggleSoftInput(int showFlags, int hideFlags) {
2286 if (DEBUG) Log.v(TAG, "toggleSoftInput()");
2287 if (isInputViewShown()) {
2288 requestHideSelf(hideFlags);
2289 } else {
2290 requestShowSelf(showFlags);
2291 }
2292 }
2293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 static final int MOVEMENT_DOWN = -1;
2295 static final int MOVEMENT_UP = -2;
2296
2297 void reportExtractedMovement(int keyCode, int count) {
2298 int dx = 0, dy = 0;
2299 switch (keyCode) {
2300 case KeyEvent.KEYCODE_DPAD_LEFT:
2301 dx = -count;
2302 break;
2303 case KeyEvent.KEYCODE_DPAD_RIGHT:
2304 dx = count;
2305 break;
2306 case KeyEvent.KEYCODE_DPAD_UP:
2307 dy = -count;
2308 break;
2309 case KeyEvent.KEYCODE_DPAD_DOWN:
2310 dy = count;
2311 break;
2312 }
satokab751aa2010-09-14 19:17:36 +09002313 onExtractedCursorMovement(dx, dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 boolean doMovementKey(int keyCode, KeyEvent event, int count) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002317 final ExtractEditText eet = getExtractEditTextIfVisible();
2318 if (eet != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002319 // If we are in fullscreen mode, the cursor will move around
2320 // the extract edit text, but should NOT cause focus to move
2321 // to other fields.
2322 MovementMethod movement = eet.getMovementMethod();
2323 Layout layout = eet.getLayout();
2324 if (movement != null && layout != null) {
2325 // We want our own movement method to handle the key, so the
2326 // cursor will properly move in our own word wrapping.
2327 if (count == MOVEMENT_DOWN) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002328 if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 reportExtractedMovement(keyCode, 1);
2330 return true;
2331 }
2332 } else if (count == MOVEMENT_UP) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002333 if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 return true;
2335 }
2336 } else {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002337 if (movement.onKeyOther(eet, eet.getText(), event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002338 reportExtractedMovement(keyCode, count);
2339 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002340 KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002341 if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002342 KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002343 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 while (--count > 0) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002345 movement.onKeyDown(eet, eet.getText(), keyCode, down);
2346 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002347 }
2348 reportExtractedMovement(keyCode, count);
2349 }
2350 }
2351 }
2352 }
2353 // Regardless of whether the movement method handled the key,
2354 // we never allow DPAD navigation to the application.
2355 switch (keyCode) {
2356 case KeyEvent.KEYCODE_DPAD_LEFT:
2357 case KeyEvent.KEYCODE_DPAD_RIGHT:
2358 case KeyEvent.KEYCODE_DPAD_UP:
2359 case KeyEvent.KEYCODE_DPAD_DOWN:
2360 return true;
2361 }
2362 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002364 return false;
2365 }
2366
2367 /**
2368 * Send the given key event code (as defined by {@link KeyEvent}) to the
2369 * current input connection is a key down + key up event pair. The sent
2370 * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
2371 * set, so that the recipient can identify them as coming from a software
2372 * input method, and
2373 * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
2374 * that they don't impact the current touch mode of the UI.
2375 *
Jean Chalard405bc512012-05-29 19:12:34 +09002376 * <p>Note that it's discouraged to send such key events in normal operation;
2377 * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
2378 * text fields, or for non-rich input methods. A reasonably capable software
2379 * input method should use the
2380 * {@link android.view.inputmethod.InputConnection#commitText} family of methods
2381 * to send text to an application, rather than sending key events.</p>
2382 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 * @param keyEventCode The raw key code to send, as defined by
2384 * {@link KeyEvent}.
2385 */
2386 public void sendDownUpKeyEvents(int keyEventCode) {
2387 InputConnection ic = getCurrentInputConnection();
2388 if (ic == null) return;
2389 long eventTime = SystemClock.uptimeMillis();
2390 ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002391 KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
Tadashi G. Takaokacb95cd62012-10-26 17:20:59 +09002393 ic.sendKeyEvent(new KeyEvent(eventTime, SystemClock.uptimeMillis(),
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002394 KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002395 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
2396 }
2397
2398 /**
2399 * Ask the input target to execute its default action via
2400 * {@link InputConnection#performEditorAction
2401 * InputConnection.performEditorAction()}.
2402 *
2403 * @param fromEnterKey If true, this will be executed as if the user had
2404 * pressed an enter key on the keyboard, that is it will <em>not</em>
2405 * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
2406 * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
2407 * sent regardless of how the editor has set that flag.
2408 *
2409 * @return Returns a boolean indicating whether an action has been sent.
2410 * If false, either the editor did not specify a default action or it
2411 * does not want an action from the enter key. If true, the action was
2412 * sent (or there was no input connection at all).
2413 */
2414 public boolean sendDefaultEditorAction(boolean fromEnterKey) {
2415 EditorInfo ei = getCurrentInputEditorInfo();
2416 if (ei != null &&
2417 (!fromEnterKey || (ei.imeOptions &
2418 EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
2419 (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
2420 EditorInfo.IME_ACTION_NONE) {
2421 // If the enter key was pressed, and the editor has a default
2422 // action associated with pressing enter, then send it that
2423 // explicit action instead of the key event.
2424 InputConnection ic = getCurrentInputConnection();
2425 if (ic != null) {
2426 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
2427 }
2428 return true;
2429 }
2430
2431 return false;
2432 }
2433
2434 /**
2435 * Send the given UTF-16 character to the current input connection. Most
2436 * characters will be delivered simply by calling
2437 * {@link InputConnection#commitText InputConnection.commitText()} with
2438 * the character; some, however, may be handled different. In particular,
2439 * the enter character ('\n') will either be delivered as an action code
Jean Chalard405bc512012-05-29 19:12:34 +09002440 * or a raw key event, as appropriate. Consider this as a convenience
2441 * method for IMEs that do not have a full implementation of actions; a
2442 * fully complying IME will decide of the right action for each event and
2443 * will likely never call this method except maybe to handle events coming
2444 * from an actual hardware keyboard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 *
2446 * @param charCode The UTF-16 character code to send.
2447 */
2448 public void sendKeyChar(char charCode) {
2449 switch (charCode) {
2450 case '\n': // Apps may be listening to an enter key to perform an action
2451 if (!sendDefaultEditorAction(true)) {
2452 sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
2453 }
2454 break;
2455 default:
2456 // Make sure that digits go through any text watcher on the client side.
2457 if (charCode >= '0' && charCode <= '9') {
2458 sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
2459 } else {
2460 InputConnection ic = getCurrentInputConnection();
2461 if (ic != null) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002462 ic.commitText(String.valueOf(charCode), 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 }
2464 }
2465 break;
2466 }
2467 }
2468
2469 /**
2470 * This is called when the user has moved the cursor in the extracted
2471 * text view, when running in fullsreen mode. The default implementation
2472 * performs the corresponding selection change on the underlying text
2473 * editor.
2474 */
2475 public void onExtractedSelectionChanged(int start, int end) {
2476 InputConnection conn = getCurrentInputConnection();
2477 if (conn != null) {
2478 conn.setSelection(start, end);
2479 }
2480 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002481
2482 /**
2483 * @hide
2484 */
Mathew Inwood6be79492018-07-31 14:49:38 +01002485 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002486 public void onExtractedDeleteText(int start, int end) {
2487 InputConnection conn = getCurrentInputConnection();
2488 if (conn != null) {
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002489 conn.finishComposingText();
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002490 conn.setSelection(start, start);
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002491 conn.deleteSurroundingText(0, end - start);
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002492 }
2493 }
2494
2495 /**
2496 * @hide
2497 */
Mathew Inwood6be79492018-07-31 14:49:38 +01002498 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002499 public void onExtractedReplaceText(int start, int end, CharSequence text) {
2500 InputConnection conn = getCurrentInputConnection();
2501 if (conn != null) {
2502 conn.setComposingRegion(start, end);
2503 conn.commitText(text, 1);
2504 }
2505 }
2506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002507 /**
Gilles Debunnee300be92011-12-06 10:15:56 -08002508 * @hide
2509 */
Mathew Inwood6be79492018-07-31 14:49:38 +01002510 @UnsupportedAppUsage
Gilles Debunnee300be92011-12-06 10:15:56 -08002511 public void onExtractedSetSpan(Object span, int start, int end, int flags) {
2512 InputConnection conn = getCurrentInputConnection();
2513 if (conn != null) {
2514 if (!conn.setSelection(start, end)) return;
2515 CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
2516 if (text instanceof Spannable) {
2517 ((Spannable) text).setSpan(span, 0, text.length(), flags);
2518 conn.setComposingRegion(start, end);
2519 conn.commitText(text, 1);
2520 }
2521 }
2522 }
2523
2524 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 * This is called when the user has clicked on the extracted text view,
2526 * when running in fullscreen mode. The default implementation hides
2527 * the candidates view when this happens, but only if the extracted text
2528 * editor has a vertical scroll bar because its text doesn't fit.
2529 * Re-implement this to provide whatever behavior you want.
2530 */
2531 public void onExtractedTextClicked() {
2532 if (mExtractEditText == null) {
2533 return;
2534 }
2535 if (mExtractEditText.hasVerticalScrollBar()) {
2536 setCandidatesViewShown(false);
2537 }
2538 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 /**
2541 * This is called when the user has performed a cursor movement in the
2542 * extracted text view, when it is running in fullscreen mode. The default
2543 * implementation hides the candidates view when a vertical movement
2544 * happens, but only if the extracted text editor has a vertical scroll bar
2545 * because its text doesn't fit.
2546 * Re-implement this to provide whatever behavior you want.
2547 * @param dx The amount of cursor movement in the x dimension.
2548 * @param dy The amount of cursor movement in the y dimension.
2549 */
2550 public void onExtractedCursorMovement(int dx, int dy) {
2551 if (mExtractEditText == null || dy == 0) {
2552 return;
2553 }
2554 if (mExtractEditText.hasVerticalScrollBar()) {
2555 setCandidatesViewShown(false);
2556 }
2557 }
2558
2559 /**
2560 * This is called when the user has selected a context menu item from the
2561 * extracted text view, when running in fullscreen mode. The default
2562 * implementation sends this action to the current InputConnection's
2563 * {@link InputConnection#performContextMenuAction(int)}, for it
2564 * to be processed in underlying "real" editor. Re-implement this to
2565 * provide whatever behavior you want.
2566 */
2567 public boolean onExtractTextContextMenuItem(int id) {
2568 InputConnection ic = getCurrentInputConnection();
2569 if (ic != null) {
2570 ic.performContextMenuAction(id);
2571 }
2572 return true;
2573 }
Elliot Waite54de7742017-01-11 15:30:35 -08002574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002575 /**
2576 * Return text that can be used as a button label for the given
2577 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
2578 * if there is no action requested. Note that there is no guarantee that
2579 * the returned text will be relatively short, so you probably do not
2580 * want to use it as text on a soft keyboard key label.
Elliot Waite54de7742017-01-11 15:30:35 -08002581 *
2582 * @param imeOptions The value from {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2583 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 * @return Returns a label to use, or null if there is no action.
2585 */
2586 public CharSequence getTextForImeAction(int imeOptions) {
2587 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2588 case EditorInfo.IME_ACTION_NONE:
2589 return null;
2590 case EditorInfo.IME_ACTION_GO:
2591 return getText(com.android.internal.R.string.ime_action_go);
2592 case EditorInfo.IME_ACTION_SEARCH:
2593 return getText(com.android.internal.R.string.ime_action_search);
2594 case EditorInfo.IME_ACTION_SEND:
2595 return getText(com.android.internal.R.string.ime_action_send);
2596 case EditorInfo.IME_ACTION_NEXT:
2597 return getText(com.android.internal.R.string.ime_action_next);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002598 case EditorInfo.IME_ACTION_DONE:
2599 return getText(com.android.internal.R.string.ime_action_done);
Dianne Hackborndea3ef72010-10-28 14:24:22 -07002600 case EditorInfo.IME_ACTION_PREVIOUS:
2601 return getText(com.android.internal.R.string.ime_action_previous);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 default:
2603 return getText(com.android.internal.R.string.ime_action_default);
2604 }
2605 }
Mark Renouf91eb2652016-04-11 16:03:26 -04002606
2607 /**
2608 * Return a drawable resource id that can be used as a button icon for the given
2609 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2610 *
2611 * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
2612 *
2613 * @return Returns a drawable resource id to use.
2614 */
2615 @DrawableRes
2616 private int getIconForImeAction(int imeOptions) {
2617 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2618 case EditorInfo.IME_ACTION_GO:
2619 return com.android.internal.R.drawable.ic_input_extract_action_go;
2620 case EditorInfo.IME_ACTION_SEARCH:
2621 return com.android.internal.R.drawable.ic_input_extract_action_search;
2622 case EditorInfo.IME_ACTION_SEND:
2623 return com.android.internal.R.drawable.ic_input_extract_action_send;
2624 case EditorInfo.IME_ACTION_NEXT:
2625 return com.android.internal.R.drawable.ic_input_extract_action_next;
2626 case EditorInfo.IME_ACTION_DONE:
2627 return com.android.internal.R.drawable.ic_input_extract_action_done;
2628 case EditorInfo.IME_ACTION_PREVIOUS:
2629 return com.android.internal.R.drawable.ic_input_extract_action_previous;
2630 default:
2631 return com.android.internal.R.drawable.ic_input_extract_action_return;
2632 }
2633 }
2634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07002636 * Called when the fullscreen-mode extracting editor info has changed,
2637 * to determine whether the extracting (extract text and candidates) portion
2638 * of the UI should be shown. The standard implementation hides or shows
2639 * the extract area depending on whether it makes sense for the
2640 * current editor. In particular, a {@link InputType#TYPE_NULL}
2641 * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
2642 * turn off the extract area since there is no text to be shown.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 */
The Android Open Source Project10592532009-03-18 17:39:46 -07002644 public void onUpdateExtractingVisibility(EditorInfo ei) {
2645 if (ei.inputType == InputType.TYPE_NULL ||
2646 (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
2647 // No reason to show extract UI!
2648 setExtractViewShown(false);
2649 return;
2650 }
2651
2652 setExtractViewShown(true);
2653 }
2654
2655 /**
2656 * Called when the fullscreen-mode extracting editor info has changed,
2657 * to update the state of its UI such as the action buttons shown.
2658 * You do not need to deal with this if you are using the standard
2659 * full screen extract UI. If replacing it, you will need to re-implement
2660 * this to put the appropriate action button in your own UI and handle it,
2661 * and perform any other changes.
2662 *
2663 * <p>The standard implementation turns on or off its accessory area
2664 * depending on whether there is an action button, and hides or shows
2665 * the entire extract area depending on whether it makes sense for the
2666 * current editor. In particular, a {@link InputType#TYPE_NULL} or
2667 * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
2668 * extract area since there is no text to be shown.
2669 */
2670 public void onUpdateExtractingViews(EditorInfo ei) {
2671 if (!isExtractViewShown()) {
2672 return;
2673 }
2674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 if (mExtractAccessories == null) {
2676 return;
2677 }
2678 final boolean hasAction = ei.actionLabel != null || (
2679 (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
The Android Open Source Project10592532009-03-18 17:39:46 -07002680 (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
2681 ei.inputType != InputType.TYPE_NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 if (hasAction) {
2683 mExtractAccessories.setVisibility(View.VISIBLE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002684 if (mExtractAction != null) {
Mark Renouf91eb2652016-04-11 16:03:26 -04002685 if (mExtractAction instanceof ImageButton) {
2686 ((ImageButton) mExtractAction)
2687 .setImageResource(getIconForImeAction(ei.imeOptions));
2688 if (ei.actionLabel != null) {
2689 mExtractAction.setContentDescription(ei.actionLabel);
2690 } else {
2691 mExtractAction.setContentDescription(getTextForImeAction(ei.imeOptions));
2692 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002693 } else {
Mark Renouf91eb2652016-04-11 16:03:26 -04002694 if (ei.actionLabel != null) {
2695 ((TextView) mExtractAction).setText(ei.actionLabel);
2696 } else {
2697 ((TextView) mExtractAction).setText(getTextForImeAction(ei.imeOptions));
2698 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002699 }
2700 mExtractAction.setOnClickListener(mActionClickListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 } else {
2703 mExtractAccessories.setVisibility(View.GONE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002704 if (mExtractAction != null) {
2705 mExtractAction.setOnClickListener(null);
2706 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 }
2708 }
2709
2710 /**
2711 * This is called when, while currently displayed in extract mode, the
2712 * current input target changes. The default implementation will
2713 * auto-hide the IME if the new target is not a full editor, since this
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002714 * can be a confusing experience for the user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 */
2716 public void onExtractingInputChanged(EditorInfo ei) {
2717 if (ei.inputType == InputType.TYPE_NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002718 requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 }
2720 }
2721
2722 void startExtractingText(boolean inputChanged) {
2723 final ExtractEditText eet = mExtractEditText;
2724 if (eet != null && getCurrentInputStarted()
2725 && isFullscreenMode()) {
2726 mExtractedToken++;
2727 ExtractedTextRequest req = new ExtractedTextRequest();
2728 req.token = mExtractedToken;
2729 req.flags = InputConnection.GET_TEXT_WITH_STYLES;
2730 req.hintMaxLines = 10;
2731 req.hintMaxChars = 10000;
Amith Yamasaniba4d93f2009-08-19 18:27:56 -07002732 InputConnection ic = getCurrentInputConnection();
2733 mExtractedText = ic == null? null
2734 : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
Amith Yamasania8b00c82010-03-05 15:41:31 -08002735 if (mExtractedText == null || ic == null) {
2736 Log.e(TAG, "Unexpected null in startExtractingText : mExtractedText = "
2737 + mExtractedText + ", input connection = " + ic);
2738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 final EditorInfo ei = getCurrentInputEditorInfo();
2740
2741 try {
2742 eet.startInternalChanges();
The Android Open Source Project10592532009-03-18 17:39:46 -07002743 onUpdateExtractingVisibility(ei);
2744 onUpdateExtractingViews(ei);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002745 int inputType = ei.inputType;
2746 if ((inputType&EditorInfo.TYPE_MASK_CLASS)
2747 == EditorInfo.TYPE_CLASS_TEXT) {
2748 if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
2749 inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
2750 }
2751 }
2752 eet.setInputType(inputType);
2753 eet.setHint(ei.hintText);
2754 if (mExtractedText != null) {
2755 eet.setEnabled(true);
2756 eet.setExtractedText(mExtractedText);
2757 } else {
2758 eet.setEnabled(false);
2759 eet.setText("");
2760 }
2761 } finally {
2762 eet.finishInternalChanges();
2763 }
2764
2765 if (inputChanged) {
2766 onExtractingInputChanged(ei);
2767 }
2768 }
2769 }
satokab751aa2010-09-14 19:17:36 +09002770
2771 // TODO: Handle the subtype change event
2772 /**
2773 * Called when the subtype was changed.
2774 * @param newSubtype the subtype which is being changed to.
2775 */
2776 protected void onCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2777 if (DEBUG) {
2778 int nameResId = newSubtype.getNameResId();
satok9ef02832010-11-04 21:17:48 +09002779 String mode = newSubtype.getMode();
satokab751aa2010-09-14 19:17:36 +09002780 String output = "changeInputMethodSubtype:"
2781 + (nameResId == 0 ? "<none>" : getString(nameResId)) + ","
satok9ef02832010-11-04 21:17:48 +09002782 + mode + ","
satokab751aa2010-09-14 19:17:36 +09002783 + newSubtype.getLocale() + "," + newSubtype.getExtraValue();
2784 Log.v(TAG, "--- " + output);
2785 }
2786 }
2787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 /**
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002789 * @return The recommended height of the input method window.
2790 * An IME author can get the last input method's height as the recommended height
2791 * by calling this in
2792 * {@link android.inputmethodservice.InputMethodService#onStartInputView(EditorInfo, boolean)}.
2793 * If you don't need to use a predefined fixed height, you can avoid the window-resizing of IME
2794 * switching by using this value as a visible inset height. It's efficient for the smooth
2795 * transition between different IMEs. However, note that this may return 0 (or possibly
2796 * unexpectedly low height). You should thus avoid relying on the return value of this method
2797 * all the time. Please make sure to use a reasonable height for the IME.
2798 */
2799 public int getInputMethodWindowRecommendedHeight() {
2800 return mImm.getInputMethodWindowVisibleHeight();
2801 }
2802
2803 /**
Yohei Yukawa25e08132016-06-22 16:31:41 -07002804 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
2805 * permission to the content.
2806 *
Yohei Yukawa25e08132016-06-22 16:31:41 -07002807 * @param inputContentInfo Content to be temporarily exposed from the input method to the
2808 * application.
2809 * This cannot be {@code null}.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002810 * @param inputConnection {@link InputConnection} with which
Yohei Yukawab2a0e052018-01-14 16:06:16 -08002811 * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002812 * @hide
Yohei Yukawa25e08132016-06-22 16:31:41 -07002813 */
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002814 @Override
2815 public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
2816 @NonNull InputConnection inputConnection) {
2817 if (inputConnection == null) {
2818 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002819 }
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002820 if (getCurrentInputConnection() != inputConnection) {
2821 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002822 }
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002823 mImm.exposeContent(mToken, inputContentInfo, getCurrentInputEditorInfo());
Yohei Yukawa25e08132016-06-22 16:31:41 -07002824 }
2825
Tarandeep Singh3fecef12018-01-22 14:33:33 -08002826 private static int mapToImeWindowStatus(boolean isInputViewShown) {
2827 return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
2828 }
2829
Yohei Yukawa25e08132016-06-22 16:31:41 -07002830 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 * Performs a dump of the InputMethodService's internal state. Override
2832 * to add your own information to the dump.
2833 */
2834 @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2835 final Printer p = new PrintWriterPrinter(fout);
2836 p.println("Input method service state for " + this + ":");
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07002837 p.println(" mWindowCreated=" + mWindowCreated);
The Android Open Source Project10592532009-03-18 17:39:46 -07002838 p.println(" mWindowVisible=" + mWindowVisible
2839 + " mWindowWasVisible=" + mWindowWasVisible
2840 + " mInShowWindow=" + mInShowWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002841 p.println(" Configuration=" + getResources().getConfiguration());
2842 p.println(" mToken=" + mToken);
2843 p.println(" mInputBinding=" + mInputBinding);
2844 p.println(" mInputConnection=" + mInputConnection);
2845 p.println(" mStartedInputConnection=" + mStartedInputConnection);
2846 p.println(" mInputStarted=" + mInputStarted
2847 + " mInputViewStarted=" + mInputViewStarted
2848 + " mCandidatesViewStarted=" + mCandidatesViewStarted);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08002849 p.println(" mStartInputToken=" + mStartInputToken);
2850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 if (mInputEditorInfo != null) {
2852 p.println(" mInputEditorInfo:");
2853 mInputEditorInfo.dump(p, " ");
2854 } else {
2855 p.println(" mInputEditorInfo: null");
2856 }
2857
2858 p.println(" mShowInputRequested=" + mShowInputRequested
2859 + " mLastShowInputRequested=" + mLastShowInputRequested
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
2861 p.println(" mCandidatesVisibility=" + mCandidatesVisibility
2862 + " mFullscreenApplied=" + mFullscreenApplied
The Android Open Source Project10592532009-03-18 17:39:46 -07002863 + " mIsFullscreen=" + mIsFullscreen
2864 + " mExtractViewHidden=" + mExtractViewHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002865
2866 if (mExtractedText != null) {
2867 p.println(" mExtractedText:");
2868 p.println(" text=" + mExtractedText.text.length() + " chars"
2869 + " startOffset=" + mExtractedText.startOffset);
2870 p.println(" selectionStart=" + mExtractedText.selectionStart
2871 + " selectionEnd=" + mExtractedText.selectionEnd
2872 + " flags=0x" + Integer.toHexString(mExtractedText.flags));
2873 } else {
2874 p.println(" mExtractedText: null");
2875 }
2876 p.println(" mExtractedToken=" + mExtractedToken);
2877 p.println(" mIsInputViewShown=" + mIsInputViewShown
2878 + " mStatusIcon=" + mStatusIcon);
2879 p.println("Last computed insets:");
2880 p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
2881 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
Jeff Brownfbf09772011-01-16 14:06:57 -08002882 + " touchableInsets=" + mTmpInsets.touchableInsets
2883 + " touchableRegion=" + mTmpInsets.touchableRegion);
Yohei Yukawa2977eb72015-05-27 18:54:18 -07002884 p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
Yohei Yukawa7b739a82015-12-21 13:30:44 -08002885 p.println(" mSettingsObserver=" + mSettingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 }
2887}