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.annotation.MainThread; 20 import android.annotation.NonNull; 21 import android.app.Service; 22 import android.content.Intent; 23 import android.os.IBinder; 24 import android.view.KeyEvent; 25 import android.view.MotionEvent; 26 import android.view.inputmethod.InputConnection; 27 import android.view.inputmethod.InputContentInfo; 28 import android.view.inputmethod.InputMethod; 29 import android.view.inputmethod.InputMethodSession; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 34 /** 35 * AbstractInputMethodService provides a abstract base class for input methods. 36 * Normal input method implementations will not derive from this directly, 37 * instead building on top of {@link InputMethodService} or another more 38 * complete base class. Be sure to read {@link InputMethod} for more 39 * information on the basics of writing input methods. 40 * 41 * <p>This class combines a Service (representing the input method component 42 * to the system with the InputMethod interface that input methods must 43 * implement. This base class takes care of reporting your InputMethod from 44 * the service when clients bind to it, but provides no standard implementation 45 * of the InputMethod interface itself. Derived classes must implement that 46 * interface. 47 */ 48 public abstract class AbstractInputMethodService extends Service 49 implements KeyEvent.Callback { 50 private InputMethod mInputMethod; 51 52 final KeyEvent.DispatcherState mDispatcherState 53 = new KeyEvent.DispatcherState(); 54 55 /** 56 * Base class for derived classes to implement their {@link InputMethod} 57 * interface. This takes care of basic maintenance of the input method, 58 * but most behavior must be implemented in a derived class. 59 */ 60 public abstract class AbstractInputMethodImpl implements InputMethod { 61 /** 62 * Instantiate a new client session for the input method, by calling 63 * back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface() 64 * AbstractInputMethodService.onCreateInputMethodSessionInterface()}. 65 */ 66 @MainThread createSession(SessionCallback callback)67 public void createSession(SessionCallback callback) { 68 callback.sessionCreated(onCreateInputMethodSessionInterface()); 69 } 70 71 /** 72 * Take care of enabling or disabling an existing session by calling its 73 * {@link AbstractInputMethodSessionImpl#revokeSelf() 74 * AbstractInputMethodSessionImpl.setEnabled()} method. 75 */ 76 @MainThread setSessionEnabled(InputMethodSession session, boolean enabled)77 public void setSessionEnabled(InputMethodSession session, boolean enabled) { 78 ((AbstractInputMethodSessionImpl)session).setEnabled(enabled); 79 } 80 81 /** 82 * Take care of killing an existing session by calling its 83 * {@link AbstractInputMethodSessionImpl#revokeSelf() 84 * AbstractInputMethodSessionImpl.revokeSelf()} method. 85 */ 86 @MainThread revokeSession(InputMethodSession session)87 public void revokeSession(InputMethodSession session) { 88 ((AbstractInputMethodSessionImpl)session).revokeSelf(); 89 } 90 } 91 92 /** 93 * Base class for derived classes to implement their {@link InputMethodSession} 94 * interface. This takes care of basic maintenance of the session, 95 * but most behavior must be implemented in a derived class. 96 */ 97 public abstract class AbstractInputMethodSessionImpl implements InputMethodSession { 98 boolean mEnabled = true; 99 boolean mRevoked; 100 101 /** 102 * Check whether this session has been enabled by the system. If not 103 * enabled, you should not execute any calls on to it. 104 */ isEnabled()105 public boolean isEnabled() { 106 return mEnabled; 107 } 108 109 /** 110 * Check whether this session has been revoked by the system. Revoked 111 * session is also always disabled, so there is generally no need to 112 * explicitly check for this. 113 */ isRevoked()114 public boolean isRevoked() { 115 return mRevoked; 116 } 117 118 /** 119 * Change the enabled state of the session. This only works if the 120 * session has not been revoked. 121 */ setEnabled(boolean enabled)122 public void setEnabled(boolean enabled) { 123 if (!mRevoked) { 124 mEnabled = enabled; 125 } 126 } 127 128 /** 129 * Revoke the session from the client. This disabled the session, and 130 * prevents it from ever being enabled again. 131 */ revokeSelf()132 public void revokeSelf() { 133 mRevoked = true; 134 mEnabled = false; 135 } 136 137 /** 138 * Take care of dispatching incoming key events to the appropriate 139 * callbacks on the service, and tell the client when this is done. 140 */ 141 @Override dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback)142 public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) { 143 boolean handled = event.dispatch(AbstractInputMethodService.this, 144 mDispatcherState, this); 145 if (callback != null) { 146 callback.finishedEvent(seq, handled); 147 } 148 } 149 150 /** 151 * Take care of dispatching incoming trackball events to the appropriate 152 * callbacks on the service, and tell the client when this is done. 153 */ 154 @Override dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback)155 public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) { 156 boolean handled = onTrackballEvent(event); 157 if (callback != null) { 158 callback.finishedEvent(seq, handled); 159 } 160 } 161 162 /** 163 * Take care of dispatching incoming generic motion events to the appropriate 164 * callbacks on the service, and tell the client when this is done. 165 */ 166 @Override dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback)167 public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) { 168 boolean handled = onGenericMotionEvent(event); 169 if (callback != null) { 170 callback.finishedEvent(seq, handled); 171 } 172 } 173 } 174 175 /** 176 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 177 * for used for processing events from the target application. 178 * Normally you will not need to use this directly, but 179 * just use the standard high-level event callbacks like {@link #onKeyDown}. 180 */ getKeyDispatcherState()181 public KeyEvent.DispatcherState getKeyDispatcherState() { 182 return mDispatcherState; 183 } 184 185 /** 186 * Called by the framework during initialization, when the InputMethod 187 * interface for this service needs to be created. 188 */ onCreateInputMethodInterface()189 public abstract AbstractInputMethodImpl onCreateInputMethodInterface(); 190 191 /** 192 * Called by the framework when a new InputMethodSession interface is 193 * needed for a new client of the input method. 194 */ onCreateInputMethodSessionInterface()195 public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface(); 196 197 /** 198 * Implement this to handle {@link android.os.Binder#dump Binder.dump()} 199 * calls on your input method. 200 */ 201 @Override dump(FileDescriptor fd, PrintWriter fout, String[] args)202 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 203 } 204 205 @Override onBind(Intent intent)206 final public IBinder onBind(Intent intent) { 207 if (mInputMethod == null) { 208 mInputMethod = onCreateInputMethodInterface(); 209 } 210 return new IInputMethodWrapper(this, mInputMethod); 211 } 212 213 /** 214 * Implement this to handle trackball events on your input method. 215 * 216 * @param event The motion event being received. 217 * @return True if the event was handled in this function, false otherwise. 218 * @see android.view.View#onTrackballEvent(MotionEvent) 219 */ onTrackballEvent(MotionEvent event)220 public boolean onTrackballEvent(MotionEvent event) { 221 return false; 222 } 223 224 /** 225 * Implement this to handle generic motion events on your input method. 226 * 227 * @param event The motion event being received. 228 * @return True if the event was handled in this function, false otherwise. 229 * @see android.view.View#onGenericMotionEvent(MotionEvent) 230 */ onGenericMotionEvent(MotionEvent event)231 public boolean onGenericMotionEvent(MotionEvent event) { 232 return false; 233 } 234 235 /** 236 * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access 237 * permission to the content. 238 * 239 * <p>Default implementation does nothing.</p> 240 * 241 * @param inputContentInfo Content to be temporarily exposed from the input method to the 242 * application. 243 * This cannot be {@code null}. 244 * @param inputConnection {@link InputConnection} with which 245 * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be 246 * called. 247 * @return {@code false} if we cannot allow a temporary access permission. 248 * @hide 249 */ exposeContent(@onNull InputContentInfo inputContentInfo, @NonNull InputConnection inputConnection)250 public void exposeContent(@NonNull InputContentInfo inputContentInfo, 251 @NonNull InputConnection inputConnection) { 252 return; 253 } 254 255 /** 256 * Called when the user took some actions that should be taken into consideration to update the 257 * MRU list for input method rotation. 258 * 259 * @hide 260 */ notifyUserActionIfNecessary()261 public void notifyUserActionIfNecessary() { 262 } 263 } 264