blob: 93063739cfd6eabadb42becf3373180087cb6904 [file] [log] [blame]
Kenny Root15a4d2f2010-03-11 18:20:12 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017package android.inputmethodservice;
18
19import com.android.internal.os.HandlerCaller;
Svetoslav Ganov758143e2012-08-06 16:40:27 -070020import com.android.internal.os.SomeArgs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.internal.view.IInputContext;
22import com.android.internal.view.IInputMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import com.android.internal.view.IInputMethodSession;
Michael Wright52a53522013-03-14 10:59:38 -070024import com.android.internal.view.IInputSessionCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import com.android.internal.view.InputConnectionWrapper;
26
27import android.content.Context;
28import android.content.pm.PackageManager;
29import android.os.Binder;
30import android.os.IBinder;
31import android.os.Message;
32import android.os.RemoteException;
The Android Open Source Project4df24232009-03-05 14:34:35 -080033import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.util.Log;
Jeff Brownc28867a2013-03-26 15:42:39 -070035import android.view.InputChannel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.view.inputmethod.EditorInfo;
37import android.view.inputmethod.InputBinding;
38import android.view.inputmethod.InputConnection;
39import android.view.inputmethod.InputMethod;
40import android.view.inputmethod.InputMethodSession;
satokab751aa2010-09-14 19:17:36 +090041import android.view.inputmethod.InputMethodSubtype;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43import java.io.FileDescriptor;
44import java.io.PrintWriter;
Devin Taylor0c33ed22010-02-23 13:26:46 -060045import java.lang.ref.WeakReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import java.util.concurrent.CountDownLatch;
47import java.util.concurrent.TimeUnit;
48
49/**
50 * Implements the internal IInputMethod interface to convert incoming calls
51 * on to it back to calls on the public InputMethod interface, scheduling
52 * them on the main thread of the process.
53 */
54class IInputMethodWrapper extends IInputMethod.Stub
55 implements HandlerCaller.Callback {
56 private static final String TAG = "InputMethodWrapper";
Craig Mautnere4bbb1c2013-03-15 11:38:44 -070057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 private static final int DO_DUMP = 1;
59 private static final int DO_ATTACH_TOKEN = 10;
60 private static final int DO_SET_INPUT_CONTEXT = 20;
61 private static final int DO_UNSET_INPUT_CONTEXT = 30;
62 private static final int DO_START_INPUT = 32;
63 private static final int DO_RESTART_INPUT = 34;
64 private static final int DO_CREATE_SESSION = 40;
65 private static final int DO_SET_SESSION_ENABLED = 45;
66 private static final int DO_REVOKE_SESSION = 50;
67 private static final int DO_SHOW_SOFT_INPUT = 60;
68 private static final int DO_HIDE_SOFT_INPUT = 70;
satokab751aa2010-09-14 19:17:36 +090069 private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
Devin Taylor0c33ed22010-02-23 13:26:46 -060071 final WeakReference<AbstractInputMethodService> mTarget;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 final HandlerCaller mCaller;
Devin Taylor0c33ed22010-02-23 13:26:46 -060073 final WeakReference<InputMethod> mInputMethod;
Dianne Hackborndea3ef72010-10-28 14:24:22 -070074 final int mTargetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075
76 static class Notifier {
77 boolean notified;
78 }
79
80 // NOTE: we should have a cache of these.
Jeff Brownc28867a2013-03-26 15:42:39 -070081 static final class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 final Context mContext;
Jeff Brownc28867a2013-03-26 15:42:39 -070083 final InputChannel mChannel;
Michael Wright52a53522013-03-14 10:59:38 -070084 final IInputSessionCallback mCb;
Jeff Brownc28867a2013-03-26 15:42:39 -070085
86 InputMethodSessionCallbackWrapper(Context context, InputChannel channel,
87 IInputSessionCallback cb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 mContext = context;
Jeff Brownc28867a2013-03-26 15:42:39 -070089 mChannel = channel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 mCb = cb;
91 }
Jeff Brownc28867a2013-03-26 15:42:39 -070092
93 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 public void sessionCreated(InputMethodSession session) {
95 try {
96 if (session != null) {
97 IInputMethodSessionWrapper wrap =
Jeff Brownc28867a2013-03-26 15:42:39 -070098 new IInputMethodSessionWrapper(mContext, session, mChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 mCb.sessionCreated(wrap);
100 } else {
Jeff Brownc28867a2013-03-26 15:42:39 -0700101 if (mChannel != null) {
102 mChannel.dispose();
103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 mCb.sessionCreated(null);
105 }
106 } catch (RemoteException e) {
107 }
108 }
109 }
110
111 public IInputMethodWrapper(AbstractInputMethodService context,
112 InputMethod inputMethod) {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600113 mTarget = new WeakReference<AbstractInputMethodService>(context);
Mita Yuned218c72012-12-06 17:18:25 -0800114 mCaller = new HandlerCaller(context.getApplicationContext(), null,
115 this, true /*asyncHandler*/);
Devin Taylor0c33ed22010-02-23 13:26:46 -0600116 mInputMethod = new WeakReference<InputMethod>(inputMethod);
Dianne Hackborndea3ef72010-10-28 14:24:22 -0700117 mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 }
119
120 public InputMethod getInternalInputMethod() {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600121 return mInputMethod.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 }
123
Jeff Brownc28867a2013-03-26 15:42:39 -0700124 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 public void executeMessage(Message msg) {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600126 InputMethod inputMethod = mInputMethod.get();
127 // Need a valid reference to the inputMethod for everything except a dump.
128 if (inputMethod == null && msg.what != DO_DUMP) {
129 Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
130 return;
131 }
132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 switch (msg.what) {
134 case DO_DUMP: {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600135 AbstractInputMethodService target = mTarget.get();
136 if (target == null) {
137 return;
138 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700139 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 try {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600141 target.dump((FileDescriptor)args.arg1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 (PrintWriter)args.arg2, (String[])args.arg3);
143 } catch (RuntimeException e) {
144 ((PrintWriter)args.arg2).println("Exception: " + e);
145 }
146 synchronized (args.arg4) {
147 ((CountDownLatch)args.arg4).countDown();
148 }
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700149 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 return;
151 }
152
153 case DO_ATTACH_TOKEN: {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600154 inputMethod.attachToken((IBinder)msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 return;
156 }
157 case DO_SET_INPUT_CONTEXT: {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600158 inputMethod.bindInput((InputBinding)msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 return;
160 }
161 case DO_UNSET_INPUT_CONTEXT:
Devin Taylor0c33ed22010-02-23 13:26:46 -0600162 inputMethod.unbindInput();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 return;
164 case DO_START_INPUT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700165 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 IInputContext inputContext = (IInputContext)args.arg1;
167 InputConnection ic = inputContext != null
168 ? new InputConnectionWrapper(inputContext) : null;
Dianne Hackborndea3ef72010-10-28 14:24:22 -0700169 EditorInfo info = (EditorInfo)args.arg2;
170 info.makeCompatible(mTargetSdkVersion);
171 inputMethod.startInput(ic, info);
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700172 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 return;
174 }
175 case DO_RESTART_INPUT: {
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700176 SomeArgs args = (SomeArgs)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 IInputContext inputContext = (IInputContext)args.arg1;
178 InputConnection ic = inputContext != null
179 ? new InputConnectionWrapper(inputContext) : null;
Dianne Hackborndea3ef72010-10-28 14:24:22 -0700180 EditorInfo info = (EditorInfo)args.arg2;
181 info.makeCompatible(mTargetSdkVersion);
182 inputMethod.restartInput(ic, info);
Svetoslav Ganov758143e2012-08-06 16:40:27 -0700183 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 return;
185 }
186 case DO_CREATE_SESSION: {
Jeff Brownc28867a2013-03-26 15:42:39 -0700187 SomeArgs args = (SomeArgs)msg.obj;
Devin Taylor0c33ed22010-02-23 13:26:46 -0600188 inputMethod.createSession(new InputMethodSessionCallbackWrapper(
Jeff Brownc28867a2013-03-26 15:42:39 -0700189 mCaller.mContext, (InputChannel)args.arg1,
190 (IInputSessionCallback)args.arg2));
191 args.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 return;
193 }
194 case DO_SET_SESSION_ENABLED:
Devin Taylor0c33ed22010-02-23 13:26:46 -0600195 inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 msg.arg1 != 0);
197 return;
198 case DO_REVOKE_SESSION:
Devin Taylor0c33ed22010-02-23 13:26:46 -0600199 inputMethod.revokeSession((InputMethodSession)msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 return;
201 case DO_SHOW_SOFT_INPUT:
Devin Taylor0c33ed22010-02-23 13:26:46 -0600202 inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 return;
204 case DO_HIDE_SOFT_INPUT:
Devin Taylor0c33ed22010-02-23 13:26:46 -0600205 inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 return;
satokab751aa2010-09-14 19:17:36 +0900207 case DO_CHANGE_INPUTMETHOD_SUBTYPE:
208 inputMethod.changeInputMethodSubtype((InputMethodSubtype)msg.obj);
209 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 }
211 Log.w(TAG, "Unhandled message code: " + msg.what);
212 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700213
214 @Override
215 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Devin Taylor0c33ed22010-02-23 13:26:46 -0600216 AbstractInputMethodService target = mTarget.get();
217 if (target == null) {
218 return;
219 }
220 if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 != PackageManager.PERMISSION_GRANTED) {
222
223 fout.println("Permission Denial: can't dump InputMethodManager from from pid="
224 + Binder.getCallingPid()
225 + ", uid=" + Binder.getCallingUid());
226 return;
227 }
228
229 CountDownLatch latch = new CountDownLatch(1);
230 mCaller.executeOrSendMessage(mCaller.obtainMessageOOOO(DO_DUMP,
231 fd, fout, args, latch));
232 try {
233 if (!latch.await(5, TimeUnit.SECONDS)) {
234 fout.println("Timeout waiting for dump");
235 }
236 } catch (InterruptedException e) {
237 fout.println("Interrupted waiting for dump");
238 }
239 }
240
Jeff Brownc28867a2013-03-26 15:42:39 -0700241 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 public void attachToken(IBinder token) {
243 mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
244 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700245
246 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 public void bindInput(InputBinding binding) {
248 InputConnection ic = new InputConnectionWrapper(
249 IInputContext.Stub.asInterface(binding.getConnectionToken()));
250 InputBinding nu = new InputBinding(ic, binding);
251 mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
252 }
253
Jeff Brownc28867a2013-03-26 15:42:39 -0700254 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 public void unbindInput() {
256 mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
257 }
258
Jeff Brownc28867a2013-03-26 15:42:39 -0700259 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 public void startInput(IInputContext inputContext, EditorInfo attribute) {
261 mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,
262 inputContext, attribute));
263 }
264
Jeff Brownc28867a2013-03-26 15:42:39 -0700265 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 public void restartInput(IInputContext inputContext, EditorInfo attribute) {
267 mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_RESTART_INPUT,
268 inputContext, attribute));
269 }
270
Jeff Brownc28867a2013-03-26 15:42:39 -0700271 @Override
272 public void createSession(InputChannel channel, IInputSessionCallback callback) {
273 mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_SESSION,
274 channel, callback));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 }
276
Jeff Brownc28867a2013-03-26 15:42:39 -0700277 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 public void setSessionEnabled(IInputMethodSession session, boolean enabled) {
279 try {
280 InputMethodSession ls = ((IInputMethodSessionWrapper)
281 session).getInternalInputMethodSession();
282 mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
283 DO_SET_SESSION_ENABLED, enabled ? 1 : 0, ls));
284 } catch (ClassCastException e) {
285 Log.w(TAG, "Incoming session not of correct type: " + session, e);
286 }
287 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700288
289 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 public void revokeSession(IInputMethodSession session) {
291 try {
292 InputMethodSession ls = ((IInputMethodSessionWrapper)
293 session).getInternalInputMethodSession();
294 mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REVOKE_SESSION, ls));
295 } catch (ClassCastException e) {
296 Log.w(TAG, "Incoming session not of correct type: " + session, e);
297 }
298 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700299
300 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800301 public void showSoftInput(int flags, ResultReceiver resultReceiver) {
302 mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
303 flags, resultReceiver));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 }
Jeff Brownc28867a2013-03-26 15:42:39 -0700305
306 @Override
The Android Open Source Project4df24232009-03-05 14:34:35 -0800307 public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
308 mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
309 flags, resultReceiver));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 }
satokab751aa2010-09-14 19:17:36 +0900311
Jeff Brownc28867a2013-03-26 15:42:39 -0700312 @Override
satokab751aa2010-09-14 19:17:36 +0900313 public void changeInputMethodSubtype(InputMethodSubtype subtype) {
314 mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,
315 subtype));
316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317}