• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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