blob: 333cfbd400dd70aafee592694e27af6af5ac9419 [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) {
595 // TODO: notify visibility to insets consumer.
596 if (DEBUG) {
597 Log.v(TAG, "Making IME window invisible");
598 }
599 setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800600 applyVisibilityInInsetsConsumer(false /* setVisible */);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100601 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
602 } else {
603 mShowInputFlags = 0;
604 mShowInputRequested = false;
605 doHideWindow();
606 }
607 final boolean isVisible = mIsPreRendered
608 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
609 final boolean visibilityChanged = isVisible != wasVisible;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800610 if (resultReceiver != null) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100611 resultReceiver.send(visibilityChanged
The Android Open Source Project4df24232009-03-05 14:34:35 -0800612 ? InputMethodManager.RESULT_HIDDEN
Tarandeep Singheadb1392018-11-09 18:15:57 +0100613 : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
The Android Open Source Project4df24232009-03-05 14:34:35 -0800614 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 }
617
618 /**
Yohei Yukawa16f04072017-10-18 20:19:43 -0700619 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700621 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700622 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800623 public void showSoftInput(int flags, ResultReceiver resultReceiver) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -0700624 if (DEBUG) Log.v(TAG, "showSoftInput()");
Tarandeep Singheadb1392018-11-09 18:15:57 +0100625 final boolean wasVisible = mIsPreRendered
626 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
Yohei Yukawaef5b4652016-04-03 22:50:11 -0700627 if (dispatchOnShowInputRequested(flags, false)) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100628 if (mIsPreRendered) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100629 if (DEBUG) {
630 Log.v(TAG, "Making IME window visible");
631 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -0800632 applyVisibilityInInsetsConsumer(true /* setVisible */);
Tarandeep Singheadb1392018-11-09 18:15:57 +0100633 onPreRenderedWindowVisibilityChanged(true /* setVisible */);
634 } else {
635 showWindow(true);
636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 }
satok865b9772011-01-21 02:45:06 +0900638 // If user uses hard keyboard, IME button should always be shown.
Tarandeep Singheadb1392018-11-09 18:15:57 +0100639 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
640 final boolean isVisible = mIsPreRendered
641 ? mDecorViewVisible && mWindowVisible : isInputViewShown();
642 final boolean visibilityChanged = isVisible != wasVisible;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800643 if (resultReceiver != null) {
Tarandeep Singheadb1392018-11-09 18:15:57 +0100644 resultReceiver.send(visibilityChanged
The Android Open Source Project4df24232009-03-05 14:34:35 -0800645 ? InputMethodManager.RESULT_SHOWN
Tarandeep Singheadb1392018-11-09 18:15:57 +0100646 : (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
The Android Open Source Project4df24232009-03-05 14:34:35 -0800647 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 }
satokab751aa2010-09-14 19:17:36 +0900650
Yohei Yukawa16f04072017-10-18 20:19:43 -0700651 /**
652 * {@inheritDoc}
653 */
Yohei Yukawa930328c2017-10-18 20:19:53 -0700654 @MainThread
Yohei Yukawa16f04072017-10-18 20:19:43 -0700655 @Override
satokab751aa2010-09-14 19:17:36 +0900656 public void changeInputMethodSubtype(InputMethodSubtype subtype) {
Yohei Yukawac07fd4c2018-09-11 11:37:13 -0700657 dispatchOnCurrentInputMethodSubtypeChanged(subtype);
satokab751aa2010-09-14 19:17:36 +0900658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
satokab751aa2010-09-14 19:17:36 +0900660
Yohei Yukawac54c1172018-09-06 11:39:50 -0700661 private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -0700662 mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
Yohei Yukawac54c1172018-09-06 11:39:50 -0700663 }
664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 /**
666 * Concrete implementation of
667 * {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
668 * all of the standard behavior for an input method session.
669 */
670 public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
671 public void finishInput() {
672 if (!isEnabled()) {
673 return;
674 }
675 if (DEBUG) Log.v(TAG, "finishInput() in " + this);
676 doFinishInput();
677 }
678
679 /**
680 * Call {@link InputMethodService#onDisplayCompletions
681 * InputMethodService.onDisplayCompletions()}.
682 */
683 public void displayCompletions(CompletionInfo[] completions) {
684 if (!isEnabled()) {
685 return;
686 }
687 mCurCompletions = completions;
688 onDisplayCompletions(completions);
689 }
690
691 /**
692 * Call {@link InputMethodService#onUpdateExtractedText
693 * InputMethodService.onUpdateExtractedText()}.
694 */
695 public void updateExtractedText(int token, ExtractedText text) {
696 if (!isEnabled()) {
697 return;
698 }
699 onUpdateExtractedText(token, text);
700 }
701
702 /**
703 * Call {@link InputMethodService#onUpdateSelection
704 * InputMethodService.onUpdateSelection()}.
705 */
706 public void updateSelection(int oldSelStart, int oldSelEnd,
707 int newSelStart, int newSelEnd,
708 int candidatesStart, int candidatesEnd) {
709 if (!isEnabled()) {
710 return;
711 }
712 InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
713 newSelStart, newSelEnd, candidatesStart, candidatesEnd);
714 }
satok863fcd62011-06-21 17:38:02 +0900715
716 @Override
717 public void viewClicked(boolean focusChanged) {
718 if (!isEnabled()) {
719 return;
720 }
721 InputMethodService.this.onViewClicked(focusChanged);
722 }
723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 /**
725 * Call {@link InputMethodService#onUpdateCursor
726 * InputMethodService.onUpdateCursor()}.
727 */
728 public void updateCursor(Rect newCursor) {
729 if (!isEnabled()) {
730 return;
731 }
732 InputMethodService.this.onUpdateCursor(newCursor);
733 }
734
735 /**
736 * Call {@link InputMethodService#onAppPrivateCommand
737 * InputMethodService.onAppPrivateCommand()}.
738 */
739 public void appPrivateCommand(String action, Bundle data) {
740 if (!isEnabled()) {
741 return;
742 }
743 InputMethodService.this.onAppPrivateCommand(action, data);
744 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800745
746 /**
747 *
748 */
749 public void toggleSoftInput(int showFlags, int hideFlags) {
750 InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
751 }
Yohei Yukawac2ddd602014-05-06 21:22:49 +0900752
753 /**
754 * Call {@link InputMethodService#onUpdateCursorAnchorInfo
755 * InputMethodService.onUpdateCursorAnchorInfo()}.
756 */
757 public void updateCursorAnchorInfo(CursorAnchorInfo info) {
758 if (!isEnabled()) {
759 return;
760 }
761 InputMethodService.this.onUpdateCursorAnchorInfo(info);
762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
764
765 /**
766 * Information about where interesting parts of the input method UI appear.
767 */
768 public static final class Insets {
769 /**
770 * This is the top part of the UI that is the main content. It is
771 * used to determine the basic space needed, to resize/pan the
772 * application behind. It is assumed that this inset does not
773 * change very much, since any change will cause a full resize/pan
774 * of the application behind. This value is relative to the top edge
775 * of the input method window.
776 */
777 public int contentTopInsets;
778
779 /**
780 * This is the top part of the UI that is visibly covering the
781 * application behind it. This provides finer-grained control over
782 * visibility, allowing you to change it relatively frequently (such
783 * as hiding or showing candidates) without disrupting the underlying
784 * UI too much. For example, this will never resize the application
785 * UI, will only pan if needed to make the current focus visible, and
786 * will not aggressively move the pan position when this changes unless
787 * needed to make the focus visible. This value is relative to the top edge
788 * of the input method window.
789 */
790 public int visibleTopInsets;
Jeff Brownfbf09772011-01-16 14:06:57 -0800791
792 /**
793 * This is the region of the UI that is touchable. It is used when
794 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
795 * The region should be specified relative to the origin of the window frame.
796 */
797 public final Region touchableRegion = new Region();
798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 /**
800 * Option for {@link #touchableInsets}: the entire window frame
801 * can be touched.
802 */
803 public static final int TOUCHABLE_INSETS_FRAME
804 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
805
806 /**
807 * Option for {@link #touchableInsets}: the area inside of
808 * the content insets can be touched.
809 */
810 public static final int TOUCHABLE_INSETS_CONTENT
811 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
812
813 /**
814 * Option for {@link #touchableInsets}: the area inside of
815 * the visible insets can be touched.
816 */
817 public static final int TOUCHABLE_INSETS_VISIBLE
818 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -0800819
820 /**
821 * Option for {@link #touchableInsets}: the region specified by
822 * {@link #touchableRegion} can be touched.
823 */
824 public static final int TOUCHABLE_INSETS_REGION
825 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 /**
828 * Determine which area of the window is touchable by the user. May
829 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
Jeff Brownfbf09772011-01-16 14:06:57 -0800830 * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
831 * or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 */
833 public int touchableInsets;
834 }
satok865b9772011-01-21 02:45:06 +0900835
The Android Open Source Project10592532009-03-18 17:39:46 -0700836 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800837 * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
838 *
839 * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
840 * Basically this functionality still needs to be considered as implementation details.</p>
841 */
842 @MainThread
843 private static final class SettingsObserver extends ContentObserver {
844 @Retention(RetentionPolicy.SOURCE)
845 @IntDef({
846 ShowImeWithHardKeyboardType.UNKNOWN,
847 ShowImeWithHardKeyboardType.FALSE,
848 ShowImeWithHardKeyboardType.TRUE,
849 })
850 private @interface ShowImeWithHardKeyboardType {
851 int UNKNOWN = 0;
852 int FALSE = 1;
853 int TRUE = 2;
854 }
855 @ShowImeWithHardKeyboardType
856 private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
857
858 private final InputMethodService mService;
859
860 private SettingsObserver(InputMethodService service) {
861 super(new Handler(service.getMainLooper()));
862 mService = service;
863 }
864
865 /**
866 * A factory method that internally enforces two-phase initialization to make sure that the
867 * object reference will not be escaped until the object is properly constructed.
868 *
869 * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence
870 * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
871 *
872 * @param service {@link InputMethodService} that needs to receive the callback.
873 * @return {@link SettingsObserver} that is already registered to
874 * {@link android.content.ContentResolver}. The caller must call
875 * {@link SettingsObserver#unregister()}.
876 */
877 public static SettingsObserver createAndRegister(InputMethodService service) {
878 final SettingsObserver observer = new SettingsObserver(service);
879 // The observer is properly constructed. Let's start accepting the event.
880 service.getContentResolver().registerContentObserver(
881 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
882 false, observer);
883 return observer;
884 }
885
886 void unregister() {
887 mService.getContentResolver().unregisterContentObserver(this);
888 }
889
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100890 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800891 private boolean shouldShowImeWithHardKeyboard() {
892 // Lazily initialize as needed.
893 if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
894 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
895 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
896 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
897 }
898 switch (mShowImeWithHardKeyboard) {
899 case ShowImeWithHardKeyboardType.TRUE:
900 return true;
901 case ShowImeWithHardKeyboardType.FALSE:
902 return false;
903 default:
904 Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
905 return false;
906 }
907 }
908
909 @Override
910 public void onChange(boolean selfChange, Uri uri) {
911 final Uri showImeWithHardKeyboardUri =
912 Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
913 if (showImeWithHardKeyboardUri.equals(uri)) {
914 mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
915 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
916 ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
Yohei Yukawa2dbc5322016-04-03 22:50:18 -0700917 // In Android M and prior, state change of
918 // Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD has triggered
919 // #onConfigurationChanged(). For compatibility reasons, we reset the internal
920 // state as if configuration was changed.
921 mService.resetStateForNewConfiguration();
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800922 }
923 }
924
925 @Override
926 public String toString() {
927 return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}";
928 }
929 }
Mathew Inwood1dd7d112018-07-31 14:53:29 +0100930 @UnsupportedAppUsage
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800931 private SettingsObserver mSettingsObserver;
932
933 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700934 * You can call this to customize the theme used by your IME's window.
935 * This theme should typically be one that derives from
936 * {@link android.R.style#Theme_InputMethod}, which is the default theme
937 * you will get. This must be set before {@link #onCreate}, so you
938 * will typically call it in your constructor with the resource ID
939 * of your custom theme.
940 */
satokab751aa2010-09-14 19:17:36 +0900941 @Override
The Android Open Source Project10592532009-03-18 17:39:46 -0700942 public void setTheme(int theme) {
943 if (mWindow != null) {
944 throw new IllegalStateException("Must be called before onCreate()");
945 }
946 mTheme = theme;
947 }
satok865b9772011-01-21 02:45:06 +0900948
Dianne Hackborn836531b2012-08-01 19:00:38 -0700949 /**
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700950 * You can call this to try to enable accelerated drawing for your IME. This must be set before
951 * {@link #onCreate()}, so you will typically call it in your constructor. It is not always
952 * possible to use hardware accelerated drawing in an IME (for example on low-end devices that
953 * do not have the resources to support this), so the call {@code true} if it succeeds otherwise
954 * {@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 -0700955 *
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700956 * <p>In API 21 and later, system may automatically enable hardware accelerated drawing for your
957 * IME on capable devices even if this method is not explicitly called. Make sure that your IME
958 * is able to handle either case.</p>
959 *
960 * @return {@code true} if accelerated drawing is successfully enabled otherwise {@code false}.
961 * On API 21 and later devices the return value is basically just a hint and your IME
962 * does not need to change the behavior based on the it
963 * @deprecated Starting in API 21, hardware acceleration is always enabled on capable devices
Dianne Hackborn836531b2012-08-01 19:00:38 -0700964 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700965 @Deprecated
Dianne Hackborn836531b2012-08-01 19:00:38 -0700966 public boolean enableHardwareAcceleration() {
967 if (mWindow != null) {
968 throw new IllegalStateException("Must be called before onCreate()");
969 }
Yohei Yukawaac0211a2016-09-01 12:41:58 -0700970 return ActivityManager.isHighEndGfx();
Dianne Hackborn836531b2012-08-01 19:00:38 -0700971 }
972
Alan Viverette5effd7e2014-05-05 12:25:33 -0700973 @Override public void onCreate() {
974 mTheme = Resources.selectSystemTheme(mTheme,
975 getApplicationInfo().targetSdkVersion,
976 android.R.style.Theme_InputMethod,
977 android.R.style.Theme_Holo_InputMethod,
978 android.R.style.Theme_DeviceDefault_InputMethod,
979 android.R.style.Theme_DeviceDefault_InputMethod);
The Android Open Source Project10592532009-03-18 17:39:46 -0700980 super.setTheme(mTheme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 super.onCreate();
982 mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
Yohei Yukawa7b739a82015-12-21 13:30:44 -0800983 mSettingsObserver = SettingsObserver.createAndRegister(this);
lumark90120a82018-08-15 00:33:03 +0800984 // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
985 // for update resources & configuration correctly when show soft input
986 // in non-default display.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 mInflater = (LayoutInflater)getSystemService(
988 Context.LAYOUT_INFLATER_SERVICE);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700989 mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700990 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
Yohei Yukawa8f162c62018-01-10 13:18:09 -0800991 // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
992 // by default (but IME developers can opt this out later if they want a new behavior).
993 mWindow.getWindow().setFlags(
994 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 initViews();
Romain Guy980a9382010-01-08 15:06:28 -0800997 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
satokab751aa2010-09-14 19:17:36 +0900999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 /**
1001 * This is a hook that subclasses can use to perform initialization of
1002 * their interface. It is called for you prior to any of your UI objects
1003 * being created, both after the service is first created and after a
1004 * configuration change happens.
1005 */
1006 public void onInitializeInterface() {
Gilles Debunne34703b62011-09-08 11:16:25 -07001007 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
satokab751aa2010-09-14 19:17:36 +09001009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 void initialize() {
1011 if (!mInitialized) {
1012 mInitialized = true;
1013 onInitializeInterface();
1014 }
1015 }
satokab751aa2010-09-14 19:17:36 +09001016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 void initViews() {
1018 mInitialized = false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001019 mViewsCreated = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 mShowInputRequested = false;
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001021 mShowInputFlags = 0;
1022
The Android Open Source Project10592532009-03-18 17:39:46 -07001023 mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 mRootView = mInflater.inflate(
1025 com.android.internal.R.layout.input_method, null);
1026 mWindow.setContentView(mRootView);
Seonggoo Kang72745ff2014-12-24 13:55:50 +09001027 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
Jeff Sharkey6e2bee72012-10-01 13:39:08 -07001029 if (Settings.Global.getInt(getContentResolver(),
1030 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 mWindow.getWindow().setWindowAnimations(
1032 com.android.internal.R.style.Animation_InputMethodFancy);
1033 }
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001034 mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
The Android Open Source Project10592532009-03-18 17:39:46 -07001035 mExtractViewHidden = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001036 mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 mExtractView = null;
1038 mExtractEditText = null;
1039 mExtractAccessories = null;
1040 mExtractAction = null;
1041 mFullscreenApplied = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001042
1043 mCandidatesFrame = mRootView.findViewById(android.R.id.candidatesArea);
1044 mInputFrame = mRootView.findViewById(android.R.id.inputArea);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 mInputView = null;
1046 mIsInputViewShown = false;
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 mExtractFrame.setVisibility(View.GONE);
1049 mCandidatesVisibility = getCandidatesHiddenVisibility();
1050 mCandidatesFrame.setVisibility(mCandidatesVisibility);
1051 mInputFrame.setVisibility(View.GONE);
1052 }
satokab751aa2010-09-14 19:17:36 +09001053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 @Override public void onDestroy() {
1055 super.onDestroy();
1056 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
1057 mInsetsComputer);
Satoshi Kataokac56191f2013-05-30 13:14:47 +09001058 doFinishInput();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001059 mWindow.dismissForDestroyIfNecessary();
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001060 if (mSettingsObserver != null) {
1061 mSettingsObserver.unregister();
1062 mSettingsObserver = null;
1063 }
Yohei Yukawaeec552e2018-09-09 20:48:41 -07001064 if (mToken != null) {
1065 // This is completely optional, but allows us to show more explicit error messages
1066 // when IME developers are doing something unsupported.
Yohei Yukawad746a7e2018-09-18 18:55:02 -07001067 InputMethodPrivilegedOperationsRegistry.remove(mToken);
Yohei Yukawaeec552e2018-09-09 20:48:41 -07001068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
satokf17db9f2011-09-14 18:55:58 +09001070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 /**
1072 * Take care of handling configuration changes. Subclasses of
1073 * InputMethodService generally don't need to deal directly with
1074 * this on their own; the standard implementation here takes care of
1075 * regenerating the input method UI as a result of the configuration
1076 * change, so you can rely on your {@link #onCreateInputView} and
1077 * other methods being called as appropriate due to a configuration change.
1078 *
1079 * <p>When a configuration change does happen,
1080 * {@link #onInitializeInterface()} is guaranteed to be called the next
1081 * time prior to any of the other input or UI creation callbacks. The
1082 * following will be called immediately depending if appropriate for current
1083 * state: {@link #onStartInput} if input is active, and
1084 * {@link #onCreateInputView} and {@link #onStartInputView} and related
1085 * appropriate functions if the UI is displayed.
1086 */
1087 @Override public void onConfigurationChanged(Configuration newConfig) {
1088 super.onConfigurationChanged(newConfig);
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001089 resetStateForNewConfiguration();
1090 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001091
Yohei Yukawa2dbc5322016-04-03 22:50:18 -07001092 private void resetStateForNewConfiguration() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01001093 boolean visible = mDecorViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 int showFlags = mShowInputFlags;
1095 boolean showingInput = mShowInputRequested;
1096 CompletionInfo[] completions = mCurCompletions;
1097 initViews();
1098 mInputViewStarted = false;
1099 mCandidatesViewStarted = false;
1100 if (mInputStarted) {
1101 doStartInput(getCurrentInputConnection(),
1102 getCurrentInputEditorInfo(), true);
1103 }
1104 if (visible) {
1105 if (showingInput) {
1106 // If we were last showing the soft keyboard, try to do so again.
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001107 if (dispatchOnShowInputRequested(showFlags, true)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 showWindow(true);
1109 if (completions != null) {
1110 mCurCompletions = completions;
1111 onDisplayCompletions(completions);
1112 }
1113 } else {
satok2f913d92012-05-10 01:48:03 +09001114 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116 } else if (mCandidatesVisibility == View.VISIBLE) {
1117 // If the candidates are currently visible, make sure the
1118 // window is shown for them.
1119 showWindow(false);
1120 } else {
1121 // Otherwise hide the window.
satok2f913d92012-05-10 01:48:03 +09001122 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 }
satok865b9772011-01-21 02:45:06 +09001124 // If user uses hard keyboard, IME button should always be shown.
Joe Onorato857fd9b2011-01-27 15:08:35 -08001125 boolean showing = onEvaluateInputViewShown();
Yohei Yukawac54c1172018-09-06 11:39:50 -07001126 setImeWindowStatus(IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
1128 }
1129
1130 /**
1131 * Implement to return our standard {@link InputMethodImpl}. Subclasses
1132 * can override to provide their own customized version.
1133 */
satokab751aa2010-09-14 19:17:36 +09001134 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 public AbstractInputMethodImpl onCreateInputMethodInterface() {
1136 return new InputMethodImpl();
1137 }
1138
1139 /**
1140 * Implement to return our standard {@link InputMethodSessionImpl}. Subclasses
1141 * can override to provide their own customized version.
1142 */
satokab751aa2010-09-14 19:17:36 +09001143 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
1145 return new InputMethodSessionImpl();
1146 }
1147
1148 public LayoutInflater getLayoutInflater() {
1149 return mInflater;
1150 }
1151
1152 public Dialog getWindow() {
1153 return mWindow;
1154 }
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001155
1156 /**
1157 * Sets the disposition mode that indicates the expected affordance for the back button.
1158 *
1159 * <p>Keep in mind that specifying this flag does not change the the default behavior of
1160 * {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that
1161 * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
1162 * specified to this API.</p>
1163 *
1164 * @see #getBackDisposition()
1165 * @param disposition disposition mode to be set
1166 */
1167 public void setBackDisposition(@BackDispositionMode int disposition) {
Tarandeep Singh3fecef12018-01-22 14:33:33 -08001168 if (disposition == mBackDisposition) {
1169 return;
1170 }
1171 if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
1172 Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
1173 return;
1174 }
Joe Onorato857fd9b2011-01-27 15:08:35 -08001175 mBackDisposition = disposition;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001176 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
Joe Onorato857fd9b2011-01-27 15:08:35 -08001177 }
1178
Yohei Yukawa386f50e2018-03-14 13:03:42 -07001179 /**
1180 * Retrieves the current disposition mode that indicates the expected back button affordance.
1181 *
1182 * @see #setBackDisposition(int)
1183 * @return currently selected disposition mode
1184 */
1185 @BackDispositionMode
Joe Onorato857fd9b2011-01-27 15:08:35 -08001186 public int getBackDisposition() {
1187 return mBackDisposition;
1188 }
1189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 /**
1191 * Return the maximum width, in pixels, available the input method.
1192 * Input methods are positioned at the bottom of the screen and, unless
1193 * running in fullscreen, will generally want to be as short as possible
1194 * so should compute their height based on their contents. However, they
1195 * can stretch as much as needed horizontally. The function returns to
1196 * you the maximum amount of space available horizontally, which you can
1197 * use if needed for UI placement.
1198 *
1199 * <p>In many cases this is not needed, you can just rely on the normal
1200 * view layout mechanisms to position your views within the full horizontal
1201 * space given to the input method.
1202 *
1203 * <p>Note that this value can change dynamically, in particular when the
1204 * screen orientation changes.
1205 */
1206 public int getMaxWidth() {
1207 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
1208 return wm.getDefaultDisplay().getWidth();
1209 }
1210
1211 /**
1212 * Return the currently active InputBinding for the input method, or
1213 * null if there is none.
1214 */
1215 public InputBinding getCurrentInputBinding() {
1216 return mInputBinding;
1217 }
1218
1219 /**
1220 * Retrieve the currently active InputConnection that is bound to
1221 * the input method, or null if there is none.
1222 */
1223 public InputConnection getCurrentInputConnection() {
1224 InputConnection ic = mStartedInputConnection;
1225 if (ic != null) {
1226 return ic;
1227 }
1228 return mInputConnection;
1229 }
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001230
1231 /**
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001232 * Force switch to the last used input method and subtype. If the last input method didn't have
1233 * any subtypes, the framework will simply switch to the last input method with no subtype
1234 * specified.
1235 * @return true if the current input method and subtype was successfully switched to the last
1236 * used input method and subtype.
1237 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001238 public final boolean switchToPreviousInputMethod() {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001239 return mPrivOps.switchToPreviousInputMethod();
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001240 }
1241
1242 /**
1243 * Force switch to the next input method and subtype. If there is no IME enabled except
1244 * current IME and subtype, do nothing.
1245 * @param onlyCurrentIme if true, the framework will find the next subtype which
1246 * belongs to the current IME
1247 * @return true if the current input method and subtype was successfully switched to the next
1248 * input method and subtype.
1249 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001250 public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001251 return mPrivOps.switchToNextInputMethod(onlyCurrentIme);
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001252 }
1253
1254 /**
1255 * Returns true if the current IME needs to offer the users ways to switch to a next input
1256 * method (e.g. a globe key.).
1257 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
1258 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
1259 * <p> Note that the system determines the most appropriate next input method
1260 * and subtype in order to provide the consistent user experience in switching
1261 * between IMEs and subtypes.
1262 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001263 public final boolean shouldOfferSwitchingToNextInputMethod() {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001264 return mPrivOps.shouldOfferSwitchingToNextInputMethod();
Tarandeep Singhd8d03a82017-11-28 13:35:32 -08001265 }
1266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 public boolean getCurrentInputStarted() {
1268 return mInputStarted;
1269 }
1270
1271 public EditorInfo getCurrentInputEditorInfo() {
1272 return mInputEditorInfo;
1273 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07001274
1275 private void reportFullscreenMode() {
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07001276 mPrivOps.reportFullscreenMode(mIsFullscreen);
Yohei Yukawac54c1172018-09-06 11:39:50 -07001277 }
1278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 /**
1280 * Re-evaluate whether the input method should be running in fullscreen
1281 * mode, and update its UI if this has changed since the last time it
1282 * was evaluated. This will call {@link #onEvaluateFullscreenMode()} to
1283 * determine whether it should currently run in fullscreen mode. You
1284 * can use {@link #isFullscreenMode()} to determine if the input method
1285 * is currently running in fullscreen mode.
1286 */
1287 public void updateFullscreenMode() {
1288 boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
1289 boolean changed = mLastShowInputRequested != mShowInputRequested;
1290 if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
1291 changed = true;
1292 mIsFullscreen = isFullscreen;
Yohei Yukawac54c1172018-09-06 11:39:50 -07001293 reportFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 mFullscreenApplied = true;
1295 initialize();
The Android Open Source Project10592532009-03-18 17:39:46 -07001296 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
1297 mFullscreenArea.getLayoutParams();
1298 if (isFullscreen) {
1299 mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
1300 com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
1301 lp.height = 0;
1302 lp.weight = 1;
1303 } else {
1304 mFullscreenArea.setBackgroundDrawable(null);
1305 lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
1306 lp.weight = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001308 ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
1309 mFullscreenArea, lp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 if (isFullscreen) {
1311 if (mExtractView == null) {
1312 View v = onCreateExtractTextView();
1313 if (v != null) {
1314 setExtractView(v);
1315 }
1316 }
1317 startExtractingText(false);
1318 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001319 updateExtractFrameVisibility();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 }
1321
1322 if (changed) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001323 onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 mLastShowInputRequested = mShowInputRequested;
1325 }
1326 }
1327
1328 /**
1329 * Update the given window's parameters for the given mode. This is called
1330 * when the window is first displayed and each time the fullscreen or
1331 * candidates only mode changes.
1332 *
1333 * <p>The default implementation makes the layout for the window
Romain Guy980a9382010-01-08 15:06:28 -08001334 * MATCH_PARENT x MATCH_PARENT when in fullscreen mode, and
1335 * MATCH_PARENT x WRAP_CONTENT when in non-fullscreen mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 *
1337 * @param win The input method's window.
1338 * @param isFullscreen If true, the window is running in fullscreen mode
1339 * and intended to cover the entire application display.
1340 * @param isCandidatesOnly If true, the window is only showing the
1341 * candidates view and none of the rest of its UI. This is mutually
1342 * exclusive with fullscreen mode.
1343 */
1344 public void onConfigureWindow(Window win, boolean isFullscreen,
1345 boolean isCandidatesOnly) {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001346 final int currentHeight = mWindow.getWindow().getAttributes().height;
1347 final int newHeight = isFullscreen ? MATCH_PARENT : WRAP_CONTENT;
1348 if (mIsInputViewShown && currentHeight != newHeight) {
Yohei Yukawad0332832017-02-01 13:59:43 -08001349 if (DEBUG) {
1350 Log.w(TAG,"Window size has been changed. This may cause jankiness of resizing "
1351 + "window: " + currentHeight + " -> " + newHeight);
1352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 }
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001354 mWindow.getWindow().setLayout(MATCH_PARENT, newHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356
1357 /**
1358 * Return whether the input method is <em>currently</em> running in
1359 * fullscreen mode. This is the mode that was last determined and
1360 * applied by {@link #updateFullscreenMode()}.
1361 */
1362 public boolean isFullscreenMode() {
1363 return mIsFullscreen;
1364 }
1365
1366 /**
1367 * Override this to control when the input method should run in
1368 * fullscreen mode. The default implementation runs in fullsceen only
1369 * when the screen is in landscape mode. If you change what
1370 * this returns, you will need to call {@link #updateFullscreenMode()}
1371 * yourself whenever the returned value may have changed to have it
1372 * re-evaluated and applied.
1373 */
1374 public boolean onEvaluateFullscreenMode() {
1375 Configuration config = getResources().getConfiguration();
Leon Scroggins2edd6822010-01-12 11:36:13 -05001376 if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
1377 return false;
1378 }
1379 if (mInputEditorInfo != null
1380 && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
1381 return false;
1382 }
1383 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
Gilles Debunne34703b62011-09-08 11:16:25 -07001385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07001387 * Controls the visibility of the extracted text area. This only applies
1388 * when the input method is in fullscreen mode, and thus showing extracted
1389 * text. When false, the extracted text will not be shown, allowing some
1390 * of the application to be seen behind. This is normally set for you
1391 * by {@link #onUpdateExtractingVisibility}. This controls the visibility
1392 * of both the extracted text and candidate view; the latter since it is
1393 * not useful if there is no text to see.
1394 */
1395 public void setExtractViewShown(boolean shown) {
1396 if (mExtractViewHidden == shown) {
1397 mExtractViewHidden = !shown;
1398 updateExtractFrameVisibility();
1399 }
1400 }
1401
1402 /**
1403 * Return whether the fullscreen extract view is shown. This will only
1404 * return true if {@link #isFullscreenMode()} returns true, and in that
1405 * case its value depends on the last call to
1406 * {@link #setExtractViewShown(boolean)}. This effectively lets you
1407 * determine if the application window is entirely covered (when this
1408 * returns true) or if some part of it may be shown (if this returns
1409 * false, though if {@link #isFullscreenMode()} returns true in that case
1410 * then it is probably only a sliver of the application).
1411 */
1412 public boolean isExtractViewShown() {
1413 return mIsFullscreen && !mExtractViewHidden;
1414 }
1415
1416 void updateExtractFrameVisibility() {
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001417 final int vis;
The Android Open Source Project10592532009-03-18 17:39:46 -07001418 if (isFullscreenMode()) {
1419 vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
Satoshi Kataoka8b117c82012-11-06 18:59:23 +09001420 // "vis" should be applied for the extract frame as well in the fullscreen mode.
1421 mExtractFrame.setVisibility(vis);
The Android Open Source Project10592532009-03-18 17:39:46 -07001422 } else {
1423 vis = View.VISIBLE;
1424 mExtractFrame.setVisibility(View.GONE);
1425 }
1426 updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001427 if (mDecorViewWasVisible && mFullscreenArea.getVisibility() != vis) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001428 int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
1429 ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
1430 : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
1431 0);
1432 if (animRes != 0) {
1433 mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
1434 this, animRes));
1435 }
1436 }
1437 mFullscreenArea.setVisibility(vis);
1438 }
1439
1440 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 * Compute the interesting insets into your UI. The default implementation
1442 * uses the top of the candidates frame for the visible insets, and the
1443 * top of the input frame for the content insets. The default touchable
1444 * insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
1445 *
The Android Open Source Project10592532009-03-18 17:39:46 -07001446 * <p>Note that this method is not called when
1447 * {@link #isExtractViewShown} returns true, since
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 * in that case the application is left as-is behind the input method and
1449 * not impacted by anything in its UI.
1450 *
1451 * @param outInsets Fill in with the current UI insets.
1452 */
1453 public void onComputeInsets(Insets outInsets) {
1454 int[] loc = mTmpLocation;
1455 if (mInputFrame.getVisibility() == View.VISIBLE) {
1456 mInputFrame.getLocationInWindow(loc);
1457 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001458 View decor = getWindow().getWindow().getDecorView();
1459 loc[1] = decor.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001461 if (isFullscreenMode()) {
1462 // In fullscreen mode, we never resize the underlying window.
1463 View decor = getWindow().getWindow().getDecorView();
1464 outInsets.contentTopInsets = decor.getHeight();
1465 } else {
1466 outInsets.contentTopInsets = loc[1];
1467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
1469 mCandidatesFrame.getLocationInWindow(loc);
1470 }
1471 outInsets.visibleTopInsets = loc[1];
1472 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
Jeff Brownfbf09772011-01-16 14:06:57 -08001473 outInsets.touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 }
1475
1476 /**
1477 * Re-evaluate whether the soft input area should currently be shown, and
1478 * update its UI if this has changed since the last time it
1479 * was evaluated. This will call {@link #onEvaluateInputViewShown()} to
1480 * determine whether the input view should currently be shown. You
1481 * can use {@link #isInputViewShown()} to determine if the input view
1482 * is currently shown.
1483 */
1484 public void updateInputViewShown() {
1485 boolean isShown = mShowInputRequested && onEvaluateInputViewShown();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001486 if (mIsInputViewShown != isShown && mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 mIsInputViewShown = isShown;
1488 mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
1489 if (mInputView == null) {
1490 initialize();
1491 View v = onCreateInputView();
1492 if (v != null) {
1493 setInputView(v);
1494 }
1495 }
1496 }
1497 }
1498
1499 /**
1500 * Returns true if we have been asked to show our input view.
1501 */
1502 public boolean isShowInputRequested() {
1503 return mShowInputRequested;
1504 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 /**
1507 * Return whether the soft input view is <em>currently</em> shown to the
1508 * user. This is the state that was last determined and
1509 * applied by {@link #updateInputViewShown()}.
1510 */
1511 public boolean isInputViewShown() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01001512 return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 /**
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001516 * Override this to control when the soft input area should be shown to the user. The default
1517 * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
1518 * unless the user shows an intention to use software keyboard. If you change what this
1519 * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
1520 * value may have changed to have it re-evaluated and applied.
1521 *
1522 * <p>When you override this method, it is recommended to call
1523 * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
1524 * returned.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 */
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001526 @CallSuper
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 public boolean onEvaluateInputViewShown() {
Yohei Yukawacf8403b2016-01-12 11:54:58 -08001528 if (mSettingsObserver == null) {
1529 Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
1530 return false;
1531 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001532 if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
1533 return true;
1534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 Configuration config = getResources().getConfiguration();
1536 return config.keyboard == Configuration.KEYBOARD_NOKEYS
Ken Wakasa8710e762011-01-30 11:02:09 +09001537 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
Yohei Yukawa7b739a82015-12-21 13:30:44 -08001539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 /**
1541 * Controls the visibility of the candidates display area. By default
1542 * it is hidden.
1543 */
1544 public void setCandidatesViewShown(boolean shown) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001545 updateCandidatesVisibility(shown);
Tarandeep Singheadb1392018-11-09 18:15:57 +01001546 if (!mShowInputRequested && mDecorViewVisible != shown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 // If we are being asked to show the candidates view while the app
1548 // has not asked for the input view to be shown, then we need
1549 // to update whether the window is shown.
1550 if (shown) {
1551 showWindow(false);
1552 } else {
satok2f913d92012-05-10 01:48:03 +09001553 doHideWindow();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555 }
1556 }
1557
The Android Open Source Project10592532009-03-18 17:39:46 -07001558 void updateCandidatesVisibility(boolean shown) {
1559 int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
1560 if (mCandidatesVisibility != vis) {
1561 mCandidatesFrame.setVisibility(vis);
1562 mCandidatesVisibility = vis;
1563 }
1564 }
1565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 /**
1567 * Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
1568 * or {@link View#GONE View.GONE}) of the candidates view when it is not
The Android Open Source Project10592532009-03-18 17:39:46 -07001569 * shown. The default implementation returns GONE when
1570 * {@link #isExtractViewShown} returns true,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 * otherwise VISIBLE. Be careful if you change this to return GONE in
1572 * other situations -- if showing or hiding the candidates view causes
1573 * your window to resize, this can cause temporary drawing artifacts as
1574 * the resize takes place.
1575 */
1576 public int getCandidatesHiddenVisibility() {
The Android Open Source Project10592532009-03-18 17:39:46 -07001577 return isExtractViewShown() ? View.GONE : View.INVISIBLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001579
Tor Norbye7b9c9122013-05-30 16:48:33 -07001580 public void showStatusIcon(@DrawableRes int iconResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 mStatusIcon = iconResId;
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001582 mPrivOps.updateStatusIcon(getPackageName(), iconResId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 public void hideStatusIcon() {
1586 mStatusIcon = 0;
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001587 mPrivOps.updateStatusIcon(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 /**
1591 * Force switch to a new input method, as identified by <var>id</var>. This
1592 * input method will be destroyed, and the requested one started on the
1593 * current input field.
1594 *
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001595 * @param id Unique identifier of the new input method to start.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 */
1597 public void switchInputMethod(String id) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001598 mPrivOps.setInputMethod(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 }
Yohei Yukawa2b634342018-01-14 16:15:31 -08001600
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001601 /**
1602 * Force switch to a new input method, as identified by {@code id}. This
1603 * input method will be destroyed, and the requested one started on the
1604 * current input field.
1605 *
1606 * @param id Unique identifier of the new input method to start.
1607 * @param subtype The new subtype of the new input method to be switched to.
1608 */
Tarandeep Singh45136992018-03-08 10:52:03 -08001609 public final void switchInputMethod(String id, InputMethodSubtype subtype) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07001610 mPrivOps.setInputMethodAndSubtype(id, subtype);
Tarandeep Singh164cfba2018-02-28 14:17:43 -08001611 }
1612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 public void setExtractView(View view) {
1614 mExtractFrame.removeAllViews();
1615 mExtractFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001616 ViewGroup.LayoutParams.MATCH_PARENT,
1617 ViewGroup.LayoutParams.MATCH_PARENT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 mExtractView = view;
1619 if (view != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001620 mExtractEditText = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 com.android.internal.R.id.inputExtractEditText);
1622 mExtractEditText.setIME(this);
Mark Renouf91eb2652016-04-11 16:03:26 -04001623 mExtractAction = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 com.android.internal.R.id.inputExtractAction);
1625 if (mExtractAction != null) {
Yohei Yukawa31a260f2018-01-14 16:24:26 -08001626 mExtractAccessories = view.findViewById(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 com.android.internal.R.id.inputExtractAccessories);
1628 }
1629 startExtractingText(false);
1630 } else {
1631 mExtractEditText = null;
1632 mExtractAccessories = null;
1633 mExtractAction = null;
1634 }
1635 }
1636
1637 /**
1638 * Replaces the current candidates view with a new one. You only need to
1639 * call this when dynamically changing the view; normally, you should
1640 * implement {@link #onCreateCandidatesView()} and create your view when
1641 * first needed by the input method.
1642 */
1643 public void setCandidatesView(View view) {
1644 mCandidatesFrame.removeAllViews();
1645 mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001646 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 ViewGroup.LayoutParams.WRAP_CONTENT));
1648 }
1649
1650 /**
1651 * Replaces the current input view with a new one. You only need to
1652 * call this when dynamically changing the view; normally, you should
1653 * implement {@link #onCreateInputView()} and create your view when
1654 * first needed by the input method.
1655 */
1656 public void setInputView(View view) {
1657 mInputFrame.removeAllViews();
1658 mInputFrame.addView(view, new FrameLayout.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -08001659 ViewGroup.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 ViewGroup.LayoutParams.WRAP_CONTENT));
1661 mInputView = view;
1662 }
1663
1664 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 * Called by the framework to create the layout for showing extacted text.
1666 * Only called when in fullscreen mode. The returned view hierarchy must
1667 * have an {@link ExtractEditText} whose ID is
1668 * {@link android.R.id#inputExtractEditText}.
1669 */
1670 public View onCreateExtractTextView() {
1671 return mInflater.inflate(
1672 com.android.internal.R.layout.input_method_extract_view, null);
1673 }
1674
1675 /**
1676 * Create and return the view hierarchy used to show candidates. This will
1677 * be called once, when the candidates are first displayed. You can return
1678 * null to have no candidates view; the default implementation returns null.
1679 *
1680 * <p>To control when the candidates view is displayed, use
1681 * {@link #setCandidatesViewShown(boolean)}.
1682 * To change the candidates view after the first one is created by this
1683 * function, use {@link #setCandidatesView(View)}.
1684 */
1685 public View onCreateCandidatesView() {
1686 return null;
1687 }
1688
1689 /**
1690 * Create and return the view hierarchy used for the input area (such as
1691 * a soft keyboard). This will be called once, when the input area is
1692 * first displayed. You can return null to have no input area; the default
1693 * implementation returns null.
1694 *
1695 * <p>To control when the input view is displayed, implement
1696 * {@link #onEvaluateInputViewShown()}.
1697 * To change the input view after the first one is created by this
1698 * function, use {@link #setInputView(View)}.
1699 */
1700 public View onCreateInputView() {
1701 return null;
1702 }
1703
1704 /**
1705 * Called when the input view is being shown and input has started on
1706 * a new editor. This will always be called after {@link #onStartInput},
1707 * allowing you to do your general setup there and just view-specific
1708 * setup here. You are guaranteed that {@link #onCreateInputView()} will
1709 * have been called some time before this function is called.
1710 *
1711 * @param info Description of the type of text being edited.
1712 * @param restarting Set to true if we are restarting input on the
1713 * same text field as before.
1714 */
1715 public void onStartInputView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001716 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
1718
1719 /**
1720 * Called when the input view is being hidden from the user. This will
1721 * be called either prior to hiding the window, or prior to switching to
1722 * another target for editing.
1723 *
1724 * <p>The default
1725 * implementation uses the InputConnection to clear any active composing
1726 * text; you can override this (not calling the base class implementation)
1727 * to perform whatever behavior you would like.
1728 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001729 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 * called immediately after.
1731 */
1732 public void onFinishInputView(boolean finishingInput) {
1733 if (!finishingInput) {
1734 InputConnection ic = getCurrentInputConnection();
1735 if (ic != null) {
1736 ic.finishComposingText();
1737 }
1738 }
1739 }
1740
1741 /**
1742 * Called when only the candidates view has been shown for showing
1743 * processing as the user enters text through a hard keyboard.
1744 * This will always be called after {@link #onStartInput},
1745 * allowing you to do your general setup there and just view-specific
1746 * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
1747 * will have been called some time before this function is called.
1748 *
1749 * <p>Note that this will <em>not</em> be called when the input method
1750 * is running in full editing mode, and thus receiving
1751 * {@link #onStartInputView} to initiate that operation. This is only
1752 * for the case when candidates are being shown while the input method
1753 * editor is hidden but wants to show its candidates UI as text is
1754 * entered through some other mechanism.
1755 *
1756 * @param info Description of the type of text being edited.
1757 * @param restarting Set to true if we are restarting input on the
1758 * same text field as before.
1759 */
1760 public void onStartCandidatesView(EditorInfo info, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07001761 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 }
1763
1764 /**
1765 * Called when the candidates view is being hidden from the user. This will
1766 * be called either prior to hiding the window, or prior to switching to
1767 * another target for editing.
1768 *
1769 * <p>The default
1770 * implementation uses the InputConnection to clear any active composing
1771 * text; you can override this (not calling the base class implementation)
1772 * to perform whatever behavior you would like.
1773 *
The Android Open Source Project4df24232009-03-05 14:34:35 -08001774 * @param finishingInput If true, {@link #onFinishInput} will be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 * called immediately after.
1776 */
1777 public void onFinishCandidatesView(boolean finishingInput) {
1778 if (!finishingInput) {
1779 InputConnection ic = getCurrentInputConnection();
1780 if (ic != null) {
1781 ic.finishComposingText();
1782 }
1783 }
1784 }
1785
1786 /**
1787 * The system has decided that it may be time to show your input method.
1788 * This is called due to a corresponding call to your
The Android Open Source Project4df24232009-03-05 14:34:35 -08001789 * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 * method. The default implementation uses
1791 * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
1792 * and the current configuration to decide whether the input view should
1793 * be shown at this point.
1794 *
1795 * @param flags Provides additional information about the show request,
The Android Open Source Project4df24232009-03-05 14:34:35 -08001796 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 * @param configChange This is true if we are re-showing due to a
1798 * configuration change.
1799 * @return Returns true to indicate that the window should be shown.
1800 */
1801 public boolean onShowInputRequested(int flags, boolean configChange) {
1802 if (!onEvaluateInputViewShown()) {
1803 return false;
1804 }
1805 if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
1806 if (!configChange && onEvaluateFullscreenMode()) {
1807 // Don't show if this is not explicitly requested by the user and
1808 // the input method is fullscreen. That would be too disruptive.
1809 // However, we skip this change for a config change, since if
1810 // the IME is already shown we do want to go into fullscreen
1811 // mode at this point.
1812 return false;
1813 }
Yohei Yukawad0d07972016-05-04 11:56:35 -07001814 if (!mSettingsObserver.shouldShowImeWithHardKeyboard() &&
1815 getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 // And if the device has a hard keyboard, even if it is
1817 // currently hidden, don't show the input method implicitly.
1818 // These kinds of devices don't need it that much.
1819 return false;
1820 }
1821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 return true;
1823 }
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001824
1825 /**
1826 * A utility method to call {{@link #onShowInputRequested(int, boolean)}} and update internal
1827 * states depending on its result. Since {@link #onShowInputRequested(int, boolean)} is
1828 * exposed to IME authors as an overridable public method without {@code @CallSuper}, we have
1829 * to have this method to ensure that those internal states are always updated no matter how
1830 * {@link #onShowInputRequested(int, boolean)} is overridden by the IME author.
1831 * @param flags Provides additional information about the show request,
1832 * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
1833 * @param configChange This is true if we are re-showing due to a
1834 * configuration change.
1835 * @return Returns true to indicate that the window should be shown.
1836 * @see #onShowInputRequested(int, boolean)
1837 */
1838 private boolean dispatchOnShowInputRequested(int flags, boolean configChange) {
1839 final boolean result = onShowInputRequested(flags, configChange);
1840 if (result) {
1841 mShowInputFlags = flags;
1842 } else {
1843 mShowInputFlags = 0;
1844 }
1845 return result;
1846 }
1847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 public void showWindow(boolean showInput) {
Craig Mautnere4bbb1c2013-03-15 11:38:44 -07001849 if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 + " mShowInputRequested=" + mShowInputRequested
Tarandeep Singheadb1392018-11-09 18:15:57 +01001851 + " mViewsCreated=" + mViewsCreated
1852 + " mDecorViewVisible=" + mDecorViewVisible
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 + " mWindowVisible=" + mWindowVisible
Yohei Yukawaef5b4652016-04-03 22:50:11 -07001854 + " mInputStarted=" + mInputStarted
1855 + " mShowInputFlags=" + mShowInputFlags);
1856
The Android Open Source Project10592532009-03-18 17:39:46 -07001857 if (mInShowWindow) {
1858 Log.w(TAG, "Re-entrance in to showWindow");
1859 return;
1860 }
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001861
Tarandeep Singheadb1392018-11-09 18:15:57 +01001862 mDecorViewWasVisible = mDecorViewVisible;
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001863 mInShowWindow = true;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001864 boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible;
1865 final int previousImeWindowStatus =
1866 (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
1867 ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
1868 startViews(prepareWindow(showInput));
1869 final int nextImeWindowStatus = mapToImeWindowStatus();
1870 if (previousImeWindowStatus != nextImeWindowStatus) {
1871 setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
1872 }
1873
1874 // compute visibility
1875 onWindowShown();
1876 mIsPreRendered = mCanPreRender;
1877 if (mIsPreRendered) {
1878 onPreRenderedWindowVisibilityChanged(true /* setVisible */);
1879 } else {
1880 // Pre-rendering not supported.
1881 if (DEBUG) Log.d(TAG, "No pre-rendering supported");
1882 mWindowVisible = true;
1883 }
1884
1885 // request draw for the IME surface.
1886 // When IME is not pre-rendered, this will actually show the IME.
1887 if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
1888 if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
1889 mWindow.show();
1890 }
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001891 maybeNotifyPreRendered();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001892 mDecorViewWasVisible = true;
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001893 mInShowWindow = false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001894 }
satok06487a52010-10-29 11:37:18 +09001895
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001896 /**
1897 * Notify {@link android.view.ImeInsetsSourceConsumer} if IME has been pre-rendered
1898 * for current EditorInfo, when pre-rendering is enabled.
1899 */
1900 private void maybeNotifyPreRendered() {
1901 if (!mCanPreRender || !mIsPreRendered) {
1902 return;
1903 }
1904 mPrivOps.reportPreRendered(getCurrentInputEditorInfo());
1905 }
1906
1907
Tarandeep Singheadb1392018-11-09 18:15:57 +01001908 private boolean prepareWindow(boolean showInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 boolean doShowInput = false;
Tarandeep Singheadb1392018-11-09 18:15:57 +01001910 mDecorViewVisible = true;
Yohei Yukawaac8bdd22015-09-11 18:17:11 -07001911 if (!mShowInputRequested && mInputStarted && showInput) {
1912 doShowInput = true;
1913 mShowInputRequested = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 }
satok06487a52010-10-29 11:37:18 +09001915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 if (DEBUG) Log.v(TAG, "showWindow: updating UI");
1917 initialize();
1918 updateFullscreenMode();
1919 updateInputViewShown();
Yohei Yukawa13a9ffb2018-08-29 19:56:02 -07001920
Tarandeep Singheadb1392018-11-09 18:15:57 +01001921 if (!mViewsCreated) {
1922 mViewsCreated = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 initialize();
1924 if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
1925 View v = onCreateCandidatesView();
1926 if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
1927 if (v != null) {
1928 setCandidatesView(v);
1929 }
1930 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001931 return doShowInput;
1932 }
1933
1934 private void startViews(boolean doShowInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 if (mShowInputRequested) {
1936 if (!mInputViewStarted) {
1937 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
1938 mInputViewStarted = true;
1939 onStartInputView(mInputEditorInfo, false);
1940 }
1941 } else if (!mCandidatesViewStarted) {
1942 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
1943 mCandidatesViewStarted = true;
1944 onStartCandidatesView(mInputEditorInfo, false);
1945 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01001946 if (doShowInput) startExtractingText(false);
1947 }
satok06487a52010-10-29 11:37:18 +09001948
Tarandeep Singheadb1392018-11-09 18:15:57 +01001949 private void onPreRenderedWindowVisibilityChanged(boolean setVisible) {
1950 mWindowVisible = setVisible;
1951 mShowInputFlags = setVisible ? mShowInputFlags : 0;
1952 mShowInputRequested = setVisible;
1953 mDecorViewVisible = setVisible;
1954 if (setVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 onWindowShown();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 }
1957 }
satok06487a52010-10-29 11:37:18 +09001958
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08001959 /**
1960 * Apply the IME visibility in {@link android.view.ImeInsetsSourceConsumer} when
1961 * pre-rendering is enabled.
1962 * @param setVisible {@code true} to make it visible, false to hide it.
1963 */
1964 private void applyVisibilityInInsetsConsumer(boolean setVisible) {
1965 if (!mIsPreRendered) {
1966 return;
1967 }
1968 mPrivOps.applyImeVisibility(setVisible);
1969 }
1970
Tarandeep Singheadb1392018-11-09 18:15:57 +01001971 private void finishViews(boolean finishingInput) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 if (mInputViewStarted) {
1973 if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
Tarandeep Singheadb1392018-11-09 18:15:57 +01001974 onFinishInputView(finishingInput);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 } else if (mCandidatesViewStarted) {
1976 if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
Tarandeep Singheadb1392018-11-09 18:15:57 +01001977 onFinishCandidatesView(finishingInput);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 }
1979 mInputViewStarted = false;
1980 mCandidatesViewStarted = false;
satokf17db9f2011-09-14 18:55:58 +09001981 }
1982
satok2f913d92012-05-10 01:48:03 +09001983 private void doHideWindow() {
Yohei Yukawac54c1172018-09-06 11:39:50 -07001984 setImeWindowStatus(0, mBackDisposition);
satok2f913d92012-05-10 01:48:03 +09001985 hideWindow();
1986 }
1987
satokf17db9f2011-09-14 18:55:58 +09001988 public void hideWindow() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01001989 if (DEBUG) Log.v(TAG, "CALL: hideWindow");
1990 mIsPreRendered = false;
1991 mWindowVisible = false;
1992 finishViews(false /* finishingInput */);
1993 if (mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 mWindow.hide();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001995 mDecorViewVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 onWindowHidden();
Tarandeep Singheadb1392018-11-09 18:15:57 +01001997 mDecorViewWasVisible = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
Seigo Nonaka93c47ea2015-07-14 15:05:04 +09001999 updateFullscreenMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
satok06487a52010-10-29 11:37:18 +09002001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 /**
tiansiming [田思明]b9025932018-02-05 18:28:28 +08002003 * Called immediately before the input method window is shown to the user.
2004 * You could override this to prepare for the window to be shown
2005 * (update view structure etc).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 */
2007 public void onWindowShown() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002008 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 }
2010
2011 /**
2012 * Called when the input method window has been hidden from the user,
2013 * after previously being visible.
2014 */
2015 public void onWindowHidden() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002016 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 }
Yohei Yukawa2977eb72015-05-27 18:54:18 -07002018
2019 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 * Called when a new client has bound to the input method. This
2021 * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
2022 * and {@link #onFinishInput()} calls as the user navigates through its
2023 * UI. Upon this call you know that {@link #getCurrentInputBinding}
2024 * and {@link #getCurrentInputConnection} return valid objects.
2025 */
2026 public void onBindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002027 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 }
2029
2030 /**
2031 * Called when the previous bound client is no longer associated
2032 * with the input method. After returning {@link #getCurrentInputBinding}
2033 * and {@link #getCurrentInputConnection} will no longer return
2034 * valid objects.
2035 */
2036 public void onUnbindInput() {
Gilles Debunne34703b62011-09-08 11:16:25 -07002037 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 }
2039
2040 /**
2041 * Called to inform the input method that text input has started in an
2042 * editor. You should use this callback to initialize the state of your
2043 * input to match the state of the editor given to it.
2044 *
2045 * @param attribute The attributes of the editor that input is starting
2046 * in.
2047 * @param restarting Set to true if input is restarting in the same
2048 * editor such as because the application has changed the text in
2049 * the editor. Otherwise will be false, indicating this is a new
2050 * session with the editor.
2051 */
2052 public void onStartInput(EditorInfo attribute, boolean restarting) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002053 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055
2056 void doFinishInput() {
Tarandeep Singheadb1392018-11-09 18:15:57 +01002057 if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
2058 finishViews(true /* finishingInput */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 if (mInputStarted) {
2060 if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
2061 onFinishInput();
2062 }
2063 mInputStarted = false;
2064 mStartedInputConnection = null;
2065 mCurCompletions = null;
2066 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08002067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068 void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
2069 if (!restarting) {
2070 doFinishInput();
2071 }
2072 mInputStarted = true;
2073 mStartedInputConnection = ic;
2074 mInputEditorInfo = attribute;
2075 initialize();
2076 if (DEBUG) Log.v(TAG, "CALL: onStartInput");
2077 onStartInput(attribute, restarting);
Tarandeep Singheadb1392018-11-09 18:15:57 +01002078 if (mDecorViewVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 if (mShowInputRequested) {
2080 if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
2081 mInputViewStarted = true;
2082 onStartInputView(mInputEditorInfo, restarting);
2083 startExtractingText(true);
2084 } else if (mCandidatesVisibility == View.VISIBLE) {
2085 if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
2086 mCandidatesViewStarted = true;
2087 onStartCandidatesView(mInputEditorInfo, restarting);
2088 }
Tarandeep Singheadb1392018-11-09 18:15:57 +01002089 } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) {
2090 // Pre-render IME views and window when real EditorInfo is available.
2091 // pre-render IME window and keep it invisible.
2092 if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName);
2093 if (mInShowWindow) {
2094 Log.w(TAG, "Re-entrance in to showWindow");
2095 return;
2096 }
2097
2098 mDecorViewWasVisible = mDecorViewVisible;
2099 mInShowWindow = true;
2100 startViews(prepareWindow(true /* showInput */));
2101
2102 // compute visibility
2103 mIsPreRendered = true;
2104 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
2105
2106 // request draw for the IME surface.
2107 // When IME is not pre-rendered, this will actually show the IME.
2108 if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
2109 mWindow.show();
Tarandeep Singh2cbcd7f2019-01-25 11:47:57 -08002110 maybeNotifyPreRendered();
Tarandeep Singheadb1392018-11-09 18:15:57 +01002111 mDecorViewWasVisible = true;
2112 mInShowWindow = false;
2113 } else {
2114 mIsPreRendered = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 }
2116 }
2117
2118 /**
2119 * Called to inform the input method that text input has finished in
2120 * the last editor. At this point there may be a call to
2121 * {@link #onStartInput(EditorInfo, boolean)} to perform input in a
2122 * new editor, or the input method may be left idle. This method is
2123 * <em>not</em> called when input restarts in the same editor.
2124 *
2125 * <p>The default
2126 * implementation uses the InputConnection to clear any active composing
2127 * text; you can override this (not calling the base class implementation)
2128 * to perform whatever behavior you would like.
2129 */
2130 public void onFinishInput() {
2131 InputConnection ic = getCurrentInputConnection();
2132 if (ic != null) {
2133 ic.finishComposingText();
2134 }
2135 }
2136
2137 /**
2138 * Called when the application has reported auto-completion candidates that
2139 * it would like to have the input method displayed. Typically these are
2140 * only used when an input method is running in full-screen mode, since
2141 * otherwise the user can see and interact with the pop-up window of
2142 * completions shown by the application.
2143 *
2144 * <p>The default implementation here does nothing.
2145 */
2146 public void onDisplayCompletions(CompletionInfo[] completions) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002147 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 }
2149
2150 /**
2151 * Called when the application has reported new extracted text to be shown
2152 * due to changes in its current text state. The default implementation
2153 * here places the new text in the extract edit text, when the input
2154 * method is running in fullscreen mode.
2155 */
2156 public void onUpdateExtractedText(int token, ExtractedText text) {
2157 if (mExtractedToken != token) {
2158 return;
2159 }
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07002160 if (text != null) {
2161 if (mExtractEditText != null) {
2162 mExtractedText = text;
2163 mExtractEditText.setExtractedText(text);
2164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 }
2166 }
2167
2168 /**
2169 * Called when the application has reported a new selection region of
2170 * the text. This is called whether or not the input method has requested
2171 * extracted text updates, although if so it will not receive this call
2172 * if the extracted text has changed as well.
Jean Chalardc743cb92013-09-12 16:28:45 +09002173 *
2174 * <p>Be careful about changing the text in reaction to this call with
2175 * methods such as setComposingText, commitText or
2176 * deleteSurroundingText. If the cursor moves as a result, this method
2177 * will be called again, which may result in an infinite loop.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 *
2179 * <p>The default implementation takes care of updating the cursor in
2180 * the extract text, if it is being shown.
2181 */
2182 public void onUpdateSelection(int oldSelStart, int oldSelEnd,
2183 int newSelStart, int newSelEnd,
2184 int candidatesStart, int candidatesEnd) {
2185 final ExtractEditText eet = mExtractEditText;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002186 if (eet != null && isFullscreenMode() && mExtractedText != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 final int off = mExtractedText.startOffset;
2188 eet.startInternalChanges();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07002189 newSelStart -= off;
2190 newSelEnd -= off;
2191 final int len = eet.getText().length();
2192 if (newSelStart < 0) newSelStart = 0;
2193 else if (newSelStart > len) newSelStart = len;
2194 if (newSelEnd < 0) newSelEnd = 0;
2195 else if (newSelEnd > len) newSelEnd = len;
2196 eet.setSelection(newSelStart, newSelEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 eet.finishInternalChanges();
2198 }
2199 }
2200
2201 /**
satok863fcd62011-06-21 17:38:02 +09002202 * Called when the user tapped or clicked a text view.
2203 * IMEs can't rely on this method being called because this was not part of the original IME
2204 * protocol, so applications with custom text editing written before this method appeared will
2205 * not call to inform the IME of this interaction.
2206 * @param focusChanged true if the user changed the focused view by this click.
Yohei Yukawa0eb8d162019-01-22 21:47:57 -08002207 * @see InputMethodManager#viewClicked(View)
2208 * @deprecated The method may not be called for composite {@link View} that works as a giant
2209 * "Canvas", which can host its own UI hierarchy and sub focus state.
2210 * {@link android.webkit.WebView} is a good example. Application / IME developers
2211 * should not rely on this method. If your goal is just being notified when an
2212 * on-going input is interrupted, simply monitor {@link #onFinishInput()}.
satok863fcd62011-06-21 17:38:02 +09002213 */
Yohei Yukawa0eb8d162019-01-22 21:47:57 -08002214 @Deprecated
satok863fcd62011-06-21 17:38:02 +09002215 public void onViewClicked(boolean focusChanged) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002216 // Intentionally empty
satok863fcd62011-06-21 17:38:02 +09002217 }
2218
2219 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07002220 * Called when the application has reported a new location of its text
2221 * cursor. This is only called if explicitly requested by the input method.
2222 * The default implementation does nothing.
Andrew Solovay5c05ded2018-10-02 14:14:42 -07002223 * @deprecated Use {@link #onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07002225 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 public void onUpdateCursor(Rect newCursor) {
Gilles Debunne34703b62011-09-08 11:16:25 -07002227 // Intentionally empty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229
2230 /**
Yohei Yukawac2ddd602014-05-06 21:22:49 +09002231 * Called when the application has reported a new location of its text insertion point and
2232 * characters in the composition string. This is only called if explicitly requested by the
2233 * input method. The default implementation does nothing.
2234 * @param cursorAnchorInfo The positional information of the text insertion point and the
2235 * composition string.
2236 */
2237 public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
2238 // Intentionally empty
2239 }
2240
2241 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 * Close this input method's soft input area, removing it from the display.
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002243 *
2244 * The input method will continue running, but the user can no longer use it to generate input
2245 * by touching the screen.
2246 *
2247 * @see InputMethodManager#HIDE_IMPLICIT_ONLY
2248 * @see InputMethodManager#HIDE_NOT_ALWAYS
2249 * @param flags Provides additional operating flags.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08002251 public void requestHideSelf(int flags) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07002252 mPrivOps.hideMySoftInput(flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 /**
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002256 * Show the input method's soft input area, so the user sees the input method window and can
2257 * interact with it.
2258 *
2259 * @see InputMethodManager#SHOW_IMPLICIT
2260 * @see InputMethodManager#SHOW_FORCED
2261 * @param flags Provides additional operating flags.
The Android Open Source Project4df24232009-03-05 14:34:35 -08002262 */
Tarandeep Singh45136992018-03-08 10:52:03 -08002263 public final void requestShowSelf(int flags) {
Yohei Yukawac7ca3682018-09-09 20:48:38 -07002264 mPrivOps.showMySoftInput(flags);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002265 }
Yohei Yukawafbc2f7a2018-01-16 08:09:11 -08002266
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002267 private boolean handleBack(boolean doIt) {
2268 if (mShowInputRequested) {
2269 // If the soft input area is shown, back closes it and we
2270 // consume the back key.
2271 if (doIt) requestHideSelf(0);
2272 return true;
Tarandeep Singheadb1392018-11-09 18:15:57 +01002273 } else if (mDecorViewVisible) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002274 if (mCandidatesVisibility == View.VISIBLE) {
2275 // If we are showing candidates even if no input area, then
2276 // hide them.
2277 if (doIt) setCandidatesViewShown(false);
2278 } else {
2279 // If we have the window visible for some other reason --
2280 // most likely to show candidates -- then just get rid
2281 // of it. This really shouldn't happen, but just in case...
satok2f913d92012-05-10 01:48:03 +09002282 if (doIt) doHideWindow();
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002283 }
2284 return true;
2285 }
2286 return false;
2287 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002288
2289 /**
Andrew Solovay5c05ded2018-10-02 14:14:42 -07002290 * @return {@link ExtractEditText} if it is considered to be visible and active. Otherwise
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002291 * {@code null} is returned.
2292 */
2293 private ExtractEditText getExtractEditTextIfVisible() {
2294 if (!isExtractViewShown() || !isInputViewShown()) {
2295 return null;
2296 }
2297 return mExtractEditText;
2298 }
2299
The Android Open Source Project4df24232009-03-05 14:34:35 -08002300 /**
Yohei Yukawa386f50e2018-03-14 13:03:42 -07002301 * Called back when a {@link KeyEvent} is forwarded from the target application.
2302 *
2303 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
2304 * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
2305 * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
2306 * in the extracted text view, not allowing them to perform navigation in the underlying
2307 * application.</p>
2308 *
2309 * <p>The default implementation does not take flags specified to
2310 * {@link #setBackDisposition(int)} into account, even on API version
2311 * {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible
2312 * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
2313 * with the flag they specified to {@link #setBackDisposition(int)}.</p>
2314 *
2315 * @param keyCode The value in {@code event.getKeyCode()}
2316 * @param event Description of the key event
2317 *
2318 * @return {@code true} if the event is consumed by the IME and the application no longer needs
2319 * to consume it. Return {@code false} when the event should be handled as if the IME
2320 * had not seen the event at all.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 */
2322 public boolean onKeyDown(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002323 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002324 final ExtractEditText eet = getExtractEditTextIfVisible();
2325 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2326 return true;
2327 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002328 if (handleBack(false)) {
2329 event.startTracking();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002330 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002332 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 return doMovementKey(keyCode, event, MOVEMENT_DOWN);
2335 }
2336
2337 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002338 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
2339 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
2340 * the event).
2341 */
2342 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
2343 return false;
2344 }
2345
2346 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002347 * Override this to intercept special key multiple events before they are
2348 * processed by the
2349 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002350 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002351 * will occur as if the IME had not seen the event at all.
2352 *
2353 * <p>The default implementation always returns false, except when
2354 * in fullscreen mode, where it will consume DPAD movement
2355 * events to move the cursor in the extracted text view, not allowing
2356 * them to perform navigation in the underlying application.
2357 */
2358 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
2359 return doMovementKey(keyCode, event, count);
2360 }
2361
2362 /**
2363 * Override this to intercept key up events before they are processed by the
2364 * application. If you return true, the application will not itself
Victoria Leaseb38070c2012-08-24 13:46:02 -07002365 * process the event. If you return false, the normal application processing
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 * will occur as if the IME had not seen the event at all.
2367 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002368 * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
2369 * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
2370 * addition, in fullscreen mode only, it will consume DPAD movement
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002371 * events to move the cursor in the extracted text view, not allowing
2372 * them to perform navigation in the underlying application.
2373 */
2374 public boolean onKeyUp(int keyCode, KeyEvent event) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002375 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
2376 final ExtractEditText eet = getExtractEditTextIfVisible();
2377 if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
2378 return true;
2379 }
2380 if (event.isTracking() && !event.isCanceled()) {
2381 return handleBack(true);
2382 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07002383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 return doMovementKey(keyCode, event, MOVEMENT_UP);
2385 }
2386
Victoria Leaseb38070c2012-08-24 13:46:02 -07002387 /**
2388 * Override this to intercept trackball motion events before they are
2389 * processed by the application.
2390 * If you return true, the application will not itself process the event.
2391 * If you return false, the normal application processing will occur as if
2392 * the IME had not seen the event at all.
2393 */
satokab751aa2010-09-14 19:17:36 +09002394 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002395 public boolean onTrackballEvent(MotionEvent event) {
Victoria Leaseb38070c2012-08-24 13:46:02 -07002396 if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
2397 return false;
2398 }
2399
2400 /**
2401 * Override this to intercept generic motion events before they are
2402 * processed by the application.
2403 * If you return true, the application will not itself process the event.
2404 * If you return false, the normal application processing will occur as if
2405 * the IME had not seen the event at all.
2406 */
2407 @Override
2408 public boolean onGenericMotionEvent(MotionEvent event) {
2409 if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410 return false;
2411 }
2412
2413 public void onAppPrivateCommand(String action, Bundle data) {
2414 }
2415
The Android Open Source Project4df24232009-03-05 14:34:35 -08002416 /**
2417 * Handle a request by the system to toggle the soft input area.
2418 */
2419 private void onToggleSoftInput(int showFlags, int hideFlags) {
2420 if (DEBUG) Log.v(TAG, "toggleSoftInput()");
2421 if (isInputViewShown()) {
2422 requestHideSelf(hideFlags);
2423 } else {
2424 requestShowSelf(showFlags);
2425 }
2426 }
2427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 static final int MOVEMENT_DOWN = -1;
2429 static final int MOVEMENT_UP = -2;
2430
2431 void reportExtractedMovement(int keyCode, int count) {
2432 int dx = 0, dy = 0;
2433 switch (keyCode) {
2434 case KeyEvent.KEYCODE_DPAD_LEFT:
2435 dx = -count;
2436 break;
2437 case KeyEvent.KEYCODE_DPAD_RIGHT:
2438 dx = count;
2439 break;
2440 case KeyEvent.KEYCODE_DPAD_UP:
2441 dy = -count;
2442 break;
2443 case KeyEvent.KEYCODE_DPAD_DOWN:
2444 dy = count;
2445 break;
2446 }
satokab751aa2010-09-14 19:17:36 +09002447 onExtractedCursorMovement(dx, dy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 boolean doMovementKey(int keyCode, KeyEvent event, int count) {
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002451 final ExtractEditText eet = getExtractEditTextIfVisible();
2452 if (eet != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002453 // If we are in fullscreen mode, the cursor will move around
2454 // the extract edit text, but should NOT cause focus to move
2455 // to other fields.
2456 MovementMethod movement = eet.getMovementMethod();
2457 Layout layout = eet.getLayout();
2458 if (movement != null && layout != null) {
2459 // We want our own movement method to handle the key, so the
2460 // cursor will properly move in our own word wrapping.
2461 if (count == MOVEMENT_DOWN) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002462 if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 reportExtractedMovement(keyCode, 1);
2464 return true;
2465 }
2466 } else if (count == MOVEMENT_UP) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002467 if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002468 return true;
2469 }
2470 } else {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002471 if (movement.onKeyOther(eet, eet.getText(), event)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002472 reportExtractedMovement(keyCode, count);
2473 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07002474 KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002475 if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002476 KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
Yohei Yukawa24182f32015-09-11 18:33:33 -07002477 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 while (--count > 0) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002479 movement.onKeyDown(eet, eet.getText(), keyCode, down);
2480 movement.onKeyUp(eet, eet.getText(), keyCode, up);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 }
2482 reportExtractedMovement(keyCode, count);
2483 }
2484 }
2485 }
2486 }
2487 // Regardless of whether the movement method handled the key,
2488 // we never allow DPAD navigation to the application.
2489 switch (keyCode) {
2490 case KeyEvent.KEYCODE_DPAD_LEFT:
2491 case KeyEvent.KEYCODE_DPAD_RIGHT:
2492 case KeyEvent.KEYCODE_DPAD_UP:
2493 case KeyEvent.KEYCODE_DPAD_DOWN:
2494 return true;
2495 }
2496 }
Yohei Yukawa38940aa2015-06-24 00:20:24 -07002497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 return false;
2499 }
2500
2501 /**
2502 * Send the given key event code (as defined by {@link KeyEvent}) to the
2503 * current input connection is a key down + key up event pair. The sent
2504 * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
2505 * set, so that the recipient can identify them as coming from a software
2506 * input method, and
2507 * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
2508 * that they don't impact the current touch mode of the UI.
2509 *
Jean Chalard405bc512012-05-29 19:12:34 +09002510 * <p>Note that it's discouraged to send such key events in normal operation;
2511 * this is mainly for use with {@link android.text.InputType#TYPE_NULL} type
2512 * text fields, or for non-rich input methods. A reasonably capable software
2513 * input method should use the
2514 * {@link android.view.inputmethod.InputConnection#commitText} family of methods
2515 * to send text to an application, rather than sending key events.</p>
2516 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 * @param keyEventCode The raw key code to send, as defined by
2518 * {@link KeyEvent}.
2519 */
2520 public void sendDownUpKeyEvents(int keyEventCode) {
2521 InputConnection ic = getCurrentInputConnection();
2522 if (ic == null) return;
2523 long eventTime = SystemClock.uptimeMillis();
2524 ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002525 KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
Tadashi G. Takaokacb95cd62012-10-26 17:20:59 +09002527 ic.sendKeyEvent(new KeyEvent(eventTime, SystemClock.uptimeMillis(),
Jeff Brown6b53e8d2010-11-10 16:03:06 -08002528 KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
2530 }
2531
2532 /**
2533 * Ask the input target to execute its default action via
2534 * {@link InputConnection#performEditorAction
2535 * InputConnection.performEditorAction()}.
2536 *
2537 * @param fromEnterKey If true, this will be executed as if the user had
2538 * pressed an enter key on the keyboard, that is it will <em>not</em>
2539 * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
2540 * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
2541 * sent regardless of how the editor has set that flag.
2542 *
2543 * @return Returns a boolean indicating whether an action has been sent.
2544 * If false, either the editor did not specify a default action or it
2545 * does not want an action from the enter key. If true, the action was
2546 * sent (or there was no input connection at all).
2547 */
2548 public boolean sendDefaultEditorAction(boolean fromEnterKey) {
2549 EditorInfo ei = getCurrentInputEditorInfo();
2550 if (ei != null &&
2551 (!fromEnterKey || (ei.imeOptions &
2552 EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
2553 (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
2554 EditorInfo.IME_ACTION_NONE) {
2555 // If the enter key was pressed, and the editor has a default
2556 // action associated with pressing enter, then send it that
2557 // explicit action instead of the key event.
2558 InputConnection ic = getCurrentInputConnection();
2559 if (ic != null) {
2560 ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
2561 }
2562 return true;
2563 }
2564
2565 return false;
2566 }
2567
2568 /**
2569 * Send the given UTF-16 character to the current input connection. Most
2570 * characters will be delivered simply by calling
2571 * {@link InputConnection#commitText InputConnection.commitText()} with
2572 * the character; some, however, may be handled different. In particular,
2573 * the enter character ('\n') will either be delivered as an action code
Jean Chalard405bc512012-05-29 19:12:34 +09002574 * or a raw key event, as appropriate. Consider this as a convenience
2575 * method for IMEs that do not have a full implementation of actions; a
2576 * fully complying IME will decide of the right action for each event and
2577 * will likely never call this method except maybe to handle events coming
2578 * from an actual hardware keyboard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 *
2580 * @param charCode The UTF-16 character code to send.
2581 */
2582 public void sendKeyChar(char charCode) {
2583 switch (charCode) {
2584 case '\n': // Apps may be listening to an enter key to perform an action
2585 if (!sendDefaultEditorAction(true)) {
2586 sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
2587 }
2588 break;
2589 default:
2590 // Make sure that digits go through any text watcher on the client side.
2591 if (charCode >= '0' && charCode <= '9') {
2592 sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
2593 } else {
2594 InputConnection ic = getCurrentInputConnection();
2595 if (ic != null) {
Yohei Yukawa24182f32015-09-11 18:33:33 -07002596 ic.commitText(String.valueOf(charCode), 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 }
2598 }
2599 break;
2600 }
2601 }
2602
2603 /**
2604 * This is called when the user has moved the cursor in the extracted
2605 * text view, when running in fullsreen mode. The default implementation
2606 * performs the corresponding selection change on the underlying text
2607 * editor.
2608 */
2609 public void onExtractedSelectionChanged(int start, int end) {
2610 InputConnection conn = getCurrentInputConnection();
2611 if (conn != null) {
2612 conn.setSelection(start, end);
2613 }
2614 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002615
2616 /**
2617 * @hide
2618 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002619 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002620 public void onExtractedDeleteText(int start, int end) {
2621 InputConnection conn = getCurrentInputConnection();
2622 if (conn != null) {
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002623 conn.finishComposingText();
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002624 conn.setSelection(start, start);
Keisuke Kuroyanagi755c0092016-03-14 19:09:20 +09002625 conn.deleteSurroundingText(0, end - start);
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002626 }
2627 }
2628
2629 /**
2630 * @hide
2631 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002632 @UnsupportedAppUsage
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002633 public void onExtractedReplaceText(int start, int end, CharSequence text) {
2634 InputConnection conn = getCurrentInputConnection();
2635 if (conn != null) {
2636 conn.setComposingRegion(start, end);
2637 conn.commitText(text, 1);
2638 }
2639 }
2640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 /**
Gilles Debunnee300be92011-12-06 10:15:56 -08002642 * @hide
2643 */
Mathew Inwood1dd7d112018-07-31 14:53:29 +01002644 @UnsupportedAppUsage
Gilles Debunnee300be92011-12-06 10:15:56 -08002645 public void onExtractedSetSpan(Object span, int start, int end, int flags) {
2646 InputConnection conn = getCurrentInputConnection();
2647 if (conn != null) {
2648 if (!conn.setSelection(start, end)) return;
2649 CharSequence text = conn.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
2650 if (text instanceof Spannable) {
2651 ((Spannable) text).setSpan(span, 0, text.length(), flags);
2652 conn.setComposingRegion(start, end);
2653 conn.commitText(text, 1);
2654 }
2655 }
2656 }
2657
2658 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 * This is called when the user has clicked on the extracted text view,
2660 * when running in fullscreen mode. The default implementation hides
2661 * the candidates view when this happens, but only if the extracted text
2662 * editor has a vertical scroll bar because its text doesn't fit.
2663 * Re-implement this to provide whatever behavior you want.
2664 */
2665 public void onExtractedTextClicked() {
2666 if (mExtractEditText == null) {
2667 return;
2668 }
2669 if (mExtractEditText.hasVerticalScrollBar()) {
2670 setCandidatesViewShown(false);
2671 }
2672 }
Gilles Debunne39ba6d92011-11-09 05:26:26 +01002673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 /**
2675 * This is called when the user has performed a cursor movement in the
2676 * extracted text view, when it is running in fullscreen mode. The default
2677 * implementation hides the candidates view when a vertical movement
2678 * happens, but only if the extracted text editor has a vertical scroll bar
2679 * because its text doesn't fit.
2680 * Re-implement this to provide whatever behavior you want.
2681 * @param dx The amount of cursor movement in the x dimension.
2682 * @param dy The amount of cursor movement in the y dimension.
2683 */
2684 public void onExtractedCursorMovement(int dx, int dy) {
2685 if (mExtractEditText == null || dy == 0) {
2686 return;
2687 }
2688 if (mExtractEditText.hasVerticalScrollBar()) {
2689 setCandidatesViewShown(false);
2690 }
2691 }
2692
2693 /**
2694 * This is called when the user has selected a context menu item from the
2695 * extracted text view, when running in fullscreen mode. The default
2696 * implementation sends this action to the current InputConnection's
2697 * {@link InputConnection#performContextMenuAction(int)}, for it
2698 * to be processed in underlying "real" editor. Re-implement this to
2699 * provide whatever behavior you want.
2700 */
2701 public boolean onExtractTextContextMenuItem(int id) {
2702 InputConnection ic = getCurrentInputConnection();
2703 if (ic != null) {
2704 ic.performContextMenuAction(id);
2705 }
2706 return true;
2707 }
Elliot Waite54de7742017-01-11 15:30:35 -08002708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 /**
2710 * Return text that can be used as a button label for the given
2711 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
2712 * if there is no action requested. Note that there is no guarantee that
2713 * the returned text will be relatively short, so you probably do not
2714 * want to use it as text on a soft keyboard key label.
Elliot Waite54de7742017-01-11 15:30:35 -08002715 *
2716 * @param imeOptions The value from {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2717 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 * @return Returns a label to use, or null if there is no action.
2719 */
2720 public CharSequence getTextForImeAction(int imeOptions) {
2721 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2722 case EditorInfo.IME_ACTION_NONE:
2723 return null;
2724 case EditorInfo.IME_ACTION_GO:
2725 return getText(com.android.internal.R.string.ime_action_go);
2726 case EditorInfo.IME_ACTION_SEARCH:
2727 return getText(com.android.internal.R.string.ime_action_search);
2728 case EditorInfo.IME_ACTION_SEND:
2729 return getText(com.android.internal.R.string.ime_action_send);
2730 case EditorInfo.IME_ACTION_NEXT:
2731 return getText(com.android.internal.R.string.ime_action_next);
The Android Open Source Project4df24232009-03-05 14:34:35 -08002732 case EditorInfo.IME_ACTION_DONE:
2733 return getText(com.android.internal.R.string.ime_action_done);
Dianne Hackborndea3ef72010-10-28 14:24:22 -07002734 case EditorInfo.IME_ACTION_PREVIOUS:
2735 return getText(com.android.internal.R.string.ime_action_previous);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002736 default:
2737 return getText(com.android.internal.R.string.ime_action_default);
2738 }
2739 }
Mark Renouf91eb2652016-04-11 16:03:26 -04002740
2741 /**
2742 * Return a drawable resource id that can be used as a button icon for the given
2743 * {@link EditorInfo#imeOptions EditorInfo.imeOptions}.
2744 *
2745 * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
2746 *
2747 * @return Returns a drawable resource id to use.
2748 */
2749 @DrawableRes
2750 private int getIconForImeAction(int imeOptions) {
2751 switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
2752 case EditorInfo.IME_ACTION_GO:
2753 return com.android.internal.R.drawable.ic_input_extract_action_go;
2754 case EditorInfo.IME_ACTION_SEARCH:
2755 return com.android.internal.R.drawable.ic_input_extract_action_search;
2756 case EditorInfo.IME_ACTION_SEND:
2757 return com.android.internal.R.drawable.ic_input_extract_action_send;
2758 case EditorInfo.IME_ACTION_NEXT:
2759 return com.android.internal.R.drawable.ic_input_extract_action_next;
2760 case EditorInfo.IME_ACTION_DONE:
2761 return com.android.internal.R.drawable.ic_input_extract_action_done;
2762 case EditorInfo.IME_ACTION_PREVIOUS:
2763 return com.android.internal.R.drawable.ic_input_extract_action_previous;
2764 default:
2765 return com.android.internal.R.drawable.ic_input_extract_action_return;
2766 }
2767 }
2768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002769 /**
The Android Open Source Project10592532009-03-18 17:39:46 -07002770 * Called when the fullscreen-mode extracting editor info has changed,
2771 * to determine whether the extracting (extract text and candidates) portion
2772 * of the UI should be shown. The standard implementation hides or shows
2773 * the extract area depending on whether it makes sense for the
2774 * current editor. In particular, a {@link InputType#TYPE_NULL}
2775 * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
2776 * turn off the extract area since there is no text to be shown.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777 */
The Android Open Source Project10592532009-03-18 17:39:46 -07002778 public void onUpdateExtractingVisibility(EditorInfo ei) {
2779 if (ei.inputType == InputType.TYPE_NULL ||
2780 (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
2781 // No reason to show extract UI!
2782 setExtractViewShown(false);
2783 return;
2784 }
2785
2786 setExtractViewShown(true);
2787 }
2788
2789 /**
2790 * Called when the fullscreen-mode extracting editor info has changed,
2791 * to update the state of its UI such as the action buttons shown.
2792 * You do not need to deal with this if you are using the standard
2793 * full screen extract UI. If replacing it, you will need to re-implement
2794 * this to put the appropriate action button in your own UI and handle it,
2795 * and perform any other changes.
2796 *
2797 * <p>The standard implementation turns on or off its accessory area
2798 * depending on whether there is an action button, and hides or shows
2799 * the entire extract area depending on whether it makes sense for the
2800 * current editor. In particular, a {@link InputType#TYPE_NULL} or
2801 * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
2802 * extract area since there is no text to be shown.
2803 */
2804 public void onUpdateExtractingViews(EditorInfo ei) {
2805 if (!isExtractViewShown()) {
2806 return;
2807 }
2808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002809 if (mExtractAccessories == null) {
2810 return;
2811 }
2812 final boolean hasAction = ei.actionLabel != null || (
2813 (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
The Android Open Source Project10592532009-03-18 17:39:46 -07002814 (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
2815 ei.inputType != InputType.TYPE_NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816 if (hasAction) {
2817 mExtractAccessories.setVisibility(View.VISIBLE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002818 if (mExtractAction != null) {
Mark Renouf91eb2652016-04-11 16:03:26 -04002819 if (mExtractAction instanceof ImageButton) {
2820 ((ImageButton) mExtractAction)
2821 .setImageResource(getIconForImeAction(ei.imeOptions));
2822 if (ei.actionLabel != null) {
2823 mExtractAction.setContentDescription(ei.actionLabel);
2824 } else {
2825 mExtractAction.setContentDescription(getTextForImeAction(ei.imeOptions));
2826 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002827 } else {
Mark Renouf91eb2652016-04-11 16:03:26 -04002828 if (ei.actionLabel != null) {
2829 ((TextView) mExtractAction).setText(ei.actionLabel);
2830 } else {
2831 ((TextView) mExtractAction).setText(getTextForImeAction(ei.imeOptions));
2832 }
Steve Kondik59eb6912009-09-07 22:53:34 -04002833 }
2834 mExtractAction.setOnClickListener(mActionClickListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 } else {
2837 mExtractAccessories.setVisibility(View.GONE);
Steve Kondik59eb6912009-09-07 22:53:34 -04002838 if (mExtractAction != null) {
2839 mExtractAction.setOnClickListener(null);
2840 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002841 }
2842 }
2843
2844 /**
2845 * This is called when, while currently displayed in extract mode, the
2846 * current input target changes. The default implementation will
2847 * auto-hide the IME if the new target is not a full editor, since this
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002848 * can be a confusing experience for the user.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 */
2850 public void onExtractingInputChanged(EditorInfo ei) {
2851 if (ei.inputType == InputType.TYPE_NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002852 requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853 }
2854 }
2855
2856 void startExtractingText(boolean inputChanged) {
2857 final ExtractEditText eet = mExtractEditText;
2858 if (eet != null && getCurrentInputStarted()
2859 && isFullscreenMode()) {
2860 mExtractedToken++;
2861 ExtractedTextRequest req = new ExtractedTextRequest();
2862 req.token = mExtractedToken;
2863 req.flags = InputConnection.GET_TEXT_WITH_STYLES;
2864 req.hintMaxLines = 10;
2865 req.hintMaxChars = 10000;
Amith Yamasaniba4d93f2009-08-19 18:27:56 -07002866 InputConnection ic = getCurrentInputConnection();
2867 mExtractedText = ic == null? null
2868 : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
Amith Yamasania8b00c82010-03-05 15:41:31 -08002869 if (mExtractedText == null || ic == null) {
2870 Log.e(TAG, "Unexpected null in startExtractingText : mExtractedText = "
2871 + mExtractedText + ", input connection = " + ic);
2872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 final EditorInfo ei = getCurrentInputEditorInfo();
2874
2875 try {
2876 eet.startInternalChanges();
The Android Open Source Project10592532009-03-18 17:39:46 -07002877 onUpdateExtractingVisibility(ei);
2878 onUpdateExtractingViews(ei);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 int inputType = ei.inputType;
2880 if ((inputType&EditorInfo.TYPE_MASK_CLASS)
2881 == EditorInfo.TYPE_CLASS_TEXT) {
2882 if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
2883 inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
2884 }
2885 }
2886 eet.setInputType(inputType);
2887 eet.setHint(ei.hintText);
2888 if (mExtractedText != null) {
2889 eet.setEnabled(true);
2890 eet.setExtractedText(mExtractedText);
2891 } else {
2892 eet.setEnabled(false);
2893 eet.setText("");
2894 }
2895 } finally {
2896 eet.finishInternalChanges();
2897 }
2898
2899 if (inputChanged) {
2900 onExtractingInputChanged(ei);
2901 }
2902 }
2903 }
satokab751aa2010-09-14 19:17:36 +09002904
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002905 private void dispatchOnCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2906 synchronized (mLock) {
2907 mNotifyUserActionSent = false;
2908 }
2909 onCurrentInputMethodSubtypeChanged(newSubtype);
2910 }
2911
satokab751aa2010-09-14 19:17:36 +09002912 // TODO: Handle the subtype change event
2913 /**
2914 * Called when the subtype was changed.
2915 * @param newSubtype the subtype which is being changed to.
2916 */
2917 protected void onCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
2918 if (DEBUG) {
2919 int nameResId = newSubtype.getNameResId();
satok9ef02832010-11-04 21:17:48 +09002920 String mode = newSubtype.getMode();
satokab751aa2010-09-14 19:17:36 +09002921 String output = "changeInputMethodSubtype:"
2922 + (nameResId == 0 ? "<none>" : getString(nameResId)) + ","
satok9ef02832010-11-04 21:17:48 +09002923 + mode + ","
satokab751aa2010-09-14 19:17:36 +09002924 + newSubtype.getLocale() + "," + newSubtype.getExtraValue();
2925 Log.v(TAG, "--- " + output);
2926 }
2927 }
2928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002929 /**
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002930 * Aimed to return the previous input method's {@link Insets#contentTopInsets}, but its actual
2931 * semantics has never been well defined.
2932 *
2933 * <p>Note that the previous document clearly mentioned that this method could return {@code 0}
2934 * at any time for whatever reason. Now this method is just always returning {@code 0}.</p>
2935 *
2936 * @return on Android {@link android.os.Build.VERSION_CODES#Q} and later devices this method
2937 * always returns {@code 0}
2938 * @deprecated the actual behavior of this method has never been well defined. You cannot use
2939 * this method in a reliable and predictable way
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002940 */
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002941 @Deprecated
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002942 public int getInputMethodWindowRecommendedHeight() {
Yohei Yukawa9d73f2e2018-09-26 18:19:21 -07002943 Log.w(TAG, "getInputMethodWindowRecommendedHeight() is deprecated and now always returns 0."
2944 + " Do not use this method.");
2945 return 0;
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002946 }
2947
2948 /**
Yohei Yukawa25e08132016-06-22 16:31:41 -07002949 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
2950 * permission to the content.
2951 *
Yohei Yukawa25e08132016-06-22 16:31:41 -07002952 * @param inputContentInfo Content to be temporarily exposed from the input method to the
2953 * application.
2954 * This cannot be {@code null}.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002955 * @param inputConnection {@link InputConnection} with which
Yohei Yukawab2a0e052018-01-14 16:06:16 -08002956 * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002957 * @hide
Yohei Yukawa25e08132016-06-22 16:31:41 -07002958 */
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002959 @Override
2960 public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
2961 @NonNull InputConnection inputConnection) {
2962 if (inputConnection == null) {
2963 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002964 }
Yohei Yukawa45700fa2016-06-23 17:12:59 -07002965 if (getCurrentInputConnection() != inputConnection) {
2966 return;
Yohei Yukawa25e08132016-06-22 16:31:41 -07002967 }
Yohei Yukawac54c1172018-09-06 11:39:50 -07002968 exposeContentInternal(inputContentInfo, getCurrentInputEditorInfo());
2969 }
2970
2971 /**
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002972 * {@inheritDoc}
2973 * @hide
2974 */
2975 @AnyThread
2976 @Override
2977 public final void notifyUserActionIfNecessary() {
2978 synchronized (mLock) {
2979 if (mNotifyUserActionSent) {
2980 return;
2981 }
Yohei Yukawa9b60ba02019-01-21 00:06:27 -08002982 mPrivOps.notifyUserAction();
Yohei Yukawac07fd4c2018-09-11 11:37:13 -07002983 mNotifyUserActionSent = true;
2984 }
2985 }
2986
2987 /**
Yohei Yukawac54c1172018-09-06 11:39:50 -07002988 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
2989 * permission to the content.
2990 *
2991 * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo,
2992 * InputConnection)} for details.</p>
2993 *
2994 * @param inputContentInfo Content to be temporarily exposed from the input method to the
2995 * application.
2996 * This cannot be {@code null}.
2997 * @param editorInfo The editor that receives {@link InputContentInfo}.
2998 */
2999 private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
3000 @NonNull EditorInfo editorInfo) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07003001 final Uri contentUri = inputContentInfo.getContentUri();
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07003002 final IInputContentUriToken uriToken =
3003 mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
3004 if (uriToken == null) {
Yohei Yukawac54c1172018-09-06 11:39:50 -07003005 Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
Yohei Yukawa2bc3d6f2018-09-09 20:48:34 -07003006 + " packageName=" + editorInfo.packageName);
Yohei Yukawac54c1172018-09-06 11:39:50 -07003007 return;
3008 }
3009 inputContentInfo.setUriToken(uriToken);
Yohei Yukawa25e08132016-06-22 16:31:41 -07003010 }
3011
Tarandeep Singheadb1392018-11-09 18:15:57 +01003012 private int mapToImeWindowStatus() {
3013 return IME_ACTIVE
3014 | (isInputViewShown()
3015 ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE)
3016 : IME_VISIBLE) : 0);
Tarandeep Singh3fecef12018-01-22 14:33:33 -08003017 }
3018
Yohei Yukawa25e08132016-06-22 16:31:41 -07003019 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 * Performs a dump of the InputMethodService's internal state. Override
3021 * to add your own information to the dump.
3022 */
3023 @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
3024 final Printer p = new PrintWriterPrinter(fout);
3025 p.println("Input method service state for " + this + ":");
Tarandeep Singheadb1392018-11-09 18:15:57 +01003026 p.println(" mViewsCreated=" + mViewsCreated);
3027 p.println(" mDecorViewVisible=" + mDecorViewVisible
3028 + " mDecorViewWasVisible=" + mDecorViewWasVisible
3029 + " mWindowVisible=" + mWindowVisible
The Android Open Source Project10592532009-03-18 17:39:46 -07003030 + " mInShowWindow=" + mInShowWindow);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003031 p.println(" Configuration=" + getResources().getConfiguration());
3032 p.println(" mToken=" + mToken);
3033 p.println(" mInputBinding=" + mInputBinding);
3034 p.println(" mInputConnection=" + mInputConnection);
3035 p.println(" mStartedInputConnection=" + mStartedInputConnection);
3036 p.println(" mInputStarted=" + mInputStarted
3037 + " mInputViewStarted=" + mInputViewStarted
3038 + " mCandidatesViewStarted=" + mCandidatesViewStarted);
Yohei Yukawa6db3bfe2017-02-13 12:04:41 -08003039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003040 if (mInputEditorInfo != null) {
3041 p.println(" mInputEditorInfo:");
3042 mInputEditorInfo.dump(p, " ");
3043 } else {
3044 p.println(" mInputEditorInfo: null");
3045 }
3046
3047 p.println(" mShowInputRequested=" + mShowInputRequested
3048 + " mLastShowInputRequested=" + mLastShowInputRequested
Tarandeep Singheadb1392018-11-09 18:15:57 +01003049 + " mCanPreRender=" + mCanPreRender
3050 + " mIsPreRendered=" + mIsPreRendered
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
3052 p.println(" mCandidatesVisibility=" + mCandidatesVisibility
3053 + " mFullscreenApplied=" + mFullscreenApplied
The Android Open Source Project10592532009-03-18 17:39:46 -07003054 + " mIsFullscreen=" + mIsFullscreen
3055 + " mExtractViewHidden=" + mExtractViewHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003056
3057 if (mExtractedText != null) {
3058 p.println(" mExtractedText:");
3059 p.println(" text=" + mExtractedText.text.length() + " chars"
3060 + " startOffset=" + mExtractedText.startOffset);
3061 p.println(" selectionStart=" + mExtractedText.selectionStart
3062 + " selectionEnd=" + mExtractedText.selectionEnd
3063 + " flags=0x" + Integer.toHexString(mExtractedText.flags));
3064 } else {
3065 p.println(" mExtractedText: null");
3066 }
3067 p.println(" mExtractedToken=" + mExtractedToken);
3068 p.println(" mIsInputViewShown=" + mIsInputViewShown
3069 + " mStatusIcon=" + mStatusIcon);
3070 p.println("Last computed insets:");
3071 p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
3072 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
Jeff Brownfbf09772011-01-16 14:06:57 -08003073 + " touchableInsets=" + mTmpInsets.touchableInsets
3074 + " touchableRegion=" + mTmpInsets.touchableRegion);
Yohei Yukawa7b739a82015-12-21 13:30:44 -08003075 p.println(" mSettingsObserver=" + mSettingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 }
3077}