blob: f5908a50ec64b5009f92949ed7a58826a45687bb [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.view.inputmethod;
18
Svetoslav Ganov758143e2012-08-06 16:40:27 -070019import com.android.internal.os.SomeArgs;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080020import com.android.internal.view.IInputConnectionWrapper;
21import com.android.internal.view.IInputContext;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080022import com.android.internal.view.IInputMethodClient;
23import com.android.internal.view.IInputMethodManager;
24import com.android.internal.view.IInputMethodSession;
25import com.android.internal.view.InputBindResult;
Yohei Yukawa33e81792015-11-17 21:14:42 -080026import com.android.internal.view.InputMethodClient;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080027
Yohei Yukawa2afe2aa2016-01-07 18:09:44 -080028import android.annotation.NonNull;
29import android.annotation.Nullable;
Yoshiki Iguchi00d51222015-05-29 15:36:22 +090030import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.Context;
32import android.graphics.Rect;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Looper;
37import android.os.Message;
38import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080039import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.ServiceManager;
Jeff Brownf9e989d2013-04-04 23:04:03 -070041import android.os.Trace;
satokf9f01002011-05-19 21:31:50 +090042import android.text.style.SuggestionSpan;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.util.Log;
Jeff Brownf9e989d2013-04-04 23:04:03 -070044import android.util.Pools.Pool;
45import android.util.Pools.SimplePool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.util.PrintWriterPrinter;
47import android.util.Printer;
Yohei Yukawab7b79072014-03-25 11:02:00 +090048import android.util.SparseArray;
Jeff Brownc28867a2013-03-26 15:42:39 -070049import android.view.InputChannel;
50import android.view.InputEvent;
51import android.view.InputEventSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.view.View;
Dianne Hackborn6dd005b2011-07-18 13:22:50 -070054import android.view.ViewRootImpl;
Gilles Debunned4723bb2010-09-02 15:27:32 -070055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import java.io.FileDescriptor;
57import java.io.PrintWriter;
satok4e4569d2010-11-19 18:45:53 +090058import java.util.ArrayList;
Andreas Gampee6748ce2015-12-11 18:00:38 -080059import java.util.Arrays;
satokf3db1af2010-11-23 13:34:33 +090060import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import java.util.List;
satokf3db1af2010-11-23 13:34:33 +090062import java.util.Map;
Yohei Yukawac941fed2014-05-14 19:33:35 +090063import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.util.concurrent.CountDownLatch;
65import java.util.concurrent.TimeUnit;
66
Yoshiki Iguchi00d51222015-05-29 15:36:22 +090067import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
68
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069/**
70 * Central system API to the overall input method framework (IMF) architecture,
71 * which arbitrates interaction between applications and the current input method.
72 * You can retrieve an instance of this interface with
73 * {@link Context#getSystemService(String) Context.getSystemService()}.
74 *
75 * <p>Topics covered here:
76 * <ol>
77 * <li><a href="#ArchitectureOverview">Architecture Overview</a>
Ken Wakasa384f8ba2012-03-10 09:59:31 +090078 * <li><a href="#Applications">Applications</a>
79 * <li><a href="#InputMethods">Input Methods</a>
80 * <li><a href="#Security">Security</a>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 * </ol>
82 *
83 * <a name="ArchitectureOverview"></a>
84 * <h3>Architecture Overview</h3>
85 *
86 * <p>There are three primary parties involved in the input method
87 * framework (IMF) architecture:</p>
88 *
89 * <ul>
90 * <li> The <strong>input method manager</strong> as expressed by this class
91 * is the central point of the system that manages interaction between all
92 * other parts. It is expressed as the client-side API here which exists
93 * in each application context and communicates with a global system service
94 * that manages the interaction across all processes.
95 * <li> An <strong>input method (IME)</strong> implements a particular
96 * interaction model allowing the user to generate text. The system binds
97 * to the current input method that is use, causing it to be created and run,
98 * and tells it when to hide and show its UI. Only one IME is running at a time.
99 * <li> Multiple <strong>client applications</strong> arbitrate with the input
100 * method manager for input focus and control over the state of the IME. Only
101 * one such client is ever active (working with the IME) at a time.
102 * </ul>
103 *
104 *
105 * <a name="Applications"></a>
106 * <h3>Applications</h3>
107 *
108 * <p>In most cases, applications that are using the standard
109 * {@link android.widget.TextView} or its subclasses will have little they need
110 * to do to work well with soft input methods. The main things you need to
111 * be aware of are:</p>
112 *
113 * <ul>
Gilles Debunne8cbb4c62011-01-24 12:33:56 -0800114 * <li> Properly set the {@link android.R.attr#inputType} in your editable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 * text views, so that the input method will have enough context to help the
116 * user in entering text into them.
117 * <li> Deal well with losing screen space when the input method is
118 * displayed. Ideally an application should handle its window being resized
119 * smaller, but it can rely on the system performing panning of the window
120 * if needed. You should set the {@link android.R.attr#windowSoftInputMode}
121 * attribute on your activity or the corresponding values on windows you
122 * create to help the system determine whether to pan or resize (it will
123 * try to determine this automatically but may get it wrong).
124 * <li> You can also control the preferred soft input state (open, closed, etc)
125 * for your window using the same {@link android.R.attr#windowSoftInputMode}
126 * attribute.
127 * </ul>
128 *
129 * <p>More finer-grained control is available through the APIs here to directly
130 * interact with the IMF and its IME -- either showing or hiding the input
131 * area, letting the user pick an input method, etc.</p>
132 *
133 * <p>For the rare people amongst us writing their own text editors, you
134 * will need to implement {@link android.view.View#onCreateInputConnection}
135 * to return a new instance of your own {@link InputConnection} interface
136 * allowing the IME to interact with your editor.</p>
137 *
138 *
139 * <a name="InputMethods"></a>
140 * <h3>Input Methods</h3>
141 *
142 * <p>An input method (IME) is implemented
143 * as a {@link android.app.Service}, typically deriving from
144 * {@link android.inputmethodservice.InputMethodService}. It must provide
145 * the core {@link InputMethod} interface, though this is normally handled by
146 * {@link android.inputmethodservice.InputMethodService} and implementors will
147 * only need to deal with the higher-level API there.</p>
148 *
149 * See the {@link android.inputmethodservice.InputMethodService} class for
150 * more information on implementing IMEs.
151 *
152 *
153 * <a name="Security"></a>
154 * <h3>Security</h3>
155 *
156 * <p>There are a lot of security issues associated with input methods,
157 * since they essentially have freedom to completely drive the UI and monitor
158 * everything the user enters. The Android input method framework also allows
159 * arbitrary third party IMEs, so care must be taken to restrict their
160 * selection and interactions.</p>
161 *
162 * <p>Here are some key points about the security architecture behind the
163 * IMF:</p>
164 *
165 * <ul>
166 * <li> <p>Only the system is allowed to directly access an IME's
167 * {@link InputMethod} interface, via the
168 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission. This is
169 * enforced in the system by not binding to an input method service that does
170 * not require this permission, so the system can guarantee no other untrusted
171 * clients are accessing the current input method outside of its control.</p>
172 *
173 * <li> <p>There may be many client processes of the IMF, but only one may
174 * be active at a time. The inactive clients can not interact with key
175 * parts of the IMF through the mechanisms described below.</p>
176 *
177 * <li> <p>Clients of an input method are only given access to its
178 * {@link InputMethodSession} interface. One instance of this interface is
179 * created for each client, and only calls from the session associated with
180 * the active client will be processed by the current IME. This is enforced
181 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal
182 * IMEs, but must be explicitly handled by an IME that is customizing the
183 * raw {@link InputMethodSession} implementation.</p>
184 *
185 * <li> <p>Only the active client's {@link InputConnection} will accept
186 * operations. The IMF tells each client process whether it is active, and
187 * the framework enforces that in inactive processes calls on to the current
188 * InputConnection will be ignored. This ensures that the current IME can
189 * only deliver events and text edits to the UI that the user sees as
190 * being in focus.</p>
191 *
192 * <li> <p>An IME can never interact with an {@link InputConnection} while
193 * the screen is off. This is enforced by making all clients inactive while
194 * the screen is off, and prevents bad IMEs from driving the UI when the user
195 * can not be aware of its behavior.</p>
196 *
197 * <li> <p>A client application can ask that the system let the user pick a
198 * new IME, but can not programmatically switch to one itself. This avoids
199 * malicious applications from switching the user to their own IME, which
200 * remains running when the user navigates away to another application. An
201 * IME, on the other hand, <em>is</em> allowed to programmatically switch
202 * the system to another IME, since it already has full control of user
203 * input.</p>
204 *
205 * <li> <p>The user must explicitly enable a new IME in settings before
206 * they can switch to it, to confirm with the system that they know about it
207 * and want to make it available for use.</p>
208 * </ul>
209 */
210public final class InputMethodManager {
Dianne Hackborn4eba2712009-03-24 19:20:06 -0700211 static final boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 static final String TAG = "InputMethodManager";
213
Jeff Brownf9e989d2013-04-04 23:04:03 -0700214 static final String PENDING_EVENT_COUNTER = "aq:imm";
215
216 static InputMethodManager sInstance;
Dianne Hackborn7663d802012-02-24 13:08:49 -0800217
218 /**
219 * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
220 * the window has input focus.
221 */
222 public static final int CONTROL_WINDOW_VIEW_HAS_FOCUS = 1<<0;
223
224 /**
225 * @hide Flag for IInputMethodManager.windowGainedFocus: the focus
226 * is a text editor.
227 */
228 public static final int CONTROL_WINDOW_IS_TEXT_EDITOR = 1<<1;
229
230 /**
231 * @hide Flag for IInputMethodManager.windowGainedFocus: this is the first
232 * time the window has gotten focus.
233 */
234 public static final int CONTROL_WINDOW_FIRST = 1<<2;
235
236 /**
237 * @hide Flag for IInputMethodManager.startInput: this is the first
238 * time the window has gotten focus.
239 */
240 public static final int CONTROL_START_INITIAL = 1<<8;
241
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700242 /**
243 * Timeout in milliseconds for delivering a key to an IME.
244 */
245 static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500;
246
Jeff Brownf9e989d2013-04-04 23:04:03 -0700247 /** @hide */
248 public static final int DISPATCH_IN_PROGRESS = -1;
249
250 /** @hide */
251 public static final int DISPATCH_NOT_HANDLED = 0;
252
253 /** @hide */
254 public static final int DISPATCH_HANDLED = 1;
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700255
Seigo Nonaka14e13912015-05-06 21:04:13 -0700256 /** @hide */
257 public static final int SHOW_IM_PICKER_MODE_AUTO = 0;
258 /** @hide */
259 public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1;
260 /** @hide */
261 public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 final IInputMethodManager mService;
264 final Looper mMainLooper;
265
266 // For scheduling work on the main thread. This also serves as our
267 // global lock.
268 final H mH;
269
270 // Our generic input connection if the current target does not have its own.
271 final IInputContext mIInputContext;
272
273 /**
274 * True if this input method client is active, initially false.
275 */
276 boolean mActive = false;
277
278 /**
279 * Set whenever this client becomes inactive, to know we need to reset
Dianne Hackborn7663d802012-02-24 13:08:49 -0800280 * state with the IME the next time we receive focus.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 */
282 boolean mHasBeenInactive = true;
283
284 /**
285 * As reported by IME through InputConnection.
286 */
287 boolean mFullscreenMode;
288
289 // -----------------------------------------------------------
Wale Ogunwale159c3d82015-05-14 12:20:53 -0700290
291 /**
292 * This is the root view of the overall window that currently has input
293 * method focus.
294 */
295 View mCurRootView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 /**
297 * This is the view that should currently be served by an input method,
298 * regardless of the state of setting that up.
299 */
300 View mServedView;
301 /**
302 * This is then next view that will be served by the input method, when
303 * we get around to updating things.
304 */
305 View mNextServedView;
306 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 * This is set when we are in the process of connecting, to determine
308 * when we have actually finished.
309 */
310 boolean mServedConnecting;
311 /**
312 * This is non-null when we have connected the served view; it holds
313 * the attributes that were last retrieved from the served view and given
314 * to the input connection.
315 */
316 EditorInfo mCurrentTextBoxAttribute;
317 /**
318 * The InputConnection that was last retrieved from the served view.
319 */
Dianne Hackbornac920872012-05-22 11:49:49 -0700320 ControlledInputConnectionWrapper mServedInputConnectionWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 /**
322 * The completions that were last provided by the served view.
323 */
324 CompletionInfo[] mCompletions;
325
326 // Cursor position on the screen.
Yohei Yukawaa277db22014-08-21 18:38:44 -0700327 Rect mTmpCursorRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 Rect mCursorRect = new Rect();
329 int mCursorSelStart;
330 int mCursorSelEnd;
331 int mCursorCandStart;
332 int mCursorCandEnd;
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900333
334 /**
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900335 * Represents an invalid action notification sequence number. {@link InputMethodManagerService}
336 * always issues a positive integer for action notification sequence numbers. Thus -1 is
337 * guaranteed to be different from any valid sequence number.
338 */
339 private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
340 /**
341 * The next sequence number that is to be sent to {@link InputMethodManagerService} via
342 * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
343 */
344 private int mNextUserActionNotificationSequenceNumber =
345 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
346
347 /**
348 * The last sequence number that is already sent to {@link InputMethodManagerService}.
349 */
350 private int mLastSentUserActionNotificationSequenceNumber =
351 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
352
353 /**
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900354 * The instance that has previously been sent to the input method.
355 */
356 private CursorAnchorInfo mCursorAnchorInfo = null;
357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 // -----------------------------------------------------------
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 /**
361 * Sequence number of this binding, as returned by the server.
362 */
363 int mBindSequence = -1;
364 /**
365 * ID of the method we are bound to.
366 */
367 String mCurId;
368 /**
369 * The actual instance of the method to make calls on it.
370 */
371 IInputMethodSession mCurMethod;
Jeff Brownc28867a2013-03-26 15:42:39 -0700372 InputChannel mCurChannel;
373 ImeInputEventSender mCurSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
Yohei Yukawaa277db22014-08-21 18:38:44 -0700375 private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900376
377 /**
378 * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
379 */
Yohei Yukawaa277db22014-08-21 18:38:44 -0700380 private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawab7b79072014-03-25 11:02:00 +0900381
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700382 final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
383 final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 // -----------------------------------------------------------
386
387 static final int MSG_DUMP = 1;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800388 static final int MSG_BIND = 2;
389 static final int MSG_UNBIND = 3;
390 static final int MSG_SET_ACTIVE = 4;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700391 static final int MSG_SEND_INPUT_EVENT = 5;
392 static final int MSG_TIMEOUT_INPUT_EVENT = 6;
393 static final int MSG_FLUSH_INPUT_EVENT = 7;
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900394 static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 class H extends Handler {
397 H(Looper looper) {
Jeff Brown29c0ed22013-01-14 13:50:37 -0800398 super(looper, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400
401 @Override
402 public void handleMessage(Message msg) {
403 switch (msg.what) {
404 case MSG_DUMP: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700405 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 try {
407 doDump((FileDescriptor)args.arg1,
408 (PrintWriter)args.arg2, (String[])args.arg3);
409 } catch (RuntimeException e) {
410 ((PrintWriter)args.arg2).println("Exception: " + e);
411 }
412 synchronized (args.arg4) {
413 ((CountDownLatch)args.arg4).countDown();
414 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700415 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 return;
417 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800418 case MSG_BIND: {
419 final InputBindResult res = (InputBindResult)msg.obj;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900420 if (DEBUG) {
421 Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
422 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800423 synchronized (mH) {
424 if (mBindSequence < 0 || mBindSequence != res.sequence) {
425 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
426 + ", given seq=" + res.sequence);
Jeff Brown4d656882013-04-03 14:39:19 -0700427 if (res.channel != null && res.channel != mCurChannel) {
Jeff Brownc28867a2013-03-26 15:42:39 -0700428 res.channel.dispose();
429 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800430 return;
431 }
Jeff Brown4d656882013-04-03 14:39:19 -0700432
Yohei Yukawaa277db22014-08-21 18:38:44 -0700433 mRequestUpdateCursorAnchorInfoMonitorMode =
434 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900435
Jeff Brown4d656882013-04-03 14:39:19 -0700436 setInputChannelLocked(res.channel);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800437 mCurMethod = res.method;
438 mCurId = res.id;
439 mBindSequence = res.sequence;
440 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800441 startInputInner(InputMethodClient.START_INPUT_REASON_BOUND_TO_IMMS,
442 null, 0, 0, 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800443 return;
444 }
445 case MSG_UNBIND: {
446 final int sequence = msg.arg1;
Yohei Yukawa33e81792015-11-17 21:14:42 -0800447 @InputMethodClient.UnbindReason
448 final int reason = msg.arg2;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900449 if (DEBUG) {
Yohei Yukawa33e81792015-11-17 21:14:42 -0800450 Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence +
451 " reason=" + InputMethodClient.getUnbindReason(reason));
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900452 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800453 final boolean startInput;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800454 synchronized (mH) {
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800455 if (mBindSequence != sequence) {
456 return;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800457 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800458 clearBindingLocked();
459 // If we were actively using the last input method, then
460 // we would like to re-connect to the next input method.
461 if (mServedView != null && mServedView.isFocused()) {
462 mServedConnecting = true;
463 }
464 startInput = mActive;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800465 }
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800466 if (startInput) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800467 startInputInner(
468 InputMethodClient.START_INPUT_REASON_UNBOUND_FROM_IMMS, null, 0, 0,
469 0);
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800470 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800471 return;
472 }
473 case MSG_SET_ACTIVE: {
474 final boolean active = msg.arg1 != 0;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900475 if (DEBUG) {
476 Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
477 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800478 synchronized (mH) {
479 mActive = active;
480 mFullscreenMode = false;
481 if (!active) {
482 // Some other client has starting using the IME, so note
483 // that this happened and make sure our own editor's
484 // state is reset.
485 mHasBeenInactive = true;
486 try {
487 // Note that finishComposingText() is allowed to run
488 // even when we are not active.
489 mIInputContext.finishComposingText();
490 } catch (RemoteException e) {
491 }
Mikael Gullstrand82ae3ff2014-11-25 12:41:53 +0100492 }
493 // Check focus again in case that "onWindowFocus" is called before
494 // handling this message.
495 if (mServedView != null && mServedView.hasWindowFocus()) {
Yohei Yukawa241eac22016-03-28 00:28:50 -0700496 if (checkFocusNoStartInput(mHasBeenInactive)) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800497 final int reason = active ?
498 InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
499 InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS;
500 startInputInner(reason, null, 0, 0, 0);
satok05a6cbe2012-04-05 23:04:08 +0900501 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800502 }
503 }
504 return;
505 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700506 case MSG_SEND_INPUT_EVENT: {
507 sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
508 return;
509 }
510 case MSG_TIMEOUT_INPUT_EVENT: {
511 finishedInputEvent(msg.arg1, false, true);
512 return;
513 }
514 case MSG_FLUSH_INPUT_EVENT: {
515 finishedInputEvent(msg.arg1, false, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700516 return;
517 }
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900518 case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
519 synchronized (mH) {
520 mNextUserActionNotificationSequenceNumber = msg.arg1;
521 }
522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524 }
525 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800526
Jean Chalardde9dbb02011-10-20 19:50:45 +0900527 private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
528 private final InputMethodManager mParentInputMethodManager;
529
530 public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
531 final InputMethodManager inputMethodManager) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 super(mainLooper, conn);
Jean Chalardde9dbb02011-10-20 19:50:45 +0900533 mParentInputMethodManager = inputMethodManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 }
535
Gilles Debunne8cbb4c62011-01-24 12:33:56 -0800536 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 public boolean isActive() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700538 return mParentInputMethodManager.mActive && !isFinished();
Dianne Hackbornac920872012-05-22 11:49:49 -0700539 }
540
541 void deactivate() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700542 if (isFinished()) {
543 // This is a small performance optimization. Still only the 1st call of
544 // reportFinish() will take effect.
545 return;
546 }
547 reportFinish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800549
550 @Override
Yohei Yukawa159dd472016-01-07 16:52:33 -0800551 protected void onUserAction() {
552 mParentInputMethodManager.notifyUserAction();
553 }
554
555 @Override
556 protected void onReportFullscreenMode(boolean enabled) {
557 mParentInputMethodManager.setFullscreenMode(enabled);
558 }
559
560 @Override
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800561 public String toString() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700562 return "ControlledInputConnectionWrapper{"
563 + "connection=" + getInputConnection()
564 + " finished=" + isFinished()
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800565 + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
566 + "}";
567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
Jeff Brownc28867a2013-03-26 15:42:39 -0700571 @Override
572 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 // No need to check for dump permission, since we only give this
574 // interface to the system.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 CountDownLatch latch = new CountDownLatch(1);
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700576 SomeArgs sargs = SomeArgs.obtain();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 sargs.arg1 = fd;
578 sargs.arg2 = fout;
579 sargs.arg3 = args;
580 sargs.arg4 = latch;
581 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
582 try {
583 if (!latch.await(5, TimeUnit.SECONDS)) {
584 fout.println("Timeout waiting for dump");
585 }
586 } catch (InterruptedException e) {
587 fout.println("Interrupted waiting for dump");
588 }
589 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700590
591 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 public void setUsingInputMethod(boolean state) {
593 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700594
595 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 public void onBindMethod(InputBindResult res) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800597 mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700599
600 @Override
Yohei Yukawa33e81792015-11-17 21:14:42 -0800601 public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) {
602 mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, unbindReason));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700604
605 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 public void setActive(boolean active) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800607 mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Yohei Yukawab7b79072014-03-25 11:02:00 +0900609
610 @Override
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900611 public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
612 mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
613 sequenceNumber, 0));
614 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700615 };
616
Dianne Hackborn51bf0772009-03-24 19:11:41 -0700617 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 InputMethodManager(IInputMethodManager service, Looper looper) {
620 mService = service;
621 mMainLooper = looper;
622 mH = new H(looper);
623 mIInputContext = new ControlledInputConnectionWrapper(looper,
Jean Chalardde9dbb02011-10-20 19:50:45 +0900624 mDummyInputConnection, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 }
626
627 /**
628 * Retrieve the global InputMethodManager instance, creating it if it
629 * doesn't already exist.
630 * @hide
631 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700632 public static InputMethodManager getInstance() {
633 synchronized (InputMethodManager.class) {
634 if (sInstance == null) {
635 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
636 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
637 sInstance = new InputMethodManager(service, Looper.getMainLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700639 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
642
643 /**
644 * Private optimization: retrieve the global InputMethodManager instance,
645 * if it exists.
646 * @hide
647 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700648 public static InputMethodManager peekInstance() {
649 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
651
652 /** @hide */
653 public IInputMethodClient getClient() {
654 return mClient;
655 }
656
657 /** @hide */
658 public IInputContext getInputContext() {
659 return mIInputContext;
660 }
661
662 public List<InputMethodInfo> getInputMethodList() {
663 try {
664 return mService.getInputMethodList();
665 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700666 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
668 }
669
670 public List<InputMethodInfo> getEnabledInputMethodList() {
671 try {
672 return mService.getEnabledInputMethodList();
673 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700674 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 }
676 }
677
satokd4fce2b2011-04-11 12:07:13 +0900678 /**
679 * Returns a list of enabled input method subtypes for the specified input method info.
680 * @param imi An input method info whose subtypes list will be returned.
681 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
682 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
683 * will implicitly enable subtypes according to the current system language.
684 */
satok16331c82010-12-20 23:48:46 +0900685 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
686 boolean allowsImplicitlySelectedSubtypes) {
satok67ddf9c2010-11-17 09:45:54 +0900687 try {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +0900688 return mService.getEnabledInputMethodSubtypeList(
689 imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +0900690 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700691 throw e.rethrowFromSystemServer();
satok67ddf9c2010-11-17 09:45:54 +0900692 }
693 }
694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
696 try {
697 mService.updateStatusIcon(imeToken, packageName, iconId);
698 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700699 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 }
701 }
702
703 public void hideStatusIcon(IBinder imeToken) {
704 try {
705 mService.updateStatusIcon(imeToken, null, 0);
706 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700707 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 }
709 }
710
711 /** @hide */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800712 public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
satok06487a52010-10-29 11:37:18 +0900713 try {
Joe Onorato857fd9b2011-01-27 15:08:35 -0800714 mService.setImeWindowStatus(imeToken, vis, backDisposition);
satok06487a52010-10-29 11:37:18 +0900715 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700716 throw e.rethrowFromSystemServer();
satok06487a52010-10-29 11:37:18 +0900717 }
718 }
719
720 /** @hide */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 public void setFullscreenMode(boolean fullScreen) {
722 mFullscreenMode = fullScreen;
723 }
satokf9f01002011-05-19 21:31:50 +0900724
725 /** @hide */
726 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
727 try {
728 mService.registerSuggestionSpansForNotification(spans);
729 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700730 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900731 }
732 }
733
734 /** @hide */
735 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
736 try {
737 mService.notifySuggestionPicked(span, originalString, index);
738 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700739 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900740 }
741 }
742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 /**
744 * Allows you to discover whether the attached input method is running
745 * in fullscreen mode. Return true if it is fullscreen, entirely covering
746 * your UI, else returns false.
747 */
748 public boolean isFullscreenMode() {
749 return mFullscreenMode;
750 }
751
752 /**
753 * Return true if the given view is the currently active view for the
754 * input method.
755 */
756 public boolean isActive(View view) {
757 checkFocus();
758 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700759 return (mServedView == view
760 || (mServedView != null
761 && mServedView.checkInputConnectionProxy(view)))
762 && mCurrentTextBoxAttribute != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
764 }
765
766 /**
767 * Return true if any view is currently active in the input method.
768 */
769 public boolean isActive() {
770 checkFocus();
771 synchronized (mH) {
772 return mServedView != null && mCurrentTextBoxAttribute != null;
773 }
774 }
775
776 /**
777 * Return true if the currently served view is accepting full text edits.
778 * If false, it has no input connection, so can only handle raw key events.
779 */
780 public boolean isAcceptingText() {
781 checkFocus();
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700782 return mServedInputConnectionWrapper != null &&
783 mServedInputConnectionWrapper.getInputConnection() != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 }
785
786 /**
787 * Reset all of the state associated with being bound to an input method.
788 */
789 void clearBindingLocked() {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -0700790 if (DEBUG) Log.v(TAG, "Clearing binding!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 clearConnectionLocked();
Jeff Brown4d656882013-04-03 14:39:19 -0700792 setInputChannelLocked(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 mBindSequence = -1;
794 mCurId = null;
795 mCurMethod = null;
Jeff Brown4d656882013-04-03 14:39:19 -0700796 }
797
798 void setInputChannelLocked(InputChannel channel) {
799 if (mCurChannel != channel) {
800 if (mCurSender != null) {
801 flushPendingEventsLocked();
802 mCurSender.dispose();
803 mCurSender = null;
804 }
805 if (mCurChannel != null) {
806 mCurChannel.dispose();
807 }
808 mCurChannel = channel;
Jeff Brownc28867a2013-03-26 15:42:39 -0700809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
Jeff Brown4d656882013-04-03 14:39:19 -0700811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 /**
813 * Reset all of the state associated with a served view being connected
814 * to an input method
815 */
816 void clearConnectionLocked() {
817 mCurrentTextBoxAttribute = null;
Dianne Hackbornac920872012-05-22 11:49:49 -0700818 if (mServedInputConnectionWrapper != null) {
819 mServedInputConnectionWrapper.deactivate();
820 mServedInputConnectionWrapper = null;
821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
Yohei Yukawa0f3a99d2015-05-21 00:15:05 -0700823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 /**
825 * Disconnect any existing input connection, clearing the served view.
826 */
827 void finishInputLocked() {
828 mNextServedView = null;
829 if (mServedView != null) {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -0700830 if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 if (mCurrentTextBoxAttribute != null) {
832 try {
833 mService.finishInput(mClient);
834 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700835 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 }
837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 mServedView = null;
839 mCompletions = null;
840 mServedConnecting = false;
841 clearConnectionLocked();
842 }
843 }
Gilles Debunnec478c172011-12-19 17:29:24 -0800844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 public void displayCompletions(View view, CompletionInfo[] completions) {
846 checkFocus();
847 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700848 if (mServedView != view && (mServedView == null
849 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 return;
851 }
852
853 mCompletions = completions;
854 if (mCurMethod != null) {
855 try {
856 mCurMethod.displayCompletions(mCompletions);
857 } catch (RemoteException e) {
858 }
859 }
860 }
861 }
862
863 public void updateExtractedText(View view, int token, ExtractedText text) {
864 checkFocus();
865 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700866 if (mServedView != view && (mServedView == null
867 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 return;
869 }
870
871 if (mCurMethod != null) {
872 try {
873 mCurMethod.updateExtractedText(token, text);
874 } catch (RemoteException e) {
875 }
876 }
877 }
878 }
879
880 /**
881 * Flag for {@link #showSoftInput} to indicate that this is an implicit
882 * request to show the input window, not as the result of a direct request
883 * by the user. The window may not be shown in this case.
884 */
885 public static final int SHOW_IMPLICIT = 0x0001;
886
887 /**
888 * Flag for {@link #showSoftInput} to indicate that the user has forced
889 * the input method open (such as by long-pressing menu) so it should
890 * not be closed until they explicitly do so.
891 */
892 public static final int SHOW_FORCED = 0x0002;
893
894 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800895 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
896 * a result receiver: explicitly request that the current input method's
897 * soft input area be shown to the user, if needed.
898 *
899 * @param view The currently focused view, which would like to receive
900 * soft keyboard input.
901 * @param flags Provides additional operating flags. Currently may be
902 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
903 */
904 public boolean showSoftInput(View view, int flags) {
905 return showSoftInput(view, flags, null);
906 }
907
908 /**
909 * Flag for the {@link ResultReceiver} result code from
910 * {@link #showSoftInput(View, int, ResultReceiver)} and
911 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
912 * state of the soft input window was unchanged and remains shown.
913 */
914 public static final int RESULT_UNCHANGED_SHOWN = 0;
915
916 /**
917 * Flag for the {@link ResultReceiver} result code from
918 * {@link #showSoftInput(View, int, ResultReceiver)} and
919 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
920 * state of the soft input window was unchanged and remains hidden.
921 */
922 public static final int RESULT_UNCHANGED_HIDDEN = 1;
923
924 /**
925 * Flag for the {@link ResultReceiver} result code from
926 * {@link #showSoftInput(View, int, ResultReceiver)} and
927 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
928 * state of the soft input window changed from hidden to shown.
929 */
930 public static final int RESULT_SHOWN = 2;
931
932 /**
933 * Flag for the {@link ResultReceiver} result code from
934 * {@link #showSoftInput(View, int, ResultReceiver)} and
935 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
936 * state of the soft input window changed from shown to hidden.
937 */
938 public static final int RESULT_HIDDEN = 3;
939
940 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 * Explicitly request that the current input method's soft input area be
942 * shown to the user, if needed. Call this if the user interacts with
943 * your view in such a way that they have expressed they would like to
944 * start performing input into it.
Yohei Yukawad552a522016-03-20 15:08:31 -0700945 *
946 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
947 * this method can be a long-lived object, because it may not be
948 * garbage-collected until all the corresponding {@link ResultReceiver}
949 * objects transferred to different processes get garbage-collected.
950 * Follow the general patterns to avoid memory leaks in Android.
951 * Consider to use {@link java.lang.ref.WeakReference} so that application
952 * logic objects such as {@link android.app.Activity} and {@link Context}
953 * can be garbage collected regardless of the lifetime of
954 * {@link ResultReceiver}.
955 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 * @param view The currently focused view, which would like to receive
957 * soft keyboard input.
958 * @param flags Provides additional operating flags. Currently may be
959 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -0800960 * @param resultReceiver If non-null, this will be called by the IME when
961 * it has processed your request to tell you what it has done. The result
962 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
963 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
964 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 */
Gilles Debunnead8484b2011-02-17 17:37:51 -0800966 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 checkFocus();
968 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700969 if (mServedView != view && (mServedView == null
970 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800971 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973
974 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800975 return mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700977 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
979 }
980 }
981
982 /** @hide */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800983 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800985 mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700987 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 }
989 }
990
991 /**
992 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
993 * input window should only be hidden if it was not explicitly shown
994 * by the user.
995 */
996 public static final int HIDE_IMPLICIT_ONLY = 0x0001;
997
998 /**
999 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
1000 * input window should normally be hidden, unless it was originally
1001 * shown with {@link #SHOW_FORCED}.
1002 */
1003 public static final int HIDE_NOT_ALWAYS = 0x0002;
Gilles Debunnec478c172011-12-19 17:29:24 -08001004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 /**
Gilles Debunne7c8c6d62011-01-24 14:48:14 -08001006 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
The Android Open Source Project4df24232009-03-05 14:34:35 -08001007 * without a result: request to hide the soft input window from the
1008 * context of the window that is currently accepting input.
1009 *
1010 * @param windowToken The token of the window that is making the request,
1011 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1012 * @param flags Provides additional operating flags. Currently may be
1013 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
1014 */
1015 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
1016 return hideSoftInputFromWindow(windowToken, flags, null);
1017 }
1018
1019 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 * Request to hide the soft input window from the context of the window
1021 * that is currently accepting input. This should be called as a result
1022 * of the user doing some actually than fairly explicitly requests to
1023 * have the input window hidden.
Yohei Yukawad552a522016-03-20 15:08:31 -07001024 *
1025 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
1026 * this method can be a long-lived object, because it may not be
1027 * garbage-collected until all the corresponding {@link ResultReceiver}
1028 * objects transferred to different processes get garbage-collected.
1029 * Follow the general patterns to avoid memory leaks in Android.
1030 * Consider to use {@link java.lang.ref.WeakReference} so that application
1031 * logic objects such as {@link android.app.Activity} and {@link Context}
1032 * can be garbage collected regardless of the lifetime of
1033 * {@link ResultReceiver}.
1034 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 * @param windowToken The token of the window that is making the request,
1036 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1037 * @param flags Provides additional operating flags. Currently may be
1038 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -08001039 * @param resultReceiver If non-null, this will be called by the IME when
1040 * it has processed your request to tell you what it has done. The result
1041 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
1042 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
1043 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001045 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
1046 ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 checkFocus();
1048 synchronized (mH) {
1049 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001050 return false;
1051 }
1052
1053 try {
1054 return mService.hideSoftInput(mClient, flags, resultReceiver);
1055 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001056 throw e.rethrowFromSystemServer();
The Android Open Source Project4df24232009-03-05 14:34:35 -08001057 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001058 }
1059 }
1060
1061
1062 /**
1063 * This method toggles the input method window display.
1064 * If the input window is already displayed, it gets hidden.
1065 * If not the input window will be displayed.
1066 * @param windowToken The token of the window that is making the request,
1067 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1068 * @param showFlags Provides additional operating flags. May be
1069 * 0 or have the {@link #SHOW_IMPLICIT},
1070 * {@link #SHOW_FORCED} bit set.
1071 * @param hideFlags Provides additional operating flags. May be
1072 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1073 * {@link #HIDE_NOT_ALWAYS} bit set.
1074 **/
1075 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
1076 synchronized (mH) {
1077 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 return;
1079 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001080 if (mCurMethod != null) {
1081 try {
1082 mCurMethod.toggleSoftInput(showFlags, hideFlags);
1083 } catch (RemoteException e) {
1084 }
1085 }
1086 }
1087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088
The Android Open Source Project4df24232009-03-05 14:34:35 -08001089 /*
1090 * This method toggles the input method window display.
1091 * If the input window is already displayed, it gets hidden.
1092 * If not the input window will be displayed.
1093 * @param showFlags Provides additional operating flags. May be
1094 * 0 or have the {@link #SHOW_IMPLICIT},
1095 * {@link #SHOW_FORCED} bit set.
1096 * @param hideFlags Provides additional operating flags. May be
1097 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1098 * {@link #HIDE_NOT_ALWAYS} bit set.
1099 * @hide
1100 */
1101 public void toggleSoftInput(int showFlags, int hideFlags) {
1102 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001104 mCurMethod.toggleSoftInput(showFlags, hideFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } catch (RemoteException e) {
1106 }
1107 }
1108 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 /**
1111 * If the input method is currently connected to the given view,
1112 * restart it with its new contents. You should call this when the text
1113 * within your view changes outside of the normal input method or key
1114 * input flow, such as when an application calls TextView.setText().
1115 *
1116 * @param view The view whose text has changed.
1117 */
1118 public void restartInput(View view) {
1119 checkFocus();
1120 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001121 if (mServedView != view && (mServedView == null
1122 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 return;
1124 }
1125
1126 mServedConnecting = true;
1127 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001128
1129 startInputInner(InputMethodClient.START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, null, 0,
1130 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001132
1133 boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
1134 IBinder windowGainingFocus, int controlFlags, int softInputMode,
Dianne Hackborn7663d802012-02-24 13:08:49 -08001135 int windowFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 final View view;
1137 synchronized (mH) {
1138 view = mServedView;
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 // Make sure we have a window token for the served view.
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001141 if (DEBUG) {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001142 Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) +
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001143 " reason=" + InputMethodClient.getStartInputReason(startInputReason));
1144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 if (view == null) {
1146 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
Dianne Hackborn7663d802012-02-24 13:08:49 -08001147 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 }
1149 }
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 // Now we need to get an input connection from the served view.
1152 // This is complicated in a couple ways: we can't be holding our lock
1153 // when calling out to the view, and we need to make sure we call into
1154 // the view on the same thread that is driving its view hierarchy.
1155 Handler vh = view.getHandler();
1156 if (vh == null) {
1157 // If the view doesn't have a handler, something has changed out
Satoshi Kataoka35739502012-10-02 19:00:26 +09001158 // from under us, so just close the current input.
1159 // If we don't close the current input, the current input method can remain on the
1160 // screen without a connection.
1161 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");
1162 closeCurrentInput();
Dianne Hackborn7663d802012-02-24 13:08:49 -08001163 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 }
1165 if (vh.getLooper() != Looper.myLooper()) {
1166 // The view is running on a different thread than our own, so
1167 // we need to reschedule our work for over there.
1168 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
1169 vh.post(new Runnable() {
Jeff Brownc28867a2013-03-26 15:42:39 -07001170 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 public void run() {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001172 startInputInner(startInputReason, null, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174 });
Dianne Hackborn7663d802012-02-24 13:08:49 -08001175 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 }
1177
1178 // Okay we are now ready to call into the served view and have it
1179 // do its stuff.
1180 // Life is good: let's hook everything up!
1181 EditorInfo tba = new EditorInfo();
Yohei Yukawa02df3282015-06-03 15:58:59 -07001182 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
1183 // system can verify the consistency between the uid of this process and package name passed
1184 // from here. See comment of Context#getOpPackageName() for details.
1185 tba.packageName = view.getContext().getOpPackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 tba.fieldId = view.getId();
1187 InputConnection ic = view.onCreateInputConnection(tba);
1188 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
Gilles Debunnec478c172011-12-19 17:29:24 -08001189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 synchronized (mH) {
1191 // Now that we are locked again, validate that our state hasn't
1192 // changed.
1193 if (mServedView != view || !mServedConnecting) {
1194 // Something else happened, so abort.
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001195 if (DEBUG) Log.v(TAG,
1196 "Starting input: finished by someone else. view=" + dumpViewInfo(view)
1197 + " mServedView=" + dumpViewInfo(mServedView)
1198 + " mServedConnecting=" + mServedConnecting);
Dianne Hackborn7663d802012-02-24 13:08:49 -08001199 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 // If we already have a text box, then this view is already
1203 // connected so we want to restart it.
Dianne Hackborn7663d802012-02-24 13:08:49 -08001204 if (mCurrentTextBoxAttribute == null) {
1205 controlFlags |= CONTROL_START_INITIAL;
1206 }
Yohei Yukawa612cce92016-02-11 17:47:33 -08001207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 // Hook 'em up and let 'er rip.
1209 mCurrentTextBoxAttribute = tba;
1210 mServedConnecting = false;
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001211 if (mServedInputConnectionWrapper != null) {
1212 mServedInputConnectionWrapper.deactivate();
1213 mServedInputConnectionWrapper = null;
1214 }
Dianne Hackbornac920872012-05-22 11:49:49 -07001215 ControlledInputConnectionWrapper servedContext;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001216 final int missingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 if (ic != null) {
1218 mCursorSelStart = tba.initialSelStart;
1219 mCursorSelEnd = tba.initialSelEnd;
1220 mCursorCandStart = -1;
1221 mCursorCandEnd = -1;
1222 mCursorRect.setEmpty();
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001223 mCursorAnchorInfo = null;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001224 final Handler icHandler;
1225 missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
1226 if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
1227 != 0) {
1228 // InputConnection#getHandler() is not implemented.
1229 icHandler = null;
1230 } else {
1231 icHandler = ic.getHandler();
1232 }
Yohei Yukawa612cce92016-02-11 17:47:33 -08001233 servedContext = new ControlledInputConnectionWrapper(
1234 icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 } else {
1236 servedContext = null;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001237 missingMethodFlags = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 }
Dianne Hackbornac920872012-05-22 11:49:49 -07001239 mServedInputConnectionWrapper = servedContext;
Yohei Yukawa612cce92016-02-11 17:47:33 -08001240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 try {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001242 if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
Dianne Hackborn7663d802012-02-24 13:08:49 -08001243 + ic + " tba=" + tba + " controlFlags=#"
1244 + Integer.toHexString(controlFlags));
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001245 final InputBindResult res = mService.startInputOrWindowGainedFocus(
1246 startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001247 windowFlags, tba, servedContext, missingMethodFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
1249 if (res != null) {
1250 if (res.id != null) {
Jeff Brown4d656882013-04-03 14:39:19 -07001251 setInputChannelLocked(res.channel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 mBindSequence = res.sequence;
1253 mCurMethod = res.method;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001254 mCurId = res.id;
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09001255 mNextUserActionNotificationSequenceNumber =
1256 res.userActionNotificationSequenceNumber;
Jeff Brownc28867a2013-03-26 15:42:39 -07001257 } else {
Jeff Brown4d656882013-04-03 14:39:19 -07001258 if (res.channel != null && res.channel != mCurChannel) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001259 res.channel.dispose();
1260 }
1261 if (mCurMethod == null) {
1262 // This means there is no input method available.
1263 if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
1264 return true;
1265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267 }
1268 if (mCurMethod != null && mCompletions != null) {
1269 try {
1270 mCurMethod.displayCompletions(mCompletions);
1271 } catch (RemoteException e) {
1272 }
1273 }
1274 } catch (RemoteException e) {
1275 Log.w(TAG, "IME died: " + mCurId, e);
1276 }
1277 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001278
1279 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281
1282 /**
1283 * When the focused window is dismissed, this method is called to finish the
1284 * input method started before.
1285 * @hide
1286 */
1287 public void windowDismissed(IBinder appWindowToken) {
1288 checkFocus();
1289 synchronized (mH) {
1290 if (mServedView != null &&
1291 mServedView.getWindowToken() == appWindowToken) {
1292 finishInputLocked();
1293 }
1294 }
1295 }
1296
1297 /**
1298 * Call this when a view receives focus.
1299 * @hide
1300 */
1301 public void focusIn(View view) {
1302 synchronized (mH) {
1303 focusInLocked(view);
1304 }
1305 }
1306
1307 void focusInLocked(View view) {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001308 if (DEBUG) Log.v(TAG, "focusIn: " + dumpViewInfo(view));
Yohei Yukawa5f059652015-05-14 22:16:41 -07001309
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001310 if (mCurRootView != view.getRootView()) {
1311 // This is a request from a window that isn't in the window with
1312 // IME focus, so ignore it.
1313 if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 return;
1315 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 mNextServedView = view;
1318 scheduleCheckFocusLocked(view);
1319 }
1320
1321 /**
1322 * Call this when a view loses focus.
1323 * @hide
1324 */
1325 public void focusOut(View view) {
1326 synchronized (mH) {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001327 if (DEBUG) Log.v(TAG, "focusOut: view=" + dumpViewInfo(view)
1328 + " mServedView=" + dumpViewInfo(mServedView));
Yohei Yukawa0b52ed02015-05-29 11:07:02 -07001329 if (mServedView != view) {
1330 // The following code would auto-hide the IME if we end up
1331 // with no more views with focus. This can happen, however,
1332 // whenever we go into touch mode, so it ends up hiding
1333 // at times when we don't really want it to. For now it
1334 // seems better to just turn it all off.
1335 if (false && view.hasWindowFocus()) {
1336 mNextServedView = null;
1337 scheduleCheckFocusLocked(view);
1338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 }
1340 }
1341 }
1342
Yohei Yukawab13f0152015-05-29 17:09:14 -07001343 /**
1344 * Call this when a view is being detached from a {@link android.view.Window}.
1345 * @hide
1346 */
1347 public void onViewDetachedFromWindow(View view) {
1348 synchronized (mH) {
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07001349 if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: view=" + dumpViewInfo(view)
1350 + " mServedView=" + dumpViewInfo(mServedView));
Yohei Yukawab13f0152015-05-29 17:09:14 -07001351 if (mServedView == view && view.hasWindowFocus()) {
1352 mNextServedView = null;
1353 scheduleCheckFocusLocked(view);
1354 }
1355 }
1356 }
1357
Gilles Debunnec478c172011-12-19 17:29:24 -08001358 static void scheduleCheckFocusLocked(View view) {
Jeff Browna175a5b2012-02-15 19:18:31 -08001359 ViewRootImpl viewRootImpl = view.getViewRootImpl();
1360 if (viewRootImpl != null) {
1361 viewRootImpl.dispatchCheckFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 }
1363 }
Jeff Browna175a5b2012-02-15 19:18:31 -08001364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 /**
1366 * @hide
1367 */
1368 public void checkFocus() {
Yohei Yukawa241eac22016-03-28 00:28:50 -07001369 if (checkFocusNoStartInput(false)) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001370 startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001371 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001372 }
1373
Yohei Yukawa241eac22016-03-28 00:28:50 -07001374 private boolean checkFocusNoStartInput(boolean forceNewFocus) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 // This is called a lot, so short-circuit before locking.
Dianne Hackborn7663d802012-02-24 13:08:49 -08001376 if (mServedView == mNextServedView && !forceNewFocus) {
Dianne Hackborna82ba542012-02-15 18:19:55 -08001377 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 }
satok863fcd62011-06-21 17:38:02 +09001379
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001380 final ControlledInputConnectionWrapper ic;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 synchronized (mH) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001382 if (mServedView == mNextServedView && !forceNewFocus) {
Dianne Hackborna82ba542012-02-15 18:19:55 -08001383 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385 if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
1386 + " next=" + mNextServedView
satok05a6cbe2012-04-05 23:04:08 +09001387 + " forceNewFocus=" + forceNewFocus
1388 + " package="
1389 + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));
Dianne Hackborna82ba542012-02-15 18:19:55 -08001390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 if (mNextServedView == null) {
1392 finishInputLocked();
1393 // In this case, we used to have a focused view on the window,
1394 // but no longer do. We should make sure the input method is
1395 // no longer shown, since it serves no purpose.
1396 closeCurrentInput();
Dianne Hackborna82ba542012-02-15 18:19:55 -08001397 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001399
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001400 ic = mServedInputConnectionWrapper;
Dianne Hackborna82ba542012-02-15 18:19:55 -08001401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mServedView = mNextServedView;
1403 mCurrentTextBoxAttribute = null;
1404 mCompletions = null;
1405 mServedConnecting = true;
1406 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001407
Yohei Yukawa241eac22016-03-28 00:28:50 -07001408 if (ic != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 ic.finishComposingText();
1410 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001411
1412 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 }
1414
1415 void closeCurrentInput() {
1416 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001417 mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001419 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
1421 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 /**
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07001424 * Called by ViewAncestor when its window gets input focus.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 * @hide
1426 */
Yohei Yukawa5f059652015-05-14 22:16:41 -07001427 public void onPostWindowFocus(View rootView, View focusedView, int softInputMode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 boolean first, int windowFlags) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001429 boolean forceNewFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 synchronized (mH) {
1431 if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
1432 + " softInputMode=" + softInputMode
1433 + " first=" + first + " flags=#"
1434 + Integer.toHexString(windowFlags));
1435 if (mHasBeenInactive) {
1436 if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh");
1437 mHasBeenInactive = false;
Dianne Hackborn7663d802012-02-24 13:08:49 -08001438 forceNewFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 }
1440 focusInLocked(focusedView != null ? focusedView : rootView);
1441 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001442
1443 int controlFlags = 0;
1444 if (focusedView != null) {
1445 controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
1446 if (focusedView.onCheckIsTextEditor()) {
1447 controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001450 if (first) {
1451 controlFlags |= CONTROL_WINDOW_FIRST;
1452 }
1453
Yohei Yukawa241eac22016-03-28 00:28:50 -07001454 if (checkFocusNoStartInput(forceNewFocus)) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001455 // We need to restart input on the current focus view. This
1456 // should be done in conjunction with telling the system service
1457 // about the window gaining focus, to help make the transition
1458 // smooth.
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001459 if (startInputInner(InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN,
1460 rootView.getWindowToken(), controlFlags, softInputMode, windowFlags)) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001461 return;
1462 }
1463 }
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001464
Dianne Hackborn7663d802012-02-24 13:08:49 -08001465 // For some reason we didn't do a startInput + windowFocusGain, so
1466 // we'll just do a window focus gain and call it a day.
1467 synchronized (mH) {
1468 try {
Dianne Hackbornac920872012-05-22 11:49:49 -07001469 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001470 mService.startInputOrWindowGainedFocus(
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001471 InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
1472 rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001473 null, 0 /* missingMethodFlags */);
Dianne Hackborn7663d802012-02-24 13:08:49 -08001474 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001475 throw e.rethrowFromSystemServer();
Dianne Hackborn7663d802012-02-24 13:08:49 -08001476 }
Dianne Hackborn06a591c2012-02-16 10:25:26 -08001477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001479
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001480 /** @hide */
Yohei Yukawa5f059652015-05-14 22:16:41 -07001481 public void onPreWindowFocus(View rootView, boolean hasWindowFocus) {
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001482 synchronized (mH) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07001483 if (rootView == null) {
1484 mCurRootView = null;
1485 } if (hasWindowFocus) {
1486 mCurRootView = rootView;
1487 } else if (rootView == mCurRootView) {
1488 // If the mCurRootView is losing window focus, release the strong reference to it
1489 // so as not to prevent it from being garbage-collected.
1490 mCurRootView = null;
1491 } else {
1492 if (DEBUG) {
1493 Log.v(TAG, "Ignoring onPreWindowFocus()."
1494 + " mCurRootView=" + mCurRootView + " rootView=" + rootView);
1495 }
1496 }
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001497 }
1498 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 /**
1501 * Report the current selection range.
Jean Chalard6fd68e02014-02-20 17:48:46 +09001502 *
1503 * <p><strong>Editor authors</strong>, you need to call this method whenever
1504 * the cursor moves in your editor. Remember that in addition to doing this, your
1505 * editor needs to always supply current cursor values in
1506 * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every
1507 * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is
1508 * called, which happens whenever the keyboard shows up or the focus changes
1509 * to a text field, among other cases.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 */
1511 public void updateSelection(View view, int selStart, int selEnd,
1512 int candidatesStart, int candidatesEnd) {
1513 checkFocus();
1514 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001515 if ((mServedView != view && (mServedView == null
1516 || !mServedView.checkInputConnectionProxy(view)))
1517 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 return;
1519 }
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
1522 || mCursorCandStart != candidatesStart
1523 || mCursorCandEnd != candidatesEnd) {
1524 if (DEBUG) Log.d(TAG, "updateSelection");
1525
1526 try {
1527 if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
Jean Chalardc743cb92013-09-12 16:28:45 +09001528 final int oldSelStart = mCursorSelStart;
1529 final int oldSelEnd = mCursorSelEnd;
1530 // Update internal values before sending updateSelection to the IME, because
1531 // if it changes the text within its onUpdateSelection handler in a way that
1532 // does not move the cursor we don't want to call it again with the same values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 mCursorSelStart = selStart;
1534 mCursorSelEnd = selEnd;
1535 mCursorCandStart = candidatesStart;
1536 mCursorCandEnd = candidatesEnd;
Jean Chalardc743cb92013-09-12 16:28:45 +09001537 mCurMethod.updateSelection(oldSelStart, oldSelEnd,
1538 selStart, selEnd, candidatesStart, candidatesEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 } catch (RemoteException e) {
1540 Log.w(TAG, "IME died: " + mCurId, e);
1541 }
1542 }
1543 }
1544 }
1545
1546 /**
satok863fcd62011-06-21 17:38:02 +09001547 * Notify the event when the user tapped or clicked the text view.
1548 */
1549 public void viewClicked(View view) {
1550 final boolean focusChanged = mServedView != mNextServedView;
1551 checkFocus();
1552 synchronized (mH) {
1553 if ((mServedView != view && (mServedView == null
1554 || !mServedView.checkInputConnectionProxy(view)))
1555 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1556 return;
1557 }
1558 try {
1559 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
1560 mCurMethod.viewClicked(focusChanged);
1561 } catch (RemoteException e) {
1562 Log.w(TAG, "IME died: " + mCurId, e);
1563 }
1564 }
1565 }
1566
1567 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001568 * Return true if the current input method wants to watch the location
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 * of the input editor's cursor in its window.
Yohei Yukawa4de04792014-04-17 12:40:31 +09001570 *
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001571 * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead.
Yohei Yukawa4de04792014-04-17 12:40:31 +09001572 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001573 @Deprecated
1574 public boolean isWatchingCursor(View view) {
1575 return false;
Yohei Yukawa4de04792014-04-17 12:40:31 +09001576 }
1577
1578 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001579 * Return true if the current input method wants to be notified when cursor/anchor location
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001580 * is changed.
Yohei Yukawab7b79072014-03-25 11:02:00 +09001581 *
1582 * @hide
1583 */
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001584 public boolean isCursorAnchorInfoEnabled() {
1585 synchronized (mH) {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001586 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001587 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
Yohei Yukawaa277db22014-08-21 18:38:44 -07001588 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001589 InputConnection.CURSOR_UPDATE_MONITOR) != 0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001590 return isImmediate || isMonitoring;
1591 }
1592 }
1593
1594 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001595 * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001596 *
1597 * @hide
1598 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001599 public void setUpdateCursorAnchorInfoMode(int flags) {
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001600 synchronized (mH) {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001601 mRequestUpdateCursorAnchorInfoMonitorMode = flags;
Yohei Yukawab7b79072014-03-25 11:02:00 +09001602 }
1603 }
1604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 /**
1606 * Report the current cursor location in its window.
Yohei Yukawaa277db22014-08-21 18:38:44 -07001607 *
1608 * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001610 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 public void updateCursor(View view, int left, int top, int right, int bottom) {
1612 checkFocus();
1613 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001614 if ((mServedView != view && (mServedView == null
1615 || !mServedView.checkInputConnectionProxy(view)))
1616 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 return;
1618 }
Yohei Yukawaa277db22014-08-21 18:38:44 -07001619
1620 mTmpCursorRect.set(left, top, right, bottom);
1621 if (!mCursorRect.equals(mTmpCursorRect)) {
1622 if (DEBUG) Log.d(TAG, "updateCursor");
1623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 try {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001625 if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
1626 mCurMethod.updateCursor(mTmpCursorRect);
1627 mCursorRect.set(mTmpCursorRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 } catch (RemoteException e) {
1629 Log.w(TAG, "IME died: " + mCurId, e);
1630 }
1631 }
1632 }
1633 }
1634
1635 /**
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001636 * Report positional change of the text insertion point and/or characters in the composition
1637 * string.
1638 */
1639 public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
1640 if (view == null || cursorAnchorInfo == null) {
1641 return;
1642 }
1643 checkFocus();
1644 synchronized (mH) {
1645 if ((mServedView != view &&
1646 (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
1647 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1648 return;
1649 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001650 // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
1651 // not been changed from the previous call.
Yohei Yukawaa277db22014-08-21 18:38:44 -07001652 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001653 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001654 if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
Yohei Yukawa73605912014-08-13 16:49:35 +09001655 // TODO: Consider always emitting this message once we have addressed redundant
1656 // calls of this method from android.widget.Editor.
1657 if (DEBUG) {
1658 Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info="
1659 + cursorAnchorInfo);
1660 }
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001661 return;
1662 }
1663 if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001664 try {
1665 mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001666 mCursorAnchorInfo = cursorAnchorInfo;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001667 // Clear immediate bit (if any).
Yohei Yukawaa277db22014-08-21 18:38:44 -07001668 mRequestUpdateCursorAnchorInfoMonitorMode &=
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001669 ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001670 } catch (RemoteException e) {
1671 Log.w(TAG, "IME died: " + mCurId, e);
1672 }
1673 }
1674 }
1675
1676 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
1678 * InputMethodSession.appPrivateCommand()} on the current Input Method.
1679 * @param view Optional View that is sending the command, or null if
1680 * you want to send the command regardless of the view that is attached
1681 * to the input method.
1682 * @param action Name of the command to be performed. This <em>must</em>
1683 * be a scoped name, i.e. prefixed with a package name you own, so that
1684 * different developers will not create conflicting commands.
1685 * @param data Any data to include with the command.
1686 */
1687 public void sendAppPrivateCommand(View view, String action, Bundle data) {
1688 checkFocus();
1689 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001690 if ((mServedView != view && (mServedView == null
1691 || !mServedView.checkInputConnectionProxy(view)))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1693 return;
1694 }
1695 try {
1696 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
1697 mCurMethod.appPrivateCommand(action, data);
1698 } catch (RemoteException e) {
1699 Log.w(TAG, "IME died: " + mCurId, e);
1700 }
1701 }
1702 }
satok28203512010-11-24 11:06:49 +09001703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 /**
satok28203512010-11-24 11:06:49 +09001705 * Force switch to a new input method component. This can only be called
1706 * from an application or a service which has a token of the currently active input method.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 * @param token Supplies the identifying token given to an input method
1708 * when it was started, which allows it to perform this operation on
1709 * itself.
1710 * @param id The unique identifier for the new input method to be switched to.
1711 */
1712 public void setInputMethod(IBinder token, String id) {
1713 try {
1714 mService.setInputMethod(token, id);
1715 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001716 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
1718 }
satok28203512010-11-24 11:06:49 +09001719
1720 /**
1721 * Force switch to a new input method and subtype. This can only be called
1722 * from an application or a service which has a token of the currently active input method.
1723 * @param token Supplies the identifying token given to an input method
1724 * when it was started, which allows it to perform this operation on
1725 * itself.
1726 * @param id The unique identifier for the new input method to be switched to.
1727 * @param subtype The new subtype of the new input method to be switched to.
1728 */
1729 public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
1730 try {
1731 mService.setInputMethodAndSubtype(token, id, subtype);
1732 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001733 throw e.rethrowFromSystemServer();
satok28203512010-11-24 11:06:49 +09001734 }
1735 }
1736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 /**
1738 * Close/hide the input method's soft input area, so the user no longer
1739 * sees it or can interact with it. This can only be called
1740 * from the currently active input method, as validated by the given token.
1741 *
1742 * @param token Supplies the identifying token given to an input method
1743 * when it was started, which allows it to perform this operation on
1744 * itself.
1745 * @param flags Provides additional operating flags. Currently may be
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1747 * {@link #HIDE_NOT_ALWAYS} bit set.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 */
1749 public void hideSoftInputFromInputMethod(IBinder token, int flags) {
1750 try {
1751 mService.hideMySoftInput(token, flags);
1752 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001753 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
1755 }
1756
1757 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -08001758 * Show the input method's soft input area, so the user
1759 * sees the input method window and can interact with it.
1760 * This can only be called from the currently active input method,
1761 * as validated by the given token.
1762 *
1763 * @param token Supplies the identifying token given to an input method
1764 * when it was started, which allows it to perform this operation on
1765 * itself.
1766 * @param flags Provides additional operating flags. Currently may be
1767 * 0 or have the {@link #SHOW_IMPLICIT} or
1768 * {@link #SHOW_FORCED} bit set.
1769 */
1770 public void showSoftInputFromInputMethod(IBinder token, int flags) {
1771 try {
1772 mService.showMySoftInput(token, flags);
1773 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001774 throw e.rethrowFromSystemServer();
The Android Open Source Project4df24232009-03-05 14:34:35 -08001775 }
1776 }
Jeff Brownc28867a2013-03-26 15:42:39 -07001777
The Android Open Source Project4df24232009-03-05 14:34:35 -08001778 /**
Jeff Brownf9e989d2013-04-04 23:04:03 -07001779 * Dispatches an input event to the IME.
1780 *
1781 * Returns {@link #DISPATCH_HANDLED} if the event was handled.
1782 * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled.
1783 * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the
1784 * callback will be invoked later.
1785 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 * @hide
1787 */
Jeff Brownf9e989d2013-04-04 23:04:03 -07001788 public int dispatchInputEvent(InputEvent event, Object token,
1789 FinishedInputEventCallback callback, Handler handler) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 synchronized (mH) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001791 if (mCurMethod != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001792 if (event instanceof KeyEvent) {
1793 KeyEvent keyEvent = (KeyEvent)event;
1794 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
1795 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM
1796 && keyEvent.getRepeatCount() == 0) {
1797 showInputMethodPickerLocked();
Jeff Brownf9e989d2013-04-04 23:04:03 -07001798 return DISPATCH_HANDLED;
Jeff Brownc28867a2013-03-26 15:42:39 -07001799 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08001800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801
Jeff Brownc28867a2013-03-26 15:42:39 -07001802 if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
Jeff Brownf9e989d2013-04-04 23:04:03 -07001803
1804 PendingEvent p = obtainPendingEventLocked(
1805 event, token, mCurId, callback, handler);
1806 if (mMainLooper.isCurrentThread()) {
1807 // Already running on the IMM thread so we can send the event immediately.
1808 return sendInputEventOnMainLooperLocked(p);
Victoria Leaseb38070c2012-08-24 13:46:02 -07001809 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001810
1811 // Post the event to the IMM thread.
1812 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p);
1813 msg.setAsynchronous(true);
1814 mH.sendMessage(msg);
1815 return DISPATCH_IN_PROGRESS;
Victoria Leaseb38070c2012-08-24 13:46:02 -07001816 }
1817 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001818 return DISPATCH_NOT_HANDLED;
Victoria Leaseb38070c2012-08-24 13:46:02 -07001819 }
1820
Yohei Yukawa2afe2aa2016-01-07 18:09:44 -08001821 /**
1822 * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which
1823 * is expected to dispatch an keyboard event sent from the IME to an appropriate event target
1824 * depending on the given {@link View} and the current focus state.
1825 *
1826 * <p>CAUTION: This method is provided only for the situation where
1827 * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on
1828 * {@link BaseInputConnection}. Do not use this API for anything else.</p>
1829 *
1830 * @param targetView the default target view. If {@code null} is specified, then this method
1831 * tries to find a good event target based on the current focus state.
1832 * @param event the key event to be dispatched.
1833 */
1834 public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
1835 @NonNull KeyEvent event) {
1836 synchronized (mH) {
1837 ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
1838 if (viewRootImpl == null) {
1839 if (mServedView != null) {
1840 viewRootImpl = mServedView.getViewRootImpl();
1841 }
1842 }
1843 if (viewRootImpl != null) {
1844 viewRootImpl.dispatchKeyFromIme(event);
1845 }
1846 }
1847 }
1848
Jeff Brownf9e989d2013-04-04 23:04:03 -07001849 // Must be called on the main looper
1850 void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
1851 final boolean handled;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001852 synchronized (mH) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001853 int result = sendInputEventOnMainLooperLocked(p);
1854 if (result == DISPATCH_IN_PROGRESS) {
1855 return;
1856 }
1857
1858 handled = (result == DISPATCH_HANDLED);
1859 }
1860
1861 invokeFinishedInputEventCallback(p, handled);
1862 }
1863
1864 // Must be called on the main looper
1865 int sendInputEventOnMainLooperLocked(PendingEvent p) {
1866 if (mCurChannel != null) {
1867 if (mCurSender == null) {
1868 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
1869 }
1870
1871 final InputEvent event = p.mEvent;
1872 final int seq = event.getSequenceNumber();
1873 if (mCurSender.sendInputEvent(seq, event)) {
1874 mPendingEvents.put(seq, p);
1875 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
1876 mPendingEvents.size());
1877
1878 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
1879 msg.setAsynchronous(true);
1880 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
1881 return DISPATCH_IN_PROGRESS;
1882 }
1883
1884 Log.w(TAG, "Unable to send input event to IME: "
1885 + mCurId + " dropping: " + event);
1886 }
1887 return DISPATCH_NOT_HANDLED;
1888 }
1889
1890 void finishedInputEvent(int seq, boolean handled, boolean timeout) {
1891 final PendingEvent p;
1892 synchronized (mH) {
1893 int index = mPendingEvents.indexOfKey(seq);
1894 if (index < 0) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001895 return; // spurious, event already finished or timed out
1896 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001897
Jeff Brownf9e989d2013-04-04 23:04:03 -07001898 p = mPendingEvents.valueAt(index);
1899 mPendingEvents.removeAt(index);
1900 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001901
Jeff Brownf9e989d2013-04-04 23:04:03 -07001902 if (timeout) {
1903 Log.w(TAG, "Timeout waiting for IME to handle input event after "
1904 + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId);
1905 } else {
1906 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p);
Jeff Brown4d656882013-04-03 14:39:19 -07001907 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001908 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001909
1910 invokeFinishedInputEventCallback(p, handled);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001911 }
1912
Jeff Brownf9e989d2013-04-04 23:04:03 -07001913 // Assumes the event has already been removed from the queue.
1914 void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
1915 p.mHandled = handled;
1916 if (p.mHandler.getLooper().isCurrentThread()) {
1917 // Already running on the callback handler thread so we can send the
1918 // callback immediately.
1919 p.run();
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001920 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001921 // Post the event to the callback handler thread.
1922 // In this case, the callback will be responsible for recycling the event.
1923 Message msg = Message.obtain(p.mHandler, p);
1924 msg.setAsynchronous(true);
1925 msg.sendToTarget();
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 }
satokab751aa2010-09-14 19:17:36 +09001928
Michael Wrightef17e872013-04-01 13:15:55 -07001929 private void flushPendingEventsLocked() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001930 mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
Jeff Brown4d656882013-04-03 14:39:19 -07001931
Jeff Brownf9e989d2013-04-04 23:04:03 -07001932 final int count = mPendingEvents.size();
1933 for (int i = 0; i < count; i++) {
1934 int seq = mPendingEvents.keyAt(i);
1935 Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0);
Michael Wrightef17e872013-04-01 13:15:55 -07001936 msg.setAsynchronous(true);
Jeff Brownf9e989d2013-04-04 23:04:03 -07001937 msg.sendToTarget();
Michael Wrightef17e872013-04-01 13:15:55 -07001938 }
1939 }
1940
Jeff Brownf9e989d2013-04-04 23:04:03 -07001941 private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
1942 String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
1943 PendingEvent p = mPendingEventPool.acquire();
1944 if (p == null) {
1945 p = new PendingEvent();
1946 }
1947 p.mEvent = event;
1948 p.mToken = token;
1949 p.mInputMethodId = inputMethodId;
1950 p.mCallback = callback;
1951 p.mHandler = handler;
1952 return p;
1953 }
1954
1955 private void recyclePendingEventLocked(PendingEvent p) {
1956 p.recycle();
1957 mPendingEventPool.release(p);
1958 }
1959
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 public void showInputMethodPicker() {
1961 synchronized (mH) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001962 showInputMethodPickerLocked();
1963 }
1964 }
1965
Seigo Nonaka14e13912015-05-06 21:04:13 -07001966 /**
1967 * Shows the input method chooser dialog.
1968 *
1969 * @param showAuxiliarySubtypes Set true to show auxiliary input methods.
1970 * @hide
1971 */
1972 public void showInputMethodPicker(boolean showAuxiliarySubtypes) {
1973 synchronized (mH) {
1974 try {
1975 final int mode = showAuxiliarySubtypes ?
1976 SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
1977 SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
1978 mService.showInputMethodPickerFromClient(mClient, mode);
1979 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001980 throw e.rethrowFromSystemServer();
Seigo Nonaka14e13912015-05-06 21:04:13 -07001981 }
1982 }
1983 }
1984
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001985 private void showInputMethodPickerLocked() {
1986 try {
Seigo Nonaka14e13912015-05-06 21:04:13 -07001987 mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001988 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001989 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001992
satokd4fce2b2011-04-11 12:07:13 +09001993 /**
1994 * Show the settings for enabling subtypes of the specified input method.
1995 * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
1996 * subtypes of all input methods will be shown.
1997 */
1998 public void showInputMethodAndSubtypeEnabler(String imiId) {
satok47a44912010-10-06 16:03:58 +09001999 synchronized (mH) {
2000 try {
satokd4fce2b2011-04-11 12:07:13 +09002001 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
satok47a44912010-10-06 16:03:58 +09002002 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002003 throw e.rethrowFromSystemServer();
satok47a44912010-10-06 16:03:58 +09002004 }
2005 }
2006 }
2007
satokd4fce2b2011-04-11 12:07:13 +09002008 /**
2009 * Returns the current input method subtype. This subtype is one of the subtypes in
2010 * the current input method. This method returns null when the current input method doesn't
2011 * have any input method subtype.
2012 */
satok04d50202010-10-25 22:20:12 +09002013 public InputMethodSubtype getCurrentInputMethodSubtype() {
2014 synchronized (mH) {
2015 try {
2016 return mService.getCurrentInputMethodSubtype();
2017 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002018 throw e.rethrowFromSystemServer();
satok04d50202010-10-25 22:20:12 +09002019 }
2020 }
2021 }
2022
satokd4fce2b2011-04-11 12:07:13 +09002023 /**
2024 * Switch to a new input method subtype of the current input method.
2025 * @param subtype A new input method subtype to switch.
2026 * @return true if the current subtype was successfully switched. When the specified subtype is
2027 * null, this method returns false.
2028 */
Yoshiki Iguchi00d51222015-05-29 15:36:22 +09002029 @RequiresPermission(WRITE_SECURE_SETTINGS)
satokb66d2872010-11-10 01:04:04 +09002030 public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
2031 synchronized (mH) {
2032 try {
2033 return mService.setCurrentInputMethodSubtype(subtype);
2034 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002035 throw e.rethrowFromSystemServer();
satokb66d2872010-11-10 01:04:04 +09002036 }
2037 }
2038 }
2039
satokd4fce2b2011-04-11 12:07:13 +09002040 /**
Yohei Yukawa02970512014-06-05 16:16:18 +09002041 * Notify that a user took some action with this input method.
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002042 * @hide
2043 */
Yohei Yukawa02970512014-06-05 16:16:18 +09002044 public void notifyUserAction() {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002045 synchronized (mH) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002046 if (mLastSentUserActionNotificationSequenceNumber ==
2047 mNextUserActionNotificationSequenceNumber) {
2048 if (DEBUG) {
2049 Log.w(TAG, "Ignoring notifyUserAction as it has already been sent."
2050 + " mLastSentUserActionNotificationSequenceNumber: "
2051 + mLastSentUserActionNotificationSequenceNumber
2052 + " mNextUserActionNotificationSequenceNumber: "
2053 + mNextUserActionNotificationSequenceNumber);
2054 }
2055 return;
2056 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002057 try {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002058 if (DEBUG) {
2059 Log.w(TAG, "notifyUserAction: "
2060 + " mLastSentUserActionNotificationSequenceNumber: "
2061 + mLastSentUserActionNotificationSequenceNumber
2062 + " mNextUserActionNotificationSequenceNumber: "
2063 + mNextUserActionNotificationSequenceNumber);
2064 }
2065 mService.notifyUserAction(mNextUserActionNotificationSequenceNumber);
2066 mLastSentUserActionNotificationSequenceNumber =
2067 mNextUserActionNotificationSequenceNumber;
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002068 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002069 throw e.rethrowFromSystemServer();
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002070 }
2071 }
2072 }
2073
2074 /**
satokd4fce2b2011-04-11 12:07:13 +09002075 * Returns a map of all shortcut input method info and their subtypes.
2076 */
satokf3db1af2010-11-23 13:34:33 +09002077 public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
satok4e4569d2010-11-19 18:45:53 +09002078 synchronized (mH) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002079 HashMap<InputMethodInfo, List<InputMethodSubtype>> ret = new HashMap<>();
satok4e4569d2010-11-19 18:45:53 +09002080 try {
2081 // TODO: We should change the return type from List<Object> to List<Parcelable>
2082 List<Object> info = mService.getShortcutInputMethodsAndSubtypes();
satokf3db1af2010-11-23 13:34:33 +09002083 // "info" has imi1, subtype1, subtype2, imi2, subtype2, imi3, subtype3..in the list
2084 ArrayList<InputMethodSubtype> subtypes = null;
Andreas Gampe4236ad72015-03-17 21:07:21 -07002085 if (info != null && !info.isEmpty()) {
2086 final int N = info.size();
satokf3db1af2010-11-23 13:34:33 +09002087 for (int i = 0; i < N; ++i) {
2088 Object o = info.get(i);
2089 if (o instanceof InputMethodInfo) {
2090 if (ret.containsKey(o)) {
2091 Log.e(TAG, "IMI list already contains the same InputMethod.");
2092 break;
satok4e4569d2010-11-19 18:45:53 +09002093 }
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002094 subtypes = new ArrayList<>();
satokf3db1af2010-11-23 13:34:33 +09002095 ret.put((InputMethodInfo)o, subtypes);
2096 } else if (subtypes != null && o instanceof InputMethodSubtype) {
2097 subtypes.add((InputMethodSubtype)o);
satok4e4569d2010-11-19 18:45:53 +09002098 }
satok4e4569d2010-11-19 18:45:53 +09002099 }
2100 }
2101 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002102 throw e.rethrowFromSystemServer();
satok4e4569d2010-11-19 18:45:53 +09002103 }
2104 return ret;
2105 }
2106 }
satokf3db1af2010-11-23 13:34:33 +09002107
satokd4fce2b2011-04-11 12:07:13 +09002108 /**
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002109 * @return The current height of the input method window.
2110 * @hide
2111 */
2112 public int getInputMethodWindowVisibleHeight() {
2113 synchronized (mH) {
2114 try {
2115 return mService.getInputMethodWindowVisibleHeight();
2116 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002117 throw e.rethrowFromSystemServer();
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002118 }
2119 }
2120 }
2121
2122 /**
satokd4fce2b2011-04-11 12:07:13 +09002123 * Force switch to the last used input method and subtype. If the last input method didn't have
2124 * any subtypes, the framework will simply switch to the last input method with no subtype
2125 * specified.
2126 * @param imeToken Supplies the identifying token given to an input method when it was started,
2127 * which allows it to perform this operation on itself.
2128 * @return true if the current input method and subtype was successfully switched to the last
2129 * used input method and subtype.
2130 */
satok735cf382010-11-11 20:40:09 +09002131 public boolean switchToLastInputMethod(IBinder imeToken) {
2132 synchronized (mH) {
2133 try {
2134 return mService.switchToLastInputMethod(imeToken);
2135 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002136 throw e.rethrowFromSystemServer();
satok735cf382010-11-11 20:40:09 +09002137 }
2138 }
2139 }
2140
satoke7c6998e2011-06-03 17:57:59 +09002141 /**
satok688bd472012-02-09 20:09:17 +09002142 * Force switch to the next input method and subtype. If there is no IME enabled except
2143 * current IME and subtype, do nothing.
2144 * @param imeToken Supplies the identifying token given to an input method when it was started,
2145 * which allows it to perform this operation on itself.
2146 * @param onlyCurrentIme if true, the framework will find the next subtype which
2147 * belongs to the current IME
2148 * @return true if the current input method and subtype was successfully switched to the next
2149 * input method and subtype.
2150 */
2151 public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
2152 synchronized (mH) {
2153 try {
2154 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
2155 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002156 throw e.rethrowFromSystemServer();
satok688bd472012-02-09 20:09:17 +09002157 }
2158 }
2159 }
2160
2161 /**
satok15ab6b02013-08-26 14:17:18 +09002162 * Returns true if the current IME needs to offer the users ways to switch to a next input
2163 * method (e.g. a globe key.).
2164 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
2165 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
2166 * <p> Note that the system determines the most appropriate next input method
2167 * and subtype in order to provide the consistent user experience in switching
2168 * between IMEs and subtypes.
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09002169 * @param imeToken Supplies the identifying token given to an input method when it was started,
2170 * which allows it to perform this operation on itself.
2171 */
2172 public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
2173 synchronized (mH) {
2174 try {
2175 return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
2176 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002177 throw e.rethrowFromSystemServer();
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09002178 }
2179 }
2180 }
2181
2182 /**
satok91e88122011-07-18 11:11:42 +09002183 * Set additional input method subtypes. Only a process which shares the same uid with the IME
2184 * can add additional input method subtypes to the IME.
satok75917b62011-08-31 23:27:39 +09002185 * Please note that a subtype's status is stored in the system.
2186 * For example, enabled subtypes are remembered by the framework even after they are removed
2187 * by using this method. If you re-add the same subtypes again,
2188 * they will just get enabled. If you want to avoid such conflicts, for instance, you may
2189 * want to create a "different" new subtype even with the same locale and mode,
2190 * by changing its extra value. The different subtype won't get affected by the stored past
2191 * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
2192 * to the current implementation.)
Yohei Yukawa70f5c482016-01-04 19:42:36 -08002193 *
2194 * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes
2195 * specified by {@code subtypes}, those multiple instances are automatically merged into one
2196 * instance.</p>
2197 *
2198 * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty
2199 * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing
2200 * the last one entry of additional subtypes. If your IME statically defines one or more
2201 * subtypes in the manifest XML file, you may be able to work around this limitation by
2202 * specifying one of those statically defined subtypes in {@code subtypes}.</p>
2203 *
satok91e88122011-07-18 11:11:42 +09002204 * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
satoke7c6998e2011-06-03 17:57:59 +09002205 * @param subtypes subtypes will be added as additional subtypes of the current input method.
satoke7c6998e2011-06-03 17:57:59 +09002206 */
satokee5e77c2011-09-02 18:50:15 +09002207 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satoke7c6998e2011-06-03 17:57:59 +09002208 synchronized (mH) {
2209 try {
satokee5e77c2011-09-02 18:50:15 +09002210 mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
satoke7c6998e2011-06-03 17:57:59 +09002211 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002212 throw e.rethrowFromSystemServer();
satoke7c6998e2011-06-03 17:57:59 +09002213 }
2214 }
2215 }
2216
satok68f1b782011-04-11 14:26:04 +09002217 public InputMethodSubtype getLastInputMethodSubtype() {
2218 synchronized (mH) {
2219 try {
2220 return mService.getLastInputMethodSubtype();
2221 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002222 throw e.rethrowFromSystemServer();
satok68f1b782011-04-11 14:26:04 +09002223 }
2224 }
2225 }
2226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
2228 final Printer p = new PrintWriterPrinter(fout);
2229 p.println("Input method client state for " + this + ":");
2230
2231 p.println(" mService=" + mService);
2232 p.println(" mMainLooper=" + mMainLooper);
2233 p.println(" mIInputContext=" + mIInputContext);
2234 p.println(" mActive=" + mActive
2235 + " mHasBeenInactive=" + mHasBeenInactive
2236 + " mBindSequence=" + mBindSequence
2237 + " mCurId=" + mCurId);
2238 p.println(" mCurMethod=" + mCurMethod);
Wale Ogunwale159c3d82015-05-14 12:20:53 -07002239 p.println(" mCurRootView=" + mCurRootView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 p.println(" mServedView=" + mServedView);
Dianne Hackborn7663d802012-02-24 13:08:49 -08002241 p.println(" mNextServedView=" + mNextServedView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 p.println(" mServedConnecting=" + mServedConnecting);
2243 if (mCurrentTextBoxAttribute != null) {
2244 p.println(" mCurrentTextBoxAttribute:");
2245 mCurrentTextBoxAttribute.dump(p, " ");
2246 } else {
2247 p.println(" mCurrentTextBoxAttribute: null");
2248 }
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07002249 p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
Andreas Gampee6748ce2015-12-11 18:00:38 -08002250 p.println(" mCompletions=" + Arrays.toString(mCompletions));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 p.println(" mCursorRect=" + mCursorRect);
2252 p.println(" mCursorSelStart=" + mCursorSelStart
2253 + " mCursorSelEnd=" + mCursorSelEnd
2254 + " mCursorCandStart=" + mCursorCandStart
2255 + " mCursorCandEnd=" + mCursorCandEnd);
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002256 p.println(" mNextUserActionNotificationSequenceNumber="
2257 + mNextUserActionNotificationSequenceNumber
2258 + " mLastSentUserActionNotificationSequenceNumber="
2259 + mLastSentUserActionNotificationSequenceNumber);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002260 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002261
2262 /**
2263 * Callback that is invoked when an input event that was dispatched to
2264 * the IME has been finished.
2265 * @hide
2266 */
Jeff Brownf9e989d2013-04-04 23:04:03 -07002267 public interface FinishedInputEventCallback {
2268 public void onFinishedInputEvent(Object token, boolean handled);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002269 }
2270
Jeff Brownc28867a2013-03-26 15:42:39 -07002271 private final class ImeInputEventSender extends InputEventSender {
2272 public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
2273 super(inputChannel, looper);
2274 }
2275
2276 @Override
2277 public void onInputEventFinished(int seq, boolean handled) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07002278 finishedInputEvent(seq, handled, false);
Jeff Brownc28867a2013-03-26 15:42:39 -07002279 }
2280 }
2281
Jeff Brownf9e989d2013-04-04 23:04:03 -07002282 private final class PendingEvent implements Runnable {
2283 public InputEvent mEvent;
2284 public Object mToken;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002285 public String mInputMethodId;
Jeff Brownf9e989d2013-04-04 23:04:03 -07002286 public FinishedInputEventCallback mCallback;
2287 public Handler mHandler;
2288 public boolean mHandled;
2289
2290 public void recycle() {
2291 mEvent = null;
2292 mToken = null;
2293 mInputMethodId = null;
2294 mCallback = null;
2295 mHandler = null;
2296 mHandled = false;
2297 }
2298
2299 @Override
2300 public void run() {
2301 mCallback.onFinishedInputEvent(mToken, mHandled);
2302
2303 synchronized (mH) {
2304 recyclePendingEventLocked(this);
2305 }
2306 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002307 }
Yohei Yukawa5c1e6752016-03-28 01:52:47 -07002308
2309 private static String dumpViewInfo(@Nullable final View view) {
2310 if (view == null) {
2311 return "null";
2312 }
2313 final StringBuilder sb = new StringBuilder();
2314 sb.append(view);
2315 sb.append(",focus=" + view.hasFocus());
2316 sb.append(",windowFocus=" + view.hasWindowFocus());
2317 sb.append(",window=" + view.getWindowToken());
2318 return sb.toString();
2319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002320}