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