blob: 897381d20854470dd7ae3fd7453f92240cfc1741 [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 com.android.internal.view;
18
19import android.os.Bundle;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.os.RemoteException;
24import android.util.Log;
25import android.view.KeyEvent;
26import android.view.inputmethod.CompletionInfo;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080027import android.view.inputmethod.CorrectionInfo;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +090028import android.view.inputmethod.CursorAnchorInfoRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.view.inputmethod.ExtractedTextRequest;
30import android.view.inputmethod.InputConnection;
31
32import java.lang.ref.WeakReference;
33
34public class IInputConnectionWrapper extends IInputContext.Stub {
35 static final String TAG = "IInputConnectionWrapper";
Amith Yamasania90b7f02010-08-25 18:27:20 -070036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
38 private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
Amith Yamasania90b7f02010-08-25 18:27:20 -070039 private static final int DO_GET_SELECTED_TEXT = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 private static final int DO_GET_CURSOR_CAPS_MODE = 30;
41 private static final int DO_GET_EXTRACTED_TEXT = 40;
42 private static final int DO_COMMIT_TEXT = 50;
43 private static final int DO_COMMIT_COMPLETION = 55;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080044 private static final int DO_COMMIT_CORRECTION = 56;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 private static final int DO_SET_SELECTION = 57;
46 private static final int DO_PERFORM_EDITOR_ACTION = 58;
47 private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
48 private static final int DO_SET_COMPOSING_TEXT = 60;
Amith Yamasania90b7f02010-08-25 18:27:20 -070049 private static final int DO_SET_COMPOSING_REGION = 63;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 private static final int DO_FINISH_COMPOSING_TEXT = 65;
51 private static final int DO_SEND_KEY_EVENT = 70;
52 private static final int DO_DELETE_SURROUNDING_TEXT = 80;
53 private static final int DO_BEGIN_BATCH_EDIT = 90;
54 private static final int DO_END_BATCH_EDIT = 95;
55 private static final int DO_REPORT_FULLSCREEN_MODE = 100;
56 private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
57 private static final int DO_CLEAR_META_KEY_STATES = 130;
Yohei Yukawa0023d0e2014-07-11 04:13:03 +090058 private static final int DO_REQUEST_CURSOR_ANCHOR_INFO = 140;
Amith Yamasania90b7f02010-08-25 18:27:20 -070059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 private WeakReference<InputConnection> mInputConnection;
61
62 private Looper mMainLooper;
63 private Handler mH;
64
65 static class SomeArgs {
66 Object arg1;
67 Object arg2;
68 IInputContextCallback callback;
69 int seq;
70 }
71
72 class MyHandler extends Handler {
73 MyHandler(Looper looper) {
74 super(looper);
75 }
76
77 @Override
78 public void handleMessage(Message msg) {
79 executeMessage(msg);
80 }
81 }
82
83 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
84 mInputConnection = new WeakReference<InputConnection>(conn);
85 mMainLooper = mainLooper;
86 mH = new MyHandler(mMainLooper);
87 }
88
89 public boolean isActive() {
90 return true;
91 }
92
93 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
94 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
95 }
96
97 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
98 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
99 }
100
Amith Yamasania90b7f02010-08-25 18:27:20 -0700101 public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
102 dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
103 }
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
106 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
107 }
108
109 public void getExtractedText(ExtractedTextRequest request,
110 int flags, int seq, IInputContextCallback callback) {
111 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
112 request, seq, callback));
113 }
114
115 public void commitText(CharSequence text, int newCursorPosition) {
116 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
117 }
118
119 public void commitCompletion(CompletionInfo text) {
120 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
121 }
122
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800123 public void commitCorrection(CorrectionInfo info) {
124 dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
125 }
126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 public void setSelection(int start, int end) {
128 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
129 }
130
131 public void performEditorAction(int id) {
132 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
133 }
134
135 public void performContextMenuAction(int id) {
136 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
137 }
138
Amith Yamasania90b7f02010-08-25 18:27:20 -0700139 public void setComposingRegion(int start, int end) {
140 dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
141 }
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 public void setComposingText(CharSequence text, int newCursorPosition) {
144 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
145 }
146
147 public void finishComposingText() {
148 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
149 }
150
151 public void sendKeyEvent(KeyEvent event) {
152 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
153 }
154
155 public void clearMetaKeyStates(int states) {
156 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
157 }
158
159 public void deleteSurroundingText(int leftLength, int rightLength) {
160 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
161 leftLength, rightLength));
162 }
163
164 public void beginBatchEdit() {
165 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
166 }
167
168 public void endBatchEdit() {
169 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
170 }
171
172 public void reportFullscreenMode(boolean enabled) {
173 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
174 }
175
176 public void performPrivateCommand(String action, Bundle data) {
177 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
178 }
satokadb43582011-03-09 10:08:47 +0900179
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900180 public void requestCursorAnchorInfo(CursorAnchorInfoRequest request, int seq,
181 IInputContextCallback callback) {
182 dispatchMessage(obtainMessageOSC(DO_REQUEST_CURSOR_ANCHOR_INFO, request, seq, callback));
183 }
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 void dispatchMessage(Message msg) {
186 // If we are calling this from the main thread, then we can call
187 // right through. Otherwise, we need to send the message to the
188 // main thread.
189 if (Looper.myLooper() == mMainLooper) {
190 executeMessage(msg);
191 msg.recycle();
192 return;
193 }
194
195 mH.sendMessage(msg);
196 }
197
198 void executeMessage(Message msg) {
199 switch (msg.what) {
200 case DO_GET_TEXT_AFTER_CURSOR: {
201 SomeArgs args = (SomeArgs)msg.obj;
202 try {
203 InputConnection ic = mInputConnection.get();
204 if (ic == null || !isActive()) {
205 Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
206 args.callback.setTextAfterCursor(null, args.seq);
207 return;
208 }
209 args.callback.setTextAfterCursor(ic.getTextAfterCursor(
210 msg.arg1, msg.arg2), args.seq);
211 } catch (RemoteException e) {
212 Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
213 }
214 return;
215 }
216 case DO_GET_TEXT_BEFORE_CURSOR: {
217 SomeArgs args = (SomeArgs)msg.obj;
218 try {
219 InputConnection ic = mInputConnection.get();
220 if (ic == null || !isActive()) {
221 Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
222 args.callback.setTextBeforeCursor(null, args.seq);
223 return;
224 }
225 args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
226 msg.arg1, msg.arg2), args.seq);
227 } catch (RemoteException e) {
228 Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
229 }
230 return;
231 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700232 case DO_GET_SELECTED_TEXT: {
233 SomeArgs args = (SomeArgs)msg.obj;
234 try {
235 InputConnection ic = mInputConnection.get();
236 if (ic == null || !isActive()) {
237 Log.w(TAG, "getSelectedText on inactive InputConnection");
238 args.callback.setSelectedText(null, args.seq);
239 return;
240 }
241 args.callback.setSelectedText(ic.getSelectedText(
242 msg.arg1), args.seq);
243 } catch (RemoteException e) {
244 Log.w(TAG, "Got RemoteException calling setSelectedText", e);
245 }
246 return;
247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 case DO_GET_CURSOR_CAPS_MODE: {
249 SomeArgs args = (SomeArgs)msg.obj;
250 try {
251 InputConnection ic = mInputConnection.get();
252 if (ic == null || !isActive()) {
253 Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
254 args.callback.setCursorCapsMode(0, args.seq);
255 return;
256 }
257 args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
258 args.seq);
259 } catch (RemoteException e) {
260 Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
261 }
262 return;
263 }
264 case DO_GET_EXTRACTED_TEXT: {
265 SomeArgs args = (SomeArgs)msg.obj;
266 try {
267 InputConnection ic = mInputConnection.get();
268 if (ic == null || !isActive()) {
269 Log.w(TAG, "getExtractedText on inactive InputConnection");
270 args.callback.setExtractedText(null, args.seq);
271 return;
272 }
273 args.callback.setExtractedText(ic.getExtractedText(
274 (ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
275 } catch (RemoteException e) {
276 Log.w(TAG, "Got RemoteException calling setExtractedText", e);
277 }
278 return;
279 }
280 case DO_COMMIT_TEXT: {
281 InputConnection ic = mInputConnection.get();
282 if (ic == null || !isActive()) {
283 Log.w(TAG, "commitText on inactive InputConnection");
284 return;
285 }
286 ic.commitText((CharSequence)msg.obj, msg.arg1);
287 return;
288 }
289 case DO_SET_SELECTION: {
290 InputConnection ic = mInputConnection.get();
291 if (ic == null || !isActive()) {
292 Log.w(TAG, "setSelection on inactive InputConnection");
293 return;
294 }
295 ic.setSelection(msg.arg1, msg.arg2);
296 return;
297 }
298 case DO_PERFORM_EDITOR_ACTION: {
299 InputConnection ic = mInputConnection.get();
300 if (ic == null || !isActive()) {
301 Log.w(TAG, "performEditorAction on inactive InputConnection");
302 return;
303 }
304 ic.performEditorAction(msg.arg1);
305 return;
306 }
307 case DO_PERFORM_CONTEXT_MENU_ACTION: {
308 InputConnection ic = mInputConnection.get();
309 if (ic == null || !isActive()) {
310 Log.w(TAG, "performContextMenuAction on inactive InputConnection");
311 return;
312 }
313 ic.performContextMenuAction(msg.arg1);
314 return;
315 }
316 case DO_COMMIT_COMPLETION: {
317 InputConnection ic = mInputConnection.get();
318 if (ic == null || !isActive()) {
319 Log.w(TAG, "commitCompletion on inactive InputConnection");
320 return;
321 }
322 ic.commitCompletion((CompletionInfo)msg.obj);
323 return;
324 }
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800325 case DO_COMMIT_CORRECTION: {
326 InputConnection ic = mInputConnection.get();
327 if (ic == null || !isActive()) {
328 Log.w(TAG, "commitCorrection on inactive InputConnection");
329 return;
330 }
331 ic.commitCorrection((CorrectionInfo)msg.obj);
332 return;
333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 case DO_SET_COMPOSING_TEXT: {
335 InputConnection ic = mInputConnection.get();
336 if (ic == null || !isActive()) {
337 Log.w(TAG, "setComposingText on inactive InputConnection");
338 return;
339 }
340 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
341 return;
342 }
Amith Yamasania90b7f02010-08-25 18:27:20 -0700343 case DO_SET_COMPOSING_REGION: {
344 InputConnection ic = mInputConnection.get();
345 if (ic == null || !isActive()) {
346 Log.w(TAG, "setComposingRegion on inactive InputConnection");
347 return;
348 }
349 ic.setComposingRegion(msg.arg1, msg.arg2);
350 return;
351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 case DO_FINISH_COMPOSING_TEXT: {
353 InputConnection ic = mInputConnection.get();
354 // Note we do NOT check isActive() here, because this is safe
355 // for an IME to call at any time, and we need to allow it
356 // through to clean up our state after the IME has switched to
357 // another client.
358 if (ic == null) {
359 Log.w(TAG, "finishComposingText on inactive InputConnection");
360 return;
361 }
362 ic.finishComposingText();
363 return;
364 }
365 case DO_SEND_KEY_EVENT: {
366 InputConnection ic = mInputConnection.get();
367 if (ic == null || !isActive()) {
368 Log.w(TAG, "sendKeyEvent on inactive InputConnection");
369 return;
370 }
371 ic.sendKeyEvent((KeyEvent)msg.obj);
372 return;
373 }
374 case DO_CLEAR_META_KEY_STATES: {
375 InputConnection ic = mInputConnection.get();
376 if (ic == null || !isActive()) {
377 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
378 return;
379 }
380 ic.clearMetaKeyStates(msg.arg1);
381 return;
382 }
383 case DO_DELETE_SURROUNDING_TEXT: {
384 InputConnection ic = mInputConnection.get();
385 if (ic == null || !isActive()) {
386 Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
387 return;
388 }
389 ic.deleteSurroundingText(msg.arg1, msg.arg2);
390 return;
391 }
392 case DO_BEGIN_BATCH_EDIT: {
393 InputConnection ic = mInputConnection.get();
394 if (ic == null || !isActive()) {
395 Log.w(TAG, "beginBatchEdit on inactive InputConnection");
396 return;
397 }
398 ic.beginBatchEdit();
399 return;
400 }
401 case DO_END_BATCH_EDIT: {
402 InputConnection ic = mInputConnection.get();
403 if (ic == null || !isActive()) {
404 Log.w(TAG, "endBatchEdit on inactive InputConnection");
405 return;
406 }
407 ic.endBatchEdit();
408 return;
409 }
410 case DO_REPORT_FULLSCREEN_MODE: {
411 InputConnection ic = mInputConnection.get();
412 if (ic == null || !isActive()) {
413 Log.w(TAG, "showStatusIcon on inactive InputConnection");
414 return;
415 }
416 ic.reportFullscreenMode(msg.arg1 == 1);
417 return;
418 }
419 case DO_PERFORM_PRIVATE_COMMAND: {
420 InputConnection ic = mInputConnection.get();
421 if (ic == null || !isActive()) {
422 Log.w(TAG, "performPrivateCommand on inactive InputConnection");
423 return;
424 }
425 SomeArgs args = (SomeArgs)msg.obj;
426 ic.performPrivateCommand((String)args.arg1,
427 (Bundle)args.arg2);
428 return;
429 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900430 case DO_REQUEST_CURSOR_ANCHOR_INFO: {
431 SomeArgs args = (SomeArgs)msg.obj;
432 try {
433 InputConnection ic = mInputConnection.get();
434 if (ic == null || !isActive()) {
435 Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
436 args.callback.setRequestCursorAnchorInfoResult(0, args.seq);
437 return;
438 }
439 args.callback.setRequestCursorAnchorInfoResult(
440 ic.requestCursorAnchorInfo((CursorAnchorInfoRequest)args.arg1),
441 args.seq);
442 } catch (RemoteException e) {
443 Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
444 }
445 return;
446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 }
448 Log.w(TAG, "Unhandled message code: " + msg.what);
449 }
450
451 Message obtainMessage(int what) {
452 return mH.obtainMessage(what);
453 }
454
455 Message obtainMessageII(int what, int arg1, int arg2) {
456 return mH.obtainMessage(what, arg1, arg2);
457 }
458
459 Message obtainMessageO(int what, Object arg1) {
460 return mH.obtainMessage(what, 0, 0, arg1);
461 }
462
463 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
464 SomeArgs args = new SomeArgs();
465 args.callback = callback;
466 args.seq = seq;
467 return mH.obtainMessage(what, arg1, 0, args);
468 }
469
470 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
471 SomeArgs args = new SomeArgs();
472 args.callback = callback;
473 args.seq = seq;
474 return mH.obtainMessage(what, arg1, arg2, args);
475 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900476
477 Message obtainMessageOSC(int what, Object arg1, int seq, IInputContextCallback callback) {
478 SomeArgs args = new SomeArgs();
479 args.arg1 = arg1;
480 args.callback = callback;
481 args.seq = seq;
482 return mH.obtainMessage(what, 0, 0, args);
483 }
484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
486 IInputContextCallback callback) {
487 SomeArgs args = new SomeArgs();
488 args.arg1 = arg2;
489 args.callback = callback;
490 args.seq = seq;
491 return mH.obtainMessage(what, arg1, 0, args);
492 }
493
494 Message obtainMessageIO(int what, int arg1, Object arg2) {
495 return mH.obtainMessage(what, arg1, 0, arg2);
496 }
497
498 Message obtainMessageOO(int what, Object arg1, Object arg2) {
499 SomeArgs args = new SomeArgs();
500 args.arg1 = arg1;
501 args.arg2 = arg2;
502 return mH.obtainMessage(what, 0, 0, args);
503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504}