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