blob: 4bb0c3cbb5ee8db505e0e9b53b15b73cfced93c7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package android.view.inputmethod;
18
Svetoslav Ganov758143e2012-08-06 16:40:27 -070019import com.android.internal.os.SomeArgs;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080020import com.android.internal.view.IInputConnectionWrapper;
21import com.android.internal.view.IInputContext;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080022import com.android.internal.view.IInputMethodClient;
23import com.android.internal.view.IInputMethodManager;
24import com.android.internal.view.IInputMethodSession;
25import com.android.internal.view.InputBindResult;
Yohei Yukawa33e81792015-11-17 21:14:42 -080026import com.android.internal.view.InputMethodClient;
Gilles Debunne8cbb4c62011-01-24 12:33:56 -080027
Yohei Yukawa2afe2aa2016-01-07 18:09:44 -080028import android.annotation.NonNull;
29import android.annotation.Nullable;
Yoshiki Iguchi00d51222015-05-29 15:36:22 +090030import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.Context;
32import android.graphics.Rect;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Looper;
37import android.os.Message;
38import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080039import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.ServiceManager;
Jeff Brownf9e989d2013-04-04 23:04:03 -070041import android.os.Trace;
satokf9f01002011-05-19 21:31:50 +090042import android.text.style.SuggestionSpan;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.util.Log;
Jeff Brownf9e989d2013-04-04 23:04:03 -070044import android.util.Pools.Pool;
45import android.util.Pools.SimplePool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.util.PrintWriterPrinter;
47import android.util.Printer;
Yohei Yukawab7b79072014-03-25 11:02:00 +090048import android.util.SparseArray;
Jeff Brownc28867a2013-03-26 15:42:39 -070049import android.view.InputChannel;
50import android.view.InputEvent;
51import android.view.InputEventSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.view.View;
Dianne Hackborn6dd005b2011-07-18 13:22:50 -070054import android.view.ViewRootImpl;
Gilles Debunned4723bb2010-09-02 15:27:32 -070055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import java.io.FileDescriptor;
57import java.io.PrintWriter;
satok4e4569d2010-11-19 18:45:53 +090058import java.util.ArrayList;
Andreas Gampee6748ce2015-12-11 18:00:38 -080059import java.util.Arrays;
satokf3db1af2010-11-23 13:34:33 +090060import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import java.util.List;
satokf3db1af2010-11-23 13:34:33 +090062import java.util.Map;
Yohei Yukawac941fed2014-05-14 19:33:35 +090063import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.util.concurrent.CountDownLatch;
65import java.util.concurrent.TimeUnit;
66
Yoshiki Iguchi00d51222015-05-29 15:36:22 +090067import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
68
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069/**
70 * Central system API to the overall input method framework (IMF) architecture,
71 * which arbitrates interaction between applications and the current input method.
72 * You can retrieve an instance of this interface with
73 * {@link Context#getSystemService(String) Context.getSystemService()}.
74 *
75 * <p>Topics covered here:
76 * <ol>
77 * <li><a href="#ArchitectureOverview">Architecture Overview</a>
Ken Wakasa384f8ba2012-03-10 09:59:31 +090078 * <li><a href="#Applications">Applications</a>
79 * <li><a href="#InputMethods">Input Methods</a>
80 * <li><a href="#Security">Security</a>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 * </ol>
82 *
83 * <a name="ArchitectureOverview"></a>
84 * <h3>Architecture Overview</h3>
85 *
86 * <p>There are three primary parties involved in the input method
87 * framework (IMF) architecture:</p>
88 *
89 * <ul>
90 * <li> The <strong>input method manager</strong> as expressed by this class
91 * is the central point of the system that manages interaction between all
92 * other parts. It is expressed as the client-side API here which exists
93 * in each application context and communicates with a global system service
94 * that manages the interaction across all processes.
95 * <li> An <strong>input method (IME)</strong> implements a particular
96 * interaction model allowing the user to generate text. The system binds
97 * to the current input method that is use, causing it to be created and run,
98 * and tells it when to hide and show its UI. Only one IME is running at a time.
99 * <li> Multiple <strong>client applications</strong> arbitrate with the input
100 * method manager for input focus and control over the state of the IME. Only
101 * one such client is ever active (working with the IME) at a time.
102 * </ul>
103 *
104 *
105 * <a name="Applications"></a>
106 * <h3>Applications</h3>
107 *
108 * <p>In most cases, applications that are using the standard
109 * {@link android.widget.TextView} or its subclasses will have little they need
110 * to do to work well with soft input methods. The main things you need to
111 * be aware of are:</p>
112 *
113 * <ul>
Gilles Debunne8cbb4c62011-01-24 12:33:56 -0800114 * <li> Properly set the {@link android.R.attr#inputType} in your editable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 * text views, so that the input method will have enough context to help the
116 * user in entering text into them.
117 * <li> Deal well with losing screen space when the input method is
118 * displayed. Ideally an application should handle its window being resized
119 * smaller, but it can rely on the system performing panning of the window
120 * if needed. You should set the {@link android.R.attr#windowSoftInputMode}
121 * attribute on your activity or the corresponding values on windows you
122 * create to help the system determine whether to pan or resize (it will
123 * try to determine this automatically but may get it wrong).
124 * <li> You can also control the preferred soft input state (open, closed, etc)
125 * for your window using the same {@link android.R.attr#windowSoftInputMode}
126 * attribute.
127 * </ul>
128 *
129 * <p>More finer-grained control is available through the APIs here to directly
130 * interact with the IMF and its IME -- either showing or hiding the input
131 * area, letting the user pick an input method, etc.</p>
132 *
133 * <p>For the rare people amongst us writing their own text editors, you
134 * will need to implement {@link android.view.View#onCreateInputConnection}
135 * to return a new instance of your own {@link InputConnection} interface
136 * allowing the IME to interact with your editor.</p>
137 *
138 *
139 * <a name="InputMethods"></a>
140 * <h3>Input Methods</h3>
141 *
142 * <p>An input method (IME) is implemented
143 * as a {@link android.app.Service}, typically deriving from
144 * {@link android.inputmethodservice.InputMethodService}. It must provide
145 * the core {@link InputMethod} interface, though this is normally handled by
146 * {@link android.inputmethodservice.InputMethodService} and implementors will
147 * only need to deal with the higher-level API there.</p>
148 *
149 * See the {@link android.inputmethodservice.InputMethodService} class for
150 * more information on implementing IMEs.
151 *
152 *
153 * <a name="Security"></a>
154 * <h3>Security</h3>
155 *
156 * <p>There are a lot of security issues associated with input methods,
157 * since they essentially have freedom to completely drive the UI and monitor
158 * everything the user enters. The Android input method framework also allows
159 * arbitrary third party IMEs, so care must be taken to restrict their
160 * selection and interactions.</p>
161 *
162 * <p>Here are some key points about the security architecture behind the
163 * IMF:</p>
164 *
165 * <ul>
166 * <li> <p>Only the system is allowed to directly access an IME's
167 * {@link InputMethod} interface, via the
168 * {@link android.Manifest.permission#BIND_INPUT_METHOD} permission. This is
169 * enforced in the system by not binding to an input method service that does
170 * not require this permission, so the system can guarantee no other untrusted
171 * clients are accessing the current input method outside of its control.</p>
172 *
173 * <li> <p>There may be many client processes of the IMF, but only one may
174 * be active at a time. The inactive clients can not interact with key
175 * parts of the IMF through the mechanisms described below.</p>
176 *
177 * <li> <p>Clients of an input method are only given access to its
178 * {@link InputMethodSession} interface. One instance of this interface is
179 * created for each client, and only calls from the session associated with
180 * the active client will be processed by the current IME. This is enforced
181 * by {@link android.inputmethodservice.AbstractInputMethodService} for normal
182 * IMEs, but must be explicitly handled by an IME that is customizing the
183 * raw {@link InputMethodSession} implementation.</p>
184 *
185 * <li> <p>Only the active client's {@link InputConnection} will accept
186 * operations. The IMF tells each client process whether it is active, and
187 * the framework enforces that in inactive processes calls on to the current
188 * InputConnection will be ignored. This ensures that the current IME can
189 * only deliver events and text edits to the UI that the user sees as
190 * being in focus.</p>
191 *
192 * <li> <p>An IME can never interact with an {@link InputConnection} while
193 * the screen is off. This is enforced by making all clients inactive while
194 * the screen is off, and prevents bad IMEs from driving the UI when the user
195 * can not be aware of its behavior.</p>
196 *
197 * <li> <p>A client application can ask that the system let the user pick a
198 * new IME, but can not programmatically switch to one itself. This avoids
199 * malicious applications from switching the user to their own IME, which
200 * remains running when the user navigates away to another application. An
201 * IME, on the other hand, <em>is</em> allowed to programmatically switch
202 * the system to another IME, since it already has full control of user
203 * input.</p>
204 *
205 * <li> <p>The user must explicitly enable a new IME in settings before
206 * they can switch to it, to confirm with the system that they know about it
207 * and want to make it available for use.</p>
208 * </ul>
209 */
210public final class InputMethodManager {
Dianne Hackborn4eba2712009-03-24 19:20:06 -0700211 static final boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 static final String TAG = "InputMethodManager";
213
Jeff Brownf9e989d2013-04-04 23:04:03 -0700214 static final String PENDING_EVENT_COUNTER = "aq:imm";
215
216 static InputMethodManager sInstance;
Dianne Hackborn7663d802012-02-24 13:08:49 -0800217
218 /**
219 * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
220 * the window has input focus.
221 */
222 public static final int CONTROL_WINDOW_VIEW_HAS_FOCUS = 1<<0;
223
224 /**
225 * @hide Flag for IInputMethodManager.windowGainedFocus: the focus
226 * is a text editor.
227 */
228 public static final int CONTROL_WINDOW_IS_TEXT_EDITOR = 1<<1;
229
230 /**
231 * @hide Flag for IInputMethodManager.windowGainedFocus: this is the first
232 * time the window has gotten focus.
233 */
234 public static final int CONTROL_WINDOW_FIRST = 1<<2;
235
236 /**
237 * @hide Flag for IInputMethodManager.startInput: this is the first
238 * time the window has gotten focus.
239 */
240 public static final int CONTROL_START_INITIAL = 1<<8;
241
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700242 /**
243 * Timeout in milliseconds for delivering a key to an IME.
244 */
245 static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500;
246
Jeff Brownf9e989d2013-04-04 23:04:03 -0700247 /** @hide */
248 public static final int DISPATCH_IN_PROGRESS = -1;
249
250 /** @hide */
251 public static final int DISPATCH_NOT_HANDLED = 0;
252
253 /** @hide */
254 public static final int DISPATCH_HANDLED = 1;
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700255
Seigo Nonaka14e13912015-05-06 21:04:13 -0700256 /** @hide */
257 public static final int SHOW_IM_PICKER_MODE_AUTO = 0;
258 /** @hide */
259 public static final int SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES = 1;
260 /** @hide */
261 public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 final IInputMethodManager mService;
264 final Looper mMainLooper;
265
266 // For scheduling work on the main thread. This also serves as our
267 // global lock.
268 final H mH;
269
270 // Our generic input connection if the current target does not have its own.
271 final IInputContext mIInputContext;
272
273 /**
274 * True if this input method client is active, initially false.
275 */
276 boolean mActive = false;
277
278 /**
279 * Set whenever this client becomes inactive, to know we need to reset
Dianne Hackborn7663d802012-02-24 13:08:49 -0800280 * state with the IME the next time we receive focus.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 */
282 boolean mHasBeenInactive = true;
283
284 /**
285 * As reported by IME through InputConnection.
286 */
287 boolean mFullscreenMode;
288
289 // -----------------------------------------------------------
Wale Ogunwale159c3d82015-05-14 12:20:53 -0700290
291 /**
292 * This is the root view of the overall window that currently has input
293 * method focus.
294 */
295 View mCurRootView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 /**
297 * This is the view that should currently be served by an input method,
298 * regardless of the state of setting that up.
299 */
300 View mServedView;
301 /**
302 * This is then next view that will be served by the input method, when
303 * we get around to updating things.
304 */
305 View mNextServedView;
306 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 * This is set when we are in the process of connecting, to determine
308 * when we have actually finished.
309 */
310 boolean mServedConnecting;
311 /**
312 * This is non-null when we have connected the served view; it holds
313 * the attributes that were last retrieved from the served view and given
314 * to the input connection.
315 */
316 EditorInfo mCurrentTextBoxAttribute;
317 /**
318 * The InputConnection that was last retrieved from the served view.
319 */
Dianne Hackbornac920872012-05-22 11:49:49 -0700320 ControlledInputConnectionWrapper mServedInputConnectionWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 /**
322 * The completions that were last provided by the served view.
323 */
324 CompletionInfo[] mCompletions;
325
326 // Cursor position on the screen.
Yohei Yukawaa277db22014-08-21 18:38:44 -0700327 Rect mTmpCursorRect = new Rect();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 Rect mCursorRect = new Rect();
329 int mCursorSelStart;
330 int mCursorSelEnd;
331 int mCursorCandStart;
332 int mCursorCandEnd;
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900333
334 /**
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900335 * Represents an invalid action notification sequence number. {@link InputMethodManagerService}
336 * always issues a positive integer for action notification sequence numbers. Thus -1 is
337 * guaranteed to be different from any valid sequence number.
338 */
339 private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
340 /**
341 * The next sequence number that is to be sent to {@link InputMethodManagerService} via
342 * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
343 */
344 private int mNextUserActionNotificationSequenceNumber =
345 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
346
347 /**
348 * The last sequence number that is already sent to {@link InputMethodManagerService}.
349 */
350 private int mLastSentUserActionNotificationSequenceNumber =
351 NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
352
353 /**
Yohei Yukawa056ffe62014-05-13 14:26:09 +0900354 * The instance that has previously been sent to the input method.
355 */
356 private CursorAnchorInfo mCursorAnchorInfo = null;
357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 // -----------------------------------------------------------
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 /**
361 * Sequence number of this binding, as returned by the server.
362 */
363 int mBindSequence = -1;
364 /**
365 * ID of the method we are bound to.
366 */
367 String mCurId;
368 /**
369 * The actual instance of the method to make calls on it.
370 */
371 IInputMethodSession mCurMethod;
Jeff Brownc28867a2013-03-26 15:42:39 -0700372 InputChannel mCurChannel;
373 ImeInputEventSender mCurSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
Yohei Yukawaa277db22014-08-21 18:38:44 -0700375 private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900376
377 /**
378 * The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
379 */
Yohei Yukawaa277db22014-08-21 18:38:44 -0700380 private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawab7b79072014-03-25 11:02:00 +0900381
Yohei Yukawab0377bb2015-08-10 21:06:30 -0700382 final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
383 final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 // -----------------------------------------------------------
386
387 static final int MSG_DUMP = 1;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800388 static final int MSG_BIND = 2;
389 static final int MSG_UNBIND = 3;
390 static final int MSG_SET_ACTIVE = 4;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700391 static final int MSG_SEND_INPUT_EVENT = 5;
392 static final int MSG_TIMEOUT_INPUT_EVENT = 6;
393 static final int MSG_FLUSH_INPUT_EVENT = 7;
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900394 static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
Jeff Brownf9e989d2013-04-04 23:04:03 -0700395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 class H extends Handler {
397 H(Looper looper) {
Jeff Brown29c0ed22013-01-14 13:50:37 -0800398 super(looper, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400
401 @Override
402 public void handleMessage(Message msg) {
403 switch (msg.what) {
404 case MSG_DUMP: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700405 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 try {
407 doDump((FileDescriptor)args.arg1,
408 (PrintWriter)args.arg2, (String[])args.arg3);
409 } catch (RuntimeException e) {
410 ((PrintWriter)args.arg2).println("Exception: " + e);
411 }
412 synchronized (args.arg4) {
413 ((CountDownLatch)args.arg4).countDown();
414 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700415 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 return;
417 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800418 case MSG_BIND: {
419 final InputBindResult res = (InputBindResult)msg.obj;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900420 if (DEBUG) {
421 Log.i(TAG, "handleMessage: MSG_BIND " + res.sequence + "," + res.id);
422 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800423 synchronized (mH) {
424 if (mBindSequence < 0 || mBindSequence != res.sequence) {
425 Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
426 + ", given seq=" + res.sequence);
Jeff Brown4d656882013-04-03 14:39:19 -0700427 if (res.channel != null && res.channel != mCurChannel) {
Jeff Brownc28867a2013-03-26 15:42:39 -0700428 res.channel.dispose();
429 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800430 return;
431 }
Jeff Brown4d656882013-04-03 14:39:19 -0700432
Yohei Yukawaa277db22014-08-21 18:38:44 -0700433 mRequestUpdateCursorAnchorInfoMonitorMode =
434 REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900435
Jeff Brown4d656882013-04-03 14:39:19 -0700436 setInputChannelLocked(res.channel);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800437 mCurMethod = res.method;
438 mCurId = res.id;
439 mBindSequence = res.sequence;
440 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800441 startInputInner(InputMethodClient.START_INPUT_REASON_BOUND_TO_IMMS,
442 null, 0, 0, 0);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800443 return;
444 }
445 case MSG_UNBIND: {
446 final int sequence = msg.arg1;
Yohei Yukawa33e81792015-11-17 21:14:42 -0800447 @InputMethodClient.UnbindReason
448 final int reason = msg.arg2;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900449 if (DEBUG) {
Yohei Yukawa33e81792015-11-17 21:14:42 -0800450 Log.i(TAG, "handleMessage: MSG_UNBIND " + sequence +
451 " reason=" + InputMethodClient.getUnbindReason(reason));
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900452 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800453 final boolean startInput;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800454 synchronized (mH) {
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800455 if (mBindSequence != sequence) {
456 return;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800457 }
Yohei Yukawa678e38e2015-11-13 18:36:21 -0800458 clearBindingLocked();
459 // If we were actively using the last input method, then
460 // we would like to re-connect to the next input method.
461 if (mServedView != null && mServedView.isFocused()) {
462 mServedConnecting = true;
463 }
464 startInput = mActive;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800465 }
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800466 if (startInput) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800467 startInputInner(
468 InputMethodClient.START_INPUT_REASON_UNBOUND_FROM_IMMS, null, 0, 0,
469 0);
Dianne Hackborn06a591c2012-02-16 10:25:26 -0800470 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800471 return;
472 }
473 case MSG_SET_ACTIVE: {
474 final boolean active = msg.arg1 != 0;
Satoshi Kataoka4e5184f2012-07-13 23:10:58 +0900475 if (DEBUG) {
476 Log.i(TAG, "handleMessage: MSG_SET_ACTIVE " + active + ", was " + mActive);
477 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800478 synchronized (mH) {
479 mActive = active;
480 mFullscreenMode = false;
481 if (!active) {
482 // Some other client has starting using the IME, so note
483 // that this happened and make sure our own editor's
484 // state is reset.
485 mHasBeenInactive = true;
486 try {
487 // Note that finishComposingText() is allowed to run
488 // even when we are not active.
489 mIInputContext.finishComposingText();
490 } catch (RemoteException e) {
491 }
Mikael Gullstrand82ae3ff2014-11-25 12:41:53 +0100492 }
493 // Check focus again in case that "onWindowFocus" is called before
494 // handling this message.
495 if (mServedView != null && mServedView.hasWindowFocus()) {
496 // Please note that this handler thread could be different
497 // from a thread that created mServedView. That could happen
498 // the current activity is running in the system process.
499 // In that case, we really should not call
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700500 // mServedInputConnectionWrapper.finishComposingText().
Mikael Gullstrand82ae3ff2014-11-25 12:41:53 +0100501 if (checkFocusNoStartInput(mHasBeenInactive, false)) {
Yohei Yukawa35d3f372015-11-25 11:07:19 -0800502 final int reason = active ?
503 InputMethodClient.START_INPUT_REASON_ACTIVATED_BY_IMMS :
504 InputMethodClient.START_INPUT_REASON_DEACTIVATED_BY_IMMS;
505 startInputInner(reason, null, 0, 0, 0);
satok05a6cbe2012-04-05 23:04:08 +0900506 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800507 }
508 }
509 return;
510 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700511 case MSG_SEND_INPUT_EVENT: {
512 sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
513 return;
514 }
515 case MSG_TIMEOUT_INPUT_EVENT: {
516 finishedInputEvent(msg.arg1, false, true);
517 return;
518 }
519 case MSG_FLUSH_INPUT_EVENT: {
520 finishedInputEvent(msg.arg1, false, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700521 return;
522 }
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900523 case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
524 synchronized (mH) {
525 mNextUserActionNotificationSequenceNumber = msg.arg1;
526 }
527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529 }
530 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800531
Jean Chalardde9dbb02011-10-20 19:50:45 +0900532 private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
533 private final InputMethodManager mParentInputMethodManager;
534
535 public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
536 final InputMethodManager inputMethodManager) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 super(mainLooper, conn);
Jean Chalardde9dbb02011-10-20 19:50:45 +0900538 mParentInputMethodManager = inputMethodManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 }
540
Gilles Debunne8cbb4c62011-01-24 12:33:56 -0800541 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 public boolean isActive() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700543 return mParentInputMethodManager.mActive && !isFinished();
Dianne Hackbornac920872012-05-22 11:49:49 -0700544 }
545
546 void deactivate() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700547 if (isFinished()) {
548 // This is a small performance optimization. Still only the 1st call of
549 // reportFinish() will take effect.
550 return;
551 }
552 reportFinish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800554
555 @Override
Yohei Yukawa159dd472016-01-07 16:52:33 -0800556 protected void onUserAction() {
557 mParentInputMethodManager.notifyUserAction();
558 }
559
560 @Override
561 protected void onReportFullscreenMode(boolean enabled) {
562 mParentInputMethodManager.setFullscreenMode(enabled);
563 }
564
565 @Override
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800566 public String toString() {
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700567 return "ControlledInputConnectionWrapper{"
568 + "connection=" + getInputConnection()
569 + " finished=" + isFinished()
Yohei Yukawa12d66c22015-11-18 13:44:14 -0800570 + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
571 + "}";
572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 }
Yohei Yukawa159dd472016-01-07 16:52:33 -0800574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
Jeff Brownc28867a2013-03-26 15:42:39 -0700576 @Override
577 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 // No need to check for dump permission, since we only give this
579 // interface to the system.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 CountDownLatch latch = new CountDownLatch(1);
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700581 SomeArgs sargs = SomeArgs.obtain();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 sargs.arg1 = fd;
583 sargs.arg2 = fout;
584 sargs.arg3 = args;
585 sargs.arg4 = latch;
586 mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
587 try {
588 if (!latch.await(5, TimeUnit.SECONDS)) {
589 fout.println("Timeout waiting for dump");
590 }
591 } catch (InterruptedException e) {
592 fout.println("Interrupted waiting for dump");
593 }
594 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700595
596 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 public void setUsingInputMethod(boolean state) {
598 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700599
600 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 public void onBindMethod(InputBindResult res) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800602 mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700604
605 @Override
Yohei Yukawa33e81792015-11-17 21:14:42 -0800606 public void onUnbindMethod(int sequence, @InputMethodClient.UnbindReason int unbindReason) {
607 mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, unbindReason));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700609
610 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 public void setActive(boolean active) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800612 mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
Yohei Yukawab7b79072014-03-25 11:02:00 +0900614
615 @Override
Yohei Yukawa3d1e8122014-06-06 19:12:47 +0900616 public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
617 mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
618 sequenceNumber, 0));
619 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700620 };
621
Dianne Hackborn51bf0772009-03-24 19:11:41 -0700622 final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
Jeff Brown04ddf3c2012-06-14 03:57:49 -0700623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 InputMethodManager(IInputMethodManager service, Looper looper) {
625 mService = service;
626 mMainLooper = looper;
627 mH = new H(looper);
628 mIInputContext = new ControlledInputConnectionWrapper(looper,
Jean Chalardde9dbb02011-10-20 19:50:45 +0900629 mDummyInputConnection, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 }
631
632 /**
633 * Retrieve the global InputMethodManager instance, creating it if it
634 * doesn't already exist.
635 * @hide
636 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700637 public static InputMethodManager getInstance() {
638 synchronized (InputMethodManager.class) {
639 if (sInstance == null) {
640 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
641 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
642 sInstance = new InputMethodManager(service, Looper.getMainLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
Jeff Brownf9e989d2013-04-04 23:04:03 -0700644 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
647
648 /**
649 * Private optimization: retrieve the global InputMethodManager instance,
650 * if it exists.
651 * @hide
652 */
Jeff Brownf9e989d2013-04-04 23:04:03 -0700653 public static InputMethodManager peekInstance() {
654 return sInstance;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 }
656
657 /** @hide */
658 public IInputMethodClient getClient() {
659 return mClient;
660 }
661
662 /** @hide */
663 public IInputContext getInputContext() {
664 return mIInputContext;
665 }
666
667 public List<InputMethodInfo> getInputMethodList() {
668 try {
669 return mService.getInputMethodList();
670 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700671 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
673 }
674
675 public List<InputMethodInfo> getEnabledInputMethodList() {
676 try {
677 return mService.getEnabledInputMethodList();
678 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700679 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681 }
682
satokd4fce2b2011-04-11 12:07:13 +0900683 /**
684 * Returns a list of enabled input method subtypes for the specified input method info.
685 * @param imi An input method info whose subtypes list will be returned.
686 * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
687 * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
688 * will implicitly enable subtypes according to the current system language.
689 */
satok16331c82010-12-20 23:48:46 +0900690 public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
691 boolean allowsImplicitlySelectedSubtypes) {
satok67ddf9c2010-11-17 09:45:54 +0900692 try {
Satoshi Kataokab3c21ac2013-08-07 15:43:29 +0900693 return mService.getEnabledInputMethodSubtypeList(
694 imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
satok67ddf9c2010-11-17 09:45:54 +0900695 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700696 throw e.rethrowFromSystemServer();
satok67ddf9c2010-11-17 09:45:54 +0900697 }
698 }
699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
701 try {
702 mService.updateStatusIcon(imeToken, packageName, iconId);
703 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700704 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
706 }
707
708 public void hideStatusIcon(IBinder imeToken) {
709 try {
710 mService.updateStatusIcon(imeToken, null, 0);
711 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700712 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
714 }
715
716 /** @hide */
Joe Onorato857fd9b2011-01-27 15:08:35 -0800717 public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
satok06487a52010-10-29 11:37:18 +0900718 try {
Joe Onorato857fd9b2011-01-27 15:08:35 -0800719 mService.setImeWindowStatus(imeToken, vis, backDisposition);
satok06487a52010-10-29 11:37:18 +0900720 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700721 throw e.rethrowFromSystemServer();
satok06487a52010-10-29 11:37:18 +0900722 }
723 }
724
725 /** @hide */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 public void setFullscreenMode(boolean fullScreen) {
727 mFullscreenMode = fullScreen;
728 }
satokf9f01002011-05-19 21:31:50 +0900729
730 /** @hide */
731 public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
732 try {
733 mService.registerSuggestionSpansForNotification(spans);
734 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700735 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900736 }
737 }
738
739 /** @hide */
740 public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
741 try {
742 mService.notifySuggestionPicked(span, originalString, index);
743 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700744 throw e.rethrowFromSystemServer();
satokf9f01002011-05-19 21:31:50 +0900745 }
746 }
747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 /**
749 * Allows you to discover whether the attached input method is running
750 * in fullscreen mode. Return true if it is fullscreen, entirely covering
751 * your UI, else returns false.
752 */
753 public boolean isFullscreenMode() {
754 return mFullscreenMode;
755 }
756
757 /**
758 * Return true if the given view is the currently active view for the
759 * input method.
760 */
761 public boolean isActive(View view) {
762 checkFocus();
763 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700764 return (mServedView == view
765 || (mServedView != null
766 && mServedView.checkInputConnectionProxy(view)))
767 && mCurrentTextBoxAttribute != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
769 }
770
771 /**
772 * Return true if any view is currently active in the input method.
773 */
774 public boolean isActive() {
775 checkFocus();
776 synchronized (mH) {
777 return mServedView != null && mCurrentTextBoxAttribute != null;
778 }
779 }
780
781 /**
782 * Return true if the currently served view is accepting full text edits.
783 * If false, it has no input connection, so can only handle raw key events.
784 */
785 public boolean isAcceptingText() {
786 checkFocus();
Yohei Yukawaaaa38c92016-03-27 23:46:04 -0700787 return mServedInputConnectionWrapper != null &&
788 mServedInputConnectionWrapper.getInputConnection() != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
790
791 /**
792 * Reset all of the state associated with being bound to an input method.
793 */
794 void clearBindingLocked() {
Dianne Hackborn6b6b3fd2014-03-24 11:27:18 -0700795 if (DEBUG) Log.v(TAG, "Clearing binding!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 clearConnectionLocked();
Jeff Brown4d656882013-04-03 14:39:19 -0700797 setInputChannelLocked(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 mBindSequence = -1;
799 mCurId = null;
800 mCurMethod = null;
Jeff Brown4d656882013-04-03 14:39:19 -0700801 }
802
803 void setInputChannelLocked(InputChannel channel) {
804 if (mCurChannel != channel) {
805 if (mCurSender != null) {
806 flushPendingEventsLocked();
807 mCurSender.dispose();
808 mCurSender = null;
809 }
810 if (mCurChannel != null) {
811 mCurChannel.dispose();
812 }
813 mCurChannel = channel;
Jeff Brownc28867a2013-03-26 15:42:39 -0700814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
Jeff Brown4d656882013-04-03 14:39:19 -0700816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 /**
818 * Reset all of the state associated with a served view being connected
819 * to an input method
820 */
821 void clearConnectionLocked() {
822 mCurrentTextBoxAttribute = null;
Dianne Hackbornac920872012-05-22 11:49:49 -0700823 if (mServedInputConnectionWrapper != null) {
824 mServedInputConnectionWrapper.deactivate();
825 mServedInputConnectionWrapper = null;
826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
Yohei Yukawa0f3a99d2015-05-21 00:15:05 -0700828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 /**
830 * Disconnect any existing input connection, clearing the served view.
831 */
832 void finishInputLocked() {
833 mNextServedView = null;
834 if (mServedView != null) {
835 if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 if (mCurrentTextBoxAttribute != null) {
837 try {
838 mService.finishInput(mClient);
839 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700840 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 }
842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 mServedView = null;
844 mCompletions = null;
845 mServedConnecting = false;
846 clearConnectionLocked();
847 }
848 }
Gilles Debunnec478c172011-12-19 17:29:24 -0800849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 public void displayCompletions(View view, CompletionInfo[] completions) {
851 checkFocus();
852 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700853 if (mServedView != view && (mServedView == null
854 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 return;
856 }
857
858 mCompletions = completions;
859 if (mCurMethod != null) {
860 try {
861 mCurMethod.displayCompletions(mCompletions);
862 } catch (RemoteException e) {
863 }
864 }
865 }
866 }
867
868 public void updateExtractedText(View view, int token, ExtractedText text) {
869 checkFocus();
870 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700871 if (mServedView != view && (mServedView == null
872 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 return;
874 }
875
876 if (mCurMethod != null) {
877 try {
878 mCurMethod.updateExtractedText(token, text);
879 } catch (RemoteException e) {
880 }
881 }
882 }
883 }
884
885 /**
886 * Flag for {@link #showSoftInput} to indicate that this is an implicit
887 * request to show the input window, not as the result of a direct request
888 * by the user. The window may not be shown in this case.
889 */
890 public static final int SHOW_IMPLICIT = 0x0001;
891
892 /**
893 * Flag for {@link #showSoftInput} to indicate that the user has forced
894 * the input method open (such as by long-pressing menu) so it should
895 * not be closed until they explicitly do so.
896 */
897 public static final int SHOW_FORCED = 0x0002;
898
899 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800900 * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
901 * a result receiver: explicitly request that the current input method's
902 * soft input area be shown to the user, if needed.
903 *
904 * @param view The currently focused view, which would like to receive
905 * soft keyboard input.
906 * @param flags Provides additional operating flags. Currently may be
907 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
908 */
909 public boolean showSoftInput(View view, int flags) {
910 return showSoftInput(view, flags, null);
911 }
912
913 /**
914 * Flag for the {@link ResultReceiver} result code from
915 * {@link #showSoftInput(View, int, ResultReceiver)} and
916 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
917 * state of the soft input window was unchanged and remains shown.
918 */
919 public static final int RESULT_UNCHANGED_SHOWN = 0;
920
921 /**
922 * Flag for the {@link ResultReceiver} result code from
923 * {@link #showSoftInput(View, int, ResultReceiver)} and
924 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
925 * state of the soft input window was unchanged and remains hidden.
926 */
927 public static final int RESULT_UNCHANGED_HIDDEN = 1;
928
929 /**
930 * Flag for the {@link ResultReceiver} result code from
931 * {@link #showSoftInput(View, int, ResultReceiver)} and
932 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
933 * state of the soft input window changed from hidden to shown.
934 */
935 public static final int RESULT_SHOWN = 2;
936
937 /**
938 * Flag for the {@link ResultReceiver} result code from
939 * {@link #showSoftInput(View, int, ResultReceiver)} and
940 * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
941 * state of the soft input window changed from shown to hidden.
942 */
943 public static final int RESULT_HIDDEN = 3;
944
945 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 * Explicitly request that the current input method's soft input area be
947 * shown to the user, if needed. Call this if the user interacts with
948 * your view in such a way that they have expressed they would like to
949 * start performing input into it.
Yohei Yukawad552a522016-03-20 15:08:31 -0700950 *
951 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
952 * this method can be a long-lived object, because it may not be
953 * garbage-collected until all the corresponding {@link ResultReceiver}
954 * objects transferred to different processes get garbage-collected.
955 * Follow the general patterns to avoid memory leaks in Android.
956 * Consider to use {@link java.lang.ref.WeakReference} so that application
957 * logic objects such as {@link android.app.Activity} and {@link Context}
958 * can be garbage collected regardless of the lifetime of
959 * {@link ResultReceiver}.
960 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 * @param view The currently focused view, which would like to receive
962 * soft keyboard input.
963 * @param flags Provides additional operating flags. Currently may be
964 * 0 or have the {@link #SHOW_IMPLICIT} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -0800965 * @param resultReceiver If non-null, this will be called by the IME when
966 * it has processed your request to tell you what it has done. The result
967 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
968 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
969 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 */
Gilles Debunnead8484b2011-02-17 17:37:51 -0800971 public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 checkFocus();
973 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700974 if (mServedView != view && (mServedView == null
975 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800976 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 }
978
979 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800980 return mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700982 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 }
984 }
985 }
986
987 /** @hide */
The Android Open Source Project4df24232009-03-05 14:34:35 -0800988 public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800990 mService.showSoftInput(mClient, flags, resultReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700992 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 }
994 }
995
996 /**
997 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
998 * input window should only be hidden if it was not explicitly shown
999 * by the user.
1000 */
1001 public static final int HIDE_IMPLICIT_ONLY = 0x0001;
1002
1003 /**
1004 * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
1005 * input window should normally be hidden, unless it was originally
1006 * shown with {@link #SHOW_FORCED}.
1007 */
1008 public static final int HIDE_NOT_ALWAYS = 0x0002;
Gilles Debunnec478c172011-12-19 17:29:24 -08001009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 /**
Gilles Debunne7c8c6d62011-01-24 14:48:14 -08001011 * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
The Android Open Source Project4df24232009-03-05 14:34:35 -08001012 * without a result: request to hide the soft input window from the
1013 * context of the window that is currently accepting input.
1014 *
1015 * @param windowToken The token of the window that is making the request,
1016 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1017 * @param flags Provides additional operating flags. Currently may be
1018 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
1019 */
1020 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
1021 return hideSoftInputFromWindow(windowToken, flags, null);
1022 }
1023
1024 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 * Request to hide the soft input window from the context of the window
1026 * that is currently accepting input. This should be called as a result
1027 * of the user doing some actually than fairly explicitly requests to
1028 * have the input window hidden.
Yohei Yukawad552a522016-03-20 15:08:31 -07001029 *
1030 * <p><strong>Caveat:</strong> {@link ResultReceiver} instance passed to
1031 * this method can be a long-lived object, because it may not be
1032 * garbage-collected until all the corresponding {@link ResultReceiver}
1033 * objects transferred to different processes get garbage-collected.
1034 * Follow the general patterns to avoid memory leaks in Android.
1035 * Consider to use {@link java.lang.ref.WeakReference} so that application
1036 * logic objects such as {@link android.app.Activity} and {@link Context}
1037 * can be garbage collected regardless of the lifetime of
1038 * {@link ResultReceiver}.
1039 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 * @param windowToken The token of the window that is making the request,
1041 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1042 * @param flags Provides additional operating flags. Currently may be
1043 * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
The Android Open Source Project4df24232009-03-05 14:34:35 -08001044 * @param resultReceiver If non-null, this will be called by the IME when
1045 * it has processed your request to tell you what it has done. The result
1046 * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
1047 * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
1048 * {@link #RESULT_HIDDEN}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 */
The Android Open Source Project4df24232009-03-05 14:34:35 -08001050 public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
1051 ResultReceiver resultReceiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 checkFocus();
1053 synchronized (mH) {
1054 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001055 return false;
1056 }
1057
1058 try {
1059 return mService.hideSoftInput(mClient, flags, resultReceiver);
1060 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -07001061 throw e.rethrowFromSystemServer();
The Android Open Source Project4df24232009-03-05 14:34:35 -08001062 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001063 }
1064 }
1065
1066
1067 /**
1068 * This method toggles the input method window display.
1069 * If the input window is already displayed, it gets hidden.
1070 * If not the input window will be displayed.
1071 * @param windowToken The token of the window that is making the request,
1072 * as returned by {@link View#getWindowToken() View.getWindowToken()}.
1073 * @param showFlags Provides additional operating flags. May be
1074 * 0 or have the {@link #SHOW_IMPLICIT},
1075 * {@link #SHOW_FORCED} bit set.
1076 * @param hideFlags Provides additional operating flags. May be
1077 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1078 * {@link #HIDE_NOT_ALWAYS} bit set.
1079 **/
1080 public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
1081 synchronized (mH) {
1082 if (mServedView == null || mServedView.getWindowToken() != windowToken) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 return;
1084 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001085 if (mCurMethod != null) {
1086 try {
1087 mCurMethod.toggleSoftInput(showFlags, hideFlags);
1088 } catch (RemoteException e) {
1089 }
1090 }
1091 }
1092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093
The Android Open Source Project4df24232009-03-05 14:34:35 -08001094 /*
1095 * This method toggles the input method window display.
1096 * If the input window is already displayed, it gets hidden.
1097 * If not the input window will be displayed.
1098 * @param showFlags Provides additional operating flags. May be
1099 * 0 or have the {@link #SHOW_IMPLICIT},
1100 * {@link #SHOW_FORCED} bit set.
1101 * @param hideFlags Provides additional operating flags. May be
1102 * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
1103 * {@link #HIDE_NOT_ALWAYS} bit set.
1104 * @hide
1105 */
1106 public void toggleSoftInput(int showFlags, int hideFlags) {
1107 if (mCurMethod != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 try {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001109 mCurMethod.toggleSoftInput(showFlags, hideFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 } catch (RemoteException e) {
1111 }
1112 }
1113 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 /**
1116 * If the input method is currently connected to the given view,
1117 * restart it with its new contents. You should call this when the text
1118 * within your view changes outside of the normal input method or key
1119 * input flow, such as when an application calls TextView.setText().
1120 *
1121 * @param view The view whose text has changed.
1122 */
1123 public void restartInput(View view) {
1124 checkFocus();
1125 synchronized (mH) {
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -07001126 if (mServedView != view && (mServedView == null
1127 || !mServedView.checkInputConnectionProxy(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 return;
1129 }
1130
1131 mServedConnecting = true;
1132 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001133
1134 startInputInner(InputMethodClient.START_INPUT_REASON_APP_CALLED_RESTART_INPUT_API, null, 0,
1135 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 }
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001137
1138 boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
1139 IBinder windowGainingFocus, int controlFlags, int softInputMode,
Dianne Hackborn7663d802012-02-24 13:08:49 -08001140 int windowFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 final View view;
1142 synchronized (mH) {
1143 view = mServedView;
1144
1145 // Make sure we have a window token for the served view.
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001146 if (DEBUG) {
1147 Log.v(TAG, "Starting input: view=" + view +
1148 " reason=" + InputMethodClient.getStartInputReason(startInputReason));
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 if (view == null) {
1151 if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
Dianne Hackborn7663d802012-02-24 13:08:49 -08001152 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 }
1154 }
1155
1156 // Now we need to get an input connection from the served view.
1157 // This is complicated in a couple ways: we can't be holding our lock
1158 // when calling out to the view, and we need to make sure we call into
1159 // the view on the same thread that is driving its view hierarchy.
1160 Handler vh = view.getHandler();
1161 if (vh == null) {
1162 // If the view doesn't have a handler, something has changed out
Satoshi Kataoka35739502012-10-02 19:00:26 +09001163 // from under us, so just close the current input.
1164 // If we don't close the current input, the current input method can remain on the
1165 // screen without a connection.
1166 if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");
1167 closeCurrentInput();
Dianne Hackborn7663d802012-02-24 13:08:49 -08001168 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170 if (vh.getLooper() != Looper.myLooper()) {
1171 // The view is running on a different thread than our own, so
1172 // we need to reschedule our work for over there.
1173 if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
1174 vh.post(new Runnable() {
Jeff Brownc28867a2013-03-26 15:42:39 -07001175 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 public void run() {
Yohei Yukawa35d3f372015-11-25 11:07:19 -08001177 startInputInner(startInputReason, null, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 }
1179 });
Dianne Hackborn7663d802012-02-24 13:08:49 -08001180 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182
1183 // Okay we are now ready to call into the served view and have it
1184 // do its stuff.
1185 // Life is good: let's hook everything up!
1186 EditorInfo tba = new EditorInfo();
Yohei Yukawa02df3282015-06-03 15:58:59 -07001187 // Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the
1188 // system can verify the consistency between the uid of this process and package name passed
1189 // from here. See comment of Context#getOpPackageName() for details.
1190 tba.packageName = view.getContext().getOpPackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 tba.fieldId = view.getId();
1192 InputConnection ic = view.onCreateInputConnection(tba);
1193 if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
Gilles Debunnec478c172011-12-19 17:29:24 -08001194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 synchronized (mH) {
1196 // Now that we are locked again, validate that our state hasn't
1197 // changed.
1198 if (mServedView != view || !mServedConnecting) {
1199 // Something else happened, so abort.
1200 if (DEBUG) Log.v(TAG,
1201 "Starting input: finished by someone else (view="
1202 + mServedView + " conn=" + mServedConnecting + ")");
Dianne Hackborn7663d802012-02-24 13:08:49 -08001203 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 }
Dianne Hackborn7663d802012-02-24 13:08:49 -08001205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 // If we already have a text box, then this view is already
1207 // connected so we want to restart it.
Dianne Hackborn7663d802012-02-24 13:08:49 -08001208 if (mCurrentTextBoxAttribute == null) {
1209 controlFlags |= CONTROL_START_INITIAL;
1210 }
Yohei Yukawa612cce92016-02-11 17:47:33 -08001211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 // Hook 'em up and let 'er rip.
1213 mCurrentTextBoxAttribute = tba;
1214 mServedConnecting = false;
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001215 if (mServedInputConnectionWrapper != null) {
1216 mServedInputConnectionWrapper.deactivate();
1217 mServedInputConnectionWrapper = null;
1218 }
Dianne Hackbornac920872012-05-22 11:49:49 -07001219 ControlledInputConnectionWrapper servedContext;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001220 final int missingMethodFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 if (ic != null) {
1222 mCursorSelStart = tba.initialSelStart;
1223 mCursorSelEnd = tba.initialSelEnd;
1224 mCursorCandStart = -1;
1225 mCursorCandEnd = -1;
1226 mCursorRect.setEmpty();
Yohei Yukawa056ffe62014-05-13 14:26:09 +09001227 mCursorAnchorInfo = null;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001228 final Handler icHandler;
1229 missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);
1230 if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)
1231 != 0) {
1232 // InputConnection#getHandler() is not implemented.
1233 icHandler = null;
1234 } else {
1235 icHandler = ic.getHandler();
1236 }
Yohei Yukawa612cce92016-02-11 17:47:33 -08001237 servedContext = new ControlledInputConnectionWrapper(
1238 icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 } else {
1240 servedContext = null;
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001241 missingMethodFlags = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
Dianne Hackbornac920872012-05-22 11:49:49 -07001243 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,
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001251 windowFlags, tba, servedContext, missingMethodFlags);
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
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001386 final ControlledInputConnectionWrapper ic;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 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
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07001406 ic = mServedInputConnectionWrapper;
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,
Yohei Yukawa19a80a12016-03-14 22:57:37 -07001479 null, 0 /* missingMethodFlags */);
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 }
Yohei Yukawaaaa38c92016-03-27 23:46:04 -07002255 p.println(" mServedInputConnectionWrapper=" + mServedInputConnectionWrapper);
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}