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