• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.inputmethodservice;
18 
19 import com.android.internal.os.HandlerCaller;
20 import com.android.internal.os.SomeArgs;
21 import com.android.internal.view.IInputMethodSession;
22 
23 import android.content.Context;
24 import android.graphics.Rect;
25 import android.os.Bundle;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.util.Log;
30 import android.util.SparseArray;
31 import android.view.InputChannel;
32 import android.view.InputDevice;
33 import android.view.InputEvent;
34 import android.view.InputEventReceiver;
35 import android.view.KeyEvent;
36 import android.view.MotionEvent;
37 import android.view.inputmethod.CompletionInfo;
38 import android.view.inputmethod.ExtractedText;
39 import android.view.inputmethod.InputMethodSession;
40 
41 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
42         implements HandlerCaller.Callback {
43     private static final String TAG = "InputMethodWrapper";
44 
45     private static final int DO_FINISH_INPUT = 60;
46     private static final int DO_DISPLAY_COMPLETIONS = 65;
47     private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
48     private static final int DO_UPDATE_SELECTION = 90;
49     private static final int DO_UPDATE_CURSOR = 95;
50     private static final int DO_APP_PRIVATE_COMMAND = 100;
51     private static final int DO_TOGGLE_SOFT_INPUT = 105;
52     private static final int DO_FINISH_SESSION = 110;
53     private static final int DO_VIEW_CLICKED = 115;
54 
55     HandlerCaller mCaller;
56     InputMethodSession mInputMethodSession;
57     InputChannel mChannel;
58     ImeInputEventReceiver mReceiver;
59 
IInputMethodSessionWrapper(Context context, InputMethodSession inputMethodSession, InputChannel channel)60     public IInputMethodSessionWrapper(Context context,
61             InputMethodSession inputMethodSession, InputChannel channel) {
62         mCaller = new HandlerCaller(context, null,
63                 this, true /*asyncHandler*/);
64         mInputMethodSession = inputMethodSession;
65         mChannel = channel;
66         if (channel != null) {
67             mReceiver = new ImeInputEventReceiver(channel, context.getMainLooper());
68         }
69     }
70 
getInternalInputMethodSession()71     public InputMethodSession getInternalInputMethodSession() {
72         return mInputMethodSession;
73     }
74 
75     @Override
executeMessage(Message msg)76     public void executeMessage(Message msg) {
77         if (mInputMethodSession == null) {
78             // The session has been finished.
79             return;
80         }
81 
82         switch (msg.what) {
83             case DO_FINISH_INPUT:
84                 mInputMethodSession.finishInput();
85                 return;
86             case DO_DISPLAY_COMPLETIONS:
87                 mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj);
88                 return;
89             case DO_UPDATE_EXTRACTED_TEXT:
90                 mInputMethodSession.updateExtractedText(msg.arg1,
91                         (ExtractedText)msg.obj);
92                 return;
93             case DO_UPDATE_SELECTION: {
94                 SomeArgs args = (SomeArgs)msg.obj;
95                 mInputMethodSession.updateSelection(args.argi1, args.argi2,
96                         args.argi3, args.argi4, args.argi5, args.argi6);
97                 args.recycle();
98                 return;
99             }
100             case DO_UPDATE_CURSOR: {
101                 mInputMethodSession.updateCursor((Rect)msg.obj);
102                 return;
103             }
104             case DO_APP_PRIVATE_COMMAND: {
105                 SomeArgs args = (SomeArgs)msg.obj;
106                 mInputMethodSession.appPrivateCommand((String)args.arg1,
107                         (Bundle)args.arg2);
108                 args.recycle();
109                 return;
110             }
111             case DO_TOGGLE_SOFT_INPUT: {
112                 mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
113                 return;
114             }
115             case DO_FINISH_SESSION: {
116                 doFinishSession();
117                 return;
118             }
119             case DO_VIEW_CLICKED: {
120                 mInputMethodSession.viewClicked(msg.arg1 == 1);
121                 return;
122             }
123         }
124         Log.w(TAG, "Unhandled message code: " + msg.what);
125     }
126 
doFinishSession()127     private void doFinishSession() {
128         mInputMethodSession = null;
129         if (mReceiver != null) {
130             mReceiver.dispose();
131             mReceiver = null;
132         }
133         if (mChannel != null) {
134             mChannel.dispose();
135             mChannel = null;
136         }
137     }
138 
139     @Override
finishInput()140     public void finishInput() {
141         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
142     }
143 
144     @Override
displayCompletions(CompletionInfo[] completions)145     public void displayCompletions(CompletionInfo[] completions) {
146         mCaller.executeOrSendMessage(mCaller.obtainMessageO(
147                 DO_DISPLAY_COMPLETIONS, completions));
148     }
149 
150     @Override
updateExtractedText(int token, ExtractedText text)151     public void updateExtractedText(int token, ExtractedText text) {
152         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
153                 DO_UPDATE_EXTRACTED_TEXT, token, text));
154     }
155 
156     @Override
updateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd)157     public void updateSelection(int oldSelStart, int oldSelEnd,
158             int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
159         mCaller.executeOrSendMessage(mCaller.obtainMessageIIIIII(DO_UPDATE_SELECTION,
160                 oldSelStart, oldSelEnd, newSelStart, newSelEnd,
161                 candidatesStart, candidatesEnd));
162     }
163 
164     @Override
viewClicked(boolean focusChanged)165     public void viewClicked(boolean focusChanged) {
166         mCaller.executeOrSendMessage(
167                 mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
168     }
169 
170     @Override
updateCursor(Rect newCursor)171     public void updateCursor(Rect newCursor) {
172         mCaller.executeOrSendMessage(
173                 mCaller.obtainMessageO(DO_UPDATE_CURSOR, newCursor));
174     }
175 
176     @Override
appPrivateCommand(String action, Bundle data)177     public void appPrivateCommand(String action, Bundle data) {
178         mCaller.executeOrSendMessage(
179                 mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
180     }
181 
182     @Override
toggleSoftInput(int showFlags, int hideFlags)183     public void toggleSoftInput(int showFlags, int hideFlags) {
184         mCaller.executeOrSendMessage(
185                 mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
186     }
187 
188     @Override
finishSession()189     public void finishSession() {
190         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
191     }
192 
193     private final class ImeInputEventReceiver extends InputEventReceiver
194             implements InputMethodSession.EventCallback {
195         private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
196 
ImeInputEventReceiver(InputChannel inputChannel, Looper looper)197         public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
198             super(inputChannel, looper);
199         }
200 
201         @Override
onInputEvent(InputEvent event)202         public void onInputEvent(InputEvent event) {
203             if (mInputMethodSession == null) {
204                 // The session has been finished.
205                 finishInputEvent(event, false);
206                 return;
207             }
208 
209             final int seq = event.getSequenceNumber();
210             mPendingEvents.put(seq, event);
211             if (event instanceof KeyEvent) {
212                 KeyEvent keyEvent = (KeyEvent)event;
213                 mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
214             } else {
215                 MotionEvent motionEvent = (MotionEvent)event;
216                 if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_TRACKBALL)) {
217                     mInputMethodSession.dispatchTrackballEvent(seq, motionEvent, this);
218                 } else {
219                     mInputMethodSession.dispatchGenericMotionEvent(seq, motionEvent, this);
220                 }
221             }
222         }
223 
224         @Override
finishedEvent(int seq, boolean handled)225         public void finishedEvent(int seq, boolean handled) {
226             int index = mPendingEvents.indexOfKey(seq);
227             if (index >= 0) {
228                 InputEvent event = mPendingEvents.valueAt(index);
229                 mPendingEvents.removeAt(index);
230                 finishInputEvent(event, handled);
231             }
232         }
233     }
234 }
235