1 /*
2  * Copyright (C) 2007-2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package android.inputmethodservice;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.os.IBinder;
22 import android.view.KeyEvent;
23 import android.view.MotionEvent;
24 import android.view.inputmethod.InputMethod;
25 import android.view.inputmethod.InputMethodSession;
26 
27 import java.io.FileDescriptor;
28 import java.io.PrintWriter;
29 
30 /**
31  * AbstractInputMethodService provides a abstract base class for input methods.
32  * Normal input method implementations will not derive from this directly,
33  * instead building on top of {@link InputMethodService} or another more
34  * complete base class.  Be sure to read {@link InputMethod} for more
35  * information on the basics of writing input methods.
36  *
37  * <p>This class combines a Service (representing the input method component
38  * to the system with the InputMethod interface that input methods must
39  * implement.  This base class takes care of reporting your InputMethod from
40  * the service when clients bind to it, but provides no standard implementation
41  * of the InputMethod interface itself.  Derived classes must implement that
42  * interface.
43  */
44 public abstract class AbstractInputMethodService extends Service
45         implements KeyEvent.Callback {
46     private InputMethod mInputMethod;
47 
48     final KeyEvent.DispatcherState mDispatcherState
49             = new KeyEvent.DispatcherState();
50 
51     /**
52      * Base class for derived classes to implement their {@link InputMethod}
53      * interface.  This takes care of basic maintenance of the input method,
54      * but most behavior must be implemented in a derived class.
55      */
56     public abstract class AbstractInputMethodImpl implements InputMethod {
57         /**
58          * Instantiate a new client session for the input method, by calling
59          * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface()
60          * AbstractInputMethodService.onCreateInputMethodSessionInterface()}.
61          */
createSession(SessionCallback callback)62         public void createSession(SessionCallback callback) {
63             callback.sessionCreated(onCreateInputMethodSessionInterface());
64         }
65 
66         /**
67          * Take care of enabling or disabling an existing session by calling its
68          * {@link AbstractInputMethodSessionImpl#revokeSelf()
69          * AbstractInputMethodSessionImpl.setEnabled()} method.
70          */
setSessionEnabled(InputMethodSession session, boolean enabled)71         public void setSessionEnabled(InputMethodSession session, boolean enabled) {
72             ((AbstractInputMethodSessionImpl)session).setEnabled(enabled);
73         }
74 
75         /**
76          * Take care of killing an existing session by calling its
77          * {@link AbstractInputMethodSessionImpl#revokeSelf()
78          * AbstractInputMethodSessionImpl.revokeSelf()} method.
79          */
revokeSession(InputMethodSession session)80         public void revokeSession(InputMethodSession session) {
81             ((AbstractInputMethodSessionImpl)session).revokeSelf();
82         }
83     }
84 
85     /**
86      * Base class for derived classes to implement their {@link InputMethodSession}
87      * interface.  This takes care of basic maintenance of the session,
88      * but most behavior must be implemented in a derived class.
89      */
90     public abstract class AbstractInputMethodSessionImpl implements InputMethodSession {
91         boolean mEnabled = true;
92         boolean mRevoked;
93 
94         /**
95          * Check whether this session has been enabled by the system.  If not
96          * enabled, you should not execute any calls on to it.
97          */
isEnabled()98         public boolean isEnabled() {
99             return mEnabled;
100         }
101 
102         /**
103          * Check whether this session has been revoked by the system.  Revoked
104          * session is also always disabled, so there is generally no need to
105          * explicitly check for this.
106          */
isRevoked()107         public boolean isRevoked() {
108             return mRevoked;
109         }
110 
111         /**
112          * Change the enabled state of the session.  This only works if the
113          * session has not been revoked.
114          */
setEnabled(boolean enabled)115         public void setEnabled(boolean enabled) {
116             if (!mRevoked) {
117                 mEnabled = enabled;
118             }
119         }
120 
121         /**
122          * Revoke the session from the client.  This disabled the session, and
123          * prevents it from ever being enabled again.
124          */
revokeSelf()125         public void revokeSelf() {
126             mRevoked = true;
127             mEnabled = false;
128         }
129 
130         /**
131          * Take care of dispatching incoming key events to the appropriate
132          * callbacks on the service, and tell the client when this is done.
133          */
134         @Override
dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback)135         public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
136             boolean handled = event.dispatch(AbstractInputMethodService.this,
137                     mDispatcherState, this);
138             if (callback != null) {
139                 callback.finishedEvent(seq, handled);
140             }
141         }
142 
143         /**
144          * Take care of dispatching incoming trackball events to the appropriate
145          * callbacks on the service, and tell the client when this is done.
146          */
147         @Override
dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback)148         public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) {
149             boolean handled = onTrackballEvent(event);
150             if (callback != null) {
151                 callback.finishedEvent(seq, handled);
152             }
153         }
154 
155         /**
156          * Take care of dispatching incoming generic motion events to the appropriate
157          * callbacks on the service, and tell the client when this is done.
158          */
159         @Override
dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback)160         public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) {
161             boolean handled = onGenericMotionEvent(event);
162             if (callback != null) {
163                 callback.finishedEvent(seq, handled);
164             }
165         }
166     }
167 
168     /**
169      * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState}
170      * for used for processing events from the target application.
171      * Normally you will not need to use this directly, but
172      * just use the standard high-level event callbacks like {@link #onKeyDown}.
173      */
getKeyDispatcherState()174     public KeyEvent.DispatcherState getKeyDispatcherState() {
175         return mDispatcherState;
176     }
177 
178     /**
179      * Called by the framework during initialization, when the InputMethod
180      * interface for this service needs to be created.
181      */
onCreateInputMethodInterface()182     public abstract AbstractInputMethodImpl onCreateInputMethodInterface();
183 
184     /**
185      * Called by the framework when a new InputMethodSession interface is
186      * needed for a new client of the input method.
187      */
onCreateInputMethodSessionInterface()188     public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
189 
190     /**
191      * Implement this to handle {@link android.os.Binder#dump Binder.dump()}
192      * calls on your input method.
193      */
194     @Override
dump(FileDescriptor fd, PrintWriter fout, String[] args)195     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
196     }
197 
198     @Override
onBind(Intent intent)199     final public IBinder onBind(Intent intent) {
200         if (mInputMethod == null) {
201             mInputMethod = onCreateInputMethodInterface();
202         }
203         return new IInputMethodWrapper(this, mInputMethod);
204     }
205 
206     /**
207      * Implement this to handle trackball events on your input method.
208      *
209      * @param event The motion event being received.
210      * @return True if the event was handled in this function, false otherwise.
211      * @see View#onTrackballEvent
212      */
onTrackballEvent(MotionEvent event)213     public boolean onTrackballEvent(MotionEvent event) {
214         return false;
215     }
216 
217     /**
218      * Implement this to handle generic motion events on your input method.
219      *
220      * @param event The motion event being received.
221      * @return True if the event was handled in this function, false otherwise.
222      * @see View#onGenericMotionEvent
223      */
onGenericMotionEvent(MotionEvent event)224     public boolean onGenericMotionEvent(MotionEvent event) {
225         return false;
226     }
227 }
228