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
17package android.inputmethodservice;
18
19import com.android.internal.os.HandlerCaller;
20import com.android.internal.os.SomeArgs;
21import com.android.internal.view.IInputMethodCallback;
22import com.android.internal.view.IInputMethodSession;
23
24import android.content.Context;
25import android.graphics.Rect;
26import android.os.Bundle;
27import android.os.Message;
28import android.os.RemoteException;
29import android.util.Log;
30import android.view.KeyEvent;
31import android.view.MotionEvent;
32import android.view.inputmethod.CompletionInfo;
33import android.view.inputmethod.ExtractedText;
34import android.view.inputmethod.InputMethodSession;
35
36class IInputMethodSessionWrapper extends IInputMethodSession.Stub
37        implements HandlerCaller.Callback {
38    private static final String TAG = "InputMethodWrapper";
39    private static final boolean DEBUG = false;
40
41    private static final int DO_FINISH_INPUT = 60;
42    private static final int DO_DISPLAY_COMPLETIONS = 65;
43    private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
44    private static final int DO_DISPATCH_KEY_EVENT = 70;
45    private static final int DO_DISPATCH_TRACKBALL_EVENT = 80;
46    private static final int DO_DISPATCH_GENERIC_MOTION_EVENT = 85;
47    private static final int DO_UPDATE_SELECTION = 90;
48    private static final int DO_UPDATE_CURSOR = 95;
49    private static final int DO_APP_PRIVATE_COMMAND = 100;
50    private static final int DO_TOGGLE_SOFT_INPUT = 105;
51    private static final int DO_FINISH_SESSION = 110;
52    private static final int DO_VIEW_CLICKED = 115;
53
54    HandlerCaller mCaller;
55    InputMethodSession mInputMethodSession;
56
57    // NOTE: we should have a cache of these.
58    static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
59        final IInputMethodCallback mCb;
60        InputMethodEventCallbackWrapper(IInputMethodCallback cb) {
61            mCb = cb;
62        }
63        public void finishedEvent(int seq, boolean handled) {
64            try {
65                mCb.finishedEvent(seq, handled);
66            } catch (RemoteException e) {
67            }
68        }
69    }
70
71    public IInputMethodSessionWrapper(Context context,
72            InputMethodSession inputMethodSession) {
73        mCaller = new HandlerCaller(context, this);
74        mInputMethodSession = inputMethodSession;
75    }
76
77    public InputMethodSession getInternalInputMethodSession() {
78        return mInputMethodSession;
79    }
80
81    public void executeMessage(Message msg) {
82        if (mInputMethodSession == null) return;
83
84        switch (msg.what) {
85            case DO_FINISH_INPUT:
86                mInputMethodSession.finishInput();
87                return;
88            case DO_DISPLAY_COMPLETIONS:
89                mInputMethodSession.displayCompletions((CompletionInfo[])msg.obj);
90                return;
91            case DO_UPDATE_EXTRACTED_TEXT:
92                mInputMethodSession.updateExtractedText(msg.arg1,
93                        (ExtractedText)msg.obj);
94                return;
95            case DO_DISPATCH_KEY_EVENT: {
96                SomeArgs args = (SomeArgs)msg.obj;
97                mInputMethodSession.dispatchKeyEvent(msg.arg1,
98                        (KeyEvent)args.arg1,
99                        new InputMethodEventCallbackWrapper(
100                                (IInputMethodCallback)args.arg2));
101                args.recycle();
102                return;
103            }
104            case DO_DISPATCH_TRACKBALL_EVENT: {
105                SomeArgs args = (SomeArgs)msg.obj;
106                mInputMethodSession.dispatchTrackballEvent(msg.arg1,
107                        (MotionEvent)args.arg1,
108                        new InputMethodEventCallbackWrapper(
109                                (IInputMethodCallback)args.arg2));
110                args.recycle();
111                return;
112            }
113            case DO_DISPATCH_GENERIC_MOTION_EVENT: {
114                SomeArgs args = (SomeArgs)msg.obj;
115                mInputMethodSession.dispatchGenericMotionEvent(msg.arg1,
116                        (MotionEvent)args.arg1,
117                        new InputMethodEventCallbackWrapper(
118                                (IInputMethodCallback)args.arg2));
119                args.recycle();
120                return;
121            }
122            case DO_UPDATE_SELECTION: {
123                SomeArgs args = (SomeArgs)msg.obj;
124                mInputMethodSession.updateSelection(args.argi1, args.argi2,
125                        args.argi3, args.argi4, args.argi5, args.argi6);
126                args.recycle();
127                return;
128            }
129            case DO_UPDATE_CURSOR: {
130                mInputMethodSession.updateCursor((Rect)msg.obj);
131                return;
132            }
133            case DO_APP_PRIVATE_COMMAND: {
134                SomeArgs args = (SomeArgs)msg.obj;
135                mInputMethodSession.appPrivateCommand((String)args.arg1,
136                        (Bundle)args.arg2);
137                args.recycle();
138                return;
139            }
140            case DO_TOGGLE_SOFT_INPUT: {
141                mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
142                return;
143            }
144            case DO_FINISH_SESSION: {
145                mInputMethodSession = null;
146                return;
147            }
148            case DO_VIEW_CLICKED: {
149                mInputMethodSession.viewClicked(msg.arg1 == 1);
150                return;
151            }
152        }
153        Log.w(TAG, "Unhandled message code: " + msg.what);
154    }
155
156    public void finishInput() {
157        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
158    }
159
160    public void displayCompletions(CompletionInfo[] completions) {
161        mCaller.executeOrSendMessage(mCaller.obtainMessageO(
162                DO_DISPLAY_COMPLETIONS, completions));
163    }
164
165    public void updateExtractedText(int token, ExtractedText text) {
166        mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
167                DO_UPDATE_EXTRACTED_TEXT, token, text));
168    }
169
170    public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
171        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_KEY_EVENT, seq,
172                event, callback));
173    }
174
175    public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) {
176        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_TRACKBALL_EVENT, seq,
177                event, callback));
178    }
179
180    public void dispatchGenericMotionEvent(int seq, MotionEvent event,
181            IInputMethodCallback callback) {
182        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_GENERIC_MOTION_EVENT, seq,
183                event, callback));
184    }
185
186    public void updateSelection(int oldSelStart, int oldSelEnd,
187            int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
188        mCaller.executeOrSendMessage(mCaller.obtainMessageIIIIII(DO_UPDATE_SELECTION,
189                oldSelStart, oldSelEnd, newSelStart, newSelEnd,
190                candidatesStart, candidatesEnd));
191    }
192
193    public void viewClicked(boolean focusChanged) {
194        mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
195    }
196
197    public void updateCursor(Rect newCursor) {
198        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR,
199                newCursor));
200    }
201
202    public void appPrivateCommand(String action, Bundle data) {
203        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
204    }
205
206    public void toggleSoftInput(int showFlags, int hideFlags) {
207        mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
208    }
209
210    public void finishSession() {
211        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
212    }
213}
214