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