1 /* 2 * Copyright (C) 2015 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 com.android.server.inputmethod; 18 19 import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_INDEX; 20 21 import static java.lang.annotation.RetentionPolicy.SOURCE; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.UserIdInt; 26 import android.inputmethodservice.InputMethodService; 27 import android.os.IBinder; 28 import android.view.inputmethod.InlineSuggestionsRequest; 29 import android.view.inputmethod.InputMethodInfo; 30 import android.view.inputmethod.InputMethodSubtype; 31 32 import com.android.internal.inputmethod.IAccessibilityInputMethodSession; 33 import com.android.internal.inputmethod.InlineSuggestionsRequestCallback; 34 import com.android.internal.inputmethod.InlineSuggestionsRequestInfo; 35 import com.android.internal.inputmethod.SoftInputShowHideReason; 36 import com.android.server.LocalServices; 37 38 import java.lang.annotation.ElementType; 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.Target; 41 import java.util.Collections; 42 import java.util.List; 43 44 /** 45 * Input method manager local system service interface. 46 */ 47 public abstract class InputMethodManagerInternal { 48 /** 49 * Indicates that the method is guaranteed to not require {@link ImfLock}. 50 * 51 * <p>You can call this method without worrying about system_server lock layering.</p> 52 */ 53 @Retention(SOURCE) 54 @Target({ElementType.METHOD}) 55 public @interface ImfLockFree { 56 } 57 58 /** 59 * Listener for input method list changed events. 60 */ 61 public interface InputMethodListListener { 62 /** 63 * Called with the list of the installed IMEs when it's updated. 64 */ onInputMethodListUpdated(List<InputMethodInfo> info, @UserIdInt int userId)65 void onInputMethodListUpdated(List<InputMethodInfo> info, @UserIdInt int userId); 66 } 67 68 /** 69 * Called by the power manager to tell the input method manager whether it 70 * should start watching for wake events. 71 * 72 * @param interactive the interactive mode parameter 73 */ 74 @ImfLockFree setInteractive(boolean interactive)75 public abstract void setInteractive(boolean interactive); 76 77 /** 78 * Hides the input method for the specified {@code originatingDisplayId}, if visible. 79 * 80 * @param reason the reason for hiding the current input method 81 * @param originatingDisplayId the display ID the request is originated 82 */ 83 @ImfLockFree hideInputMethod(@oftInputShowHideReason int reason, int originatingDisplayId)84 public abstract void hideInputMethod(@SoftInputShowHideReason int reason, 85 int originatingDisplayId); 86 87 /** 88 * Returns the list of installed input methods for the specified user. 89 * 90 * @param userId the user ID to be queried 91 * @return a list of {@link InputMethodInfo}. VR-only IMEs are already excluded 92 */ 93 @ImfLockFree 94 @NonNull getInputMethodListAsUser(@serIdInt int userId)95 public abstract List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId); 96 97 /** 98 * Returns the list of installed input methods that are enabled for the specified user. 99 * 100 * @param userId the user ID to be queried 101 * @return a list of {@link InputMethodInfo} that are enabled for {@code userId} 102 */ 103 @ImfLockFree 104 @NonNull getEnabledInputMethodListAsUser(@serIdInt int userId)105 public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId); 106 107 /** 108 * Returns the list of installed input methods that are enabled for the specified user. 109 * 110 * @param imiId IME ID to be queried about 111 * @param allowsImplicitlyEnabledSubtypes {@code true} to return the implicitly enabled subtypes 112 * @param userId the user ID to be queried about 113 * @return a list of {@link InputMethodSubtype} that are enabled for {@code userId} 114 */ 115 @ImfLockFree 116 @NonNull getEnabledInputMethodSubtypeListAsUser( String imiId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId)117 public abstract List<InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser( 118 String imiId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId); 119 120 /** 121 * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from 122 * the input method. 123 * 124 * @param userId the user ID to be queried 125 * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}. 126 * @param cb {@link InlineSuggestionsRequestCallback} used to pass back the request 127 * object 128 */ onCreateInlineSuggestionsRequest(@serIdInt int userId, InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback cb)129 public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId, 130 InlineSuggestionsRequestInfo requestInfo, InlineSuggestionsRequestCallback cb); 131 132 /** 133 * Force switch to the enabled input method by {@code imeId} for the current user. If the input 134 * method with {@code imeId} is not enabled or not installed, do nothing. 135 * 136 * @param imeId the input method ID to be switched to 137 * @param userId the user ID to be queried 138 * @return {@code true} if the current input method was successfully switched to the input 139 * method by {@code imeId}; {@code false} the input method with {@code imeId} is not available 140 * to be switched. 141 */ switchToInputMethod(@onNull String imeId, @UserIdInt int userId)142 public boolean switchToInputMethod(@NonNull String imeId, @UserIdInt int userId) { 143 return switchToInputMethod(imeId, NOT_A_SUBTYPE_INDEX, userId); 144 } 145 146 /** 147 * Force switch to the enabled input method by {@code imeId} for the current user. If the input 148 * method with {@code imeId} is not enabled or not installed, do nothing. If 149 * {@code subtypeIndex} is also supplied (not {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX}) and 150 * valid, also switches to it, otherwise the system decides the most sensible default subtype to 151 * use. 152 * 153 * @param imeId the input method ID to be switched to 154 * @param subtypeIndex the subtype to be switched to, as an index in the input method's array of 155 * subtypes, or {@link InputMethodUtils#NOT_A_SUBTYPE_INDEX} if the system 156 * should decide the most sensible subtype 157 * @param userId the user ID to be queried 158 * @return {@code true} if the current input method was successfully switched to the input 159 * method by {@code imeId}; {@code false} the input method with {@code imeId} is not available 160 * to be switched. 161 */ switchToInputMethod(@onNull String imeId, int subtypeIndex, @UserIdInt int userId)162 public abstract boolean switchToInputMethod(@NonNull String imeId, int subtypeIndex, 163 @UserIdInt int userId); 164 165 /** 166 * Force enable or disable the input method associated with {@code imeId} for given user. If 167 * the input method associated with {@code imeId} is not installed, do nothing. 168 * 169 * @param imeId the input method ID to be enabled or disabled 170 * @param enabled {@code true} if the input method associated with {@code imeId} should be 171 * enabled 172 * @param userId the user ID to be queried 173 * @return {@code true} if the input method associated with {@code imeId} was successfully 174 * enabled or disabled, {@code false} if the input method specified is not installed 175 * or was unable to be enabled/disabled for some other reason. 176 */ setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId)177 public abstract boolean setInputMethodEnabled(String imeId, boolean enabled, 178 @UserIdInt int userId); 179 180 /** 181 * Makes the input method associated with {@code imeId} the default input method for all users 182 * on displays that are owned by the virtual device with the given {@code deviceId}. If the 183 * input method associated with {@code imeId} is not available, there will be no IME on the 184 * relevant displays. 185 * 186 * <p>The caller of this method is responsible for resetting it to {@code null} after the 187 * virtual device is closed.</p> 188 * 189 * @param deviceId the device ID on which to use the given input method as default. 190 * @param imeId the input method ID to be used as default on the given device. If {@code null}, 191 * then any existing input method association with that device will be removed. 192 * @throws IllegalArgumentException if a non-{@code null} input method ID is passed for a 193 * device ID that already has a custom input method set or if 194 * the device ID is not a valid virtual device. 195 */ setVirtualDeviceInputMethodForAllUsers( int deviceId, @Nullable String imeId)196 public abstract void setVirtualDeviceInputMethodForAllUsers( 197 int deviceId, @Nullable String imeId); 198 199 /** 200 * Registers a new {@link InputMethodListListener}. 201 * 202 * @param listener the listener to add 203 */ 204 @ImfLockFree registerInputMethodListListener(InputMethodListListener listener)205 public abstract void registerInputMethodListListener(InputMethodListListener listener); 206 207 /** 208 * Transfers input focus from a given input token to that of the IME window. 209 * 210 * @param sourceInputToken the source token. 211 * @param displayId the display hosting the IME window 212 * @param userId the user ID this request is about 213 * @return {@code true} if the transfer is successful 214 */ transferTouchFocusToImeWindow(@onNull IBinder sourceInputToken, int displayId, @UserIdInt int userId)215 public abstract boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken, 216 int displayId, @UserIdInt int userId); 217 218 /** 219 * Reports that IME control has transferred to the given window token, or if null that 220 * control has been taken away from client windows (and is instead controlled by the policy 221 * or SystemUI). 222 * 223 * @param windowToken the window token that is now in control, or {@code null} if no client 224 * window is in control of the IME 225 */ reportImeControl(@ullable IBinder windowToken)226 public abstract void reportImeControl(@Nullable IBinder windowToken); 227 228 /** 229 * Indicates that the IME window has re-parented to the new target when the IME control changed. 230 * 231 * @param displayId the display hosting the IME window 232 */ onImeParentChanged(int displayId)233 public abstract void onImeParentChanged(int displayId); 234 235 /** 236 * Destroys the IME surface for the given display. 237 * 238 * @param displayId the display hosting the IME window 239 */ 240 @ImfLockFree removeImeSurface(int displayId)241 public abstract void removeImeSurface(int displayId); 242 243 /** 244 * Called when a non-IME-focusable overlay window being the IME layering target (e.g. a 245 * window with {@link android.view.WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} and 246 * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flags) 247 * has changed its window visibility. 248 * 249 * @param hasVisibleOverlay whether such an overlay window exists or not 250 * @param displayId the display ID where the overlay window exists 251 */ setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, int displayId)252 public abstract void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, int displayId); 253 254 /** 255 * Called when the visibility of IME input target window has changed. 256 * 257 * @param imeInputTarget the window token of the IME input target window 258 * @param visibleAndNotRemoved {@code true} when the new window is made visible by 259 * {@code imeInputTarget} and the IME input target window has not 260 * been removed. The new window is considered to be visible when 261 * switching to the new visible IME input target window and 262 * starting input, or the existing input target becomes visible. 263 * In contrast, {@code false} when closing the input target, or the 264 * existing input target becomes invisible 265 * @param displayId the display for which to update the IME window status 266 */ onImeInputTargetVisibilityChanged(@onNull IBinder imeInputTarget, boolean visibleAndNotRemoved, int displayId)267 public abstract void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, 268 boolean visibleAndNotRemoved, int displayId); 269 270 /** 271 * Updates the IME visibility, back disposition and show IME picker status for SystemUI. 272 * TODO(b/189923292): Making SystemUI to be true IME icon controller vs. presenter that 273 * controlled by IMMS. 274 * 275 * @param disableImeIcon indicates whether IME icon should be enabled or not 276 * @param displayId the display for which to update the IME window status 277 */ 278 @ImfLockFree updateImeWindowStatus(boolean disableImeIcon, int displayId)279 public abstract void updateImeWindowStatus(boolean disableImeIcon, int displayId); 280 281 /** 282 * Updates and reports whether the IME switcher button should be shown, regardless whether 283 * SystemUI or the IME is responsible for drawing it and the corresponding navigation bar. 284 * 285 * @param displayId the display for which to update the IME switcher button visibility. 286 * @param userId the user for which to update the IME switcher button visibility. 287 */ updateShouldShowImeSwitcher(int displayId, @UserIdInt int userId)288 public abstract void updateShouldShowImeSwitcher(int displayId, @UserIdInt int userId); 289 290 /** 291 * Finish stylus handwriting by calling {@link InputMethodService#finishStylusHandwriting()} if 292 * there is an ongoing handwriting session. 293 */ 294 @ImfLockFree maybeFinishStylusHandwriting()295 public abstract void maybeFinishStylusHandwriting(); 296 297 /** 298 * Callback when the IInputMethodSession from the accessibility service with the specified 299 * accessibilityConnectionId is created. 300 * 301 * @param accessibilityConnectionId the connection id of the accessibility service 302 * @param session the session passed back from the accessibility service 303 * @param userId the user ID to be queried 304 */ onSessionForAccessibilityCreated(int accessibilityConnectionId, IAccessibilityInputMethodSession session, @UserIdInt int userId)305 public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId, 306 IAccessibilityInputMethodSession session, @UserIdInt int userId); 307 308 /** 309 * Unbind the accessibility service with the specified accessibilityConnectionId from current 310 * client. 311 * 312 * @param accessibilityConnectionId the connection id of the accessibility service 313 * @param userId the user ID to be queried 314 */ unbindAccessibilityFromCurrentClient(int accessibilityConnectionId, @UserIdInt int userId)315 public abstract void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId, 316 @UserIdInt int userId); 317 318 /** 319 * Switch the keyboard layout in response to a keyboard shortcut. 320 * 321 * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the 322 * previous subtype 323 * @param displayId the display to which the keyboard layout switch shortcut is 324 * dispatched. Note that there is no guarantee that an IME is 325 * associated with this display. This is more or less than a hint for 326 * cases when no IME is running for the given targetWindowToken. There 327 * is a longstanding discussion whether we should allow users to 328 * rotate keyboard layout even when there is no edit field, and this 329 * displayID would be helpful for such a situation. 330 * @param targetWindowToken the window token to which other keys are being sent while handling 331 * this shortcut. 332 */ onSwitchKeyboardLayoutShortcut(int direction, int displayId, IBinder targetWindowToken)333 public abstract void onSwitchKeyboardLayoutShortcut(int direction, int displayId, 334 IBinder targetWindowToken); 335 336 /** 337 * Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing. 338 */ 339 private static final InputMethodManagerInternal NOP = 340 new InputMethodManagerInternal() { 341 @ImfLockFree 342 @Override 343 public void setInteractive(boolean interactive) { 344 } 345 346 @ImfLockFree 347 @Override 348 public void hideInputMethod(@SoftInputShowHideReason int reason, 349 int originatingDisplayId) { 350 } 351 352 @ImfLockFree 353 @NonNull 354 @Override 355 public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) { 356 return Collections.emptyList(); 357 } 358 359 @ImfLockFree 360 @NonNull 361 @Override 362 public List<InputMethodInfo> getEnabledInputMethodListAsUser( 363 @UserIdInt int userId) { 364 return Collections.emptyList(); 365 } 366 367 @ImfLockFree 368 @NonNull 369 @Override 370 public List<InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(String imiId, 371 boolean allowsImplicitlyEnabledSubtypes, int userId) { 372 return Collections.emptyList(); 373 } 374 375 @Override 376 public void onCreateInlineSuggestionsRequest(@UserIdInt int userId, 377 InlineSuggestionsRequestInfo requestInfo, 378 InlineSuggestionsRequestCallback cb) { 379 } 380 381 @Override 382 public boolean switchToInputMethod(@NonNull String imeId, int subtypeIndex, 383 @UserIdInt int userId) { 384 return false; 385 } 386 387 @Override 388 public boolean setInputMethodEnabled(String imeId, boolean enabled, 389 @UserIdInt int userId) { 390 return false; 391 } 392 393 @Override 394 public void setVirtualDeviceInputMethodForAllUsers( 395 int deviceId, @Nullable String imeId) { 396 } 397 398 @ImfLockFree 399 @Override 400 public void registerInputMethodListListener(InputMethodListListener listener) { 401 } 402 403 @Override 404 public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken, 405 int displayId, @UserIdInt int userId) { 406 return false; 407 } 408 409 @Override 410 public void reportImeControl(@Nullable IBinder windowToken) { 411 } 412 413 @Override 414 public void onImeParentChanged(int displayId) { 415 } 416 417 @ImfLockFree 418 @Override 419 public void removeImeSurface(int displayId) { 420 } 421 422 @Override 423 public void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay, 424 int displayId) { 425 } 426 427 @Override 428 public void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, 429 boolean visibleAndNotRemoved, int displayId) { 430 } 431 432 @ImfLockFree 433 @Override 434 public void updateImeWindowStatus(boolean disableImeIcon, int displayId) { 435 } 436 437 @Override 438 public void updateShouldShowImeSwitcher(int displayId, @UserIdInt int userId) { 439 } 440 441 @Override 442 public void onSessionForAccessibilityCreated(int accessibilityConnectionId, 443 IAccessibilityInputMethodSession session, @UserIdInt int userId) { 444 } 445 446 @Override 447 public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId, 448 @UserIdInt int userId) { 449 } 450 451 @ImfLockFree 452 @Override 453 public void maybeFinishStylusHandwriting() { 454 } 455 456 @Override 457 public void onSwitchKeyboardLayoutShortcut(int direction, int displayId, 458 IBinder targetWindowToken) { 459 } 460 }; 461 462 /** 463 * @return Global instance if exists. Otherwise, a fallback no-op instance. 464 */ 465 @NonNull get()466 public static InputMethodManagerInternal get() { 467 final InputMethodManagerInternal instance = 468 LocalServices.getService(InputMethodManagerInternal.class); 469 return instance != null ? instance : NOP; 470 } 471 } 472