blob: ab630fd7467bbfdaa763a9ee49881d84ceb94ed3 [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
lumark90120a82018-08-15 00:33:03 +080019import static android.view.Display.DEFAULT_DISPLAY;
Romain Guy980a9382010-01-08 15:06:28 -080020import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
Yohei Yukawa8f162c62018-01-10 13:18:09 -080022import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
Yohei Yukawa386f50e2018-03-14 13:03:42 -070024import static java.lang.annotation.RetentionPolicy.SOURCE;
25
Yohei Yukawac07fd4c2018-09-11 11:37:13 -070026import android.annotation.AnyThread;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080027import android.annotation.CallSuper;
Tor Norbye7b9c9122013-05-30 16:48:33 -070028import android.annotation.DrawableRes;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080029import android.annotation.IntDef;
30import android.annotation.MainThread;
Yohei Yukawa25e08132016-06-22 16:31:41 -070031import android.annotation.NonNull;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -080032import android.annotation.Nullable;
Mathew Inwood1dd7d112018-07-31 14:53:29 +010033import android.annotation.UnsupportedAppUsage;
Dianne Hackborn836531b2012-08-01 19:00:38 -070034import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.app.Dialog;
36import android.content.Context;
37import android.content.res.Configuration;
Dianne Hackbornd922ae02011-01-14 11:43:24 -080038import android.content.res.Resources;
The Android Open Source Project10592532009-03-18 17:39:46 -070039import android.content.res.TypedArray;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080040import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.graphics.Rect;
Jeff Brownfbf09772011-01-16 14:06:57 -080042import android.graphics.Region;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080043import android.net.Uri;
Mathew Inwood31755f92018-12-20 13:53:36 +000044import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Bundle;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080046import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.IBinder;
The Android Open Source Project4df24232009-03-05 14:34:35 -080048import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.SystemClock;
50import android.provider.Settings;
51import android.text.InputType;
52import android.text.Layout;
53import android.text.Spannable;
54import android.text.method.MovementMethod;
55import android.util.Log;
56import android.util.PrintWriterPrinter;
57import android.util.Printer;
Dianne Hackborne30e02f2014-05-27 18:24:45 -070058import android.view.Gravity;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080059import android.view.KeyCharacterMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.view.KeyEvent;
61import android.view.LayoutInflater;
62import android.view.MotionEvent;
63import android.view.View;
64import android.view.ViewGroup;
65import android.view.ViewTreeObserver;
66import android.view.Window;
67import android.view.WindowManager;
The Android Open Source Project10592532009-03-18 17:39:46 -070068import android.view.animation.AnimationUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.view.inputmethod.CompletionInfo;
Yohei Yukawac2ddd602014-05-06 21:22:49 +090070import android.view.inputmethod.CursorAnchorInfo;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080071import android.view.inputmethod.EditorInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.view.inputmethod.ExtractedText;
73import android.view.inputmethod.ExtractedTextRequest;
74import android.view.inputmethod.InputBinding;
75import android.view.inputmethod.InputConnection;
Yohei Yukawa25e08132016-06-22 16:31:41 -070076import android.view.inputmethod.InputContentInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.view.inputmethod.InputMethod;
78import android.view.inputmethod.InputMethodManager;
satokab751aa2010-09-14 19:17:36 +090079import android.view.inputmethod.InputMethodSubtype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.widget.FrameLayout;
Mark Renouf91eb2652016-04-11 16:03:26 -040081import android.widget.ImageButton;
The Android Open Source Project10592532009-03-18 17:39:46 -070082import android.widget.LinearLayout;
Mark Renouf91eb2652016-04-11 16:03:26 -040083import android.widget.TextView;
The Android Open Source Project10592532009-03-18 17:39:46 -070084
Yohei Yukawac07fd4c2018-09-11 11:37:13 -070085import com.android.internal.annotations.GuardedBy;
Yohei Yukawac54c1172018-09-06 11:39:50 -070086import com.android.internal.inputmethod.IInputContentUriToken;
87import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -070088import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
Yohei Yukawad746a7e2018-09-18 18:55:02 -070089import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
Yohei Yukawac54c1172018-09-06 11:39:50 -070090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import java.io.FileDescriptor;
92import java.io.PrintWriter;
Yohei Yukawa7b739a82015-12-21 13:30:44 -080093import java.lang.annotation.Retention;
94import java.lang.annotation.RetentionPolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96/**
97 * InputMethodService provides a standard implementation of an InputMethod,
98 * which final implementations can derive from and customize. See the
99 * base class {@link AbstractInputMethodService} and the {@link InputMethod}
100 * interface for more information on the basics of writing input methods.
101 *
102 * <p>In addition to the normal Service lifecycle methods, this class
103 * introduces some new specific callbacks that most subclasses will want
104 * to make use of:</p>
105 * <ul>
106 * <li> {@link #onInitializeInterface()} for user-interface initialization,
107 * in particular to deal with configuration changes while the service is
108 * running.
109 * <li> {@link #onBindInput} to find out about switching to a new client.
110 * <li> {@link #onStartInput} to deal with an input session starting with
111 * the client.
112 * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
113 * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
114 * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
115 * starting within the input area of the IME.
116 * </ul>
117 *
118 * <p>An input method has significant discretion in how it goes about its
119 * work: the {@link android.inputmethodservice.InputMethodService} provides
120 * a basic framework for standard UI elements (input view, candidates view,
121 * and running in fullscreen mode), but it is up to a particular implementor
122 * to decide how to use them. For example, one input method could implement
123 * an input area with a keyboard, another could allow the user to draw text,
124 * while a third could have no input area (and thus not be visible to the
125 * user) but instead listen to audio and perform text to speech conversion.</p>
126 *
127 * <p>In the implementation provided here, all of these elements are placed
128 * together in a single window managed by the InputMethodService. It will
129 * execute callbacks as it needs information about them, and provides APIs for
130 * programmatic control over them. They layout of these elements is explicitly
131 * defined:</p>
132 *
133 * <ul>
134 * <li>The soft input view, if available, is placed at the bottom of the
135 * screen.
136 * <li>The candidates view, if currently shown, is placed above the soft
137 * input view.
138 * <li>If not running fullscreen, the application is moved or resized to be
139 * above these views; if running fullscreen, the window will completely cover
140 * the application and its top part will contain the extract text of what is
141 * currently being edited by the application.
142 * </ul>
143 *
144 *
145 * <a name="SoftInputView"></a>
146 * <h3>Soft Input View</h3>
147 *
148 * <p>Central to most input methods is the soft input view. This is where most
149 * user interaction occurs: pressing on soft keys, drawing characters, or
150 * however else your input method wants to generate text. Most implementations
151 * will simply have their own view doing all of this work, and return a new
152 * instance of it when {@link #onCreateInputView()} is called. At that point,
153 * as long as the input view is visible, you will see user interaction in
154 * that view and can call back on the InputMethodService to interact with the
155 * application as appropriate.</p>
156 *
157 * <p>There are some situations where you want to decide whether or not your
158 * soft input view should be shown to the user. This is done by implementing
159 * the {@link #onEvaluateInputViewShown()} to return true or false based on
160 * whether it should be shown in the current environment. If any of your
161 * state has changed that may impact this, call
162 * {@link #updateInputViewShown()} to have it re-evaluated. The default
163 * implementation always shows the input view unless there is a hard
164 * keyboard available, which is the appropriate behavior for most input
165 * methods.</p>
166 *
167 *
168 * <a name="CandidatesView"></a>
169 * <h3>Candidates View</h3>
170 *
171 * <p>Often while the user is generating raw text, an input method wants to
172 * provide them with a list of possible interpretations of that text that can
173 * be selected for use. This is accomplished with the candidates view, and
174 * like the soft input view you implement {@link #onCreateCandidatesView()}
175 * to instantiate your own view implementing your candidates UI.</p>
176 *
177 * <p>Management of the candidates view is a little different than the input
178 * view, because the candidates view tends to be more transient, being shown
179 * only when there are possible candidates for the current text being entered
180 * by the user. To control whether the candidates view is shown, you use
181 * {@link #setCandidatesViewShown(boolean)}. Note that because the candidate
182 * view tends to be shown and hidden a lot, it does not impact the application
183 * UI in the same way as the soft input view: it will never cause application
184 * windows to resize, only cause them to be panned if needed for the user to
185 * see the current focus.</p>
186 *
187 *
188 * <a name="FullscreenMode"></a>
189 * <h3>Fullscreen Mode</h3>
190 *
191 * <p>Sometimes your input method UI is too large to integrate with the
192 * application UI, so you just want to take over the screen. This is
193 * accomplished by switching to full-screen mode, causing the input method
194 * window to fill the entire screen and add its own "extracted text" editor
195 * showing the user the text that is being typed. Unlike the other UI elements,
196 * there is a standard implementation for the extract editor that you should
197 * not need to change. The editor is placed at the top of the IME, above the
198 * input and candidates views.</p>
199 *
200 * <p>Similar to the input view, you control whether the IME is running in
201 * fullscreen mode by implementing {@link #onEvaluateFullscreenMode()}
202 * to return true or false based on
203 * whether it should be fullscreen in the current environment. If any of your
204 * state has changed that may impact this, call
205 * {@link #updateFullscreenMode()} to have it re-evaluated. The default
206 * implementation selects fullscreen mode when the screen is in a landscape
207 * orientation, which is appropriate behavior for most input methods that have
208 * a significant input area.</p>
209 *
210 * <p>When in fullscreen mode, you have some special requirements because the
211 * user can not see the application UI. In particular, you should implement
212 * {@link #onDisplayCompletions(CompletionInfo[])} to show completions
213 * generated by your application, typically in your candidates view like you
214 * would normally show candidates.
215 *
216 *
217 * <a name="GeneratingText"></a>
218 * <h3>Generating Text</h3>
219 *
220 * <p>The key part of an IME is of course generating text for the application.
221 * This is done through calls to the
222 * {@link android.view.inputmethod.InputConnection} interface to the
223 * application, which can be retrieved from {@link #getCurrentInputConnection()}.
224 * This interface allows you to generate raw key events or, if the target
225 * supports it, directly edit in strings of candidates and committed text.</p>
226 *
227 * <p>Information about what the target is expected and supports can be found
228 * through the {@link android.view.inputmethod.EditorInfo} class, which is
229 * retrieved with {@link #getCurrentInputEditorInfo()} method. The most
230 * important part of this is {@link android.view.inputmethod.EditorInfo#inputType
231 * EditorInfo.inputType}; in particular, if this is
232 * {@link android.view.inputmethod.EditorInfo#TYPE_NULL EditorInfo.TYPE_NULL},
233 * then the target does not support complex edits and you need to only deliver
234 * raw key events to it. An input method will also want to look at other
235 * values here, to for example detect password mode, auto complete text views,
236 * phone number entry, etc.</p>
237 *
238 * <p>When the user switches between input targets, you will receive calls to
239 * {@link #onFinishInput()} and {@link #onStartInput(EditorInfo, boolean)}.
240 * You can use these to reset and initialize your input state for the current
241 * target. For example, you will often want to clear any input state, and
242 * update a soft keyboard to be appropriate for the new inputType.</p>
The Android Open Source Project10592532009-03-18 17:39:46 -0700243 *
244 * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground
245 * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
246 * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 */
248public class InputMethodService extends AbstractInputMethodService {
249 static final String TAG = "InputMethodService";
250 static final boolean DEBUG = false;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800251
252 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700253 * Allows the system to optimize the back button affordance based on the presence of software
254 * keyboard.
255 *
256 * <p>For instance, on devices that have navigation bar and software-rendered back button, the
257 * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
258 * indicate that the back button has "dismiss" affordance.</p>
259 *
260 * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
261 * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
262 * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
263 * not take this mode into account.</p>
264 *
265 * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
266 * only mode you can safely specify without worrying about the compatibility.</p>
267 *
268 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800269 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700270 public static final int BACK_DISPOSITION_DEFAULT = 0;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800271
272 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700273 * Deprecated flag.
274 *
275 * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
276 *
277 * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
278 * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
279 * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
280 * of this mode had not been well defined. Most likely the end result would be the
281 * same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
282 * use this mode
283 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800284 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700285 @Deprecated
286 public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;
Joe Onorato857fd9b2011-01-27 15:08:35 -0800287
288 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700289 * Deprecated flag.
290 *
291 * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
292 *
293 * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
294 * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
295 * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
296 * of this mode had not been well defined. In AOSP implementation running on devices
297 * that have navigation bar, specifying this flag could change the software back
298 * button to "Dismiss" icon no matter whether the software keyboard is shown or not,
299 * but there would be no easy way to restore the icon state even after IME lost the
300 * connection to the application. To avoid user confusions, do not specify this mode
301 * anyway
302 * @see #setBackDisposition(int)
Joe Onorato857fd9b2011-01-27 15:08:35 -0800303 */
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700304 @Deprecated
305 public static final int BACK_DISPOSITION_WILL_DISMISS = 2;
306
307 /**
308 * Asks the system to not adjust the back button affordance even when the software keyboard is
309 * shown.
310 *
311 * <p>This mode is useful for UI modes where IME's main soft input window is used for some
312 * supplemental UI, such as floating candidate window for languages such as Chinese and
313 * Japanese, where users expect the back button is, or at least looks to be, handled by the
314 * target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
315 * returns {@code true}.</p>
316 *
317 * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
318 * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
319 * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
320 * not take this mode into account.</p>
321 *
322 * @see #setBackDisposition(int)
323 */
324 public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
325
326 /**
327 * Enum flag to be used for {@link #setBackDisposition(int)}.
328 *
329 * @hide
330 */
331 @Retention(SOURCE)
332 @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
333 BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
334 prefix = "BACK_DISPOSITION_")
335 public @interface BackDispositionMode {}
Joe Onorato857fd9b2011-01-27 15:08:35 -0800336
337 /**
338 * @hide
339 * The IME is active. It may or may not be visible.
340 */
341 public static final int IME_ACTIVE = 0x1;
342
343 /**
344 * @hide
345 * The IME is visible.
346 */
347 public static final int IME_VISIBLE = 0x2;
348
Tarandeep Singheadb1392018-11-09 18:15:57 +0100349 /**
350 * @hide
351 * The IME is active and ready with views but set invisible.
352 * This flag cannot be combined with {@link #IME_VISIBLE}.
353 */
354 public static final int IME_INVISIBLE = 0x4;
355
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800356 // Min and max values for back disposition.
357 private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700358 private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 InputMethodManager mImm;
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -0700361 private InputMethodPrivilegedOperations mPrivOps = new InputMethodPrivilegedOperations();
Yohei Yukawac54c1172018-09-06 11:39:50 -0700362
Mathew Inwood31755f92018-12-20 13:53:36 +0000363 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800364 int mTheme = 0;
The Android Open Source Project10592532009-03-18 17:39:46 -0700365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 LayoutInflater mInflater;
The Android Open Source Project10592532009-03-18 17:39:46 -0700367 TypedArray mThemeAttrs;
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100368 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 View mRootView;
370 SoftInputWindow mWindow;
371 boolean mInitialized;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100372 boolean mViewsCreated;
373 // IME views visibility.
374 boolean mDecorViewVisible;
375 boolean mDecorViewWasVisible;
The Android Open Source Project10592532009-03-18 17:39:46 -0700376 boolean mInShowWindow;
Tarandeep Singheadb1392018-11-09 18:15:57 +0100377 // True if pre-rendering of IME views/window is supported.
378 boolean mCanPreRender;
379 // If IME is pre-rendered.
380 boolean mIsPreRendered;
381 // IME window visibility.
382 // Use (mDecorViewVisible && mWindowVisible) to check if IME is visible to the user.
383 boolean mWindowVisible;
384
The Android Open Source Project10592532009-03-18 17:39:46 -0700385 ViewGroup mFullscreenArea;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 FrameLayout mExtractFrame;
387 FrameLayout mCandidatesFrame;
388 FrameLayout mInputFrame;
389
390 IBinder mToken;
391
392 InputBinding mInputBinding;
393 InputConnection mInputConnection;
394 boolean mInputStarted;
395 boolean mInputViewStarted;
396 boolean mCandidatesViewStarted;
397 InputConnection mStartedInputConnection;
398 EditorInfo mInputEditorInfo;
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 int mShowInputFlags;
401 boolean mShowInputRequested;
402 boolean mLastShowInputRequested;
403 int mCandidatesVisibility;
404 CompletionInfo[] mCurCompletions;
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 boolean mFullscreenApplied;
407 boolean mIsFullscreen;
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100408 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 View mExtractView;
The Android Open Source Project10592532009-03-18 17:39:46 -0700410 boolean mExtractViewHidden;
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100411 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 ExtractEditText mExtractEditText;
413 ViewGroup mExtractAccessories;
Mark Renouf91eb2652016-04-11 16:03:26 -0400414 View mExtractAction;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 ExtractedText mExtractedText;
416 int mExtractedToken;
417
418 View mInputView;
419 boolean mIsInputViewShown;
420
421 int mStatusIcon;
Yohei Yukawa386f50e2018-03-14 13:03:42 -0700422
423 @BackDispositionMode
Joe Onorato857fd9b2011-01-27 15:08:35 -0800424 int mBackDisposition;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425
Yohei Yukawac07fd4c2018-09-11 11:37:13 -0700426 private Object mLock = new Object();
427 @GuardedBy("mLock")
428 private boolean mNotifyUserActionSent;
429
Mathew Inwood31755f92018-12-20 13:53:36 +0000430 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 final Insets mTmpInsets = new Insets();
432 final int[] mTmpLocation = new int[2];
satokab751aa2010-09-14 19:17:36 +0900433
Yohei Yukawa623e94b2018-01-14 16:30:59 -0800434 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
435 if (isExtractViewShown()) {
436 // In true fullscreen mode, we just say the window isn't covering
437 // any content so we don't impact whatever is behind.
438 View decor = getWindow().getWindow().getDecorView();
439 info.contentInsets.top = info.visibleInsets.top = decor.getHeight();
440 info.touchableRegion.setEmpty();
441 info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
442 } else {
443 onComputeInsets(mTmpInsets);
444 info.contentInsets.top = mTmpInsets.contentTopInsets;
445 info.visibleInsets.top = mTmpInsets.visibleTopInsets;
446 info.touchableRegion.set(mTmpInsets.touchableRegion);
447 info.setTouchableInsets(mTmpInsets.touchableInsets);
448 }
449 };
450
451 final View.OnClickListener mActionClickListener = v -> {
452 final EditorInfo ei = getCurrentInputEditorInfo();
453 final InputConnection ic = getCurrentInputConnection();
454 if (ei != null && ic != null) {
455 if (ei.actionId != 0) {
456 ic.performEditorAction(ei.actionId);
457 } else if ((ei.imeOptions & EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE) {
458 ic.performEditorAction(ei.imeOptions & EditorInfo.IME_MASK_ACTION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
460 }
461 };
462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 /**
464 * Concrete implementation of
465 * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
466 * all of the standard behavior for an input method.
467 */
468 public class InputMethodImpl extends AbstractInputMethodImpl {
469 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700470 * {@inheritDoc}
Yohei Yukawac54c1172018-09-06 11:39:50 -0700471 * @hide
472 */
473 @MainThread
474 @Override
lumark90120a82018-08-15 00:33:03 +0800475 public final void initializeInternal(IBinder token, int displayId,
Yohei Yukawac54c1172018-09-06 11:39:50 -0700476 IInputMethodPrivilegedOperations privilegedOperations) {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -0700477 mPrivOps.set(privilegedOperations);
Yohei Yukawad746a7e2018-09-18 18:55:02 -0700478 InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
lumark90120a82018-08-15 00:33:03 +0800479 updateInputMethodDisplay(displayId);
Yohei Yukawac54c1172018-09-06 11:39:50 -0700480 attachToken(token);
481 }
482
483 /**
484 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700486 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700487 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 public void attachToken(IBinder token) {
Yohei Yukawa674cc4b2018-09-06 10:47:15 -0700489 if (mToken != null) {
490 throw new IllegalStateException(
491 "attachToken() must be called at most once. token=" + token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 }
Yohei Yukawa674cc4b2018-09-06 10:47:15 -0700493 mToken = token;
494 mWindow.setToken(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
Tarandeep Singhd8d03a82017-11-28 13:35:32 -0800496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700498 * {@inheritDoc}
lumark90120a82018-08-15 00:33:03 +0800499 * @hide
500 */
501 @MainThread
502 @Override
503 public void updateInputMethodDisplay(int displayId) {
504 // Update display for adding IME window to the right display.
505 if (displayId != DEFAULT_DISPLAY) {
506 // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
507 // for update resources & configuration correctly when show soft input
508 // in non-default display.
509 updateDisplay(displayId);
510 }
511 }
512
513 /**
514 * {@inheritDoc}
Yohei Yukawa16f04072017-10-18 20:19:43 -0700515 *
516 * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700518 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700519 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 public void bindInput(InputBinding binding) {
521 mInputBinding = binding;
522 mInputConnection = binding.getConnection();
523 if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
524 + " ic=" + mInputConnection);
Yohei Yukawac54c1172018-09-06 11:39:50 -0700525 reportFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 initialize();
527 onBindInput();
528 }
529
530 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700531 * {@inheritDoc}
532 *
533 * <p>Calls {@link InputMethodService#onUnbindInput()} when done.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700535 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700536 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 public void unbindInput() {
538 if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
539 + " ic=" + mInputConnection);
540 onUnbindInput();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 mInputBinding = null;
542 mInputConnection = null;
543 }
544
Yohei Yukawa16f04072017-10-18 20:19:43 -0700545 /**
546 * {@inheritDoc}
547 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700548 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700549 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 public void startInput(InputConnection ic, EditorInfo attribute) {
551 if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
552 doStartInput(ic, attribute, false);
553 }
554
Yohei Yukawa16f04072017-10-18 20:19:43 -0700555 /**
556 * {@inheritDoc}
557 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700558 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700559 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 public void restartInput(InputConnection ic, EditorInfo attribute) {
561 if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
562 doStartInput(ic, attribute, true);
563 }
564
565 /**
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800566 * {@inheritDoc}
567 * @hide
568 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700569 @MainThread
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800570 @Override
Tarandeep Singheadb1392018-11-09 18:15:57 +0100571 public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800572 @NonNull EditorInfo editorInfo, boolean restarting,
Tarandeep Singheadb1392018-11-09 18:15:57 +0100573 @NonNull IBinder startInputToken, boolean shouldPreRenderIme) {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -0700574 mPrivOps.reportStartInput(startInputToken);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100575 mCanPreRender = shouldPreRenderIme;
576 if (DEBUG) Log.v(TAG, "Will Pre-render IME: " + mCanPreRender);
577
578 if (restarting) {
579 restartInput(inputConnection, editorInfo);
580 } else {
581 startInput(inputConnection, editorInfo);
582 }
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -0800583 }
584
585 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700586 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700588 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700589 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800590 public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 if (DEBUG) Log.v(TAG, "hideSoftInput()");
Tarandeep Singheadb1392018-11-09 18:15:57 +0100592 final boolean wasVisible = mIsPreRendered
593 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
594 if (mIsPreRendered) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100595 if (DEBUG) {
596 Log.v(TAG, "Making IME window invisible");
597 }
598 setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800599 applyVisibilityInInsetsConsumer(false /* setVisible */);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100600 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
601 } else {
602 mShowInputFlags = 0;
603 mShowInputRequested = false;
604 doHideWindow();
605 }
606 final boolean isVisible = mIsPreRendered
607 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
608 final boolean visibilityChanged = isVisible != wasVisible;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800609 if (resultReceiver != null) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100610 resultReceiver.send(visibilityChanged
The Android Open Source Project4df24232009-03-05 14:34:35 -0800611 ? InputMethodManager.RESULT_HIDDEN
Tarandeep Singheadb1392018-11-09 18:15:57 +0100612 : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
The Android Open Source Project4df24232009-03-05 14:34:35 -0800613 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
616
617 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700618 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700620 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700621 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800622 public void showSoftInput(int flags, ResultReceiver resultReceiver) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -0700623 if (DEBUG) Log.v(TAG, "showSoftInput()");
Tarandeep Singheadb1392018-11-09 18:15:57 +0100624 final boolean wasVisible = mIsPreRendered
625 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700626 if (dispatchOnShowInputRequested(flags, false)) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100627 if (mIsPreRendered) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100628 if (DEBUG) {
629 Log.v(TAG, "Making IME window visible");
630 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800631 applyVisibilityInInsetsConsumer(true /* setVisible */);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100632 onPreRenderedWindowVisibilityChanged(true /* setVisible */);
633 } else {
634 showWindow(true);
635 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 }
satok865b9772011-01-21 02:45:06 +0900637 // If user uses hard keyboard, IME button should always be shown.
Tarandeep Singheadb1392018-11-09 18:15:57 +0100638 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
639 final boolean isVisible = mIsPreRendered
640 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
641 final boolean visibilityChanged = isVisible != wasVisible;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800642 if (resultReceiver != null) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100643 resultReceiver.send(visibilityChanged
The Android Open Source Project4df24232009-03-05 14:34:35 -0800644 ? InputMethodManager.RESULT_SHOWN
Tarandeep Singheadb1392018-11-09 18:15:57 +0100645 : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
The Android Open Source Project4df24232009-03-05 14:34:35 -0800646 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
satokab751aa2010-09-14 19:17:36 +0900649
Yohei Yukawa16f04072017-10-18 20:19:43 -0700650 /**
651 * {@inheritDoc}
652 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700653 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700654 @Override
satokab751aa2010-09-14 19:17:36 +0900655 public void changeInputMethodSubtype(InputMethodSubtype subtype) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -0700656 dispatchOnCurrentInputMethodSubtypeChanged(subtype);
satokab751aa2010-09-14 19:17:36 +0900657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 }
satokab751aa2010-09-14 19:17:36 +0900659
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800660 private void notifyImeHidden() {
661 setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
662 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
663 }
664
Yohei Yukawac54c1172018-09-06 11:39:50 -0700665 private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -0700666 mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
Yohei Yukawac54c1172018-09-06 11:39:50 -0700667 }
668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 /**
670 * Concrete implementation of
671 * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
672 * all of the standard behavior for an input method session.
673 */
674 public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
675 public void finishInput() {
676 if (!isEnabled()) {
677 return;
678 }
679 if (DEBUG) Log.v(TAG, "finishInput() in " + this);
680 doFinishInput();
681 }
682
683 /**
684 * Call {@link InputMethodService#onDisplayCompletions
685 * InputMethodService.onDisplayCompletions()}.
686 */
687 public void displayCompletions(CompletionInfo[] completions) {
688 if (!isEnabled()) {
689 return;
690 }
691 mCurCompletions = completions;
692 onDisplayCompletions(completions);
693 }
694
695 /**
696 * Call {@link InputMethodService#onUpdateExtractedText
697 * InputMethodService.onUpdateExtractedText()}.
698 */
699 public void updateExtractedText(int token, ExtractedText text) {
700 if (!isEnabled()) {
701 return;
702 }
703 onUpdateExtractedText(token, text);
704 }
705
706 /**
707 * Call {@link InputMethodService#onUpdateSelection
708 * InputMethodService.onUpdateSelection()}.
709 */
710 public void updateSelection(int oldSelStart, int oldSelEnd,
711 int newSelStart, int newSelEnd,
712 int candidatesStart, int candidatesEnd) {
713 if (!isEnabled()) {
714 return;
715 }
716 InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
717 newSelStart, newSelEnd, candidatesStart, candidatesEnd);
718 }
satok863fcd62011-06-21 17:38:02 +0900719
720 @Override
721 public void viewClicked(boolean focusChanged) {
722 if (!isEnabled()) {
723 return;
724 }
725 InputMethodService.this.onViewClicked(focusChanged);
726 }
727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 /**
729 * Call {@link InputMethodService#onUpdateCursor
730 * InputMethodService.onUpdateCursor()}.
731 */
732 public void updateCursor(Rect newCursor) {
733 if (!isEnabled()) {
734 return;
735 }
736 InputMethodService.this.onUpdateCursor(newCursor);
737 }
738
739 /**
740 * Call {@link InputMethodService#onAppPrivateCommand
741 * InputMethodService.onAppPrivateCommand()}.
742 */
743 public void appPrivateCommand(String action, Bundle data) {
744 if (!isEnabled()) {
745 return;
746 }
747 InputMethodService.this.onAppPrivateCommand(action, data);
748 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800749
750 /**
751 *
752 */
753 public void toggleSoftInput(int showFlags, int hideFlags) {
754 InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
755 }
Yohei Yukawac2ddd602014-05-06 21:22:49 +0900756
757 /**
758 * Call {@link InputMethodService#onUpdateCursorAnchorInfo
759 * InputMethodService.onUpdateCursorAnchorInfo()}.
760 */
761 public void updateCursorAnchorInfo(CursorAnchorInfo info) {
762 if (!isEnabled()) {
763 return;
764 }
765 InputMethodService.this.onUpdateCursorAnchorInfo(info);
766 }
Tarandeep Singh46d59f02019-01-29 18:09:15 -0800767
768 /**
769 * Notify IME that window is hidden.
770 * @hide
771 */
772 public final void notifyImeHidden() {
773 InputMethodService.this.notifyImeHidden();
774 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 }
776
777 /**
778 * Information about where interesting parts of the input method UI appear.
779 */
780 public static final class Insets {
781 /**
782 * This is the top part of the UI that is the main content. It is
783 * used to determine the basic space needed, to resize/pan the
784 * application behind. It is assumed that this inset does not
785 * change very much, since any change will cause a full resize/pan
786 * of the application behind. This value is relative to the top edge
787 * of the input method window.
788 */
789 public int contentTopInsets;
790
791 /**
792 * This is the top part of the UI that is visibly covering the
793 * application behind it. This provides finer-grained control over
794 * visibility, allowing you to change it relatively frequently (such
795 * as hiding or showing candidates) without disrupting the underlying
796 * UI too much. For example, this will never resize the application
797 * UI, will only pan if needed to make the current focus visible, and
798 * will not aggressively move the pan position when this changes unless
799 * needed to make the focus visible. This value is relative to the top edge
800 * of the input method window.
801 */
802 public int visibleTopInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -0800803
804 /**
805 * This is the region of the UI that is touchable. It is used when
806 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
807 * The region should be specified relative to the origin of the window frame.
808 */
809 public final Region touchableRegion = new Region();
810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 /**
812 * Option for {@link #touchableInsets}: the entire window frame
813 * can be touched.
814 */
815 public static final int TOUCHABLE_INSETS_FRAME
816 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
817
818 /**
819 * Option for {@link #touchableInsets}: the area inside of
820 * the content insets can be touched.
821 */
822 public static final int TOUCHABLE_INSETS_CONTENT
823 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
824
825 /**
826 * Option for {@link #touchableInsets}: the area inside of
827 * the visible insets can be touched.
828 */
829 public static final int TOUCHABLE_INSETS_VISIBLE
830 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -0800831
832 /**
833 * Option for {@link #touchableInsets}: the region specified by
834 * {@link #touchableRegion} can be touched.
835 */
836 public static final int TOUCHABLE_INSETS_REGION
837 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 /**
840 * Determine which area of the window is touchable by the user. May
841 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
Jeff Brownfbf09772011-01-16 14:06:57 -0800842 * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
843 * or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 */
845 public int touchableInsets;
846 }
satok865b9772011-01-21 02:45:06 +0900847
The Android Open Source Project10592532009-03-18 17:39:46 -0700848 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800849 * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
850 *
851 * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
852 * Basically this functionality still needs to be considered as implementation details.</p>
853 */
854 @MainThread
855 private static final class SettingsObserver extends ContentObserver {
856 @Retention(RetentionPolicy.SOURCE)
857 @IntDef({
858 ShowImeWithHardKeyboardType.UNKNOWN,
859 ShowImeWithHardKeyboardType.FALSE,
860 ShowImeWithHardKeyboardType.TRUE,
861 })
862 private @interface ShowImeWithHardKeyboardType {
863 int UNKNOWN = 0;
864 int FALSE = 1;
865 int TRUE = 2;
866 }
867 @ShowImeWithHardKeyboardType
868 private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
869
870 private final InputMethodService mService;
871
872 private SettingsObserver(InputMethodService service) {
873 super(new Handler(service.getMainLooper()));
874 mService = service;
875 }
876
877 /**
878 * A factory method that internally enforces two-phase initialization to make sure that the
879 * object reference will not be escaped until the object is properly constructed.
880 *
881 * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence
882 * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
883 *
884 * @param service {@link InputMethodService} that needs to receive the callback.
885 * @return {@link SettingsObserver} that is already registered to
886 * {@link android.content.ContentResolver}. The caller must call
887 * {@link SettingsObserver#unregister()}.
888 */
889 public static SettingsObserver createAndRegister(InputMethodService service) {
890 final SettingsObserver observer = new SettingsObserver(service);
891 // The observer is properly constructed. Let's start accepting the event.
892 service.getContentResolver().registerContentObserver(
893 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
894 false, observer);
895 return observer;
896 }
897
898 void unregister() {
899 mService.getContentResolver().unregisterContentObserver(this);
900 }
901
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100902 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800903 private boolean shouldShowImeWithHardKeyboard() {
904 // Lazily initialize as needed.
905 if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
906 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
907 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
908 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
909 }
910 switch (mShowImeWithHardKeyboard) {
911 case ShowImeWithHardKeyboardType.TRUE:
912 return true;
913 case ShowImeWithHardKeyboardType.FALSE:
914 return false;
915 default:
916 Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
917 return false;
918 }
919 }
920
921 @Override
922 public void onChange(boolean selfChange, Uri uri) {
923 final Uri showImeWithHardKeyboardUri =
924 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
925 if (showImeWithHardKeyboardUri.equals(uri)) {
926 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
927 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
928 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
Yohei Yukawa2dbc5322016-04-03 22:50:18 -0700929 // In Android M and prior, state change of
930 // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
931 // #onConfigurationChanged(). For compatibility reasons, we reset the internal
932 // state as if configuration was changed.
933 mService.resetStateForNewConfiguration();
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800934 }
935 }
936
937 @Override
938 public String toString() {
939 return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}";
940 }
941 }
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100942 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800943 private SettingsObserver mSettingsObserver;
944
945 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700946 * You can call this to customize the theme used by your IME's window.
947 * This theme should typically be one that derives from
948 * {@link android.R.style#Theme_InputMethod}, which is the default theme
949 * you will get. This must be set before {@link #onCreate}, so you
950 * will typically call it in your constructor with the resource ID
951 * of your custom theme.
952 */
satokab751aa2010-09-14 19:17:36 +0900953 @Override
The Android Open Source Project10592532009-03-18 17:39:46 -0700954 public void setTheme(int theme) {
955 if (mWindow != null) {
956 throw new IllegalStateException("Must be called before onCreate()");
957 }
958 mTheme = theme;
959 }
satok865b9772011-01-21 02:45:06 +0900960
Dianne Hackborn836531b2012-08-01 19:00:38 -0700961 /**
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700962 * You can call this to try to enable accelerated drawing for your IME. This must be set before
963 * {@link #onCreate()}, so you will typically call it in your constructor. It is not always
964 * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
965 * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
966 * {@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 -0700967 *
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700968 * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
969 * IME on capable devices even if this method is not explicitly called. Make sure that your IME
970 * is able to handle either case.</p>
971 *
972 * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
973 * On API 21 and later devices the return value is basically just a hint and your IME
974 * does not need to change the behavior based on the it
975 * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
Dianne Hackborn836531b2012-08-01 19:00:38 -0700976 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700977 @Deprecated
Dianne Hackborn836531b2012-08-01 19:00:38 -0700978 public boolean enableHardwareAcceleration() {
979 if (mWindow != null) {
980 throw new IllegalStateException("Must be called before onCreate()");
981 }
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700982 return ActivityManager.isHighEndGfx();
Dianne Hackborn836531b2012-08-01 19:00:38 -0700983 }
984
Alan Viverette5effd7e2014-05-05 12:25:33 -0700985 @Override public void onCreate() {
986 mTheme = Resources.selectSystemTheme(mTheme,
987 getApplicationInfo().targetSdkVersion,
988 android.R.style.Theme_InputMethod,
989 android.R.style.Theme_Holo_InputMethod,
990 android.R.style.Theme_DeviceDefault_InputMethod,
991 android.R.style.Theme_DeviceDefault_InputMethod);
The Android Open Source Project10592532009-03-18 17:39:46 -0700992 super.setTheme(mTheme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 super.onCreate();
994 mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800995 mSettingsObserver = SettingsObserver.createAndRegister(this);
lumark90120a82018-08-15 00:33:03 +0800996 // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
997 // for update resources & configuration correctly when show soft input
998 // in non-default display.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 mInflater = (LayoutInflater)getSystemService(
1000 Context.LAYOUT_INFLATER_SERVICE);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001001 mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001002 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
Yohei Yukawa8f162c62018-01-10 13:18:09 -08001003 // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
1004 // by default (but IME developers can opt this out later if they want a new behavior).
1005 mWindow.getWindow().setFlags(
1006 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
1007
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 initViews();
Romain Guy980a9382010-01-08 15:06:28 -08001009 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
satokab751aa2010-09-14 19:17:36 +09001011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 /**
1013 * This is a hook that subclasses can use to perform initialization of
1014 * their interface. It is called for you prior to any of your UI objects
1015 * being created, both after the service is first created and after a
1016 * configuration change happens.
1017 */
1018 public void onInitializeInterface() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001019 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
satokab751aa2010-09-14 19:17:36 +09001021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 void initialize() {
1023 if (!mInitialized) {
1024 mInitialized = true;
1025 onInitializeInterface();
1026 }
1027 }
satokab751aa2010-09-14 19:17:36 +09001028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 void initViews() {
1030 mInitialized = false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001031 mViewsCreated = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 mShowInputRequested = false;
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001033 mShowInputFlags = 0;
1034
The Android Open Source Project10592532009-03-18 17:39:46 -07001035 mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 mRootView = mInflater.inflate(
1037 com.android.internal.R.layout.input_method, null);
1038 mWindow.setContentView(mRootView);
Seonggoo Kang72745ff2014-12-24 13:55:50 +09001039 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
Jeff Sharkey6e2bee72012-10-01 13:39:08 -07001041 if (Settings.Global.getInt(getContentResolver(),
1042 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 mWindow.getWindow().setWindowAnimations(
1044 com.android.internal.R.style.Animation_InputMethodFancy);
1045 }
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001046 mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
The Android Open Source Project10592532009-03-18 17:39:46 -07001047 mExtractViewHidden = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001048 mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 mExtractView = null;
1050 mExtractEditText = null;
1051 mExtractAccessories = null;
1052 mExtractAction = null;
1053 mFullscreenApplied = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001054
1055 mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
1056 mInputFrame = mRootView.findViewById(android.R.id.inputArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 mInputView = null;
1058 mIsInputViewShown = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 mExtractFrame.setVisibility(View.GONE);
1061 mCandidatesVisibility = getCandidatesHiddenVisibility();
1062 mCandidatesFrame.setVisibility(mCandidatesVisibility);
1063 mInputFrame.setVisibility(View.GONE);
1064 }
satokab751aa2010-09-14 19:17:36 +09001065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 @Override public void onDestroy() {
1067 super.onDestroy();
1068 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
1069 mInsetsComputer);
Satoshi Kataokac56191f2013-05-30 13:14:47 +09001070 doFinishInput();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001071 mWindow.dismissForDestroyIfNecessary();
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001072 if (mSettingsObserver != null) {
1073 mSettingsObserver.unregister();
1074 mSettingsObserver = null;
1075 }
Yohei Yukawaeec552e2018-09-09 20:48:41 -07001076 if (mToken != null) {
1077 // This is completely optional, but allows us to show more explicit error messages
1078 // when IME developers are doing something unsupported.
Yohei Yukawad746a7e2018-09-18 18:55:02 -07001079 InputMethodPrivilegedOperationsRegistry.remove(mToken);
Yohei Yukawaeec552e2018-09-09 20:48:41 -07001080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 }
satokf17db9f2011-09-14 18:55:58 +09001082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 /**
1084 * Take care of handling configuration changes. Subclasses of
1085 * InputMethodService generally don't need to deal directly with
1086 * this on their own; the standard implementation here takes care of
1087 * regenerating the input method UI as a result of the configuration
1088 * change, so you can rely on your {@link #onCreateInputView} and
1089 * other methods being called as appropriate due to a configuration change.
1090 *
1091 * <p>When a configuration change does happen,
1092 * {@link #onInitializeInterface()} is guaranteed to be called the next
1093 * time prior to any of the other input or UI creation callbacks. The
1094 * following will be called immediately depending if appropriate for current
1095 * state: {@link #onStartInput} if input is active, and
1096 * {@link #onCreateInputView} and {@link #onStartInputView} and related
1097 * appropriate functions if the UI is displayed.
1098 */
1099 @Override public void onConfigurationChanged(Configuration newConfig) {
1100 super.onConfigurationChanged(newConfig);
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001101 resetStateForNewConfiguration();
1102 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001103
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001104 private void resetStateForNewConfiguration() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01001105 boolean visible = mDecorViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 int showFlags = mShowInputFlags;
1107 boolean showingInput = mShowInputRequested;
1108 CompletionInfo[] completions = mCurCompletions;
1109 initViews();
1110 mInputViewStarted = false;
1111 mCandidatesViewStarted = false;
1112 if (mInputStarted) {
1113 doStartInput(getCurrentInputConnection(),
1114 getCurrentInputEditorInfo(), true);
1115 }
1116 if (visible) {
1117 if (showingInput) {
1118 // If we were last showing the soft keyboard, try to do so again.
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001119 if (dispatchOnShowInputRequested(showFlags, true)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 showWindow(true);
1121 if (completions != null) {
1122 mCurCompletions = completions;
1123 onDisplayCompletions(completions);
1124 }
1125 } else {
satok2f913d92012-05-10 01:48:03 +09001126 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
1128 } else if (mCandidatesVisibility == View.VISIBLE) {
1129 // If the candidates are currently visible, make sure the
1130 // window is shown for them.
1131 showWindow(false);
1132 } else {
1133 // Otherwise hide the window.
satok2f913d92012-05-10 01:48:03 +09001134 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 }
satok865b9772011-01-21 02:45:06 +09001136 // If user uses hard keyboard, IME button should always be shown.
Joe Onorato857fd9b2011-01-27 15:08:35 -08001137 boolean showing = onEvaluateInputViewShown();
Yohei Yukawac54c1172018-09-06 11:39:50 -07001138 setImeWindowStatus(IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 }
1140 }
1141
1142 /**
1143 * Implement to return our standard {@link InputMethodImpl}. Subclasses
1144 * can override to provide their own customized version.
1145 */
satokab751aa2010-09-14 19:17:36 +09001146 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 public AbstractInputMethodImpl onCreateInputMethodInterface() {
1148 return new InputMethodImpl();
1149 }
1150
1151 /**
1152 * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses
1153 * can override to provide their own customized version.
1154 */
satokab751aa2010-09-14 19:17:36 +09001155 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
1157 return new InputMethodSessionImpl();
1158 }
1159
1160 public LayoutInflater getLayoutInflater() {
1161 return mInflater;
1162 }
1163
1164 public Dialog getWindow() {
1165 return mWindow;
1166 }
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001167
1168 /**
1169 * Sets the disposition mode that indicates the expected affordance for the back button.
1170 *
1171 * <p>Keep in mind that specifying this flag does not change the the default behavior of
1172 * {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that
1173 * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
1174 * specified to this API.</p>
1175 *
1176 * @see #getBackDisposition()
1177 * @param disposition disposition mode to be set
1178 */
1179 public void setBackDisposition(@BackDispositionMode int disposition) {
Tarandeep Singh3fecef12018-01-22 14:33:33 -08001180 if (disposition == mBackDisposition) {
1181 return;
1182 }
1183 if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
1184 Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
1185 return;
1186 }
Joe Onorato857fd9b2011-01-27 15:08:35 -08001187 mBackDisposition = disposition;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001188 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
Joe Onorato857fd9b2011-01-27 15:08:35 -08001189 }
1190
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001191 /**
1192 * Retrieves the current disposition mode that indicates the expected back button affordance.
1193 *
1194 * @see #setBackDisposition(int)
1195 * @return currently selected disposition mode
1196 */
1197 @BackDispositionMode
Joe Onorato857fd9b2011-01-27 15:08:35 -08001198 public int getBackDisposition() {
1199 return mBackDisposition;
1200 }
1201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 /**
1203 * Return the maximum width, in pixels, available the input method.
1204 * Input methods are positioned at the bottom of the screen and, unless
1205 * running in fullscreen, will generally want to be as short as possible
1206 * so should compute their height based on their contents. However, they
1207 * can stretch as much as needed horizontally. The function returns to
1208 * you the maximum amount of space available horizontally, which you can
1209 * use if needed for UI placement.
1210 *
1211 * <p>In many cases this is not needed, you can just rely on the normal
1212 * view layout mechanisms to position your views within the full horizontal
1213 * space given to the input method.
1214 *
1215 * <p>Note that this value can change dynamically, in particular when the
1216 * screen orientation changes.
1217 */
1218 public int getMaxWidth() {
1219 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
1220 return wm.getDefaultDisplay().getWidth();
1221 }
1222
1223 /**
1224 * Return the currently active InputBinding for the input method, or
1225 * null if there is none.
1226 */
1227 public InputBinding getCurrentInputBinding() {
1228 return mInputBinding;
1229 }
1230
1231 /**
1232 * Retrieve the currently active InputConnection that is bound to
1233 * the input method, or null if there is none.
1234 */
1235 public InputConnection getCurrentInputConnection() {
1236 InputConnection ic = mStartedInputConnection;
1237 if (ic != null) {
1238 return ic;
1239 }
1240 return mInputConnection;
1241 }
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001242
1243 /**
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001244 * Force switch to the last used input method and subtype. If the last input method didn't have
1245 * any subtypes, the framework will simply switch to the last input method with no subtype
1246 * specified.
1247 * @return true if the current input method and subtype was successfully switched to the last
1248 * used input method and subtype.
1249 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001250 public final boolean switchToPreviousInputMethod() {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001251 return mPrivOps.switchToPreviousInputMethod();
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001252 }
1253
1254 /**
1255 * Force switch to the next input method and subtype. If there is no IME enabled except
1256 * current IME and subtype, do nothing.
1257 * @param onlyCurrentIme if true, the framework will find the next subtype which
1258 * belongs to the current IME
1259 * @return true if the current input method and subtype was successfully switched to the next
1260 * input method and subtype.
1261 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001262 public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001263 return mPrivOps.switchToNextInputMethod(onlyCurrentIme);
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001264 }
1265
1266 /**
1267 * Returns true if the current IME needs to offer the users ways to switch to a next input
1268 * method (e.g. a globe key.).
1269 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
1270 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
1271 * <p> Note that the system determines the most appropriate next input method
1272 * and subtype in order to provide the consistent user experience in switching
1273 * between IMEs and subtypes.
1274 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001275 public final boolean shouldOfferSwitchingToNextInputMethod() {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001276 return mPrivOps.shouldOfferSwitchingToNextInputMethod();
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001277 }
1278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 public boolean getCurrentInputStarted() {
1280 return mInputStarted;
1281 }
1282
1283 public EditorInfo getCurrentInputEditorInfo() {
1284 return mInputEditorInfo;
1285 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07001286
1287 private void reportFullscreenMode() {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07001288 mPrivOps.reportFullscreenMode(mIsFullscreen);
Yohei Yukawac54c1172018-09-06 11:39:50 -07001289 }
1290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 /**
1292 * Re-evaluate whether the input method should be running in fullscreen
1293 * mode, and update its UI if this has changed since the last time it
1294 * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to
1295 * determine whether it should currently run in fullscreen mode. You
1296 * can use {@link #isFullscreenMode()} to determine if the input method
1297 * is currently running in fullscreen mode.
1298 */
1299 public void updateFullscreenMode() {
1300 boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
1301 boolean changed = mLastShowInputRequested != mShowInputRequested;
1302 if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
1303 changed = true;
1304 mIsFullscreen = isFullscreen;
Yohei Yukawac54c1172018-09-06 11:39:50 -07001305 reportFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 mFullscreenApplied = true;
1307 initialize();
The Android Open Source Project10592532009-03-18 17:39:46 -07001308 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1309 mFullscreenArea.getLayoutParams();
1310 if (isFullscreen) {
1311 mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
1312 com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
1313 lp.height = 0;
1314 lp.weight = 1;
1315 } else {
1316 mFullscreenArea.setBackgroundDrawable(null);
1317 lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
1318 lp.weight = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001320 ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
1321 mFullscreenArea, lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 if (isFullscreen) {
1323 if (mExtractView == null) {
1324 View v = onCreateExtractTextView();
1325 if (v != null) {
1326 setExtractView(v);
1327 }
1328 }
1329 startExtractingText(false);
1330 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001331 updateExtractFrameVisibility();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 }
1333
1334 if (changed) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001335 onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 mLastShowInputRequested = mShowInputRequested;
1337 }
1338 }
1339
1340 /**
1341 * Update the given window's parameters for the given mode. This is called
1342 * when the window is first displayed and each time the fullscreen or
1343 * candidates only mode changes.
1344 *
1345 * <p>The default implementation makes the layout for the window
Romain Guy980a9382010-01-08 15:06:28 -08001346 * MATCH_PARENT x MATCH_PARENT when in fullscreen mode, and
1347 * MATCH_PARENT x WRAP_CONTENT when in non-fullscreen mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 *
1349 * @param win The input method's window.
1350 * @param isFullscreen If true, the window is running in fullscreen mode
1351 * and intended to cover the entire application display.
1352 * @param isCandidatesOnly If true, the window is only showing the
1353 * candidates view and none of the rest of its UI. This is mutually
1354 * exclusive with fullscreen mode.
1355 */
1356 public void onConfigureWindow(Window win, boolean isFullscreen,
1357 boolean isCandidatesOnly) {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001358 final int currentHeight = mWindow.getWindow().getAttributes().height;
1359 final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
1360 if (mIsInputViewShown && currentHeight != newHeight) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001361 if (DEBUG) {
1362 Log.w(TAG,"Window size has been changed. This may cause jankiness of resizing "
1363 + "window: " + currentHeight + " -> " + newHeight);
1364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 }
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001366 mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368
1369 /**
1370 * Return whether the input method is <em>currently</em> running in
1371 * fullscreen mode. This is the mode that was last determined and
1372 * applied by {@link #updateFullscreenMode()}.
1373 */
1374 public boolean isFullscreenMode() {
1375 return mIsFullscreen;
1376 }
1377
1378 /**
1379 * Override this to control when the input method should run in
1380 * fullscreen mode. The default implementation runs in fullsceen only
1381 * when the screen is in landscape mode. If you change what
1382 * this returns, you will need to call {@link #updateFullscreenMode()}
1383 * yourself whenever the returned value may have changed to have it
1384 * re-evaluated and applied.
1385 */
1386 public boolean onEvaluateFullscreenMode() {
1387 Configuration config = getResources().getConfiguration();
Leon Scroggins2edd6822010-01-12 11:36:13 -05001388 if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
1389 return false;
1390 }
1391 if (mInputEditorInfo != null
1392 && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
1393 return false;
1394 }
1395 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 }
Gilles Debunne34703b62011-09-08 11:16:25 -07001397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07001399 * Controls the visibility of the extracted text area. This only applies
1400 * when the input method is in fullscreen mode, and thus showing extracted
1401 * text. When false, the extracted text will not be shown, allowing some
1402 * of the application to be seen behind. This is normally set for you
1403 * by {@link #onUpdateExtractingVisibility}. This controls the visibility
1404 * of both the extracted text and candidate view; the latter since it is
1405 * not useful if there is no text to see.
1406 */
1407 public void setExtractViewShown(boolean shown) {
1408 if (mExtractViewHidden == shown) {
1409 mExtractViewHidden = !shown;
1410 updateExtractFrameVisibility();
1411 }
1412 }
1413
1414 /**
1415 * Return whether the fullscreen extract view is shown. This will only
1416 * return true if {@link #isFullscreenMode()} returns true, and in that
1417 * case its value depends on the last call to
1418 * {@link #setExtractViewShown(boolean)}. This effectively lets you
1419 * determine if the application window is entirely covered (when this
1420 * returns true) or if some part of it may be shown (if this returns
1421 * false, though if {@link #isFullscreenMode()} returns true in that case
1422 * then it is probably only a sliver of the application).
1423 */
1424 public boolean isExtractViewShown() {
1425 return mIsFullscreen && !mExtractViewHidden;
1426 }
1427
1428 void updateExtractFrameVisibility() {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001429 final int vis;
The Android Open Source Project10592532009-03-18 17:39:46 -07001430 if (isFullscreenMode()) {
1431 vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001432 // "vis" should be applied for the extract frame as well in the fullscreen mode.
1433 mExtractFrame.setVisibility(vis);
The Android Open Source Project10592532009-03-18 17:39:46 -07001434 } else {
1435 vis = View.VISIBLE;
1436 mExtractFrame.setVisibility(View.GONE);
1437 }
1438 updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001439 if (mDecorViewWasVisible && mFullscreenArea.getVisibility() != vis) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001440 int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
1441 ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
1442 : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
1443 0);
1444 if (animRes != 0) {
1445 mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
1446 this, animRes));
1447 }
1448 }
1449 mFullscreenArea.setVisibility(vis);
1450 }
1451
1452 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 * Compute the interesting insets into your UI. The default implementation
1454 * uses the top of the candidates frame for the visible insets, and the
1455 * top of the input frame for the content insets. The default touchable
1456 * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
1457 *
The Android Open Source Project10592532009-03-18 17:39:46 -07001458 * <p>Note that this method is not called when
1459 * {@link #isExtractViewShown} returns true, since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 * in that case the application is left as-is behind the input method and
1461 * not impacted by anything in its UI.
1462 *
1463 * @param outInsets Fill in with the current UI insets.
1464 */
1465 public void onComputeInsets(Insets outInsets) {
1466 int[] loc = mTmpLocation;
1467 if (mInputFrame.getVisibility() == View.VISIBLE) {
1468 mInputFrame.getLocationInWindow(loc);
1469 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001470 View decor = getWindow().getWindow().getDecorView();
1471 loc[1] = decor.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001473 if (isFullscreenMode()) {
1474 // In fullscreen mode, we never resize the underlying window.
1475 View decor = getWindow().getWindow().getDecorView();
1476 outInsets.contentTopInsets = decor.getHeight();
1477 } else {
1478 outInsets.contentTopInsets = loc[1];
1479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
1481 mCandidatesFrame.getLocationInWindow(loc);
1482 }
1483 outInsets.visibleTopInsets = loc[1];
1484 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -08001485 outInsets.touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
1487
1488 /**
1489 * Re-evaluate whether the soft input area should currently be shown, and
1490 * update its UI if this has changed since the last time it
1491 * was evaluated. This will call {@link #onEvaluateInputViewShown()} to
1492 * determine whether the input view should currently be shown. You
1493 * can use {@link #isInputViewShown()} to determine if the input view
1494 * is currently shown.
1495 */
1496 public void updateInputViewShown() {
1497 boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001498 if (mIsInputViewShown != isShown && mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 mIsInputViewShown = isShown;
1500 mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
1501 if (mInputView == null) {
1502 initialize();
1503 View v = onCreateInputView();
1504 if (v != null) {
1505 setInputView(v);
1506 }
1507 }
1508 }
1509 }
1510
1511 /**
1512 * Returns true if we have been asked to show our input view.
1513 */
1514 public boolean isShowInputRequested() {
1515 return mShowInputRequested;
1516 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 /**
1519 * Return whether the soft input view is <em>currently</em> shown to the
1520 * user. This is the state that was last determined and
1521 * applied by {@link #updateInputViewShown()}.
1522 */
1523 public boolean isInputViewShown() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01001524 return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001528 * Override this to control when the soft input area should be shown to the user. The default
1529 * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
1530 * unless the user shows an intention to use software keyboard. If you change what this
1531 * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
1532 * value may have changed to have it re-evaluated and applied.
1533 *
1534 * <p>When you override this method, it is recommended to call
1535 * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
1536 * returned.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 */
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001538 @CallSuper
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 public boolean onEvaluateInputViewShown() {
Yohei Yukawacf8403b2016-01-12 11:54:58 -08001540 if (mSettingsObserver == null) {
1541 Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
1542 return false;
1543 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001544 if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
1545 return true;
1546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 Configuration config = getResources().getConfiguration();
1548 return config.keyboard == Configuration.KEYBOARD_NOKEYS
Ken Wakasa8710e762011-01-30 11:02:09 +09001549 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 /**
1553 * Controls the visibility of the candidates display area. By default
1554 * it is hidden.
1555 */
1556 public void setCandidatesViewShown(boolean shown) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001557 updateCandidatesVisibility(shown);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001558 if (!mShowInputRequested && mDecorViewVisible != shown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 // If we are being asked to show the candidates view while the app
1560 // has not asked for the input view to be shown, then we need
1561 // to update whether the window is shown.
1562 if (shown) {
1563 showWindow(false);
1564 } else {
satok2f913d92012-05-10 01:48:03 +09001565 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 }
1567 }
1568 }
1569
The Android Open Source Project10592532009-03-18 17:39:46 -07001570 void updateCandidatesVisibility(boolean shown) {
1571 int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
1572 if (mCandidatesVisibility != vis) {
1573 mCandidatesFrame.setVisibility(vis);
1574 mCandidatesVisibility = vis;
1575 }
1576 }
1577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 /**
1579 * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
1580 * or {@link View#GONE View.GONE}) of the candidates view when it is not
The Android Open Source Project10592532009-03-18 17:39:46 -07001581 * shown. The default implementation returns GONE when
1582 * {@link #isExtractViewShown} returns true,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 * otherwise VISIBLE. Be careful if you change this to return GONE in
1584 * other situations -- if showing or hiding the candidates view causes
1585 * your window to resize, this can cause temporary drawing artifacts as
1586 * the resize takes place.
1587 */
1588 public int getCandidatesHiddenVisibility() {
The Android Open Source Project10592532009-03-18 17:39:46 -07001589 return isExtractViewShown() ? View.GONE : View.INVISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001591
Tor Norbye7b9c9122013-05-30 16:48:33 -07001592 public void showStatusIcon(@DrawableRes int iconResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 mStatusIcon = iconResId;
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001594 mPrivOps.updateStatusIcon(getPackageName(), iconResId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 public void hideStatusIcon() {
1598 mStatusIcon = 0;
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001599 mPrivOps.updateStatusIcon(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 /**
1603 * Force switch to a new input method, as identified by <var>id</var>. This
1604 * input method will be destroyed, and the requested one started on the
1605 * current input field.
1606 *
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001607 * @param id Unique identifier of the new input method to start.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 */
1609 public void switchInputMethod(String id) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001610 mPrivOps.setInputMethod(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001612
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001613 /**
1614 * Force switch to a new input method, as identified by {@code id}. This
1615 * input method will be destroyed, and the requested one started on the
1616 * current input field.
1617 *
1618 * @param id Unique identifier of the new input method to start.
1619 * @param subtype The new subtype of the new input method to be switched to.
1620 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001621 public final void switchInputMethod(String id, InputMethodSubtype subtype) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001622 mPrivOps.setInputMethodAndSubtype(id, subtype);
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001623 }
1624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 public void setExtractView(View view) {
1626 mExtractFrame.removeAllViews();
1627 mExtractFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001628 ViewGroup.LayoutParams.MATCH_PARENT,
1629 ViewGroup.LayoutParams.MATCH_PARENT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 mExtractView = view;
1631 if (view != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001632 mExtractEditText = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 com.android.internal.R.id.inputExtractEditText);
1634 mExtractEditText.setIME(this);
Mark Renouf91eb2652016-04-11 16:03:26 -04001635 mExtractAction = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 com.android.internal.R.id.inputExtractAction);
1637 if (mExtractAction != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001638 mExtractAccessories = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 com.android.internal.R.id.inputExtractAccessories);
1640 }
1641 startExtractingText(false);
1642 } else {
1643 mExtractEditText = null;
1644 mExtractAccessories = null;
1645 mExtractAction = null;
1646 }
1647 }
1648
1649 /**
1650 * Replaces the current candidates view with a new one. You only need to
1651 * call this when dynamically changing the view; normally, you should
1652 * implement {@link #onCreateCandidatesView()} and create your view when
1653 * first needed by the input method.
1654 */
1655 public void setCandidatesView(View view) {
1656 mCandidatesFrame.removeAllViews();
1657 mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001658 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 ViewGroup.LayoutParams.WRAP_CONTENT));
1660 }
1661
1662 /**
1663 * Replaces the current input view with a new one. You only need to
1664 * call this when dynamically changing the view; normally, you should
1665 * implement {@link #onCreateInputView()} and create your view when
1666 * first needed by the input method.
1667 */
1668 public void setInputView(View view) {
1669 mInputFrame.removeAllViews();
1670 mInputFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001671 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 ViewGroup.LayoutParams.WRAP_CONTENT));
1673 mInputView = view;
1674 }
1675
1676 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 * Called by the framework to create the layout for showing extacted text.
1678 * Only called when in fullscreen mode. The returned view hierarchy must
1679 * have an {@link ExtractEditText} whose ID is
1680 * {@link android.R.id#inputExtractEditText}.
1681 */
1682 public View onCreateExtractTextView() {
1683 return mInflater.inflate(
1684 com.android.internal.R.layout.input_method_extract_view, null);
1685 }
1686
1687 /**
1688 * Create and return the view hierarchy used to show candidates. This will
1689 * be called once, when the candidates are first displayed. You can return
1690 * null to have no candidates view; the default implementation returns null.
1691 *
1692 * <p>To control when the candidates view is displayed, use
1693 * {@link #setCandidatesViewShown(boolean)}.
1694 * To change the candidates view after the first one is created by this
1695 * function, use {@link #setCandidatesView(View)}.
1696 */
1697 public View onCreateCandidatesView() {
1698 return null;
1699 }
1700
1701 /**
1702 * Create and return the view hierarchy used for the input area (such as
1703 * a soft keyboard). This will be called once, when the input area is
1704 * first displayed. You can return null to have no input area; the default
1705 * implementation returns null.
1706 *
1707 * <p>To control when the input view is displayed, implement
1708 * {@link #onEvaluateInputViewShown()}.
1709 * To change the input view after the first one is created by this
1710 * function, use {@link #setInputView(View)}.
1711 */
1712 public View onCreateInputView() {
1713 return null;
1714 }
1715
1716 /**
1717 * Called when the input view is being shown and input has started on
1718 * a new editor. This will always be called after {@link #onStartInput},
1719 * allowing you to do your general setup there and just view-specific
1720 * setup here. You are guaranteed that {@link #onCreateInputView()} will
1721 * have been called some time before this function is called.
1722 *
1723 * @param info Description of the type of text being edited.
1724 * @param restarting Set to true if we are restarting input on the
1725 * same text field as before.
1726 */
1727 public void onStartInputView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001728 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
1730
1731 /**
1732 * Called when the input view is being hidden from the user. This will
1733 * be called either prior to hiding the window, or prior to switching to
1734 * another target for editing.
1735 *
1736 * <p>The default
1737 * implementation uses the InputConnection to clear any active composing
1738 * text; you can override this (not calling the base class implementation)
1739 * to perform whatever behavior you would like.
1740 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001741 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 * called immediately after.
1743 */
1744 public void onFinishInputView(boolean finishingInput) {
1745 if (!finishingInput) {
1746 InputConnection ic = getCurrentInputConnection();
1747 if (ic != null) {
1748 ic.finishComposingText();
1749 }
1750 }
1751 }
1752
1753 /**
1754 * Called when only the candidates view has been shown for showing
1755 * processing as the user enters text through a hard keyboard.
1756 * This will always be called after {@link #onStartInput},
1757 * allowing you to do your general setup there and just view-specific
1758 * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
1759 * will have been called some time before this function is called.
1760 *
1761 * <p>Note that this will <em>not</em> be called when the input method
1762 * is running in full editing mode, and thus receiving
1763 * {@link #onStartInputView} to initiate that operation. This is only
1764 * for the case when candidates are being shown while the input method
1765 * editor is hidden but wants to show its candidates UI as text is
1766 * entered through some other mechanism.
1767 *
1768 * @param info Description of the type of text being edited.
1769 * @param restarting Set to true if we are restarting input on the
1770 * same text field as before.
1771 */
1772 public void onStartCandidatesView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001773 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 }
1775
1776 /**
1777 * Called when the candidates view is being hidden from the user. This will
1778 * be called either prior to hiding the window, or prior to switching to
1779 * another target for editing.
1780 *
1781 * <p>The default
1782 * implementation uses the InputConnection to clear any active composing
1783 * text; you can override this (not calling the base class implementation)
1784 * to perform whatever behavior you would like.
1785 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001786 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 * called immediately after.
1788 */
1789 public void onFinishCandidatesView(boolean finishingInput) {
1790 if (!finishingInput) {
1791 InputConnection ic = getCurrentInputConnection();
1792 if (ic != null) {
1793 ic.finishComposingText();
1794 }
1795 }
1796 }
1797
1798 /**
1799 * The system has decided that it may be time to show your input method.
1800 * This is called due to a corresponding call to your
The Android Open Source Project4df24232009-03-05 14:34:35 -08001801 * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 * method. The default implementation uses
1803 * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
1804 * and the current configuration to decide whether the input view should
1805 * be shown at this point.
1806 *
1807 * @param flags Provides additional information about the show request,
The Android Open Source Project4df24232009-03-05 14:34:35 -08001808 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 * @param configChange This is true if we are re-showing due to a
1810 * configuration change.
1811 * @return Returns true to indicate that the window should be shown.
1812 */
1813 public boolean onShowInputRequested(int flags, boolean configChange) {
1814 if (!onEvaluateInputViewShown()) {
1815 return false;
1816 }
1817 if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
1818 if (!configChange && onEvaluateFullscreenMode()) {
1819 // Don't show if this is not explicitly requested by the user and
1820 // the input method is fullscreen. That would be too disruptive.
1821 // However, we skip this change for a config change, since if
1822 // the IME is already shown we do want to go into fullscreen
1823 // mode at this point.
1824 return false;
1825 }
Yohei Yukawad0d07972016-05-04 11:56:35 -07001826 if (!mSettingsObserver.shouldShowImeWithHardKeyboard() &&
1827 getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 // And if the device has a hard keyboard, even if it is
1829 // currently hidden, don't show the input method implicitly.
1830 // These kinds of devices don't need it that much.
1831 return false;
1832 }
1833 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 return true;
1835 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001836
1837 /**
1838 * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
1839 * states depending on its result. Since {@link #onShowInputRequested(int, boolean)} is
1840 * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
1841 * to have this method to ensure that those internal states are always updated no matter how
1842 * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
1843 * @param flags Provides additional information about the show request,
1844 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
1845 * @param configChange This is true if we are re-showing due to a
1846 * configuration change.
1847 * @return Returns true to indicate that the window should be shown.
1848 * @see #onShowInputRequested(int, boolean)
1849 */
1850 private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
1851 final boolean result = onShowInputRequested(flags, configChange);
1852 if (result) {
1853 mShowInputFlags = flags;
1854 } else {
1855 mShowInputFlags = 0;
1856 }
1857 return result;
1858 }
1859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 public void showWindow(boolean showInput) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07001861 if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 + " mShowInputRequested=" + mShowInputRequested
Tarandeep Singheadb1392018-11-09 18:15:57 +01001863 + " mViewsCreated=" + mViewsCreated
1864 + " mDecorViewVisible=" + mDecorViewVisible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 + " mWindowVisible=" + mWindowVisible
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001866 + " mInputStarted=" + mInputStarted
1867 + " mShowInputFlags=" + mShowInputFlags);
1868
The Android Open Source Project10592532009-03-18 17:39:46 -07001869 if (mInShowWindow) {
1870 Log.w(TAG, "Re-entrance in to showWindow");
1871 return;
1872 }
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001873
Tarandeep Singheadb1392018-11-09 18:15:57 +01001874 mDecorViewWasVisible = mDecorViewVisible;
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001875 mInShowWindow = true;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001876 boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible;
1877 final int previousImeWindowStatus =
1878 (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
1879 ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
1880 startViews(prepareWindow(showInput));
1881 final int nextImeWindowStatus = mapToImeWindowStatus();
1882 if (previousImeWindowStatus != nextImeWindowStatus) {
1883 setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
1884 }
1885
1886 // compute visibility
1887 onWindowShown();
1888 mIsPreRendered = mCanPreRender;
1889 if (mIsPreRendered) {
1890 onPreRenderedWindowVisibilityChanged(true /* setVisible */);
1891 } else {
1892 // Pre-rendering not supported.
1893 if (DEBUG) Log.d(TAG, "No pre-rendering supported");
1894 mWindowVisible = true;
1895 }
1896
1897 // request draw for the IME surface.
1898 // When IME is not pre-rendered, this will actually show the IME.
1899 if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
1900 if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
1901 mWindow.show();
1902 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001903 maybeNotifyPreRendered();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001904 mDecorViewWasVisible = true;
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001905 mInShowWindow = false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001906 }
satok06487a52010-10-29 11:37:18 +09001907
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001908 /**
1909 * Notify {@link android.view.ImeInsetsSourceConsumer} if IME has been pre-rendered
1910 * for current EditorInfo, when pre-rendering is enabled.
1911 */
1912 private void maybeNotifyPreRendered() {
1913 if (!mCanPreRender || !mIsPreRendered) {
1914 return;
1915 }
1916 mPrivOps.reportPreRendered(getCurrentInputEditorInfo());
1917 }
1918
1919
Tarandeep Singheadb1392018-11-09 18:15:57 +01001920 private boolean prepareWindow(boolean showInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 boolean doShowInput = false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001922 mDecorViewVisible = true;
Yohei Yukawaac8bdd22015-09-11 18:17:11 -07001923 if (!mShowInputRequested && mInputStarted && showInput) {
1924 doShowInput = true;
1925 mShowInputRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 }
satok06487a52010-10-29 11:37:18 +09001927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 if (DEBUG) Log.v(TAG, "showWindow: updating UI");
1929 initialize();
1930 updateFullscreenMode();
1931 updateInputViewShown();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001932
Tarandeep Singheadb1392018-11-09 18:15:57 +01001933 if (!mViewsCreated) {
1934 mViewsCreated = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 initialize();
1936 if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
1937 View v = onCreateCandidatesView();
1938 if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
1939 if (v != null) {
1940 setCandidatesView(v);
1941 }
1942 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001943 return doShowInput;
1944 }
1945
1946 private void startViews(boolean doShowInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 if (mShowInputRequested) {
1948 if (!mInputViewStarted) {
1949 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1950 mInputViewStarted = true;
1951 onStartInputView(mInputEditorInfo, false);
1952 }
1953 } else if (!mCandidatesViewStarted) {
1954 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1955 mCandidatesViewStarted = true;
1956 onStartCandidatesView(mInputEditorInfo, false);
1957 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001958 if (doShowInput) startExtractingText(false);
1959 }
satok06487a52010-10-29 11:37:18 +09001960
Tarandeep Singheadb1392018-11-09 18:15:57 +01001961 private void onPreRenderedWindowVisibilityChanged(boolean setVisible) {
1962 mWindowVisible = setVisible;
1963 mShowInputFlags = setVisible ? mShowInputFlags : 0;
1964 mShowInputRequested = setVisible;
1965 mDecorViewVisible = setVisible;
1966 if (setVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 onWindowShown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 }
1969 }
satok06487a52010-10-29 11:37:18 +09001970
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001971 /**
1972 * Apply the IME visibility in {@link android.view.ImeInsetsSourceConsumer} when
1973 * pre-rendering is enabled.
1974 * @param setVisible {@code true} to make it visible, false to hide it.
1975 */
1976 private void applyVisibilityInInsetsConsumer(boolean setVisible) {
1977 if (!mIsPreRendered) {
1978 return;
1979 }
1980 mPrivOps.applyImeVisibility(setVisible);
1981 }
1982
Tarandeep Singheadb1392018-11-09 18:15:57 +01001983 private void finishViews(boolean finishingInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 if (mInputViewStarted) {
1985 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
Tarandeep Singheadb1392018-11-09 18:15:57 +01001986 onFinishInputView(finishingInput);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 } else if (mCandidatesViewStarted) {
1988 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
Tarandeep Singheadb1392018-11-09 18:15:57 +01001989 onFinishCandidatesView(finishingInput);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991 mInputViewStarted = false;
1992 mCandidatesViewStarted = false;
satokf17db9f2011-09-14 18:55:58 +09001993 }
1994
satok2f913d92012-05-10 01:48:03 +09001995 private void doHideWindow() {
Yohei Yukawac54c1172018-09-06 11:39:50 -07001996 setImeWindowStatus(0, mBackDisposition);
satok2f913d92012-05-10 01:48:03 +09001997 hideWindow();
1998 }
1999
satokf17db9f2011-09-14 18:55:58 +09002000 public void hideWindow() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01002001 if (DEBUG) Log.v(TAG, "CALL: hideWindow");
2002 mIsPreRendered = false;
2003 mWindowVisible = false;
2004 finishViews(false /* finishingInput */);
2005 if (mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 mWindow.hide();
Tarandeep Singheadb1392018-11-09 18:15:57 +01002007 mDecorViewVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 onWindowHidden();
Tarandeep Singheadb1392018-11-09 18:15:57 +01002009 mDecorViewWasVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 }
Seigo Nonaka93c47ea2015-07-14 15:05:04 +09002011 updateFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 }
satok06487a52010-10-29 11:37:18 +09002013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 /**
tiansiming [田思明]b9025932018-02-05 18:28:28 +08002015 * Called immediately before the input method window is shown to the user.
2016 * You could override this to prepare for the window to be shown
2017 * (update view structure etc).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 */
2019 public void onWindowShown() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002020 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
2022
2023 /**
2024 * Called when the input method window has been hidden from the user,
2025 * after previously being visible.
2026 */
2027 public void onWindowHidden() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002028 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
Yohei Yukawa2977eb72015-05-27 18:54:18 -07002030
2031 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 * Called when a new client has bound to the input method. This
2033 * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
2034 * and {@link #onFinishInput()} calls as the user navigates through its
2035 * UI. Upon this call you know that {@link #getCurrentInputBinding}
2036 * and {@link #getCurrentInputConnection} return valid objects.
2037 */
2038 public void onBindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002039 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 }
2041
2042 /**
2043 * Called when the previous bound client is no longer associated
2044 * with the input method. After returning {@link #getCurrentInputBinding}
2045 * and {@link #getCurrentInputConnection} will no longer return
2046 * valid objects.
2047 */
2048 public void onUnbindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002049 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 }
2051
2052 /**
2053 * Called to inform the input method that text input has started in an
2054 * editor. You should use this callback to initialize the state of your
2055 * input to match the state of the editor given to it.
2056 *
2057 * @param attribute The attributes of the editor that input is starting
2058 * in.
2059 * @param restarting Set to true if input is restarting in the same
2060 * editor such as because the application has changed the text in
2061 * the editor. Otherwise will be false, indicating this is a new
2062 * session with the editor.
2063 */
2064 public void onStartInput(EditorInfo attribute, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002065 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067
2068 void doFinishInput() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01002069 if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
2070 finishViews(true /* finishingInput */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 if (mInputStarted) {
2072 if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
2073 onFinishInput();
2074 }
2075 mInputStarted = false;
2076 mStartedInputConnection = null;
2077 mCurCompletions = null;
2078 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
2081 if (!restarting) {
2082 doFinishInput();
2083 }
2084 mInputStarted = true;
2085 mStartedInputConnection = ic;
2086 mInputEditorInfo = attribute;
2087 initialize();
2088 if (DEBUG) Log.v(TAG, "CALL: onStartInput");
2089 onStartInput(attribute, restarting);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002090 if (mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 if (mShowInputRequested) {
2092 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
2093 mInputViewStarted = true;
2094 onStartInputView(mInputEditorInfo, restarting);
2095 startExtractingText(true);
2096 } else if (mCandidatesVisibility == View.VISIBLE) {
2097 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
2098 mCandidatesViewStarted = true;
2099 onStartCandidatesView(mInputEditorInfo, restarting);
2100 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002101 } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) {
2102 // Pre-render IME views and window when real EditorInfo is available.
2103 // pre-render IME window and keep it invisible.
2104 if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName);
2105 if (mInShowWindow) {
2106 Log.w(TAG, "Re-entrance in to showWindow");
2107 return;
2108 }
2109
2110 mDecorViewWasVisible = mDecorViewVisible;
2111 mInShowWindow = true;
2112 startViews(prepareWindow(true /* showInput */));
2113
2114 // compute visibility
2115 mIsPreRendered = true;
2116 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
2117
2118 // request draw for the IME surface.
2119 // When IME is not pre-rendered, this will actually show the IME.
2120 if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
2121 mWindow.show();
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08002122 maybeNotifyPreRendered();
Tarandeep Singheadb1392018-11-09 18:15:57 +01002123 mDecorViewWasVisible = true;
2124 mInShowWindow = false;
2125 } else {
2126 mIsPreRendered = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 }
2128 }
2129
2130 /**
2131 * Called to inform the input method that text input has finished in
2132 * the last editor. At this point there may be a call to
2133 * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
2134 * new editor, or the input method may be left idle. This method is
2135 * <em>not</em> called when input restarts in the same editor.
2136 *
2137 * <p>The default
2138 * implementation uses the InputConnection to clear any active composing
2139 * text; you can override this (not calling the base class implementation)
2140 * to perform whatever behavior you would like.
2141 */
2142 public void onFinishInput() {
2143 InputConnection ic = getCurrentInputConnection();
2144 if (ic != null) {
2145 ic.finishComposingText();
2146 }
2147 }
2148
2149 /**
2150 * Called when the application has reported auto-completion candidates that
2151 * it would like to have the input method displayed. Typically these are
2152 * only used when an input method is running in full-screen mode, since
2153 * otherwise the user can see and interact with the pop-up window of
2154 * completions shown by the application.
2155 *
2156 * <p>The default implementation here does nothing.
2157 */
2158 public void onDisplayCompletions(CompletionInfo[] completions) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002159 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 /**
2163 * Called when the application has reported new extracted text to be shown
2164 * due to changes in its current text state. The default implementation
2165 * here places the new text in the extract edit text, when the input
2166 * method is running in fullscreen mode.
2167 */
2168 public void onUpdateExtractedText(int token, ExtractedText text) {
2169 if (mExtractedToken != token) {
2170 return;
2171 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002172 if (text != null) {
2173 if (mExtractEditText != null) {
2174 mExtractedText = text;
2175 mExtractEditText.setExtractedText(text);
2176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 }
2178 }
2179
2180 /**
2181 * Called when the application has reported a new selection region of
2182 * the text. This is called whether or not the input method has requested
2183 * extracted text updates, although if so it will not receive this call
2184 * if the extracted text has changed as well.
Jean Chalardc743cb92013-09-12 16:28:45 +09002185 *
2186 * <p>Be careful about changing the text in reaction to this call with
2187 * methods such as setComposingText, commitText or
2188 * deleteSurroundingText. If the cursor moves as a result, this method
2189 * will be called again, which may result in an infinite loop.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 *
2191 * <p>The default implementation takes care of updating the cursor in
2192 * the extract text, if it is being shown.
2193 */
2194 public void onUpdateSelection(int oldSelStart, int oldSelEnd,
2195 int newSelStart, int newSelEnd,
2196 int candidatesStart, int candidatesEnd) {
2197 final ExtractEditText eet = mExtractEditText;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002198 if (eet != null && isFullscreenMode() && mExtractedText != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 final int off = mExtractedText.startOffset;
2200 eet.startInternalChanges();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002201 newSelStart -= off;
2202 newSelEnd -= off;
2203 final int len = eet.getText().length();
2204 if (newSelStart < 0) newSelStart = 0;
2205 else if (newSelStart > len) newSelStart = len;
2206 if (newSelEnd < 0) newSelEnd = 0;
2207 else if (newSelEnd > len) newSelEnd = len;
2208 eet.setSelection(newSelStart, newSelEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 eet.finishInternalChanges();
2210 }
2211 }
2212
2213 /**
satok863fcd62011-06-21 17:38:02 +09002214 * Called when the user tapped or clicked a text view.
2215 * IMEs can't rely on this method being called because this was not part of the original IME
2216 * protocol, so applications with custom text editing written before this method appeared will
2217 * not call to inform the IME of this interaction.
2218 * @param focusChanged true if the user changed the focused view by this click.
Yohei Yukawa0eb8d162019-01-22 21:47:57 -08002219 * @see InputMethodManager#viewClicked(View)
2220 * @deprecated The method may not be called for composite {@link View} that works as a giant
2221 * "Canvas", which can host its own UI hierarchy and sub focus state.
2222 * {@link android.webkit.WebView} is a good example. Application / IME developers
2223 * should not rely on this method. If your goal is just being notified when an
2224 * on-going input is interrupted, simply monitor {@link #onFinishInput()}.
satok863fcd62011-06-21 17:38:02 +09002225 */
Yohei Yukawa0eb8d162019-01-22 21:47:57 -08002226 @Deprecated
satok863fcd62011-06-21 17:38:02 +09002227 public void onViewClicked(boolean focusChanged) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002228 // Intentionally empty
satok863fcd62011-06-21 17:38:02 +09002229 }
2230
2231 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07002232 * Called when the application has reported a new location of its text
2233 * cursor. This is only called if explicitly requested by the input method.
2234 * The default implementation does nothing.
Andrew Solovay5c05ded2018-10-02 14:14:42 -07002235 * @deprecated Use {@link #onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002236 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07002237 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 public void onUpdateCursor(Rect newCursor) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002239 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 }
2241
2242 /**
Yohei Yukawac2ddd602014-05-06 21:22:49 +09002243 * Called when the application has reported a new location of its text insertion point and
2244 * characters in the composition string. This is only called if explicitly requested by the
2245 * input method. The default implementation does nothing.
2246 * @param cursorAnchorInfo The positional information of the text insertion point and the
2247 * composition string.
2248 */
2249 public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
2250 // Intentionally empty
2251 }
2252
2253 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 * Close this input method's soft input area, removing it from the display.
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002255 *
2256 * The input method will continue running, but the user can no longer use it to generate input
2257 * by touching the screen.
2258 *
2259 * @see InputMethodManager#HIDE_IMPLICIT_ONLY
2260 * @see InputMethodManager#HIDE_NOT_ALWAYS
2261 * @param flags Provides additional operating flags.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08002263 public void requestHideSelf(int flags) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07002264 mPrivOps.hideMySoftInput(flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 /**
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002268 * Show the input method's soft input area, so the user sees the input method window and can
2269 * interact with it.
2270 *
2271 * @see InputMethodManager#SHOW_IMPLICIT
2272 * @see InputMethodManager#SHOW_FORCED
2273 * @param flags Provides additional operating flags.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002274 */
Tarandeep Singh45136992018-03-08 10:52:03 -08002275 public final void requestShowSelf(int flags) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07002276 mPrivOps.showMySoftInput(flags);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002277 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002278
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002279 private boolean handleBack(boolean doIt) {
2280 if (mShowInputRequested) {
2281 // If the soft input area is shown, back closes it and we
2282 // consume the back key.
2283 if (doIt) requestHideSelf(0);
2284 return true;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002285 } else if (mDecorViewVisible) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002286 if (mCandidatesVisibility == View.VISIBLE) {
2287 // If we are showing candidates even if no input area, then
2288 // hide them.
2289 if (doIt) setCandidatesViewShown(false);
2290 } else {
2291 // If we have the window visible for some other reason --
2292 // most likely to show candidates -- then just get rid
2293 // of it. This really shouldn't happen, but just in case...
satok2f913d92012-05-10 01:48:03 +09002294 if (doIt) doHideWindow();
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002295 }
2296 return true;
2297 }
2298 return false;
2299 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002300
2301 /**
Andrew Solovay5c05ded2018-10-02 14:14:42 -07002302 * @return {@link ExtractEditText} if it is considered to be visible and active. Otherwise
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002303 * {@code null} is returned.
2304 */
2305 private ExtractEditText getExtractEditTextIfVisible() {
2306 if (!isExtractViewShown() || !isInputViewShown()) {
2307 return null;
2308 }
2309 return mExtractEditText;
2310 }
2311
The Android Open Source Project4df24232009-03-05 14:34:35 -08002312 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -07002313 * Called back when a {@link KeyEvent} is forwarded from the target application.
2314 *
2315 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
2316 * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
2317 * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
2318 * in the extracted text view, not allowing them to perform navigation in the underlying
2319 * application.</p>
2320 *
2321 * <p>The default implementation does not take flags specified to
2322 * {@link #setBackDisposition(int)} into account, even on API version
2323 * {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible
2324 * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
2325 * with the flag they specified to {@link #setBackDisposition(int)}.</p>
2326 *
2327 * @param keyCode The value in {@code event.getKeyCode()}
2328 * @param event Description of the key event
2329 *
2330 * @return {@code true} if the event is consumed by the IME and the application no longer needs
2331 * to consume it. Return {@code false} when the event should be handled as if the IME
2332 * had not seen the event at all.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 */
2334 public boolean onKeyDown(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002335 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002336 final ExtractEditText eet = getExtractEditTextIfVisible();
2337 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2338 return true;
2339 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002340 if (handleBack(false)) {
2341 event.startTracking();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002344 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 return doMovementKey(keyCode, event, MOVEMENT_DOWN);
2347 }
2348
2349 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002350 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
2351 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
2352 * the event).
2353 */
2354 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
2355 return false;
2356 }
2357
2358 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002359 * Override this to intercept special key multiple events before they are
2360 * processed by the
2361 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002362 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 * will occur as if the IME had not seen the event at all.
2364 *
2365 * <p>The default implementation always returns false, except when
2366 * in fullscreen mode, where it will consume DPAD movement
2367 * events to move the cursor in the extracted text view, not allowing
2368 * them to perform navigation in the underlying application.
2369 */
2370 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
2371 return doMovementKey(keyCode, event, count);
2372 }
2373
2374 /**
2375 * Override this to intercept key up events before they are processed by the
2376 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002377 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002378 * will occur as if the IME had not seen the event at all.
2379 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002380 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
2381 * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
2382 * addition, in fullscreen mode only, it will consume DPAD movement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 * events to move the cursor in the extracted text view, not allowing
2384 * them to perform navigation in the underlying application.
2385 */
2386 public boolean onKeyUp(int keyCode, KeyEvent event) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002387 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
2388 final ExtractEditText eet = getExtractEditTextIfVisible();
2389 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2390 return true;
2391 }
2392 if (event.isTracking() && !event.isCanceled()) {
2393 return handleBack(true);
2394 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002396 return doMovementKey(keyCode, event, MOVEMENT_UP);
2397 }
2398
Victoria Leaseb38070c2012-08-24 13:46:02 -07002399 /**
2400 * Override this to intercept trackball motion events before they are
2401 * processed by the application.
2402 * If you return true, the application will not itself process the event.
2403 * If you return false, the normal application processing will occur as if
2404 * the IME had not seen the event at all.
2405 */
satokab751aa2010-09-14 19:17:36 +09002406 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 public boolean onTrackballEvent(MotionEvent event) {
Victoria Leaseb38070c2012-08-24 13:46:02 -07002408 if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
2409 return false;
2410 }
2411
2412 /**
2413 * Override this to intercept generic motion events before they are
2414 * processed by the application.
2415 * If you return true, the application will not itself process the event.
2416 * If you return false, the normal application processing will occur as if
2417 * the IME had not seen the event at all.
2418 */
2419 @Override
2420 public boolean onGenericMotionEvent(MotionEvent event) {
2421 if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002422 return false;
2423 }
2424
2425 public void onAppPrivateCommand(String action, Bundle data) {
2426 }
2427
The Android Open Source Project4df24232009-03-05 14:34:35 -08002428 /**
2429 * Handle a request by the system to toggle the soft input area.
2430 */
2431 private void onToggleSoftInput(int showFlags, int hideFlags) {
2432 if (DEBUG) Log.v(TAG, "toggleSoftInput()");
2433 if (isInputViewShown()) {
2434 requestHideSelf(hideFlags);
2435 } else {
2436 requestShowSelf(showFlags);
2437 }
2438 }
2439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440 static final int MOVEMENT_DOWN = -1;
2441 static final int MOVEMENT_UP = -2;
2442
2443 void reportExtractedMovement(int keyCode, int count) {
2444 int dx = 0, dy = 0;
2445 switch (keyCode) {
2446 case KeyEvent.KEYCODE_DPAD_LEFT:
2447 dx = -count;
2448 break;
2449 case KeyEvent.KEYCODE_DPAD_RIGHT:
2450 dx = count;
2451 break;
2452 case KeyEvent.KEYCODE_DPAD_UP:
2453 dy = -count;
2454 break;
2455 case KeyEvent.KEYCODE_DPAD_DOWN:
2456 dy = count;
2457 break;
2458 }
satokab751aa2010-09-14 19:17:36 +09002459 onExtractedCursorMovement(dx, dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 boolean doMovementKey(int keyCode, KeyEvent event, int count) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002463 final ExtractEditText eet = getExtractEditTextIfVisible();
2464 if (eet != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465 // If we are in fullscreen mode, the cursor will move around
2466 // the extract edit text, but should NOT cause focus to move
2467 // to other fields.
2468 MovementMethod movement = eet.getMovementMethod();
2469 Layout layout = eet.getLayout();
2470 if (movement != null && layout != null) {
2471 // We want our own movement method to handle the key, so the
2472 // cursor will properly move in our own word wrapping.
2473 if (count == MOVEMENT_DOWN) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002474 if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 reportExtractedMovement(keyCode, 1);
2476 return true;
2477 }
2478 } else if (count == MOVEMENT_UP) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002479 if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 return true;
2481 }
2482 } else {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002483 if (movement.onKeyOther(eet, eet.getText(), event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002484 reportExtractedMovement(keyCode, count);
2485 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002486 KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002487 if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002488 KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002489 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 while (--count > 0) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002491 movement.onKeyDown(eet, eet.getText(), keyCode, down);
2492 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002493 }
2494 reportExtractedMovement(keyCode, count);
2495 }
2496 }
2497 }
2498 }
2499 // Regardless of whether the movement method handled the key,
2500 // we never allow DPAD navigation to the application.
2501 switch (keyCode) {
2502 case KeyEvent.KEYCODE_DPAD_LEFT:
2503 case KeyEvent.KEYCODE_DPAD_RIGHT:
2504 case KeyEvent.KEYCODE_DPAD_UP:
2505 case KeyEvent.KEYCODE_DPAD_DOWN:
2506 return true;
2507 }
2508 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 return false;
2511 }
2512
2513 /**
2514 * Send the given key event code (as defined by {@link KeyEvent}) to the
2515 * current input connection is a key down + key up event pair. The sent
2516 * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
2517 * set, so that the recipient can identify them as coming from a software
2518 * input method, and
2519 * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
2520 * that they don't impact the current touch mode of the UI.
2521 *
Jean Chalard405bc512012-05-29 19:12:34 +09002522 * <p>Note that it's discouraged to send such key events in normal operation;
2523 * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
2524 * text fields, or for non-rich input methods. A reasonably capable software
2525 * input method should use the
2526 * {@link android.view.inputmethod.InputConnection#commitText} family of methods
2527 * to send text to an application, rather than sending key events.</p>
2528 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 * @param keyEventCode The raw key code to send, as defined by
2530 * {@link KeyEvent}.
2531 */
2532 public void sendDownUpKeyEvents(int keyEventCode) {
2533 InputConnection ic = getCurrentInputConnection();
2534 if (ic == null) return;
2535 long eventTime = SystemClock.uptimeMillis();
2536 ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002537 KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002538 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
Tadashi G. Takaokacb95cd62012-10-26 17:20:59 +09002539 ic.sendKeyEvent(new KeyEvent(eventTime, SystemClock.uptimeMillis(),
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002540 KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
2542 }
2543
2544 /**
2545 * Ask the input target to execute its default action via
2546 * {@link InputConnection#performEditorAction
2547 * InputConnection.performEditorAction()}.
2548 *
2549 * @param fromEnterKey If true, this will be executed as if the user had
2550 * pressed an enter key on the keyboard, that is it will <em>not</em>
2551 * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
2552 * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
2553 * sent regardless of how the editor has set that flag.
2554 *
2555 * @return Returns a boolean indicating whether an action has been sent.
2556 * If false, either the editor did not specify a default action or it
2557 * does not want an action from the enter key. If true, the action was
2558 * sent (or there was no input connection at all).
2559 */
2560 public boolean sendDefaultEditorAction(boolean fromEnterKey) {
2561 EditorInfo ei = getCurrentInputEditorInfo();
2562 if (ei != null &&
2563 (!fromEnterKey || (ei.imeOptions &
2564 EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
2565 (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
2566 EditorInfo.IME_ACTION_NONE) {
2567 // If the enter key was pressed, and the editor has a default
2568 // action associated with pressing enter, then send it that
2569 // explicit action instead of the key event.
2570 InputConnection ic = getCurrentInputConnection();
2571 if (ic != null) {
2572 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
2573 }
2574 return true;
2575 }
2576
2577 return false;
2578 }
2579
2580 /**
2581 * Send the given UTF-16 character to the current input connection. Most
2582 * characters will be delivered simply by calling
2583 * {@link InputConnection#commitText InputConnection.commitText()} with
2584 * the character; some, however, may be handled different. In particular,
2585 * the enter character ('\n') will either be delivered as an action code
Jean Chalard405bc512012-05-29 19:12:34 +09002586 * or a raw key event, as appropriate. Consider this as a convenience
2587 * method for IMEs that do not have a full implementation of actions; a
2588 * fully complying IME will decide of the right action for each event and
2589 * will likely never call this method except maybe to handle events coming
2590 * from an actual hardware keyboard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 *
2592 * @param charCode The UTF-16 character code to send.
2593 */
2594 public void sendKeyChar(char charCode) {
2595 switch (charCode) {
2596 case '\n': // Apps may be listening to an enter key to perform an action
2597 if (!sendDefaultEditorAction(true)) {
2598 sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
2599 }
2600 break;
2601 default:
2602 // Make sure that digits go through any text watcher on the client side.
2603 if (charCode >= '0' && charCode <= '9') {
2604 sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
2605 } else {
2606 InputConnection ic = getCurrentInputConnection();
2607 if (ic != null) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002608 ic.commitText(String.valueOf(charCode), 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 }
2610 }
2611 break;
2612 }
2613 }
2614
2615 /**
2616 * This is called when the user has moved the cursor in the extracted
2617 * text view, when running in fullsreen mode. The default implementation
2618 * performs the corresponding selection change on the underlying text
2619 * editor.
2620 */
2621 public void onExtractedSelectionChanged(int start, int end) {
2622 InputConnection conn = getCurrentInputConnection();
2623 if (conn != null) {
2624 conn.setSelection(start, end);
2625 }
2626 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002627
2628 /**
2629 * @hide
2630 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002631 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002632 public void onExtractedDeleteText(int start, int end) {
2633 InputConnection conn = getCurrentInputConnection();
2634 if (conn != null) {
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002635 conn.finishComposingText();
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002636 conn.setSelection(start, start);
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002637 conn.deleteSurroundingText(0, end - start);
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002638 }
2639 }
2640
2641 /**
2642 * @hide
2643 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002644 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002645 public void onExtractedReplaceText(int start, int end, CharSequence text) {
2646 InputConnection conn = getCurrentInputConnection();
2647 if (conn != null) {
2648 conn.setComposingRegion(start, end);
2649 conn.commitText(text, 1);
2650 }
2651 }
2652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 /**
Gilles Debunnee300be92011-12-06 10:15:56 -08002654 * @hide
2655 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002656 @UnsupportedAppUsage
Gilles Debunnee300be92011-12-06 10:15:56 -08002657 public void onExtractedSetSpan(Object span, int start, int end, int flags) {
2658 InputConnection conn = getCurrentInputConnection();
2659 if (conn != null) {
2660 if (!conn.setSelection(start, end)) return;
2661 CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
2662 if (text instanceof Spannable) {
2663 ((Spannable) text).setSpan(span, 0, text.length(), flags);
2664 conn.setComposingRegion(start, end);
2665 conn.commitText(text, 1);
2666 }
2667 }
2668 }
2669
2670 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 * This is called when the user has clicked on the extracted text view,
2672 * when running in fullscreen mode. The default implementation hides
2673 * the candidates view when this happens, but only if the extracted text
2674 * editor has a vertical scroll bar because its text doesn't fit.
2675 * Re-implement this to provide whatever behavior you want.
2676 */
2677 public void onExtractedTextClicked() {
2678 if (mExtractEditText == null) {
2679 return;
2680 }
2681 if (mExtractEditText.hasVerticalScrollBar()) {
2682 setCandidatesViewShown(false);
2683 }
2684 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 /**
2687 * This is called when the user has performed a cursor movement in the
2688 * extracted text view, when it is running in fullscreen mode. The default
2689 * implementation hides the candidates view when a vertical movement
2690 * happens, but only if the extracted text editor has a vertical scroll bar
2691 * because its text doesn't fit.
2692 * Re-implement this to provide whatever behavior you want.
2693 * @param dx The amount of cursor movement in the x dimension.
2694 * @param dy The amount of cursor movement in the y dimension.
2695 */
2696 public void onExtractedCursorMovement(int dx, int dy) {
2697 if (mExtractEditText == null || dy == 0) {
2698 return;
2699 }
2700 if (mExtractEditText.hasVerticalScrollBar()) {
2701 setCandidatesViewShown(false);
2702 }
2703 }
2704
2705 /**
2706 * This is called when the user has selected a context menu item from the
2707 * extracted text view, when running in fullscreen mode. The default
2708 * implementation sends this action to the current InputConnection's
2709 * {@link InputConnection#performContextMenuAction(int)}, for it
2710 * to be processed in underlying "real" editor. Re-implement this to
2711 * provide whatever behavior you want.
2712 */
2713 public boolean onExtractTextContextMenuItem(int id) {
2714 InputConnection ic = getCurrentInputConnection();
2715 if (ic != null) {
2716 ic.performContextMenuAction(id);
2717 }
2718 return true;
2719 }
Elliot Waite54de7742017-01-11 15:30:35 -08002720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721 /**
2722 * Return text that can be used as a button label for the given
2723 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
2724 * if there is no action requested. Note that there is no guarantee that
2725 * the returned text will be relatively short, so you probably do not
2726 * want to use it as text on a soft keyboard key label.
Elliot Waite54de7742017-01-11 15:30:35 -08002727 *
2728 * @param imeOptions The value from {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2729 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 * @return Returns a label to use, or null if there is no action.
2731 */
2732 public CharSequence getTextForImeAction(int imeOptions) {
2733 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2734 case EditorInfo.IME_ACTION_NONE:
2735 return null;
2736 case EditorInfo.IME_ACTION_GO:
2737 return getText(com.android.internal.R.string.ime_action_go);
2738 case EditorInfo.IME_ACTION_SEARCH:
2739 return getText(com.android.internal.R.string.ime_action_search);
2740 case EditorInfo.IME_ACTION_SEND:
2741 return getText(com.android.internal.R.string.ime_action_send);
2742 case EditorInfo.IME_ACTION_NEXT:
2743 return getText(com.android.internal.R.string.ime_action_next);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002744 case EditorInfo.IME_ACTION_DONE:
2745 return getText(com.android.internal.R.string.ime_action_done);
Dianne Hackborndea3ef72010-10-28 14:24:22 -07002746 case EditorInfo.IME_ACTION_PREVIOUS:
2747 return getText(com.android.internal.R.string.ime_action_previous);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 default:
2749 return getText(com.android.internal.R.string.ime_action_default);
2750 }
2751 }
Mark Renouf91eb2652016-04-11 16:03:26 -04002752
2753 /**
2754 * Return a drawable resource id that can be used as a button icon for the given
2755 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2756 *
2757 * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
2758 *
2759 * @return Returns a drawable resource id to use.
2760 */
2761 @DrawableRes
2762 private int getIconForImeAction(int imeOptions) {
2763 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2764 case EditorInfo.IME_ACTION_GO:
2765 return com.android.internal.R.drawable.ic_input_extract_action_go;
2766 case EditorInfo.IME_ACTION_SEARCH:
2767 return com.android.internal.R.drawable.ic_input_extract_action_search;
2768 case EditorInfo.IME_ACTION_SEND:
2769 return com.android.internal.R.drawable.ic_input_extract_action_send;
2770 case EditorInfo.IME_ACTION_NEXT:
2771 return com.android.internal.R.drawable.ic_input_extract_action_next;
2772 case EditorInfo.IME_ACTION_DONE:
2773 return com.android.internal.R.drawable.ic_input_extract_action_done;
2774 case EditorInfo.IME_ACTION_PREVIOUS:
2775 return com.android.internal.R.drawable.ic_input_extract_action_previous;
2776 default:
2777 return com.android.internal.R.drawable.ic_input_extract_action_return;
2778 }
2779 }
2780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07002782 * Called when the fullscreen-mode extracting editor info has changed,
2783 * to determine whether the extracting (extract text and candidates) portion
2784 * of the UI should be shown. The standard implementation hides or shows
2785 * the extract area depending on whether it makes sense for the
2786 * current editor. In particular, a {@link InputType#TYPE_NULL}
2787 * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
2788 * turn off the extract area since there is no text to be shown.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 */
The Android Open Source Project10592532009-03-18 17:39:46 -07002790 public void onUpdateExtractingVisibility(EditorInfo ei) {
2791 if (ei.inputType == InputType.TYPE_NULL ||
2792 (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
2793 // No reason to show extract UI!
2794 setExtractViewShown(false);
2795 return;
2796 }
2797
2798 setExtractViewShown(true);
2799 }
2800
2801 /**
2802 * Called when the fullscreen-mode extracting editor info has changed,
2803 * to update the state of its UI such as the action buttons shown.
2804 * You do not need to deal with this if you are using the standard
2805 * full screen extract UI. If replacing it, you will need to re-implement
2806 * this to put the appropriate action button in your own UI and handle it,
2807 * and perform any other changes.
2808 *
2809 * <p>The standard implementation turns on or off its accessory area
2810 * depending on whether there is an action button, and hides or shows
2811 * the entire extract area depending on whether it makes sense for the
2812 * current editor. In particular, a {@link InputType#TYPE_NULL} or
2813 * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
2814 * extract area since there is no text to be shown.
2815 */
2816 public void onUpdateExtractingViews(EditorInfo ei) {
2817 if (!isExtractViewShown()) {
2818 return;
2819 }
2820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 if (mExtractAccessories == null) {
2822 return;
2823 }
2824 final boolean hasAction = ei.actionLabel != null || (
2825 (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
The Android Open Source Project10592532009-03-18 17:39:46 -07002826 (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
2827 ei.inputType != InputType.TYPE_NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002828 if (hasAction) {
2829 mExtractAccessories.setVisibility(View.VISIBLE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002830 if (mExtractAction != null) {
Mark Renouf91eb2652016-04-11 16:03:26 -04002831 if (mExtractAction instanceof ImageButton) {
2832 ((ImageButton) mExtractAction)
2833 .setImageResource(getIconForImeAction(ei.imeOptions));
2834 if (ei.actionLabel != null) {
2835 mExtractAction.setContentDescription(ei.actionLabel);
2836 } else {
2837 mExtractAction.setContentDescription(getTextForImeAction(ei.imeOptions));
2838 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002839 } else {
Mark Renouf91eb2652016-04-11 16:03:26 -04002840 if (ei.actionLabel != null) {
2841 ((TextView) mExtractAction).setText(ei.actionLabel);
2842 } else {
2843 ((TextView) mExtractAction).setText(getTextForImeAction(ei.imeOptions));
2844 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002845 }
2846 mExtractAction.setOnClickListener(mActionClickListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002848 } else {
2849 mExtractAccessories.setVisibility(View.GONE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002850 if (mExtractAction != null) {
2851 mExtractAction.setOnClickListener(null);
2852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853 }
2854 }
2855
2856 /**
2857 * This is called when, while currently displayed in extract mode, the
2858 * current input target changes. The default implementation will
2859 * auto-hide the IME if the new target is not a full editor, since this
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002860 * can be a confusing experience for the user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 */
2862 public void onExtractingInputChanged(EditorInfo ei) {
2863 if (ei.inputType == InputType.TYPE_NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002864 requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002865 }
2866 }
2867
2868 void startExtractingText(boolean inputChanged) {
2869 final ExtractEditText eet = mExtractEditText;
2870 if (eet != null && getCurrentInputStarted()
2871 && isFullscreenMode()) {
2872 mExtractedToken++;
2873 ExtractedTextRequest req = new ExtractedTextRequest();
2874 req.token = mExtractedToken;
2875 req.flags = InputConnection.GET_TEXT_WITH_STYLES;
2876 req.hintMaxLines = 10;
2877 req.hintMaxChars = 10000;
Amith Yamasaniba4d93f2009-08-19 18:27:56 -07002878 InputConnection ic = getCurrentInputConnection();
2879 mExtractedText = ic == null? null
2880 : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
Amith Yamasania8b00c82010-03-05 15:41:31 -08002881 if (mExtractedText == null || ic == null) {
2882 Log.e(TAG, "Unexpected null in startExtractingText : mExtractedText = "
2883 + mExtractedText + ", input connection = " + ic);
2884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 final EditorInfo ei = getCurrentInputEditorInfo();
2886
2887 try {
2888 eet.startInternalChanges();
The Android Open Source Project10592532009-03-18 17:39:46 -07002889 onUpdateExtractingVisibility(ei);
2890 onUpdateExtractingViews(ei);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 int inputType = ei.inputType;
2892 if ((inputType&EditorInfo.TYPE_MASK_CLASS)
2893 == EditorInfo.TYPE_CLASS_TEXT) {
2894 if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
2895 inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
2896 }
2897 }
2898 eet.setInputType(inputType);
2899 eet.setHint(ei.hintText);
2900 if (mExtractedText != null) {
2901 eet.setEnabled(true);
2902 eet.setExtractedText(mExtractedText);
2903 } else {
2904 eet.setEnabled(false);
2905 eet.setText("");
2906 }
2907 } finally {
2908 eet.finishInternalChanges();
2909 }
2910
2911 if (inputChanged) {
2912 onExtractingInputChanged(ei);
2913 }
2914 }
2915 }
satokab751aa2010-09-14 19:17:36 +09002916
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002917 private void dispatchOnCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2918 synchronized (mLock) {
2919 mNotifyUserActionSent = false;
2920 }
2921 onCurrentInputMethodSubtypeChanged(newSubtype);
2922 }
2923
satokab751aa2010-09-14 19:17:36 +09002924 // TODO: Handle the subtype change event
2925 /**
2926 * Called when the subtype was changed.
2927 * @param newSubtype the subtype which is being changed to.
2928 */
2929 protected void onCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2930 if (DEBUG) {
2931 int nameResId = newSubtype.getNameResId();
satok9ef02832010-11-04 21:17:48 +09002932 String mode = newSubtype.getMode();
satokab751aa2010-09-14 19:17:36 +09002933 String output = "changeInputMethodSubtype:"
2934 + (nameResId == 0 ? "<none>" : getString(nameResId)) + ","
satok9ef02832010-11-04 21:17:48 +09002935 + mode + ","
satokab751aa2010-09-14 19:17:36 +09002936 + newSubtype.getLocale() + "," + newSubtype.getExtraValue();
2937 Log.v(TAG, "--- " + output);
2938 }
2939 }
2940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 /**
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002942 * Aimed to return the previous input method's {@link Insets#contentTopInsets}, but its actual
2943 * semantics has never been well defined.
2944 *
2945 * <p>Note that the previous document clearly mentioned that this method could return {@code 0}
2946 * at any time for whatever reason. Now this method is just always returning {@code 0}.</p>
2947 *
2948 * @return on Android {@link android.os.Build.VERSION_CODES#Q} and later devices this method
2949 * always returns {@code 0}
2950 * @deprecated the actual behavior of this method has never been well defined. You cannot use
2951 * this method in a reliable and predictable way
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002952 */
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002953 @Deprecated
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002954 public int getInputMethodWindowRecommendedHeight() {
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002955 Log.w(TAG, "getInputMethodWindowRecommendedHeight() is deprecated and now always returns 0."
2956 + " Do not use this method.");
2957 return 0;
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002958 }
2959
2960 /**
Yohei Yukawa25e08132016-06-22 16:31:41 -07002961 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
2962 * permission to the content.
2963 *
Yohei Yukawa25e08132016-06-22 16:31:41 -07002964 * @param inputContentInfo Content to be temporarily exposed from the input method to the
2965 * application.
2966 * This cannot be {@code null}.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002967 * @param inputConnection {@link InputConnection} with which
Yohei Yukawab2a0e052018-01-14 16:06:16 -08002968 * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002969 * @hide
Yohei Yukawa25e08132016-06-22 16:31:41 -07002970 */
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002971 @Override
2972 public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
2973 @NonNull InputConnection inputConnection) {
2974 if (inputConnection == null) {
2975 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002976 }
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002977 if (getCurrentInputConnection() != inputConnection) {
2978 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002979 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07002980 exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo());
2981 }
2982
2983 /**
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002984 * {@inheritDoc}
2985 * @hide
2986 */
2987 @AnyThread
2988 @Override
2989 public final void notifyUserActionIfNecessary() {
2990 synchronized (mLock) {
2991 if (mNotifyUserActionSent) {
2992 return;
2993 }
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08002994 mPrivOps.notifyUserAction();
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002995 mNotifyUserActionSent = true;
2996 }
2997 }
2998
2999 /**
Yohei Yukawac54c1172018-09-06 11:39:50 -07003000 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
3001 * permission to the content.
3002 *
3003 * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo,
3004 * InputConnection)} for details.</p>
3005 *
3006 * @param inputContentInfo Content to be temporarily exposed from the input method to the
3007 * application.
3008 * This cannot be {@code null}.
3009 * @param editorInfo The editor that receives {@link InputContentInfo}.
3010 */
3011 private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
3012 @NonNull EditorInfo editorInfo) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07003013 final Uri contentUri = inputContentInfo.getContentUri();
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07003014 final IInputContentUriToken uriToken =
3015 mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
3016 if (uriToken == null) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07003017 Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07003018 + " packageName=" + editorInfo.packageName);
Yohei Yukawac54c1172018-09-06 11:39:50 -07003019 return;
3020 }
3021 inputContentInfo.setUriToken(uriToken);
Yohei Yukawa25e08132016-06-22 16:31:41 -07003022 }
3023
Tarandeep Singheadb1392018-11-09 18:15:57 +01003024 private int mapToImeWindowStatus() {
3025 return IME_ACTIVE
3026 | (isInputViewShown()
3027 ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE)
3028 : IME_VISIBLE) : 0);
Tarandeep Singh3fecef12018-01-22 14:33:33 -08003029 }
3030
Yohei Yukawa25e08132016-06-22 16:31:41 -07003031 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 * Performs a dump of the InputMethodService's internal state. Override
3033 * to add your own information to the dump.
3034 */
3035 @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
3036 final Printer p = new PrintWriterPrinter(fout);
3037 p.println("Input method service state for " + this + ":");
Tarandeep Singheadb1392018-11-09 18:15:57 +01003038 p.println(" mViewsCreated=" + mViewsCreated);
3039 p.println(" mDecorViewVisible=" + mDecorViewVisible
3040 + " mDecorViewWasVisible=" + mDecorViewWasVisible
3041 + " mWindowVisible=" + mWindowVisible
The Android Open Source Project10592532009-03-18 17:39:46 -07003042 + " mInShowWindow=" + mInShowWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 p.println(" Configuration=" + getResources().getConfiguration());
3044 p.println(" mToken=" + mToken);
3045 p.println(" mInputBinding=" + mInputBinding);
3046 p.println(" mInputConnection=" + mInputConnection);
3047 p.println(" mStartedInputConnection=" + mStartedInputConnection);
3048 p.println(" mInputStarted=" + mInputStarted
3049 + " mInputViewStarted=" + mInputViewStarted
3050 + " mCandidatesViewStarted=" + mCandidatesViewStarted);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003052 if (mInputEditorInfo != null) {
3053 p.println(" mInputEditorInfo:");
3054 mInputEditorInfo.dump(p, " ");
3055 } else {
3056 p.println(" mInputEditorInfo: null");
3057 }
3058
3059 p.println(" mShowInputRequested=" + mShowInputRequested
3060 + " mLastShowInputRequested=" + mLastShowInputRequested
Tarandeep Singheadb1392018-11-09 18:15:57 +01003061 + " mCanPreRender=" + mCanPreRender
3062 + " mIsPreRendered=" + mIsPreRendered
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
3064 p.println(" mCandidatesVisibility=" + mCandidatesVisibility
3065 + " mFullscreenApplied=" + mFullscreenApplied
The Android Open Source Project10592532009-03-18 17:39:46 -07003066 + " mIsFullscreen=" + mIsFullscreen
3067 + " mExtractViewHidden=" + mExtractViewHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068
3069 if (mExtractedText != null) {
3070 p.println(" mExtractedText:");
3071 p.println(" text=" + mExtractedText.text.length() + " chars"
3072 + " startOffset=" + mExtractedText.startOffset);
3073 p.println(" selectionStart=" + mExtractedText.selectionStart
3074 + " selectionEnd=" + mExtractedText.selectionEnd
3075 + " flags=0x" + Integer.toHexString(mExtractedText.flags));
3076 } else {
3077 p.println(" mExtractedText: null");
3078 }
3079 p.println(" mExtractedToken=" + mExtractedToken);
3080 p.println(" mIsInputViewShown=" + mIsInputViewShown
3081 + " mStatusIcon=" + mStatusIcon);
3082 p.println("Last computed insets:");
3083 p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
3084 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
Jeff Brownfbf09772011-01-16 14:06:57 -08003085 + " touchableInsets=" + mTmpInsets.touchableInsets
3086 + " touchableRegion=" + mTmpInsets.touchableRegion);
Yohei Yukawa7b739a82015-12-21 13:30:44 -08003087 p.println(" mSettingsObserver=" + mSettingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 }
3089}