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