blob: 859df432eb8c1fd55bf551ce3a27baeaeaf6d47f [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 */
320 InputConnection mServedInputConnection;
Dianne Hackbornac920872012-05-22 11:49:49 -0700321 ControlledInputConnectionWrapper mServedInputConnectionWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 /**
323 * The completions that were last provided by the served view.
324 */
325 CompletionInfo[] mCompletions;
326
327 // Cursor position on the screen.
Yohei Yukawaa277db22014-08-21 18:38:44 -0700328 Rect mTmpCursorRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 Rect mCursorRect = new Rect();
330 int mCursorSelStart;
331 int mCursorSelEnd;
332 int mCursorCandStart;
333 int mCursorCandEnd;
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900334
335 /**
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900336 * Represents an invalid action notification sequence number. {@link InputMethodManagerService}
337 * always issues a positive integer for action notification sequence numbers. Thus -1 is
338 * guaranteed to be different from any valid sequence number.
339 */
340 private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
341 /**
342 * The next sequence number that is to be sent to {@link InputMethodManagerService} via
343 * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
344 */
345 private int mNextUserActionNotificationSequenceNumber =
346 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
347
348 /**
349 * The last sequence number that is already sent to {@link InputMethodManagerService}.
350 */
351 private int mLastSentUserActionNotificationSequenceNumber =
352 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
353
354 /**
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900355 * The instance that has previously been sent to the input method.
356 */
357 private CursorAnchorInfo mCursorAnchorInfo = null;
358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 // -----------------------------------------------------------
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 /**
362 * Sequence number of this binding, as returned by the server.
363 */
364 int mBindSequence = -1;
365 /**
366 * ID of the method we are bound to.
367 */
368 String mCurId;
369 /**
370 * The actual instance of the method to make calls on it.
371 */
372 IInputMethodSession mCurMethod;
Jeff Brownc28867a2013-03-26 15:42:39 -0700373 InputChannel mCurChannel;
374 ImeInputEventSender mCurSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Yohei Yukawaa277db22014-08-21 18:38:44 -0700376 private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900377
378 /**
379 * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
380 */
Yohei Yukawaa277db22014-08-21 18:38:44 -0700381 private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawab7b79072014-03-25 11:02:00 +0900382
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700383 final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
384 final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 // -----------------------------------------------------------
387
388 static final int MSG_DUMP = 1;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800389 static final int MSG_BIND = 2;
390 static final int MSG_UNBIND = 3;
391 static final int MSG_SET_ACTIVE = 4;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700392 static final int MSG_SEND_INPUT_EVENT = 5;
393 static final int MSG_TIMEOUT_INPUT_EVENT = 6;
394 static final int MSG_FLUSH_INPUT_EVENT = 7;
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900395 static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 class H extends Handler {
398 H(Looper looper) {
Jeff Brown29c0ed22013-01-14 13:50:37 -0800399 super(looper, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 }
401
402 @Override
403 public void handleMessage(Message msg) {
404 switch (msg.what) {
405 case MSG_DUMP: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700406 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 try {
408 doDump((FileDescriptor)args.arg1,
409 (PrintWriter)args.arg2, (String[])args.arg3);
410 } catch (RuntimeException e) {
411 ((PrintWriter)args.arg2).println("Exception: " + e);
412 }
413 synchronized (args.arg4) {
414 ((CountDownLatch)args.arg4).countDown();
415 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700416 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 return;
418 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800419 case MSG_BIND: {
420 final InputBindResult res = (InputBindResult)msg.obj;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900421 if (DEBUG) {
422 Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
423 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800424 synchronized (mH) {
425 if (mBindSequence < 0 || mBindSequence != res.sequence) {
426 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
427 + ", given seq=" + res.sequence);
Jeff Brown4d656882013-04-03 14:39:19 -0700428 if (res.channel != null && res.channel != mCurChannel) {
Jeff Brownc28867a2013-03-26 15:42:39 -0700429 res.channel.dispose();
430 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800431 return;
432 }
Jeff Brown4d656882013-04-03 14:39:19 -0700433
Yohei Yukawaa277db22014-08-21 18:38:44 -0700434 mRequestUpdateCursorAnchorInfoMonitorMode =
435 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900436
Jeff Brown4d656882013-04-03 14:39:19 -0700437 setInputChannelLocked(res.channel);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800438 mCurMethod = res.method;
439 mCurId = res.id;
440 mBindSequence = res.sequence;
441 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800442 startInputInner(InputMethodClient.START_INPUT_REASON_BOUND_TO_IMMS,
443 null, 0, 0, 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800444 return;
445 }
446 case MSG_UNBIND: {
447 final int sequence = msg.arg1;
Yohei Yukawa33e81792015-11-17 21:14:42 -0800448 @InputMethodClient.UnbindReason
449 final int reason = msg.arg2;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900450 if (DEBUG) {
Yohei Yukawa33e81792015-11-17 21:14:42 -0800451 Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence +
452 " reason=" + InputMethodClient.getUnbindReason(reason));
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900453 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800454 final boolean startInput;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800455 synchronized (mH) {
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800456 if (mBindSequence != sequence) {
457 return;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800458 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800459 clearBindingLocked();
460 // If we were actively using the last input method, then
461 // we would like to re-connect to the next input method.
462 if (mServedView != null && mServedView.isFocused()) {
463 mServedConnecting = true;
464 }
465 startInput = mActive;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800466 }
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800467 if (startInput) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800468 startInputInner(
469 InputMethodClient.START_INPUT_REASON_UNBOUND_FROM_IMMS, null, 0, 0,
470 0);
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800471 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800472 return;
473 }
474 case MSG_SET_ACTIVE: {
475 final boolean active = msg.arg1 != 0;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900476 if (DEBUG) {
477 Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
478 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800479 synchronized (mH) {
480 mActive = active;
481 mFullscreenMode = false;
482 if (!active) {
483 // Some other client has starting using the IME, so note
484 // that this happened and make sure our own editor's
485 // state is reset.
486 mHasBeenInactive = true;
487 try {
488 // Note that finishComposingText() is allowed to run
489 // even when we are not active.
490 mIInputContext.finishComposingText();
491 } catch (RemoteException e) {
492 }
Mikael Gullstrand82ae3ff2014-11-25 12:41:53 +0100493 }
494 // Check focus again in case that "onWindowFocus" is called before
495 // handling this message.
496 if (mServedView != null && mServedView.hasWindowFocus()) {
497 // Please note that this handler thread could be different
498 // from a thread that created mServedView. That could happen
499 // the current activity is running in the system process.
500 // In that case, we really should not call
501 // mServedInputConnection.finishComposingText.
502 if (checkFocusNoStartInput(mHasBeenInactive, false)) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800503 final int reason = active ?
504 InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
505 InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS;
506 startInputInner(reason, null, 0, 0, 0);
satok05a6cbe2012-04-05 23:04:08 +0900507 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800508 }
509 }
510 return;
511 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700512 case MSG_SEND_INPUT_EVENT: {
513 sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
514 return;
515 }
516 case MSG_TIMEOUT_INPUT_EVENT: {
517 finishedInputEvent(msg.arg1, false, true);
518 return;
519 }
520 case MSG_FLUSH_INPUT_EVENT: {
521 finishedInputEvent(msg.arg1, false, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700522 return;
523 }
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900524 case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
525 synchronized (mH) {
526 mNextUserActionNotificationSequenceNumber = msg.arg1;
527 }
528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 }
530 }
531 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800532
Jean Chalardde9dbb02011-10-20 19:50:45 +0900533 private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
534 private final InputMethodManager mParentInputMethodManager;
Dianne Hackbornac920872012-05-22 11:49:49 -0700535 private boolean mActive;
Jean Chalardde9dbb02011-10-20 19:50:45 +0900536
537 public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
538 final InputMethodManager inputMethodManager) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 super(mainLooper, conn);
Jean Chalardde9dbb02011-10-20 19:50:45 +0900540 mParentInputMethodManager = inputMethodManager;
Dianne Hackbornac920872012-05-22 11:49:49 -0700541 mActive = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
543
Gilles Debunne8cbb4c62011-01-24 12:33:56 -0800544 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 public boolean isActive() {
Dianne Hackbornac920872012-05-22 11:49:49 -0700546 return mParentInputMethodManager.mActive && mActive;
547 }
548
549 void deactivate() {
550 mActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 }
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800552
553 @Override
Yohei Yukawa159dd472016-01-07 16:52:33 -0800554 protected void onUserAction() {
555 mParentInputMethodManager.notifyUserAction();
556 }
557
558 @Override
559 protected void onReportFullscreenMode(boolean enabled) {
560 mParentInputMethodManager.setFullscreenMode(enabled);
561 }
562
563 @Override
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800564 public String toString() {
565 return "ControlledInputConnectionWrapper{mActive=" + mActive
566 + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
567 + "}";
568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
Jeff Brownc28867a2013-03-26 15:42:39 -0700572 @Override
573 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 // No need to check for dump permission, since we only give this
575 // interface to the system.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 CountDownLatch latch = new CountDownLatch(1);
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700577 SomeArgs sargs = SomeArgs.obtain();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 sargs.arg1 = fd;
579 sargs.arg2 = fout;
580 sargs.arg3 = args;
581 sargs.arg4 = latch;
582 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
583 try {
584 if (!latch.await(5, TimeUnit.SECONDS)) {
585 fout.println("Timeout waiting for dump");
586 }
587 } catch (InterruptedException e) {
588 fout.println("Interrupted waiting for dump");
589 }
590 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700591
592 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 public void setUsingInputMethod(boolean state) {
594 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700595
596 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 public void onBindMethod(InputBindResult res) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800598 mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700600
601 @Override
Yohei Yukawa33e81792015-11-17 21:14:42 -0800602 public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) {
603 mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, unbindReason));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700605
606 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 public void setActive(boolean active) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800608 mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
Yohei Yukawab7b79072014-03-25 11:02:00 +0900610
611 @Override
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900612 public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
613 mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
614 sequenceNumber, 0));
615 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700616 };
617
Dianne Hackborn51bf0772009-03-24 19:11:41 -0700618 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 InputMethodManager(IInputMethodManager service, Looper looper) {
621 mService = service;
622 mMainLooper = looper;
623 mH = new H(looper);
624 mIInputContext = new ControlledInputConnectionWrapper(looper,
Jean Chalardde9dbb02011-10-20 19:50:45 +0900625 mDummyInputConnection, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 }
627
628 /**
629 * Retrieve the global InputMethodManager instance, creating it if it
630 * doesn't already exist.
631 * @hide
632 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700633 public static InputMethodManager getInstance() {
634 synchronized (InputMethodManager.class) {
635 if (sInstance == null) {
636 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
637 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
638 sInstance = new InputMethodManager(service, Looper.getMainLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700640 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 }
643
644 /**
645 * Private optimization: retrieve the global InputMethodManager instance,
646 * if it exists.
647 * @hide
648 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700649 public static InputMethodManager peekInstance() {
650 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 }
652
653 /** @hide */
654 public IInputMethodClient getClient() {
655 return mClient;
656 }
657
658 /** @hide */
659 public IInputContext getInputContext() {
660 return mIInputContext;
661 }
662
663 public List<InputMethodInfo> getInputMethodList() {
664 try {
665 return mService.getInputMethodList();
666 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700667 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 }
669 }
670
671 public List<InputMethodInfo> getEnabledInputMethodList() {
672 try {
673 return mService.getEnabledInputMethodList();
674 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700675 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
677 }
678
satokd4fce2b2011-04-11 12:07:13 +0900679 /**
680 * Returns a list of enabled input method subtypes for the specified input method info.
681 * @param imi An input method info whose subtypes list will be returned.
682 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
683 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
684 * will implicitly enable subtypes according to the current system language.
685 */
satok16331c82010-12-20 23:48:46 +0900686 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
687 boolean allowsImplicitlySelectedSubtypes) {
satok67ddf9c2010-11-17 09:45:54 +0900688 try {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +0900689 return mService.getEnabledInputMethodSubtypeList(
690 imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +0900691 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700692 throw e.rethrowFromSystemServer();
satok67ddf9c2010-11-17 09:45:54 +0900693 }
694 }
695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
697 try {
698 mService.updateStatusIcon(imeToken, packageName, iconId);
699 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700700 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 }
702 }
703
704 public void hideStatusIcon(IBinder imeToken) {
705 try {
706 mService.updateStatusIcon(imeToken, null, 0);
707 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700708 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 }
710 }
711
712 /** @hide */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800713 public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
satok06487a52010-10-29 11:37:18 +0900714 try {
Joe Onorato857fd9b2011-01-27 15:08:35 -0800715 mService.setImeWindowStatus(imeToken, vis, backDisposition);
satok06487a52010-10-29 11:37:18 +0900716 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700717 throw e.rethrowFromSystemServer();
satok06487a52010-10-29 11:37:18 +0900718 }
719 }
720
721 /** @hide */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 public void setFullscreenMode(boolean fullScreen) {
723 mFullscreenMode = fullScreen;
724 }
satokf9f01002011-05-19 21:31:50 +0900725
726 /** @hide */
727 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
728 try {
729 mService.registerSuggestionSpansForNotification(spans);
730 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700731 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900732 }
733 }
734
735 /** @hide */
736 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
737 try {
738 mService.notifySuggestionPicked(span, originalString, index);
739 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700740 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900741 }
742 }
743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 /**
745 * Allows you to discover whether the attached input method is running
746 * in fullscreen mode. Return true if it is fullscreen, entirely covering
747 * your UI, else returns false.
748 */
749 public boolean isFullscreenMode() {
750 return mFullscreenMode;
751 }
752
753 /**
754 * Return true if the given view is the currently active view for the
755 * input method.
756 */
757 public boolean isActive(View view) {
758 checkFocus();
759 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700760 return (mServedView == view
761 || (mServedView != null
762 && mServedView.checkInputConnectionProxy(view)))
763 && mCurrentTextBoxAttribute != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765 }
766
767 /**
768 * Return true if any view is currently active in the input method.
769 */
770 public boolean isActive() {
771 checkFocus();
772 synchronized (mH) {
773 return mServedView != null && mCurrentTextBoxAttribute != null;
774 }
775 }
776
777 /**
778 * Return true if the currently served view is accepting full text edits.
779 * If false, it has no input connection, so can only handle raw key events.
780 */
781 public boolean isAcceptingText() {
782 checkFocus();
783 return mServedInputConnection != null;
784 }
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;
818 mServedInputConnection = null;
Dianne Hackbornac920872012-05-22 11:49:49 -0700819 if (mServedInputConnectionWrapper != null) {
820 mServedInputConnectionWrapper.deactivate();
821 mServedInputConnectionWrapper = null;
822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
Yohei Yukawa0f3a99d2015-05-21 00:15:05 -0700824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 /**
826 * Disconnect any existing input connection, clearing the served view.
827 */
828 void finishInputLocked() {
829 mNextServedView = null;
830 if (mServedView != null) {
831 if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 if (mCurrentTextBoxAttribute != null) {
833 try {
834 mService.finishInput(mClient);
835 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700836 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838 }
Gilles Debunnec478c172011-12-19 17:29:24 -0800839 notifyInputConnectionFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 mServedView = null;
841 mCompletions = null;
842 mServedConnecting = false;
843 clearConnectionLocked();
844 }
845 }
Gilles Debunnec478c172011-12-19 17:29:24 -0800846
847 /**
848 * Notifies the served view that the current InputConnection will no longer be used.
849 */
850 private void notifyInputConnectionFinished() {
851 if (mServedView != null && mServedInputConnection != null) {
852 // We need to tell the previously served view that it is no
853 // longer the input target, so it can reset its state. Schedule
854 // this call on its window's Handler so it will be on the correct
855 // thread and outside of our lock.
Jeff Browna175a5b2012-02-15 19:18:31 -0800856 ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
857 if (viewRootImpl != null) {
Gilles Debunnec478c172011-12-19 17:29:24 -0800858 // This will result in a call to reportFinishInputConnection() below.
Jeff Browna175a5b2012-02-15 19:18:31 -0800859 viewRootImpl.dispatchFinishInputConnection(mServedInputConnection);
Gilles Debunnec478c172011-12-19 17:29:24 -0800860 }
861 }
862 }
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 /**
865 * Called from the FINISH_INPUT_CONNECTION message above.
866 * @hide
867 */
868 public void reportFinishInputConnection(InputConnection ic) {
869 if (mServedInputConnection != ic) {
870 ic.finishComposingText();
Gilles Debunne9d69ecb2012-02-24 16:07:09 -0800871 // To avoid modifying the public InputConnection interface
872 if (ic instanceof BaseInputConnection) {
873 ((BaseInputConnection) ic).reportFinish();
874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876 }
Gilles Debunnec478c172011-12-19 17:29:24 -0800877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 public void displayCompletions(View view, CompletionInfo[] completions) {
879 checkFocus();
880 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700881 if (mServedView != view && (mServedView == null
882 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return;
884 }
885
886 mCompletions = completions;
887 if (mCurMethod != null) {
888 try {
889 mCurMethod.displayCompletions(mCompletions);
890 } catch (RemoteException e) {
891 }
892 }
893 }
894 }
895
896 public void updateExtractedText(View view, int token, ExtractedText text) {
897 checkFocus();
898 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700899 if (mServedView != view && (mServedView == null
900 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 return;
902 }
903
904 if (mCurMethod != null) {
905 try {
906 mCurMethod.updateExtractedText(token, text);
907 } catch (RemoteException e) {
908 }
909 }
910 }
911 }
912
913 /**
914 * Flag for {@link #showSoftInput} to indicate that this is an implicit
915 * request to show the input window, not as the result of a direct request
916 * by the user. The window may not be shown in this case.
917 */
918 public static final int SHOW_IMPLICIT = 0x0001;
919
920 /**
921 * Flag for {@link #showSoftInput} to indicate that the user has forced
922 * the input method open (such as by long-pressing menu) so it should
923 * not be closed until they explicitly do so.
924 */
925 public static final int SHOW_FORCED = 0x0002;
926
927 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800928 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
929 * a result receiver: explicitly request that the current input method's
930 * soft input area be shown to the user, if needed.
931 *
932 * @param view The currently focused view, which would like to receive
933 * soft keyboard input.
934 * @param flags Provides additional operating flags. Currently may be
935 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
936 */
937 public boolean showSoftInput(View view, int flags) {
938 return showSoftInput(view, flags, null);
939 }
940
941 /**
942 * Flag for the {@link ResultReceiver} result code from
943 * {@link #showSoftInput(View, int, ResultReceiver)} and
944 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
945 * state of the soft input window was unchanged and remains shown.
946 */
947 public static final int RESULT_UNCHANGED_SHOWN = 0;
948
949 /**
950 * Flag for the {@link ResultReceiver} result code from
951 * {@link #showSoftInput(View, int, ResultReceiver)} and
952 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
953 * state of the soft input window was unchanged and remains hidden.
954 */
955 public static final int RESULT_UNCHANGED_HIDDEN = 1;
956
957 /**
958 * Flag for the {@link ResultReceiver} result code from
959 * {@link #showSoftInput(View, int, ResultReceiver)} and
960 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
961 * state of the soft input window changed from hidden to shown.
962 */
963 public static final int RESULT_SHOWN = 2;
964
965 /**
966 * Flag for the {@link ResultReceiver} result code from
967 * {@link #showSoftInput(View, int, ResultReceiver)} and
968 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
969 * state of the soft input window changed from shown to hidden.
970 */
971 public static final int RESULT_HIDDEN = 3;
972
973 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 * Explicitly request that the current input method's soft input area be
975 * shown to the user, if needed. Call this if the user interacts with
976 * your view in such a way that they have expressed they would like to
977 * start performing input into it.
978 *
979 * @param view The currently focused view, which would like to receive
980 * soft keyboard input.
981 * @param flags Provides additional operating flags. Currently may be
982 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -0800983 * @param resultReceiver If non-null, this will be called by the IME when
984 * it has processed your request to tell you what it has done. The result
985 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
986 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
987 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 */
Gilles Debunnead8484b2011-02-17 17:37:51 -0800989 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 checkFocus();
991 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700992 if (mServedView != view && (mServedView == null
993 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800994 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
997 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800998 return mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001000 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 }
1002 }
1003 }
1004
1005 /** @hide */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001006 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001008 mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001010 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
1012 }
1013
1014 /**
1015 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
1016 * input window should only be hidden if it was not explicitly shown
1017 * by the user.
1018 */
1019 public static final int HIDE_IMPLICIT_ONLY = 0x0001;
1020
1021 /**
1022 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
1023 * input window should normally be hidden, unless it was originally
1024 * shown with {@link #SHOW_FORCED}.
1025 */
1026 public static final int HIDE_NOT_ALWAYS = 0x0002;
Gilles Debunnec478c172011-12-19 17:29:24 -08001027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 /**
Gilles Debunne7c8c6d62011-01-24 14:48:14 -08001029 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
The Android Open Source Project4df24232009-03-05 14:34:35 -08001030 * without a result: request to hide the soft input window from the
1031 * context of the window that is currently accepting input.
1032 *
1033 * @param windowToken The token of the window that is making the request,
1034 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1035 * @param flags Provides additional operating flags. Currently may be
1036 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
1037 */
1038 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
1039 return hideSoftInputFromWindow(windowToken, flags, null);
1040 }
1041
1042 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 * Request to hide the soft input window from the context of the window
1044 * that is currently accepting input. This should be called as a result
1045 * of the user doing some actually than fairly explicitly requests to
1046 * have the input window hidden.
1047 *
1048 * @param windowToken The token of the window that is making the request,
1049 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1050 * @param flags Provides additional operating flags. Currently may be
1051 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -08001052 * @param resultReceiver If non-null, this will be called by the IME when
1053 * it has processed your request to tell you what it has done. The result
1054 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
1055 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
1056 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001058 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
1059 ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 checkFocus();
1061 synchronized (mH) {
1062 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001063 return false;
1064 }
1065
1066 try {
1067 return mService.hideSoftInput(mClient, flags, resultReceiver);
1068 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001069 throw e.rethrowFromSystemServer();
The Android Open Source Project4df24232009-03-05 14:34:35 -08001070 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001071 }
1072 }
1073
1074
1075 /**
1076 * This method toggles the input method window display.
1077 * If the input window is already displayed, it gets hidden.
1078 * If not the input window will be displayed.
1079 * @param windowToken The token of the window that is making the request,
1080 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1081 * @param showFlags Provides additional operating flags. May be
1082 * 0 or have the {@link #SHOW_IMPLICIT},
1083 * {@link #SHOW_FORCED} bit set.
1084 * @param hideFlags Provides additional operating flags. May be
1085 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1086 * {@link #HIDE_NOT_ALWAYS} bit set.
1087 **/
1088 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
1089 synchronized (mH) {
1090 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 return;
1092 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001093 if (mCurMethod != null) {
1094 try {
1095 mCurMethod.toggleSoftInput(showFlags, hideFlags);
1096 } catch (RemoteException e) {
1097 }
1098 }
1099 }
1100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101
The Android Open Source Project4df24232009-03-05 14:34:35 -08001102 /*
1103 * This method toggles the input method window display.
1104 * If the input window is already displayed, it gets hidden.
1105 * If not the input window will be displayed.
1106 * @param showFlags Provides additional operating flags. May be
1107 * 0 or have the {@link #SHOW_IMPLICIT},
1108 * {@link #SHOW_FORCED} bit set.
1109 * @param hideFlags Provides additional operating flags. May be
1110 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1111 * {@link #HIDE_NOT_ALWAYS} bit set.
1112 * @hide
1113 */
1114 public void toggleSoftInput(int showFlags, int hideFlags) {
1115 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001117 mCurMethod.toggleSoftInput(showFlags, hideFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 } catch (RemoteException e) {
1119 }
1120 }
1121 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 /**
1124 * If the input method is currently connected to the given view,
1125 * restart it with its new contents. You should call this when the text
1126 * within your view changes outside of the normal input method or key
1127 * input flow, such as when an application calls TextView.setText().
1128 *
1129 * @param view The view whose text has changed.
1130 */
1131 public void restartInput(View view) {
1132 checkFocus();
1133 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001134 if (mServedView != view && (mServedView == null
1135 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 return;
1137 }
1138
1139 mServedConnecting = true;
1140 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001141
1142 startInputInner(InputMethodClient.START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, null, 0,
1143 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001145
1146 boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
1147 IBinder windowGainingFocus, int controlFlags, int softInputMode,
Dianne Hackborn7663d802012-02-24 13:08:49 -08001148 int windowFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 final View view;
1150 synchronized (mH) {
1151 view = mServedView;
1152
1153 // Make sure we have a window token for the served view.
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001154 if (DEBUG) {
1155 Log.v(TAG, "Starting input: view=" + view +
1156 " reason=" + InputMethodClient.getStartInputReason(startInputReason));
1157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 if (view == null) {
1159 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
Dianne Hackborn7663d802012-02-24 13:08:49 -08001160 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162 }
1163
1164 // Now we need to get an input connection from the served view.
1165 // This is complicated in a couple ways: we can't be holding our lock
1166 // when calling out to the view, and we need to make sure we call into
1167 // the view on the same thread that is driving its view hierarchy.
1168 Handler vh = view.getHandler();
1169 if (vh == null) {
1170 // If the view doesn't have a handler, something has changed out
Satoshi Kataoka35739502012-10-02 19:00:26 +09001171 // from under us, so just close the current input.
1172 // If we don't close the current input, the current input method can remain on the
1173 // screen without a connection.
1174 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");
1175 closeCurrentInput();
Dianne Hackborn7663d802012-02-24 13:08:49 -08001176 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 }
1178 if (vh.getLooper() != Looper.myLooper()) {
1179 // The view is running on a different thread than our own, so
1180 // we need to reschedule our work for over there.
1181 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
1182 vh.post(new Runnable() {
Jeff Brownc28867a2013-03-26 15:42:39 -07001183 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 public void run() {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001185 startInputInner(startInputReason, null, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 }
1187 });
Dianne Hackborn7663d802012-02-24 13:08:49 -08001188 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
1190
1191 // Okay we are now ready to call into the served view and have it
1192 // do its stuff.
1193 // Life is good: let's hook everything up!
1194 EditorInfo tba = new EditorInfo();
Yohei Yukawa02df3282015-06-03 15:58:59 -07001195 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
1196 // system can verify the consistency between the uid of this process and package name passed
1197 // from here. See comment of Context#getOpPackageName() for details.
1198 tba.packageName = view.getContext().getOpPackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 tba.fieldId = view.getId();
1200 InputConnection ic = view.onCreateInputConnection(tba);
1201 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
Gilles Debunnec478c172011-12-19 17:29:24 -08001202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 synchronized (mH) {
1204 // Now that we are locked again, validate that our state hasn't
1205 // changed.
1206 if (mServedView != view || !mServedConnecting) {
1207 // Something else happened, so abort.
1208 if (DEBUG) Log.v(TAG,
1209 "Starting input: finished by someone else (view="
1210 + mServedView + " conn=" + mServedConnecting + ")");
Dianne Hackborn7663d802012-02-24 13:08:49 -08001211 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 // If we already have a text box, then this view is already
1215 // connected so we want to restart it.
Dianne Hackborn7663d802012-02-24 13:08:49 -08001216 if (mCurrentTextBoxAttribute == null) {
1217 controlFlags |= CONTROL_START_INITIAL;
1218 }
Yohei Yukawa612cce92016-02-11 17:47:33 -08001219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 // Hook 'em up and let 'er rip.
1221 mCurrentTextBoxAttribute = tba;
1222 mServedConnecting = false;
Gilles Debunnec478c172011-12-19 17:29:24 -08001223 // Notify the served view that its previous input connection is finished
1224 notifyInputConnectionFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 mServedInputConnection = ic;
Dianne Hackbornac920872012-05-22 11:49:49 -07001226 ControlledInputConnectionWrapper servedContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 if (ic != null) {
1228 mCursorSelStart = tba.initialSelStart;
1229 mCursorSelEnd = tba.initialSelEnd;
1230 mCursorCandStart = -1;
1231 mCursorCandEnd = -1;
1232 mCursorRect.setEmpty();
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001233 mCursorAnchorInfo = null;
Yohei Yukawa612cce92016-02-11 17:47:33 -08001234 final Handler icHandler = ic.getHandler();
1235 servedContext = new ControlledInputConnectionWrapper(
1236 icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 } else {
1238 servedContext = null;
1239 }
Dianne Hackbornac920872012-05-22 11:49:49 -07001240 if (mServedInputConnectionWrapper != null) {
1241 mServedInputConnectionWrapper.deactivate();
1242 }
1243 mServedInputConnectionWrapper = servedContext;
Yohei Yukawa612cce92016-02-11 17:47:33 -08001244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 try {
1246 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
Dianne Hackborn7663d802012-02-24 13:08:49 -08001247 + ic + " tba=" + tba + " controlFlags=#"
1248 + Integer.toHexString(controlFlags));
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001249 final InputBindResult res = mService.startInputOrWindowGainedFocus(
1250 startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
1251 windowFlags, tba, servedContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
1253 if (res != null) {
1254 if (res.id != null) {
Jeff Brown4d656882013-04-03 14:39:19 -07001255 setInputChannelLocked(res.channel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 mBindSequence = res.sequence;
1257 mCurMethod = res.method;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001258 mCurId = res.id;
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09001259 mNextUserActionNotificationSequenceNumber =
1260 res.userActionNotificationSequenceNumber;
Jeff Brownc28867a2013-03-26 15:42:39 -07001261 } else {
Jeff Brown4d656882013-04-03 14:39:19 -07001262 if (res.channel != null && res.channel != mCurChannel) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001263 res.channel.dispose();
1264 }
1265 if (mCurMethod == null) {
1266 // This means there is no input method available.
1267 if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
1268 return true;
1269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 }
1271 }
1272 if (mCurMethod != null && mCompletions != null) {
1273 try {
1274 mCurMethod.displayCompletions(mCompletions);
1275 } catch (RemoteException e) {
1276 }
1277 }
1278 } catch (RemoteException e) {
1279 Log.w(TAG, "IME died: " + mCurId, e);
1280 }
1281 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001282
1283 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 }
1285
1286 /**
1287 * When the focused window is dismissed, this method is called to finish the
1288 * input method started before.
1289 * @hide
1290 */
1291 public void windowDismissed(IBinder appWindowToken) {
1292 checkFocus();
1293 synchronized (mH) {
1294 if (mServedView != null &&
1295 mServedView.getWindowToken() == appWindowToken) {
1296 finishInputLocked();
1297 }
1298 }
1299 }
1300
1301 /**
1302 * Call this when a view receives focus.
1303 * @hide
1304 */
1305 public void focusIn(View view) {
1306 synchronized (mH) {
1307 focusInLocked(view);
1308 }
1309 }
1310
1311 void focusInLocked(View view) {
1312 if (DEBUG) Log.v(TAG, "focusIn: " + view);
Yohei Yukawa5f059652015-05-14 22:16:41 -07001313
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001314 if (mCurRootView != view.getRootView()) {
1315 // This is a request from a window that isn't in the window with
1316 // IME focus, so ignore it.
1317 if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 return;
1319 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 mNextServedView = view;
1322 scheduleCheckFocusLocked(view);
1323 }
1324
1325 /**
1326 * Call this when a view loses focus.
1327 * @hide
1328 */
1329 public void focusOut(View view) {
1330 synchronized (mH) {
1331 if (DEBUG) Log.v(TAG, "focusOut: " + view
1332 + " mServedView=" + mServedView
1333 + " winFocus=" + view.hasWindowFocus());
Yohei Yukawa0b52ed02015-05-29 11:07:02 -07001334 if (mServedView != view) {
1335 // The following code would auto-hide the IME if we end up
1336 // with no more views with focus. This can happen, however,
1337 // whenever we go into touch mode, so it ends up hiding
1338 // at times when we don't really want it to. For now it
1339 // seems better to just turn it all off.
1340 if (false && view.hasWindowFocus()) {
1341 mNextServedView = null;
1342 scheduleCheckFocusLocked(view);
1343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
1345 }
1346 }
1347
Yohei Yukawab13f0152015-05-29 17:09:14 -07001348 /**
1349 * Call this when a view is being detached from a {@link android.view.Window}.
1350 * @hide
1351 */
1352 public void onViewDetachedFromWindow(View view) {
1353 synchronized (mH) {
1354 if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: " + view
1355 + " mServedView=" + mServedView
1356 + " hasWindowFocus=" + view.hasWindowFocus());
1357 if (mServedView == view && view.hasWindowFocus()) {
1358 mNextServedView = null;
1359 scheduleCheckFocusLocked(view);
1360 }
1361 }
1362 }
1363
Gilles Debunnec478c172011-12-19 17:29:24 -08001364 static void scheduleCheckFocusLocked(View view) {
Jeff Browna175a5b2012-02-15 19:18:31 -08001365 ViewRootImpl viewRootImpl = view.getViewRootImpl();
1366 if (viewRootImpl != null) {
1367 viewRootImpl.dispatchCheckFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 }
1369 }
Jeff Browna175a5b2012-02-15 19:18:31 -08001370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 /**
1372 * @hide
1373 */
1374 public void checkFocus() {
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001375 if (checkFocusNoStartInput(false, true)) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001376 startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001377 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001378 }
1379
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001380 private boolean checkFocusNoStartInput(boolean forceNewFocus, boolean finishComposingText) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 // This is called a lot, so short-circuit before locking.
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 }
satok863fcd62011-06-21 17:38:02 +09001385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 InputConnection ic = null;
1387 synchronized (mH) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001388 if (mServedView == mNextServedView && !forceNewFocus) {
Dianne Hackborna82ba542012-02-15 18:19:55 -08001389 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 }
1391 if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
1392 + " next=" + mNextServedView
satok05a6cbe2012-04-05 23:04:08 +09001393 + " forceNewFocus=" + forceNewFocus
1394 + " package="
1395 + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));
Dianne Hackborna82ba542012-02-15 18:19:55 -08001396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 if (mNextServedView == null) {
1398 finishInputLocked();
1399 // In this case, we used to have a focused view on the window,
1400 // but no longer do. We should make sure the input method is
1401 // no longer shown, since it serves no purpose.
1402 closeCurrentInput();
Dianne Hackborna82ba542012-02-15 18:19:55 -08001403 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 ic = mServedInputConnection;
Dianne Hackborna82ba542012-02-15 18:19:55 -08001407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mServedView = mNextServedView;
1409 mCurrentTextBoxAttribute = null;
1410 mCompletions = null;
1411 mServedConnecting = true;
1412 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001413
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001414 if (finishComposingText && ic != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 ic.finishComposingText();
1416 }
Dianne Hackborna82ba542012-02-15 18:19:55 -08001417
1418 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 }
1420
1421 void closeCurrentInput() {
1422 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001423 mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001425 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 }
1427 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 /**
Joe Onoratoc6cc0f82011-04-12 11:53:13 -07001430 * Called by ViewAncestor when its window gets input focus.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 * @hide
1432 */
Yohei Yukawa5f059652015-05-14 22:16:41 -07001433 public void onPostWindowFocus(View rootView, View focusedView, int softInputMode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 boolean first, int windowFlags) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001435 boolean forceNewFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 synchronized (mH) {
1437 if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
1438 + " softInputMode=" + softInputMode
1439 + " first=" + first + " flags=#"
1440 + Integer.toHexString(windowFlags));
1441 if (mHasBeenInactive) {
1442 if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh");
1443 mHasBeenInactive = false;
Dianne Hackborn7663d802012-02-24 13:08:49 -08001444 forceNewFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 }
1446 focusInLocked(focusedView != null ? focusedView : rootView);
1447 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001448
1449 int controlFlags = 0;
1450 if (focusedView != null) {
1451 controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
1452 if (focusedView.onCheckIsTextEditor()) {
1453 controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 }
1455 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001456 if (first) {
1457 controlFlags |= CONTROL_WINDOW_FIRST;
1458 }
1459
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +09001460 if (checkFocusNoStartInput(forceNewFocus, true)) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001461 // We need to restart input on the current focus view. This
1462 // should be done in conjunction with telling the system service
1463 // about the window gaining focus, to help make the transition
1464 // smooth.
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001465 if (startInputInner(InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN,
1466 rootView.getWindowToken(), controlFlags, softInputMode, windowFlags)) {
Dianne Hackborn7663d802012-02-24 13:08:49 -08001467 return;
1468 }
1469 }
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001470
Dianne Hackborn7663d802012-02-24 13:08:49 -08001471 // For some reason we didn't do a startInput + windowFocusGain, so
1472 // we'll just do a window focus gain and call it a day.
1473 synchronized (mH) {
1474 try {
Dianne Hackbornac920872012-05-22 11:49:49 -07001475 if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
Yohei Yukawa05c25f82016-02-22 12:41:17 -08001476 mService.startInputOrWindowGainedFocus(
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001477 InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
1478 rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
1479 null);
Dianne Hackborn7663d802012-02-24 13:08:49 -08001480 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001481 throw e.rethrowFromSystemServer();
Dianne Hackborn7663d802012-02-24 13:08:49 -08001482 }
Dianne Hackborn06a591c2012-02-16 10:25:26 -08001483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001485
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001486 /** @hide */
Yohei Yukawa5f059652015-05-14 22:16:41 -07001487 public void onPreWindowFocus(View rootView, boolean hasWindowFocus) {
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001488 synchronized (mH) {
Yohei Yukawa5f059652015-05-14 22:16:41 -07001489 if (rootView == null) {
1490 mCurRootView = null;
1491 } if (hasWindowFocus) {
1492 mCurRootView = rootView;
1493 } else if (rootView == mCurRootView) {
1494 // If the mCurRootView is losing window focus, release the strong reference to it
1495 // so as not to prevent it from being garbage-collected.
1496 mCurRootView = null;
1497 } else {
1498 if (DEBUG) {
1499 Log.v(TAG, "Ignoring onPreWindowFocus()."
1500 + " mCurRootView=" + mCurRootView + " rootView=" + rootView);
1501 }
1502 }
Wale Ogunwale159c3d82015-05-14 12:20:53 -07001503 }
1504 }
Yohei Yukawa5f059652015-05-14 22:16:41 -07001505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 /**
1507 * Report the current selection range.
Jean Chalard6fd68e02014-02-20 17:48:46 +09001508 *
1509 * <p><strong>Editor authors</strong>, you need to call this method whenever
1510 * the cursor moves in your editor. Remember that in addition to doing this, your
1511 * editor needs to always supply current cursor values in
1512 * {@link EditorInfo#initialSelStart} and {@link EditorInfo#initialSelEnd} every
1513 * time {@link android.view.View#onCreateInputConnection(EditorInfo)} is
1514 * called, which happens whenever the keyboard shows up or the focus changes
1515 * to a text field, among other cases.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 */
1517 public void updateSelection(View view, int selStart, int selEnd,
1518 int candidatesStart, int candidatesEnd) {
1519 checkFocus();
1520 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001521 if ((mServedView != view && (mServedView == null
1522 || !mServedView.checkInputConnectionProxy(view)))
1523 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 return;
1525 }
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
1528 || mCursorCandStart != candidatesStart
1529 || mCursorCandEnd != candidatesEnd) {
1530 if (DEBUG) Log.d(TAG, "updateSelection");
1531
1532 try {
1533 if (DEBUG) Log.v(TAG, "SELECTION CHANGE: " + mCurMethod);
Jean Chalardc743cb92013-09-12 16:28:45 +09001534 final int oldSelStart = mCursorSelStart;
1535 final int oldSelEnd = mCursorSelEnd;
1536 // Update internal values before sending updateSelection to the IME, because
1537 // if it changes the text within its onUpdateSelection handler in a way that
1538 // 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 -08001539 mCursorSelStart = selStart;
1540 mCursorSelEnd = selEnd;
1541 mCursorCandStart = candidatesStart;
1542 mCursorCandEnd = candidatesEnd;
Jean Chalardc743cb92013-09-12 16:28:45 +09001543 mCurMethod.updateSelection(oldSelStart, oldSelEnd,
1544 selStart, selEnd, candidatesStart, candidatesEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 } catch (RemoteException e) {
1546 Log.w(TAG, "IME died: " + mCurId, e);
1547 }
1548 }
1549 }
1550 }
1551
1552 /**
satok863fcd62011-06-21 17:38:02 +09001553 * Notify the event when the user tapped or clicked the text view.
1554 */
1555 public void viewClicked(View view) {
1556 final boolean focusChanged = mServedView != mNextServedView;
1557 checkFocus();
1558 synchronized (mH) {
1559 if ((mServedView != view && (mServedView == null
1560 || !mServedView.checkInputConnectionProxy(view)))
1561 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1562 return;
1563 }
1564 try {
1565 if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
1566 mCurMethod.viewClicked(focusChanged);
1567 } catch (RemoteException e) {
1568 Log.w(TAG, "IME died: " + mCurId, e);
1569 }
1570 }
1571 }
1572
1573 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001574 * Return true if the current input method wants to watch the location
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 * of the input editor's cursor in its window.
Yohei Yukawa4de04792014-04-17 12:40:31 +09001576 *
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001577 * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead.
Yohei Yukawa4de04792014-04-17 12:40:31 +09001578 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001579 @Deprecated
1580 public boolean isWatchingCursor(View view) {
1581 return false;
Yohei Yukawa4de04792014-04-17 12:40:31 +09001582 }
1583
1584 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001585 * Return true if the current input method wants to be notified when cursor/anchor location
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001586 * is changed.
Yohei Yukawab7b79072014-03-25 11:02:00 +09001587 *
1588 * @hide
1589 */
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001590 public boolean isCursorAnchorInfoEnabled() {
1591 synchronized (mH) {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001592 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001593 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
Yohei Yukawaa277db22014-08-21 18:38:44 -07001594 final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001595 InputConnection.CURSOR_UPDATE_MONITOR) != 0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001596 return isImmediate || isMonitoring;
1597 }
1598 }
1599
1600 /**
Yohei Yukawaa277db22014-08-21 18:38:44 -07001601 * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001602 *
1603 * @hide
1604 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001605 public void setUpdateCursorAnchorInfoMode(int flags) {
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001606 synchronized (mH) {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001607 mRequestUpdateCursorAnchorInfoMonitorMode = flags;
Yohei Yukawab7b79072014-03-25 11:02:00 +09001608 }
1609 }
1610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 /**
1612 * Report the current cursor location in its window.
Yohei Yukawaa277db22014-08-21 18:38:44 -07001613 *
1614 * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 */
Yohei Yukawaa277db22014-08-21 18:38:44 -07001616 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 public void updateCursor(View view, int left, int top, int right, int bottom) {
1618 checkFocus();
1619 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001620 if ((mServedView != view && (mServedView == null
1621 || !mServedView.checkInputConnectionProxy(view)))
1622 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 return;
1624 }
Yohei Yukawaa277db22014-08-21 18:38:44 -07001625
1626 mTmpCursorRect.set(left, top, right, bottom);
1627 if (!mCursorRect.equals(mTmpCursorRect)) {
1628 if (DEBUG) Log.d(TAG, "updateCursor");
1629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 try {
Yohei Yukawaa277db22014-08-21 18:38:44 -07001631 if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
1632 mCurMethod.updateCursor(mTmpCursorRect);
1633 mCursorRect.set(mTmpCursorRect);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 } catch (RemoteException e) {
1635 Log.w(TAG, "IME died: " + mCurId, e);
1636 }
1637 }
1638 }
1639 }
1640
1641 /**
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001642 * Report positional change of the text insertion point and/or characters in the composition
1643 * string.
1644 */
1645 public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
1646 if (view == null || cursorAnchorInfo == null) {
1647 return;
1648 }
1649 checkFocus();
1650 synchronized (mH) {
1651 if ((mServedView != view &&
1652 (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
1653 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1654 return;
1655 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001656 // If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
1657 // not been changed from the previous call.
Yohei Yukawaa277db22014-08-21 18:38:44 -07001658 final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001659 InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001660 if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
Yohei Yukawa73605912014-08-13 16:49:35 +09001661 // TODO: Consider always emitting this message once we have addressed redundant
1662 // calls of this method from android.widget.Editor.
1663 if (DEBUG) {
1664 Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info="
1665 + cursorAnchorInfo);
1666 }
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001667 return;
1668 }
1669 if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001670 try {
1671 mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001672 mCursorAnchorInfo = cursorAnchorInfo;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +09001673 // Clear immediate bit (if any).
Yohei Yukawaa277db22014-08-21 18:38:44 -07001674 mRequestUpdateCursorAnchorInfoMonitorMode &=
Yohei Yukawad8636ea2014-09-02 22:03:30 -07001675 ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
Yohei Yukawac2ddd602014-05-06 21:22:49 +09001676 } catch (RemoteException e) {
1677 Log.w(TAG, "IME died: " + mCurId, e);
1678 }
1679 }
1680 }
1681
1682 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
1684 * InputMethodSession.appPrivateCommand()} on the current Input Method.
1685 * @param view Optional View that is sending the command, or null if
1686 * you want to send the command regardless of the view that is attached
1687 * to the input method.
1688 * @param action Name of the command to be performed. This <em>must</em>
1689 * be a scoped name, i.e. prefixed with a package name you own, so that
1690 * different developers will not create conflicting commands.
1691 * @param data Any data to include with the command.
1692 */
1693 public void sendAppPrivateCommand(View view, String action, Bundle data) {
1694 checkFocus();
1695 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001696 if ((mServedView != view && (mServedView == null
1697 || !mServedView.checkInputConnectionProxy(view)))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 || mCurrentTextBoxAttribute == null || mCurMethod == null) {
1699 return;
1700 }
1701 try {
1702 if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
1703 mCurMethod.appPrivateCommand(action, data);
1704 } catch (RemoteException e) {
1705 Log.w(TAG, "IME died: " + mCurId, e);
1706 }
1707 }
1708 }
satok28203512010-11-24 11:06:49 +09001709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 /**
satok28203512010-11-24 11:06:49 +09001711 * Force switch to a new input method component. This can only be called
1712 * 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 -08001713 * @param token Supplies the identifying token given to an input method
1714 * when it was started, which allows it to perform this operation on
1715 * itself.
1716 * @param id The unique identifier for the new input method to be switched to.
1717 */
1718 public void setInputMethod(IBinder token, String id) {
1719 try {
1720 mService.setInputMethod(token, id);
1721 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001722 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 }
1724 }
satok28203512010-11-24 11:06:49 +09001725
1726 /**
1727 * Force switch to a new input method and subtype. This can only be called
1728 * from an application or a service which has a token of the currently active input method.
1729 * @param token Supplies the identifying token given to an input method
1730 * when it was started, which allows it to perform this operation on
1731 * itself.
1732 * @param id The unique identifier for the new input method to be switched to.
1733 * @param subtype The new subtype of the new input method to be switched to.
1734 */
1735 public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
1736 try {
1737 mService.setInputMethodAndSubtype(token, id, subtype);
1738 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001739 throw e.rethrowFromSystemServer();
satok28203512010-11-24 11:06:49 +09001740 }
1741 }
1742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 /**
1744 * Close/hide the input method's soft input area, so the user no longer
1745 * sees it or can interact with it. This can only be called
1746 * from the currently active input method, as validated by the given token.
1747 *
1748 * @param token Supplies the identifying token given to an input method
1749 * when it was started, which allows it to perform this operation on
1750 * itself.
1751 * @param flags Provides additional operating flags. Currently may be
The Android Open Source Project4df24232009-03-05 14:34:35 -08001752 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1753 * {@link #HIDE_NOT_ALWAYS} bit set.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 */
1755 public void hideSoftInputFromInputMethod(IBinder token, int flags) {
1756 try {
1757 mService.hideMySoftInput(token, flags);
1758 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001759 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 }
1761 }
1762
1763 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -08001764 * Show the input method's soft input area, so the user
1765 * sees the input method window and can interact with it.
1766 * This can only be called from the currently active input method,
1767 * as validated by the given token.
1768 *
1769 * @param token Supplies the identifying token given to an input method
1770 * when it was started, which allows it to perform this operation on
1771 * itself.
1772 * @param flags Provides additional operating flags. Currently may be
1773 * 0 or have the {@link #SHOW_IMPLICIT} or
1774 * {@link #SHOW_FORCED} bit set.
1775 */
1776 public void showSoftInputFromInputMethod(IBinder token, int flags) {
1777 try {
1778 mService.showMySoftInput(token, flags);
1779 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001780 throw e.rethrowFromSystemServer();
The Android Open Source Project4df24232009-03-05 14:34:35 -08001781 }
1782 }
Jeff Brownc28867a2013-03-26 15:42:39 -07001783
The Android Open Source Project4df24232009-03-05 14:34:35 -08001784 /**
Jeff Brownf9e989d2013-04-04 23:04:03 -07001785 * Dispatches an input event to the IME.
1786 *
1787 * Returns {@link #DISPATCH_HANDLED} if the event was handled.
1788 * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled.
1789 * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the
1790 * callback will be invoked later.
1791 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 * @hide
1793 */
Jeff Brownf9e989d2013-04-04 23:04:03 -07001794 public int dispatchInputEvent(InputEvent event, Object token,
1795 FinishedInputEventCallback callback, Handler handler) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 synchronized (mH) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001797 if (mCurMethod != null) {
Jeff Brownc28867a2013-03-26 15:42:39 -07001798 if (event instanceof KeyEvent) {
1799 KeyEvent keyEvent = (KeyEvent)event;
1800 if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
1801 && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM
1802 && keyEvent.getRepeatCount() == 0) {
1803 showInputMethodPickerLocked();
Jeff Brownf9e989d2013-04-04 23:04:03 -07001804 return DISPATCH_HANDLED;
Jeff Brownc28867a2013-03-26 15:42:39 -07001805 }
Jeff Brown29c0ed22013-01-14 13:50:37 -08001806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807
Jeff Brownc28867a2013-03-26 15:42:39 -07001808 if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
Jeff Brownf9e989d2013-04-04 23:04:03 -07001809
1810 PendingEvent p = obtainPendingEventLocked(
1811 event, token, mCurId, callback, handler);
1812 if (mMainLooper.isCurrentThread()) {
1813 // Already running on the IMM thread so we can send the event immediately.
1814 return sendInputEventOnMainLooperLocked(p);
Victoria Leaseb38070c2012-08-24 13:46:02 -07001815 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001816
1817 // Post the event to the IMM thread.
1818 Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p);
1819 msg.setAsynchronous(true);
1820 mH.sendMessage(msg);
1821 return DISPATCH_IN_PROGRESS;
Victoria Leaseb38070c2012-08-24 13:46:02 -07001822 }
1823 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001824 return DISPATCH_NOT_HANDLED;
Victoria Leaseb38070c2012-08-24 13:46:02 -07001825 }
1826
Yohei Yukawa2afe2aa2016-01-07 18:09:44 -08001827 /**
1828 * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which
1829 * is expected to dispatch an keyboard event sent from the IME to an appropriate event target
1830 * depending on the given {@link View} and the current focus state.
1831 *
1832 * <p>CAUTION: This method is provided only for the situation where
1833 * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on
1834 * {@link BaseInputConnection}. Do not use this API for anything else.</p>
1835 *
1836 * @param targetView the default target view. If {@code null} is specified, then this method
1837 * tries to find a good event target based on the current focus state.
1838 * @param event the key event to be dispatched.
1839 */
1840 public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
1841 @NonNull KeyEvent event) {
1842 synchronized (mH) {
1843 ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
1844 if (viewRootImpl == null) {
1845 if (mServedView != null) {
1846 viewRootImpl = mServedView.getViewRootImpl();
1847 }
1848 }
1849 if (viewRootImpl != null) {
1850 viewRootImpl.dispatchKeyFromIme(event);
1851 }
1852 }
1853 }
1854
Jeff Brownf9e989d2013-04-04 23:04:03 -07001855 // Must be called on the main looper
1856 void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
1857 final boolean handled;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001858 synchronized (mH) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001859 int result = sendInputEventOnMainLooperLocked(p);
1860 if (result == DISPATCH_IN_PROGRESS) {
1861 return;
1862 }
1863
1864 handled = (result == DISPATCH_HANDLED);
1865 }
1866
1867 invokeFinishedInputEventCallback(p, handled);
1868 }
1869
1870 // Must be called on the main looper
1871 int sendInputEventOnMainLooperLocked(PendingEvent p) {
1872 if (mCurChannel != null) {
1873 if (mCurSender == null) {
1874 mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
1875 }
1876
1877 final InputEvent event = p.mEvent;
1878 final int seq = event.getSequenceNumber();
1879 if (mCurSender.sendInputEvent(seq, event)) {
1880 mPendingEvents.put(seq, p);
1881 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
1882 mPendingEvents.size());
1883
1884 Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
1885 msg.setAsynchronous(true);
1886 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
1887 return DISPATCH_IN_PROGRESS;
1888 }
1889
1890 Log.w(TAG, "Unable to send input event to IME: "
1891 + mCurId + " dropping: " + event);
1892 }
1893 return DISPATCH_NOT_HANDLED;
1894 }
1895
1896 void finishedInputEvent(int seq, boolean handled, boolean timeout) {
1897 final PendingEvent p;
1898 synchronized (mH) {
1899 int index = mPendingEvents.indexOfKey(seq);
1900 if (index < 0) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001901 return; // spurious, event already finished or timed out
1902 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001903
Jeff Brownf9e989d2013-04-04 23:04:03 -07001904 p = mPendingEvents.valueAt(index);
1905 mPendingEvents.removeAt(index);
1906 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001907
Jeff Brownf9e989d2013-04-04 23:04:03 -07001908 if (timeout) {
1909 Log.w(TAG, "Timeout waiting for IME to handle input event after "
1910 + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId);
1911 } else {
1912 mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p);
Jeff Brown4d656882013-04-03 14:39:19 -07001913 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001914 }
Jeff Brownf9e989d2013-04-04 23:04:03 -07001915
1916 invokeFinishedInputEventCallback(p, handled);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001917 }
1918
Jeff Brownf9e989d2013-04-04 23:04:03 -07001919 // Assumes the event has already been removed from the queue.
1920 void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
1921 p.mHandled = handled;
1922 if (p.mHandler.getLooper().isCurrentThread()) {
1923 // Already running on the callback handler thread so we can send the
1924 // callback immediately.
1925 p.run();
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001926 } else {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001927 // Post the event to the callback handler thread.
1928 // In this case, the callback will be responsible for recycling the event.
1929 Message msg = Message.obtain(p.mHandler, p);
1930 msg.setAsynchronous(true);
1931 msg.sendToTarget();
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 }
satokab751aa2010-09-14 19:17:36 +09001934
Michael Wrightef17e872013-04-01 13:15:55 -07001935 private void flushPendingEventsLocked() {
Jeff Brownf9e989d2013-04-04 23:04:03 -07001936 mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
Jeff Brown4d656882013-04-03 14:39:19 -07001937
Jeff Brownf9e989d2013-04-04 23:04:03 -07001938 final int count = mPendingEvents.size();
1939 for (int i = 0; i < count; i++) {
1940 int seq = mPendingEvents.keyAt(i);
1941 Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0);
Michael Wrightef17e872013-04-01 13:15:55 -07001942 msg.setAsynchronous(true);
Jeff Brownf9e989d2013-04-04 23:04:03 -07001943 msg.sendToTarget();
Michael Wrightef17e872013-04-01 13:15:55 -07001944 }
1945 }
1946
Jeff Brownf9e989d2013-04-04 23:04:03 -07001947 private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
1948 String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
1949 PendingEvent p = mPendingEventPool.acquire();
1950 if (p == null) {
1951 p = new PendingEvent();
1952 }
1953 p.mEvent = event;
1954 p.mToken = token;
1955 p.mInputMethodId = inputMethodId;
1956 p.mCallback = callback;
1957 p.mHandler = handler;
1958 return p;
1959 }
1960
1961 private void recyclePendingEventLocked(PendingEvent p) {
1962 p.recycle();
1963 mPendingEventPool.release(p);
1964 }
1965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 public void showInputMethodPicker() {
1967 synchronized (mH) {
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001968 showInputMethodPickerLocked();
1969 }
1970 }
1971
Seigo Nonaka14e13912015-05-06 21:04:13 -07001972 /**
1973 * Shows the input method chooser dialog.
1974 *
1975 * @param showAuxiliarySubtypes Set true to show auxiliary input methods.
1976 * @hide
1977 */
1978 public void showInputMethodPicker(boolean showAuxiliarySubtypes) {
1979 synchronized (mH) {
1980 try {
1981 final int mode = showAuxiliarySubtypes ?
1982 SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
1983 SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
1984 mService.showInputMethodPickerFromClient(mClient, mode);
1985 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001986 throw e.rethrowFromSystemServer();
Seigo Nonaka14e13912015-05-06 21:04:13 -07001987 }
1988 }
1989 }
1990
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001991 private void showInputMethodPickerLocked() {
1992 try {
Seigo Nonaka14e13912015-05-06 21:04:13 -07001993 mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07001994 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001995 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 }
1997 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001998
satokd4fce2b2011-04-11 12:07:13 +09001999 /**
2000 * Show the settings for enabling subtypes of the specified input method.
2001 * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
2002 * subtypes of all input methods will be shown.
2003 */
2004 public void showInputMethodAndSubtypeEnabler(String imiId) {
satok47a44912010-10-06 16:03:58 +09002005 synchronized (mH) {
2006 try {
satokd4fce2b2011-04-11 12:07:13 +09002007 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
satok47a44912010-10-06 16:03:58 +09002008 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002009 throw e.rethrowFromSystemServer();
satok47a44912010-10-06 16:03:58 +09002010 }
2011 }
2012 }
2013
satokd4fce2b2011-04-11 12:07:13 +09002014 /**
2015 * Returns the current input method subtype. This subtype is one of the subtypes in
2016 * the current input method. This method returns null when the current input method doesn't
2017 * have any input method subtype.
2018 */
satok04d50202010-10-25 22:20:12 +09002019 public InputMethodSubtype getCurrentInputMethodSubtype() {
2020 synchronized (mH) {
2021 try {
2022 return mService.getCurrentInputMethodSubtype();
2023 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002024 throw e.rethrowFromSystemServer();
satok04d50202010-10-25 22:20:12 +09002025 }
2026 }
2027 }
2028
satokd4fce2b2011-04-11 12:07:13 +09002029 /**
2030 * Switch to a new input method subtype of the current input method.
2031 * @param subtype A new input method subtype to switch.
2032 * @return true if the current subtype was successfully switched. When the specified subtype is
2033 * null, this method returns false.
2034 */
Yoshiki Iguchi00d51222015-05-29 15:36:22 +09002035 @RequiresPermission(WRITE_SECURE_SETTINGS)
satokb66d2872010-11-10 01:04:04 +09002036 public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
2037 synchronized (mH) {
2038 try {
2039 return mService.setCurrentInputMethodSubtype(subtype);
2040 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002041 throw e.rethrowFromSystemServer();
satokb66d2872010-11-10 01:04:04 +09002042 }
2043 }
2044 }
2045
satokd4fce2b2011-04-11 12:07:13 +09002046 /**
Yohei Yukawa02970512014-06-05 16:16:18 +09002047 * Notify that a user took some action with this input method.
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002048 * @hide
2049 */
Yohei Yukawa02970512014-06-05 16:16:18 +09002050 public void notifyUserAction() {
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002051 synchronized (mH) {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002052 if (mLastSentUserActionNotificationSequenceNumber ==
2053 mNextUserActionNotificationSequenceNumber) {
2054 if (DEBUG) {
2055 Log.w(TAG, "Ignoring notifyUserAction as it has already been sent."
2056 + " mLastSentUserActionNotificationSequenceNumber: "
2057 + mLastSentUserActionNotificationSequenceNumber
2058 + " mNextUserActionNotificationSequenceNumber: "
2059 + mNextUserActionNotificationSequenceNumber);
2060 }
2061 return;
2062 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002063 try {
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002064 if (DEBUG) {
2065 Log.w(TAG, "notifyUserAction: "
2066 + " mLastSentUserActionNotificationSequenceNumber: "
2067 + mLastSentUserActionNotificationSequenceNumber
2068 + " mNextUserActionNotificationSequenceNumber: "
2069 + mNextUserActionNotificationSequenceNumber);
2070 }
2071 mService.notifyUserAction(mNextUserActionNotificationSequenceNumber);
2072 mLastSentUserActionNotificationSequenceNumber =
2073 mNextUserActionNotificationSequenceNumber;
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002074 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002075 throw e.rethrowFromSystemServer();
Satoshi Kataokad7443c82013-10-15 17:45:43 +09002076 }
2077 }
2078 }
2079
2080 /**
satokd4fce2b2011-04-11 12:07:13 +09002081 * Returns a map of all shortcut input method info and their subtypes.
2082 */
satokf3db1af2010-11-23 13:34:33 +09002083 public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
satok4e4569d2010-11-19 18:45:53 +09002084 synchronized (mH) {
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002085 HashMap<InputMethodInfo, List<InputMethodSubtype>> ret = new HashMap<>();
satok4e4569d2010-11-19 18:45:53 +09002086 try {
2087 // TODO: We should change the return type from List<Object> to List<Parcelable>
2088 List<Object> info = mService.getShortcutInputMethodsAndSubtypes();
satokf3db1af2010-11-23 13:34:33 +09002089 // "info" has imi1, subtype1, subtype2, imi2, subtype2, imi3, subtype3..in the list
2090 ArrayList<InputMethodSubtype> subtypes = null;
Andreas Gampe4236ad72015-03-17 21:07:21 -07002091 if (info != null && !info.isEmpty()) {
2092 final int N = info.size();
satokf3db1af2010-11-23 13:34:33 +09002093 for (int i = 0; i < N; ++i) {
2094 Object o = info.get(i);
2095 if (o instanceof InputMethodInfo) {
2096 if (ret.containsKey(o)) {
2097 Log.e(TAG, "IMI list already contains the same InputMethod.");
2098 break;
satok4e4569d2010-11-19 18:45:53 +09002099 }
Yohei Yukawab0377bb2015-08-10 21:06:30 -07002100 subtypes = new ArrayList<>();
satokf3db1af2010-11-23 13:34:33 +09002101 ret.put((InputMethodInfo)o, subtypes);
2102 } else if (subtypes != null && o instanceof InputMethodSubtype) {
2103 subtypes.add((InputMethodSubtype)o);
satok4e4569d2010-11-19 18:45:53 +09002104 }
satok4e4569d2010-11-19 18:45:53 +09002105 }
2106 }
2107 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002108 throw e.rethrowFromSystemServer();
satok4e4569d2010-11-19 18:45:53 +09002109 }
2110 return ret;
2111 }
2112 }
satokf3db1af2010-11-23 13:34:33 +09002113
satokd4fce2b2011-04-11 12:07:13 +09002114 /**
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002115 * @return The current height of the input method window.
2116 * @hide
2117 */
2118 public int getInputMethodWindowVisibleHeight() {
2119 synchronized (mH) {
2120 try {
2121 return mService.getInputMethodWindowVisibleHeight();
2122 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002123 throw e.rethrowFromSystemServer();
Satoshi Kataoka658c7b82013-10-10 17:03:51 +09002124 }
2125 }
2126 }
2127
2128 /**
satokd4fce2b2011-04-11 12:07:13 +09002129 * Force switch to the last used input method and subtype. If the last input method didn't have
2130 * any subtypes, the framework will simply switch to the last input method with no subtype
2131 * specified.
2132 * @param imeToken Supplies the identifying token given to an input method when it was started,
2133 * which allows it to perform this operation on itself.
2134 * @return true if the current input method and subtype was successfully switched to the last
2135 * used input method and subtype.
2136 */
satok735cf382010-11-11 20:40:09 +09002137 public boolean switchToLastInputMethod(IBinder imeToken) {
2138 synchronized (mH) {
2139 try {
2140 return mService.switchToLastInputMethod(imeToken);
2141 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002142 throw e.rethrowFromSystemServer();
satok735cf382010-11-11 20:40:09 +09002143 }
2144 }
2145 }
2146
satoke7c6998e2011-06-03 17:57:59 +09002147 /**
satok688bd472012-02-09 20:09:17 +09002148 * Force switch to the next input method and subtype. If there is no IME enabled except
2149 * current IME and subtype, do nothing.
2150 * @param imeToken Supplies the identifying token given to an input method when it was started,
2151 * which allows it to perform this operation on itself.
2152 * @param onlyCurrentIme if true, the framework will find the next subtype which
2153 * belongs to the current IME
2154 * @return true if the current input method and subtype was successfully switched to the next
2155 * input method and subtype.
2156 */
2157 public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
2158 synchronized (mH) {
2159 try {
2160 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
2161 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002162 throw e.rethrowFromSystemServer();
satok688bd472012-02-09 20:09:17 +09002163 }
2164 }
2165 }
2166
2167 /**
satok15ab6b02013-08-26 14:17:18 +09002168 * Returns true if the current IME needs to offer the users ways to switch to a next input
2169 * method (e.g. a globe key.).
2170 * When an IME sets supportsSwitchingToNextInputMethod and this method returns true,
2171 * the IME has to offer ways to to invoke {@link #switchToNextInputMethod} accordingly.
2172 * <p> Note that the system determines the most appropriate next input method
2173 * and subtype in order to provide the consistent user experience in switching
2174 * between IMEs and subtypes.
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09002175 * @param imeToken Supplies the identifying token given to an input method when it was started,
2176 * which allows it to perform this operation on itself.
2177 */
2178 public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
2179 synchronized (mH) {
2180 try {
2181 return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
2182 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002183 throw e.rethrowFromSystemServer();
Satoshi Kataoka2b10b522013-08-21 20:39:12 +09002184 }
2185 }
2186 }
2187
2188 /**
satok91e88122011-07-18 11:11:42 +09002189 * Set additional input method subtypes. Only a process which shares the same uid with the IME
2190 * can add additional input method subtypes to the IME.
satok75917b62011-08-31 23:27:39 +09002191 * Please note that a subtype's status is stored in the system.
2192 * For example, enabled subtypes are remembered by the framework even after they are removed
2193 * by using this method. If you re-add the same subtypes again,
2194 * they will just get enabled. If you want to avoid such conflicts, for instance, you may
2195 * want to create a "different" new subtype even with the same locale and mode,
2196 * by changing its extra value. The different subtype won't get affected by the stored past
2197 * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
2198 * to the current implementation.)
Yohei Yukawa70f5c482016-01-04 19:42:36 -08002199 *
2200 * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes
2201 * specified by {@code subtypes}, those multiple instances are automatically merged into one
2202 * instance.</p>
2203 *
2204 * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty
2205 * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing
2206 * the last one entry of additional subtypes. If your IME statically defines one or more
2207 * subtypes in the manifest XML file, you may be able to work around this limitation by
2208 * specifying one of those statically defined subtypes in {@code subtypes}.</p>
2209 *
satok91e88122011-07-18 11:11:42 +09002210 * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
satoke7c6998e2011-06-03 17:57:59 +09002211 * @param subtypes subtypes will be added as additional subtypes of the current input method.
satoke7c6998e2011-06-03 17:57:59 +09002212 */
satokee5e77c2011-09-02 18:50:15 +09002213 public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
satoke7c6998e2011-06-03 17:57:59 +09002214 synchronized (mH) {
2215 try {
satokee5e77c2011-09-02 18:50:15 +09002216 mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
satoke7c6998e2011-06-03 17:57:59 +09002217 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002218 throw e.rethrowFromSystemServer();
satoke7c6998e2011-06-03 17:57:59 +09002219 }
2220 }
2221 }
2222
satok68f1b782011-04-11 14:26:04 +09002223 public InputMethodSubtype getLastInputMethodSubtype() {
2224 synchronized (mH) {
2225 try {
2226 return mService.getLastInputMethodSubtype();
2227 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07002228 throw e.rethrowFromSystemServer();
satok68f1b782011-04-11 14:26:04 +09002229 }
2230 }
2231 }
2232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
2234 final Printer p = new PrintWriterPrinter(fout);
2235 p.println("Input method client state for " + this + ":");
2236
2237 p.println(" mService=" + mService);
2238 p.println(" mMainLooper=" + mMainLooper);
2239 p.println(" mIInputContext=" + mIInputContext);
2240 p.println(" mActive=" + mActive
2241 + " mHasBeenInactive=" + mHasBeenInactive
2242 + " mBindSequence=" + mBindSequence
2243 + " mCurId=" + mCurId);
2244 p.println(" mCurMethod=" + mCurMethod);
Wale Ogunwale159c3d82015-05-14 12:20:53 -07002245 p.println(" mCurRootView=" + mCurRootView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 p.println(" mServedView=" + mServedView);
Dianne Hackborn7663d802012-02-24 13:08:49 -08002247 p.println(" mNextServedView=" + mNextServedView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002248 p.println(" mServedConnecting=" + mServedConnecting);
2249 if (mCurrentTextBoxAttribute != null) {
2250 p.println(" mCurrentTextBoxAttribute:");
2251 mCurrentTextBoxAttribute.dump(p, " ");
2252 } else {
2253 p.println(" mCurrentTextBoxAttribute: null");
2254 }
2255 p.println(" mServedInputConnection=" + mServedInputConnection);
Andreas Gampee6748ce2015-12-11 18:00:38 -08002256 p.println(" mCompletions=" + Arrays.toString(mCompletions));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 p.println(" mCursorRect=" + mCursorRect);
2258 p.println(" mCursorSelStart=" + mCursorSelStart
2259 + " mCursorSelEnd=" + mCursorSelEnd
2260 + " mCursorCandStart=" + mCursorCandStart
2261 + " mCursorCandEnd=" + mCursorCandEnd);
Yohei Yukawa3d1e8122014-06-06 19:12:47 +09002262 p.println(" mNextUserActionNotificationSequenceNumber="
2263 + mNextUserActionNotificationSequenceNumber
2264 + " mLastSentUserActionNotificationSequenceNumber="
2265 + mLastSentUserActionNotificationSequenceNumber);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002267
2268 /**
2269 * Callback that is invoked when an input event that was dispatched to
2270 * the IME has been finished.
2271 * @hide
2272 */
Jeff Brownf9e989d2013-04-04 23:04:03 -07002273 public interface FinishedInputEventCallback {
2274 public void onFinishedInputEvent(Object token, boolean handled);
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002275 }
2276
Jeff Brownc28867a2013-03-26 15:42:39 -07002277 private final class ImeInputEventSender extends InputEventSender {
2278 public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
2279 super(inputChannel, looper);
2280 }
2281
2282 @Override
2283 public void onInputEventFinished(int seq, boolean handled) {
Jeff Brownf9e989d2013-04-04 23:04:03 -07002284 finishedInputEvent(seq, handled, false);
Jeff Brownc28867a2013-03-26 15:42:39 -07002285 }
2286 }
2287
Jeff Brownf9e989d2013-04-04 23:04:03 -07002288 private final class PendingEvent implements Runnable {
2289 public InputEvent mEvent;
2290 public Object mToken;
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002291 public String mInputMethodId;
Jeff Brownf9e989d2013-04-04 23:04:03 -07002292 public FinishedInputEventCallback mCallback;
2293 public Handler mHandler;
2294 public boolean mHandled;
2295
2296 public void recycle() {
2297 mEvent = null;
2298 mToken = null;
2299 mInputMethodId = null;
2300 mCallback = null;
2301 mHandler = null;
2302 mHandled = false;
2303 }
2304
2305 @Override
2306 public void run() {
2307 mCallback.onFinishedInputEvent(mToken, mHandled);
2308
2309 synchronized (mH) {
2310 recyclePendingEventLocked(this);
2311 }
2312 }
Jeff Brown04ddf3c2012-06-14 03:57:49 -07002313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314}