blob: b1f5d909cdf5f1f0731658b2449cb96a87ee1aa6 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.view.inputmethod.ExtractedTextRequest;
29import android.view.inputmethod.InputConnection;
30
31import java.lang.ref.WeakReference;
32
33public class IInputConnectionWrapper extends IInputContext.Stub {
34 static final String TAG = "IInputConnectionWrapper";
Amith Yamasania90b7f02010-08-25 18:27:20 -070035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
37 private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
Amith Yamasania90b7f02010-08-25 18:27:20 -070038 private static final int DO_GET_SELECTED_TEXT = 25;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private static final int DO_GET_CURSOR_CAPS_MODE = 30;
40 private static final int DO_GET_EXTRACTED_TEXT = 40;
41 private static final int DO_COMMIT_TEXT = 50;
42 private static final int DO_COMMIT_COMPLETION = 55;
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -080043 private static final int DO_COMMIT_CORRECTION = 56;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 private static final int DO_SET_SELECTION = 57;
45 private static final int DO_PERFORM_EDITOR_ACTION = 58;
46 private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
47 private static final int DO_SET_COMPOSING_TEXT = 60;
Amith Yamasania90b7f02010-08-25 18:27:20 -070048 private static final int DO_SET_COMPOSING_REGION = 63;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private static final int DO_FINISH_COMPOSING_TEXT = 65;
50 private static final int DO_SEND_KEY_EVENT = 70;
51 private static final int DO_DELETE_SURROUNDING_TEXT = 80;
52 private static final int DO_BEGIN_BATCH_EDIT = 90;
53 private static final int DO_END_BATCH_EDIT = 95;
54 private static final int DO_REPORT_FULLSCREEN_MODE = 100;
55 private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
56 private static final int DO_CLEAR_META_KEY_STATES = 130;
Yohei Yukawaa277db22014-08-21 18:38:44 -070057 private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
Amith Yamasania90b7f02010-08-25 18:27:20 -070058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 private WeakReference<InputConnection> mInputConnection;
60
61 private Looper mMainLooper;
62 private Handler mH;
63
64 static class SomeArgs {
65 Object arg1;
66 Object arg2;
67 IInputContextCallback callback;
68 int seq;
69 }
70
71 class MyHandler extends Handler {
72 MyHandler(Looper looper) {
73 super(looper);
74 }
75
76 @Override
77 public void handleMessage(Message msg) {
78 executeMessage(msg);
79 }
80 }
81
82 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
83 mInputConnection = new WeakReference<InputConnection>(conn);
84 mMainLooper = mainLooper;
85 mH = new MyHandler(mMainLooper);
86 }
87
88 public boolean isActive() {
89 return true;
90 }
91
92 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
93 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
94 }
95
96 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
97 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
98 }
99
Amith Yamasania90b7f02010-08-25 18:27:20 -0700100 public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
101 dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
102 }
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
105 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
106 }
107
108 public void getExtractedText(ExtractedTextRequest request,
109 int flags, int seq, IInputContextCallback callback) {
110 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags,
111 request, seq, callback));
112 }
113
114 public void commitText(CharSequence text, int newCursorPosition) {
115 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text));
116 }
117
118 public void commitCompletion(CompletionInfo text) {
119 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
120 }
121
Gilles Debunnecf9cf2f2010-12-08 17:43:58 -0800122 public void commitCorrection(CorrectionInfo info) {
123 dispatchMessage(obtainMessageO(DO_COMMIT_CORRECTION, info));
124 }
125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 public void setSelection(int start, int end) {
127 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
128 }
129
130 public void performEditorAction(int id) {
131 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
132 }
133
134 public void performContextMenuAction(int id) {
135 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
136 }
137
Amith Yamasania90b7f02010-08-25 18:27:20 -0700138 public void setComposingRegion(int start, int end) {
139 dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
140 }
141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 public void setComposingText(CharSequence text, int newCursorPosition) {
143 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
144 }
145
146 public void finishComposingText() {
147 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT));
148 }
149
150 public void sendKeyEvent(KeyEvent event) {
151 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event));
152 }
153
154 public void clearMetaKeyStates(int states) {
155 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
156 }
157
158 public void deleteSurroundingText(int leftLength, int rightLength) {
159 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
160 leftLength, rightLength));
161 }
162
163 public void beginBatchEdit() {
164 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT));
165 }
166
167 public void endBatchEdit() {
168 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
169 }
170
171 public void reportFullscreenMode(boolean enabled) {
172 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
173 }
174
175 public void performPrivateCommand(String action, Bundle data) {
176 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
177 }
satokadb43582011-03-09 10:08:47 +0900178
Yohei Yukawaa277db22014-08-21 18:38:44 -0700179 public void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900180 IInputContextCallback callback) {
Yohei Yukawaa277db22014-08-21 18:38:44 -0700181 dispatchMessage(obtainMessageISC(DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO, cursorUpdateMode,
182 seq, callback));
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900183 }
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 Yukawaa277db22014-08-21 18:38:44 -0700430 case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900431 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");
Yohei Yukawaa277db22014-08-21 18:38:44 -0700436 args.callback.setRequestUpdateCursorAnchorInfoResult(false, args.seq);
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900437 return;
438 }
Yohei Yukawaa277db22014-08-21 18:38:44 -0700439 args.callback.setRequestUpdateCursorAnchorInfoResult(
440 ic.requestUpdateCursorAnchorInfo(msg.arg1), args.seq);
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900441 } catch (RemoteException e) {
442 Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
443 }
444 return;
445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447 Log.w(TAG, "Unhandled message code: " + msg.what);
448 }
449
450 Message obtainMessage(int what) {
451 return mH.obtainMessage(what);
452 }
453
454 Message obtainMessageII(int what, int arg1, int arg2) {
455 return mH.obtainMessage(what, arg1, arg2);
456 }
457
458 Message obtainMessageO(int what, Object arg1) {
459 return mH.obtainMessage(what, 0, 0, arg1);
460 }
461
462 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) {
463 SomeArgs args = new SomeArgs();
464 args.callback = callback;
465 args.seq = seq;
466 return mH.obtainMessage(what, arg1, 0, args);
467 }
468
469 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
470 SomeArgs args = new SomeArgs();
471 args.callback = callback;
472 args.seq = seq;
473 return mH.obtainMessage(what, arg1, arg2, args);
474 }
Yohei Yukawa0023d0e2014-07-11 04:13:03 +0900475
476 Message obtainMessageOSC(int what, Object arg1, int seq, IInputContextCallback callback) {
477 SomeArgs args = new SomeArgs();
478 args.arg1 = arg1;
479 args.callback = callback;
480 args.seq = seq;
481 return mH.obtainMessage(what, 0, 0, args);
482 }
483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
485 IInputContextCallback callback) {
486 SomeArgs args = new SomeArgs();
487 args.arg1 = arg2;
488 args.callback = callback;
489 args.seq = seq;
490 return mH.obtainMessage(what, arg1, 0, args);
491 }
492
493 Message obtainMessageIO(int what, int arg1, Object arg2) {
494 return mH.obtainMessage(what, arg1, 0, arg2);
495 }
496
497 Message obtainMessageOO(int what, Object arg1, Object arg2) {
498 SomeArgs args = new SomeArgs();
499 args.arg1 = arg1;
500 args.arg2 = arg2;
501 return mH.obtainMessage(what, 0, 0, args);
502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503}