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