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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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 */ 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 195 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 196 } 197 198 @Override 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 */ 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 */ 224 public boolean onGenericMotionEvent(MotionEvent event) { 225 return false; 226 } 227 } 228