IInputConnectionWrapper.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1package com.android.internal.view; 2 3import android.os.Bundle; 4import android.os.Handler; 5import android.os.Looper; 6import android.os.Message; 7import android.os.RemoteException; 8import android.util.Log; 9import android.view.KeyEvent; 10import android.view.inputmethod.CompletionInfo; 11import android.view.inputmethod.ExtractedTextRequest; 12import android.view.inputmethod.InputConnection; 13 14import java.lang.ref.WeakReference; 15 16public class IInputConnectionWrapper extends IInputContext.Stub { 17 static final String TAG = "IInputConnectionWrapper"; 18 19 private static final int DO_GET_TEXT_AFTER_CURSOR = 10; 20 private static final int DO_GET_TEXT_BEFORE_CURSOR = 20; 21 private static final int DO_GET_CURSOR_CAPS_MODE = 30; 22 private static final int DO_GET_EXTRACTED_TEXT = 40; 23 private static final int DO_COMMIT_TEXT = 50; 24 private static final int DO_COMMIT_COMPLETION = 55; 25 private static final int DO_SET_SELECTION = 57; 26 private static final int DO_PERFORM_EDITOR_ACTION = 58; 27 private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59; 28 private static final int DO_SET_COMPOSING_TEXT = 60; 29 private static final int DO_FINISH_COMPOSING_TEXT = 65; 30 private static final int DO_SEND_KEY_EVENT = 70; 31 private static final int DO_DELETE_SURROUNDING_TEXT = 80; 32 private static final int DO_BEGIN_BATCH_EDIT = 90; 33 private static final int DO_END_BATCH_EDIT = 95; 34 private static final int DO_REPORT_FULLSCREEN_MODE = 100; 35 private static final int DO_PERFORM_PRIVATE_COMMAND = 120; 36 private static final int DO_CLEAR_META_KEY_STATES = 130; 37 38 private WeakReference<InputConnection> mInputConnection; 39 40 private Looper mMainLooper; 41 private Handler mH; 42 43 static class SomeArgs { 44 Object arg1; 45 Object arg2; 46 IInputContextCallback callback; 47 int seq; 48 } 49 50 class MyHandler extends Handler { 51 MyHandler(Looper looper) { 52 super(looper); 53 } 54 55 @Override 56 public void handleMessage(Message msg) { 57 executeMessage(msg); 58 } 59 } 60 61 public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) { 62 mInputConnection = new WeakReference<InputConnection>(conn); 63 mMainLooper = mainLooper; 64 mH = new MyHandler(mMainLooper); 65 } 66 67 public boolean isActive() { 68 return true; 69 } 70 71 public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) { 72 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback)); 73 } 74 75 public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) { 76 dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback)); 77 } 78 79 public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) { 80 dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback)); 81 } 82 83 public void getExtractedText(ExtractedTextRequest request, 84 int flags, int seq, IInputContextCallback callback) { 85 dispatchMessage(obtainMessageIOSC(DO_GET_EXTRACTED_TEXT, flags, 86 request, seq, callback)); 87 } 88 89 public void commitText(CharSequence text, int newCursorPosition) { 90 dispatchMessage(obtainMessageIO(DO_COMMIT_TEXT, newCursorPosition, text)); 91 } 92 93 public void commitCompletion(CompletionInfo text) { 94 dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text)); 95 } 96 97 public void setSelection(int start, int end) { 98 dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end)); 99 } 100 101 public void performEditorAction(int id) { 102 dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0)); 103 } 104 105 public void performContextMenuAction(int id) { 106 dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0)); 107 } 108 109 public void setComposingText(CharSequence text, int newCursorPosition) { 110 dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text)); 111 } 112 113 public void finishComposingText() { 114 dispatchMessage(obtainMessage(DO_FINISH_COMPOSING_TEXT)); 115 } 116 117 public void sendKeyEvent(KeyEvent event) { 118 dispatchMessage(obtainMessageO(DO_SEND_KEY_EVENT, event)); 119 } 120 121 public void clearMetaKeyStates(int states) { 122 dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0)); 123 } 124 125 public void deleteSurroundingText(int leftLength, int rightLength) { 126 dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT, 127 leftLength, rightLength)); 128 } 129 130 public void beginBatchEdit() { 131 dispatchMessage(obtainMessage(DO_BEGIN_BATCH_EDIT)); 132 } 133 134 public void endBatchEdit() { 135 dispatchMessage(obtainMessage(DO_END_BATCH_EDIT)); 136 } 137 138 public void reportFullscreenMode(boolean enabled) { 139 dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0)); 140 } 141 142 public void performPrivateCommand(String action, Bundle data) { 143 dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data)); 144 } 145 146 void dispatchMessage(Message msg) { 147 // If we are calling this from the main thread, then we can call 148 // right through. Otherwise, we need to send the message to the 149 // main thread. 150 if (Looper.myLooper() == mMainLooper) { 151 executeMessage(msg); 152 msg.recycle(); 153 return; 154 } 155 156 mH.sendMessage(msg); 157 } 158 159 void executeMessage(Message msg) { 160 switch (msg.what) { 161 case DO_GET_TEXT_AFTER_CURSOR: { 162 SomeArgs args = (SomeArgs)msg.obj; 163 try { 164 InputConnection ic = mInputConnection.get(); 165 if (ic == null || !isActive()) { 166 Log.w(TAG, "getTextAfterCursor on inactive InputConnection"); 167 args.callback.setTextAfterCursor(null, args.seq); 168 return; 169 } 170 args.callback.setTextAfterCursor(ic.getTextAfterCursor( 171 msg.arg1, msg.arg2), args.seq); 172 } catch (RemoteException e) { 173 Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e); 174 } 175 return; 176 } 177 case DO_GET_TEXT_BEFORE_CURSOR: { 178 SomeArgs args = (SomeArgs)msg.obj; 179 try { 180 InputConnection ic = mInputConnection.get(); 181 if (ic == null || !isActive()) { 182 Log.w(TAG, "getTextBeforeCursor on inactive InputConnection"); 183 args.callback.setTextBeforeCursor(null, args.seq); 184 return; 185 } 186 args.callback.setTextBeforeCursor(ic.getTextBeforeCursor( 187 msg.arg1, msg.arg2), args.seq); 188 } catch (RemoteException e) { 189 Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e); 190 } 191 return; 192 } 193 case DO_GET_CURSOR_CAPS_MODE: { 194 SomeArgs args = (SomeArgs)msg.obj; 195 try { 196 InputConnection ic = mInputConnection.get(); 197 if (ic == null || !isActive()) { 198 Log.w(TAG, "getCursorCapsMode on inactive InputConnection"); 199 args.callback.setCursorCapsMode(0, args.seq); 200 return; 201 } 202 args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1), 203 args.seq); 204 } catch (RemoteException e) { 205 Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e); 206 } 207 return; 208 } 209 case DO_GET_EXTRACTED_TEXT: { 210 SomeArgs args = (SomeArgs)msg.obj; 211 try { 212 InputConnection ic = mInputConnection.get(); 213 if (ic == null || !isActive()) { 214 Log.w(TAG, "getExtractedText on inactive InputConnection"); 215 args.callback.setExtractedText(null, args.seq); 216 return; 217 } 218 args.callback.setExtractedText(ic.getExtractedText( 219 (ExtractedTextRequest)args.arg1, msg.arg1), args.seq); 220 } catch (RemoteException e) { 221 Log.w(TAG, "Got RemoteException calling setExtractedText", e); 222 } 223 return; 224 } 225 case DO_COMMIT_TEXT: { 226 InputConnection ic = mInputConnection.get(); 227 if (ic == null || !isActive()) { 228 Log.w(TAG, "commitText on inactive InputConnection"); 229 return; 230 } 231 ic.commitText((CharSequence)msg.obj, msg.arg1); 232 return; 233 } 234 case DO_SET_SELECTION: { 235 InputConnection ic = mInputConnection.get(); 236 if (ic == null || !isActive()) { 237 Log.w(TAG, "setSelection on inactive InputConnection"); 238 return; 239 } 240 ic.setSelection(msg.arg1, msg.arg2); 241 return; 242 } 243 case DO_PERFORM_EDITOR_ACTION: { 244 InputConnection ic = mInputConnection.get(); 245 if (ic == null || !isActive()) { 246 Log.w(TAG, "performEditorAction on inactive InputConnection"); 247 return; 248 } 249 ic.performEditorAction(msg.arg1); 250 return; 251 } 252 case DO_PERFORM_CONTEXT_MENU_ACTION: { 253 InputConnection ic = mInputConnection.get(); 254 if (ic == null || !isActive()) { 255 Log.w(TAG, "performContextMenuAction on inactive InputConnection"); 256 return; 257 } 258 ic.performContextMenuAction(msg.arg1); 259 return; 260 } 261 case DO_COMMIT_COMPLETION: { 262 InputConnection ic = mInputConnection.get(); 263 if (ic == null || !isActive()) { 264 Log.w(TAG, "commitCompletion on inactive InputConnection"); 265 return; 266 } 267 ic.commitCompletion((CompletionInfo)msg.obj); 268 return; 269 } 270 case DO_SET_COMPOSING_TEXT: { 271 InputConnection ic = mInputConnection.get(); 272 if (ic == null || !isActive()) { 273 Log.w(TAG, "setComposingText on inactive InputConnection"); 274 return; 275 } 276 ic.setComposingText((CharSequence)msg.obj, msg.arg1); 277 return; 278 } 279 case DO_FINISH_COMPOSING_TEXT: { 280 InputConnection ic = mInputConnection.get(); 281 // Note we do NOT check isActive() here, because this is safe 282 // for an IME to call at any time, and we need to allow it 283 // through to clean up our state after the IME has switched to 284 // another client. 285 if (ic == null) { 286 Log.w(TAG, "finishComposingText on inactive InputConnection"); 287 return; 288 } 289 ic.finishComposingText(); 290 return; 291 } 292 case DO_SEND_KEY_EVENT: { 293 InputConnection ic = mInputConnection.get(); 294 if (ic == null || !isActive()) { 295 Log.w(TAG, "sendKeyEvent on inactive InputConnection"); 296 return; 297 } 298 ic.sendKeyEvent((KeyEvent)msg.obj); 299 return; 300 } 301 case DO_CLEAR_META_KEY_STATES: { 302 InputConnection ic = mInputConnection.get(); 303 if (ic == null || !isActive()) { 304 Log.w(TAG, "clearMetaKeyStates on inactive InputConnection"); 305 return; 306 } 307 ic.clearMetaKeyStates(msg.arg1); 308 return; 309 } 310 case DO_DELETE_SURROUNDING_TEXT: { 311 InputConnection ic = mInputConnection.get(); 312 if (ic == null || !isActive()) { 313 Log.w(TAG, "deleteSurroundingText on inactive InputConnection"); 314 return; 315 } 316 ic.deleteSurroundingText(msg.arg1, msg.arg2); 317 return; 318 } 319 case DO_BEGIN_BATCH_EDIT: { 320 InputConnection ic = mInputConnection.get(); 321 if (ic == null || !isActive()) { 322 Log.w(TAG, "beginBatchEdit on inactive InputConnection"); 323 return; 324 } 325 ic.beginBatchEdit(); 326 return; 327 } 328 case DO_END_BATCH_EDIT: { 329 InputConnection ic = mInputConnection.get(); 330 if (ic == null || !isActive()) { 331 Log.w(TAG, "endBatchEdit on inactive InputConnection"); 332 return; 333 } 334 ic.endBatchEdit(); 335 return; 336 } 337 case DO_REPORT_FULLSCREEN_MODE: { 338 InputConnection ic = mInputConnection.get(); 339 if (ic == null || !isActive()) { 340 Log.w(TAG, "showStatusIcon on inactive InputConnection"); 341 return; 342 } 343 ic.reportFullscreenMode(msg.arg1 == 1); 344 return; 345 } 346 case DO_PERFORM_PRIVATE_COMMAND: { 347 InputConnection ic = mInputConnection.get(); 348 if (ic == null || !isActive()) { 349 Log.w(TAG, "performPrivateCommand on inactive InputConnection"); 350 return; 351 } 352 SomeArgs args = (SomeArgs)msg.obj; 353 ic.performPrivateCommand((String)args.arg1, 354 (Bundle)args.arg2); 355 return; 356 } 357 } 358 Log.w(TAG, "Unhandled message code: " + msg.what); 359 } 360 361 Message obtainMessage(int what) { 362 return mH.obtainMessage(what); 363 } 364 365 Message obtainMessageII(int what, int arg1, int arg2) { 366 return mH.obtainMessage(what, arg1, arg2); 367 } 368 369 Message obtainMessageO(int what, Object arg1) { 370 return mH.obtainMessage(what, 0, 0, arg1); 371 } 372 373 Message obtainMessageISC(int what, int arg1, int seq, IInputContextCallback callback) { 374 SomeArgs args = new SomeArgs(); 375 args.callback = callback; 376 args.seq = seq; 377 return mH.obtainMessage(what, arg1, 0, args); 378 } 379 380 Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) { 381 SomeArgs args = new SomeArgs(); 382 args.callback = callback; 383 args.seq = seq; 384 return mH.obtainMessage(what, arg1, arg2, args); 385 } 386 387 Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq, 388 IInputContextCallback callback) { 389 SomeArgs args = new SomeArgs(); 390 args.arg1 = arg2; 391 args.callback = callback; 392 args.seq = seq; 393 return mH.obtainMessage(what, arg1, 0, args); 394 } 395 396 Message obtainMessageIO(int what, int arg1, Object arg2) { 397 return mH.obtainMessage(what, arg1, 0, arg2); 398 } 399 400 Message obtainMessageOO(int what, Object arg1, Object arg2) { 401 SomeArgs args = new SomeArgs(); 402 args.arg1 = arg1; 403 args.arg2 = arg2; 404 return mH.obtainMessage(what, 0, 0, args); 405 } 406} 407