1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.inputmethodservice; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Bundle; 23 import android.os.IBinder; 24 import android.os.Looper; 25 import android.os.ResultReceiver; 26 import android.view.KeyEvent; 27 import android.view.MotionEvent; 28 import android.view.View; 29 import android.view.WindowManager.LayoutParams.SoftInputModeFlags; 30 import android.view.inputmethod.CompletionInfo; 31 import android.view.inputmethod.CursorAnchorInfo; 32 import android.view.inputmethod.EditorInfo; 33 import android.view.inputmethod.InputConnection; 34 35 import com.android.internal.inputmethod.StartInputFlags; 36 37 /** 38 * Defines all the public APIs and interfaces that are necessary to implement multi-client IMEs. 39 * 40 * <p>Actual implementation is further delegated to 41 * {@link MultiClientInputMethodServiceDelegateImpl}.</p> 42 * 43 * @hide 44 */ 45 public final class MultiClientInputMethodServiceDelegate { 46 // @SdkConstant(SdkConstantType.SERVICE_ACTION) 47 public static final String SERVICE_INTERFACE = 48 "android.inputmethodservice.MultiClientInputMethodService"; 49 50 /** 51 * Special value that is guaranteed to be not used for IME client ID. 52 */ 53 public static final int INVALID_CLIENT_ID = -1; 54 55 /** 56 * Special value that is guaranteed to be not used for window handle. 57 */ 58 public static final int INVALID_WINDOW_HANDLE = -1; 59 60 private final MultiClientInputMethodServiceDelegateImpl mImpl; 61 62 /** 63 * Top-level callbacks for this {@link MultiClientInputMethodServiceDelegate}. 64 */ 65 public interface ServiceCallback { 66 /** 67 * Called when this {@link MultiClientInputMethodServiceDelegate} is recognized by the 68 * system and privileged operations like {@link #createInputMethodWindowToken(int)} are 69 * ready to be called. 70 */ initialized()71 void initialized(); 72 73 /** 74 * Called when a new IME client is recognized by the system. 75 * 76 * <p>Once the IME receives this callback, the IME can start interacting with the IME client 77 * by calling {@link #acceptClient(int, ClientCallback, KeyEvent.DispatcherState, Looper)}. 78 * </p> 79 * 80 * @param clientId ID of the client. 81 * @param uid UID of the IME client. 82 * @param pid PID of the IME client. 83 * @param selfReportedDisplayId display ID reported from the IME client. Since the system 84 * does not validate this display ID, and at any time the IME client can lose the 85 * access to this display ID, the IME needs to call 86 * {@link #isUidAllowedOnDisplay(int, int)} to check whether the IME client still 87 * has access to this display or not. 88 */ addClient(int clientId, int uid, int pid, int selfReportedDisplayId)89 void addClient(int clientId, int uid, int pid, int selfReportedDisplayId); 90 91 /** 92 * Called when an IME client is being destroyed. 93 * 94 * @param clientId ID of the client. 95 */ removeClient(int clientId)96 void removeClient(int clientId); 97 } 98 99 /** 100 * Per-client callbacks. 101 */ 102 public interface ClientCallback { 103 /** 104 * Called when the associated IME client called {@link 105 * android.view.inputmethod.InputMethodManager#sendAppPrivateCommand(View, String, Bundle)}. 106 * 107 * @param action Name of the command to be performed. 108 * @param data Any data to include with the command. 109 * @see android.inputmethodservice.InputMethodService#onAppPrivateCommand(String, Bundle) 110 */ onAppPrivateCommand(String action, Bundle data)111 void onAppPrivateCommand(String action, Bundle data); 112 113 /** 114 * Called when the associated IME client called {@link 115 * android.view.inputmethod.InputMethodManager#displayCompletions(View, CompletionInfo[])}. 116 * 117 * @param completions Completion information provided from the IME client. 118 * @see android.inputmethodservice.InputMethodService#onDisplayCompletions(CompletionInfo[]) 119 */ onDisplayCompletions(CompletionInfo[] completions)120 void onDisplayCompletions(CompletionInfo[] completions); 121 122 /** 123 * Called when this callback session is closed. No further callback should not happen on 124 * this callback object. 125 */ onFinishSession()126 void onFinishSession(); 127 128 /** 129 * Called when the associated IME client called {@link 130 * android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder, int)} or 131 * {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder, int, 132 * ResultReceiver)}. 133 * 134 * @param flags The flag passed by the client. 135 * @param resultReceiver The {@link ResultReceiver} passed by the client. 136 * @see android.inputmethodservice.InputMethodService#onWindowHidden() 137 */ onHideSoftInput(int flags, ResultReceiver resultReceiver)138 void onHideSoftInput(int flags, ResultReceiver resultReceiver); 139 140 /** 141 * Called when the associated IME client called {@link 142 * android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or {@link 143 * android.view.inputmethod.InputMethodManager#showSoftInput(View, int, ResultReceiver)}. 144 * 145 * @param flags The flag passed by the client. 146 * @param resultReceiver The {@link ResultReceiver} passed by the client. 147 * @see android.inputmethodservice.InputMethodService#onWindowShown() 148 */ onShowSoftInput(int flags, ResultReceiver resultReceiver)149 void onShowSoftInput(int flags, ResultReceiver resultReceiver); 150 151 /** 152 * A generic callback when {@link InputConnection} is being established. 153 * 154 * @param inputConnection The {@link InputConnection} to be established. 155 * @param editorInfo The {@link EditorInfo} reported from the IME client. 156 * @param startInputFlags Any combinations of {@link StartInputFlags}. 157 * @param softInputMode SoftWindowMode specified to this window. 158 * @param targetWindowHandle A unique Window token. 159 * @see android.inputmethodservice.InputMethodService#onStartInput(EditorInfo, boolean) 160 */ onStartInputOrWindowGainedFocus( @ullable InputConnection inputConnection, @Nullable EditorInfo editorInfo, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int targetWindowHandle)161 void onStartInputOrWindowGainedFocus( 162 @Nullable InputConnection inputConnection, 163 @Nullable EditorInfo editorInfo, 164 @StartInputFlags int startInputFlags, 165 @SoftInputModeFlags int softInputMode, 166 int targetWindowHandle); 167 168 /** 169 * Called when the associated IME client called {@link 170 * android.view.inputmethod.InputMethodManager#toggleSoftInput(int, int)}. 171 * 172 * @param showFlags The flag passed by the client. 173 * @param hideFlags The flag passed by the client. 174 * @see android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int) 175 */ onToggleSoftInput(int showFlags, int hideFlags)176 void onToggleSoftInput(int showFlags, int hideFlags); 177 178 /** 179 * Called when the associated IME client called {@link 180 * android.view.inputmethod.InputMethodManager#updateCursorAnchorInfo(View, 181 * CursorAnchorInfo)}. 182 * 183 * @param info The {@link CursorAnchorInfo} passed by the client. 184 * @see android.inputmethodservice.InputMethodService#onUpdateCursorAnchorInfo( 185 * CursorAnchorInfo) 186 */ onUpdateCursorAnchorInfo(CursorAnchorInfo info)187 void onUpdateCursorAnchorInfo(CursorAnchorInfo info); 188 189 /** 190 * Called when the associated IME client called {@link 191 * android.view.inputmethod.InputMethodManager#updateSelection(View, int, int, int, int)}. 192 * 193 * @param oldSelStart The previous selection start index. 194 * @param oldSelEnd The previous selection end index. 195 * @param newSelStart The new selection start index. 196 * @param newSelEnd The new selection end index. 197 * @param candidatesStart The new candidate start index. 198 * @param candidatesEnd The new candidate end index. 199 * @see android.inputmethodservice.InputMethodService#onUpdateSelection(int, int, int, int, 200 * int, int) 201 */ onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd)202 void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, 203 int candidatesStart, int candidatesEnd); 204 205 /** 206 * Called to give a chance for the IME to intercept generic motion events before they are 207 * processed by the application. 208 * 209 * @param event {@link MotionEvent} that is about to be handled by the IME client. 210 * @return {@code true} to tell the IME client that the IME handled this event. 211 * @see android.inputmethodservice.InputMethodService#onGenericMotionEvent(MotionEvent) 212 */ onGenericMotionEvent(MotionEvent event)213 boolean onGenericMotionEvent(MotionEvent event); 214 215 /** 216 * Called to give a chance for the IME to intercept key down events before they are 217 * processed by the application. 218 * 219 * @param keyCode The value in {@link KeyEvent#getKeyCode()}. 220 * @param event {@link KeyEvent} for this key down event. 221 * @return {@code true} to tell the IME client that the IME handled this event. 222 * @see android.inputmethodservice.InputMethodService#onKeyDown(int, KeyEvent) 223 */ onKeyDown(int keyCode, KeyEvent event)224 boolean onKeyDown(int keyCode, KeyEvent event); 225 226 /** 227 * Called to give a chance for the IME to intercept key long press events before they are 228 * processed by the application. 229 * 230 * @param keyCode The value in {@link KeyEvent#getKeyCode()}. 231 * @param event {@link KeyEvent} for this key long press event. 232 * @return {@code true} to tell the IME client that the IME handled this event. 233 * @see android.inputmethodservice.InputMethodService#onKeyLongPress(int, KeyEvent) 234 */ onKeyLongPress(int keyCode, KeyEvent event)235 boolean onKeyLongPress(int keyCode, KeyEvent event); 236 237 /** 238 * Called to give a chance for the IME to intercept key multiple events before they are 239 * processed by the application. 240 * 241 * @param keyCode The value in {@link KeyEvent#getKeyCode()}. 242 * @param event {@link KeyEvent} for this key multiple event. 243 * @return {@code true} to tell the IME client that the IME handled this event. 244 * @see android.inputmethodservice.InputMethodService#onKeyMultiple(int, int, KeyEvent) 245 */ onKeyMultiple(int keyCode, KeyEvent event)246 boolean onKeyMultiple(int keyCode, KeyEvent event); 247 248 /** 249 * Called to give a chance for the IME to intercept key up events before they are processed 250 * by the application. 251 * 252 * @param keyCode The value in {@link KeyEvent#getKeyCode()}. 253 * @param event {@link KeyEvent} for this key up event. 254 * @return {@code true} to tell the IME client that the IME handled this event. 255 * @see android.inputmethodservice.InputMethodService#onKeyUp(int, KeyEvent) 256 */ onKeyUp(int keyCode, KeyEvent event)257 boolean onKeyUp(int keyCode, KeyEvent event); 258 259 /** 260 * Called to give a chance for the IME to intercept generic motion events before they are 261 * processed by the application. 262 * 263 * @param event {@link MotionEvent} that is about to be handled by the IME client. 264 * @return {@code true} to tell the IME client that the IME handled this event. 265 * @see android.inputmethodservice.InputMethodService#onTrackballEvent(MotionEvent) 266 */ onTrackballEvent(MotionEvent event)267 boolean onTrackballEvent(MotionEvent event); 268 } 269 MultiClientInputMethodServiceDelegate(Context context, ServiceCallback serviceCallback)270 private MultiClientInputMethodServiceDelegate(Context context, 271 ServiceCallback serviceCallback) { 272 mImpl = new MultiClientInputMethodServiceDelegateImpl(context, serviceCallback); 273 } 274 275 /** 276 * Must be called by the multi-client IME implementer to create 277 * {@link MultiClientInputMethodServiceDelegate}. 278 * 279 * @param context {@link Context} with which the delegate should interact with the system. 280 * @param serviceCallback {@link ServiceCallback} to receive service-level callbacks. 281 * @return A new instance of {@link MultiClientInputMethodServiceDelegate}. 282 */ create(Context context, ServiceCallback serviceCallback)283 public static MultiClientInputMethodServiceDelegate create(Context context, 284 ServiceCallback serviceCallback) { 285 return new MultiClientInputMethodServiceDelegate(context, serviceCallback); 286 } 287 288 /** 289 * Must be called by the multi-client IME service when {@link android.app.Service#onDestroy()} 290 * is called. 291 */ onDestroy()292 public void onDestroy() { 293 mImpl.onDestroy(); 294 } 295 296 /** 297 * Must be called by the multi-client IME service when 298 * {@link android.app.Service#onBind(Intent)} is called. 299 * 300 * @param intent {@link Intent} passed to {@link android.app.Service#onBind(Intent)}. 301 * @return An {@link IBinder} object that needs to be returned from 302 * {@link android.app.Service#onBind(Intent)}. 303 */ onBind(Intent intent)304 public IBinder onBind(Intent intent) { 305 return mImpl.onBind(intent); 306 } 307 308 /** 309 * Must be called by the multi-client IME service when 310 * {@link android.app.Service#onUnbind(Intent)} is called. 311 * 312 * @param intent {@link Intent} passed to {@link android.app.Service#onUnbind(Intent)}. 313 * @return A boolean value that needs to be returned from 314 * {@link android.app.Service#onUnbind(Intent)}. 315 */ onUnbind(Intent intent)316 public boolean onUnbind(Intent intent) { 317 return mImpl.onUnbind(intent); 318 } 319 320 /** 321 * Must be called by the multi-client IME service to create a special window token for IME 322 * window. 323 * 324 * <p>This method is available only after {@link ServiceCallback#initialized()}.</p> 325 * 326 * @param displayId display ID on which the IME window will be shown. 327 * @return Window token to be specified to the IME window/ 328 */ createInputMethodWindowToken(int displayId)329 public IBinder createInputMethodWindowToken(int displayId) { 330 return mImpl.createInputMethodWindowToken(displayId); 331 } 332 333 /** 334 * Must be called by the multi-client IME service to notify the system when the IME is ready to 335 * accept callback events from the specified IME client. 336 * 337 * @param clientId The IME client ID specified in 338 * {@link ServiceCallback#addClient(int, int, int, int)}. 339 * @param clientCallback The {@link ClientCallback} to receive callback events from this IME 340 * client. 341 * @param dispatcherState {@link KeyEvent.DispatcherState} to be used when receiving key-related 342 * callbacks in {@link ClientCallback}. 343 * @param looper {@link Looper} on which {@link ClientCallback} will be called back. 344 */ acceptClient(int clientId, ClientCallback clientCallback, KeyEvent.DispatcherState dispatcherState, Looper looper)345 public void acceptClient(int clientId, ClientCallback clientCallback, 346 KeyEvent.DispatcherState dispatcherState, Looper looper) { 347 mImpl.acceptClient(clientId, clientCallback, dispatcherState, looper); 348 } 349 350 /** 351 * Must be called by the multi-client IME service to notify the system when the IME is ready to 352 * interact with the window in the IME client. 353 * 354 * @param clientId The IME client ID specified in 355 * {@link ServiceCallback#addClient(int, int, int, int)}. 356 * @param targetWindowHandle The window handle specified in 357 * {@link ClientCallback#onStartInputOrWindowGainedFocus}. 358 * @param imeWindowToken The IME window token returned from 359 * {@link #createInputMethodWindowToken(int)}. 360 */ reportImeWindowTarget(int clientId, int targetWindowHandle, IBinder imeWindowToken)361 public void reportImeWindowTarget(int clientId, int targetWindowHandle, 362 IBinder imeWindowToken) { 363 mImpl.reportImeWindowTarget(clientId, targetWindowHandle, imeWindowToken); 364 } 365 366 /** 367 * Can be called by the multi-client IME service to check if the given {@code uid} is allowed 368 * to access to {@code displayId}. 369 * 370 * @param displayId Display ID to be queried. 371 * @param uid UID to be queried. 372 * @return {@code true} if {@code uid} is allowed to access to {@code displayId}. 373 */ isUidAllowedOnDisplay(int displayId, int uid)374 public boolean isUidAllowedOnDisplay(int displayId, int uid) { 375 return mImpl.isUidAllowedOnDisplay(displayId, uid); 376 } 377 378 /** 379 * Can be called by MSIME to activate/deactivate a client when it is gaining/losing focus 380 * respectively. 381 * 382 * @param clientId client ID to activate/deactivate. 383 * @param active {@code true} to activate a client. 384 */ setActive(int clientId, boolean active)385 public void setActive(int clientId, boolean active) { 386 mImpl.setActive(clientId, active); 387 } 388 } 389