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