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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.inputmethodservice.InputMethodService;
23 import android.os.IBinder;
24 import android.view.inputmethod.InlineSuggestionsRequest;
25 import android.view.inputmethod.InputMethodInfo;
26 
27 import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
28 import com.android.internal.inputmethod.IInlineSuggestionsRequestCallback;
29 import com.android.internal.inputmethod.InlineSuggestionsRequestInfo;
30 import com.android.internal.inputmethod.SoftInputShowHideReason;
31 import com.android.server.LocalServices;
32 
33 import java.util.Collections;
34 import java.util.List;
35 
36 /**
37  * Input method manager local system service interface.
38  */
39 public abstract class InputMethodManagerInternal {
40     /**
41      * Listener for input method list changed events.
42      */
43     public interface InputMethodListListener {
44         /**
45          * Called with the list of the installed IMEs when it's updated.
46          */
onInputMethodListUpdated(List<InputMethodInfo> info, @UserIdInt int userId)47         void onInputMethodListUpdated(List<InputMethodInfo> info, @UserIdInt int userId);
48     }
49 
50     /**
51      * Called by the power manager to tell the input method manager whether it
52      * should start watching for wake events.
53      */
setInteractive(boolean interactive)54     public abstract void setInteractive(boolean interactive);
55 
56     /**
57      * Hides the current input method, if visible.
58      */
hideCurrentInputMethod(@oftInputShowHideReason int reason)59     public abstract void hideCurrentInputMethod(@SoftInputShowHideReason int reason);
60 
61     /**
62      * Returns the list of installed input methods for the specified user.
63      *
64      * @param userId The user ID to be queried.
65      * @return A list of {@link InputMethodInfo}.  VR-only IMEs are already excluded.
66      */
getInputMethodListAsUser(@serIdInt int userId)67     public abstract List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
68 
69     /**
70      * Returns the list of installed input methods that are enabled for the specified user.
71      *
72      * @param userId The user ID to be queried.
73      * @return A list of {@link InputMethodInfo} that are enabled for {@code userId}.
74      */
getEnabledInputMethodListAsUser(@serIdInt int userId)75     public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId);
76 
77     /**
78      * Called by the Autofill Frameworks to request an {@link InlineSuggestionsRequest} from
79      * the input method.
80      *
81      * @param requestInfo information needed to create an {@link InlineSuggestionsRequest}.
82      * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object.
83      */
onCreateInlineSuggestionsRequest(@serIdInt int userId, InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb)84     public abstract void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
85             InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb);
86 
87     /**
88      * Force switch to the enabled input method by {@code imeId} for current user. If the input
89      * method with {@code imeId} is not enabled or not installed, do nothing.
90      *
91      * @param imeId  The input method ID to be switched to.
92      * @param userId The user ID to be queried.
93      * @return {@code true} if the current input method was successfully switched to the input
94      * method by {@code imeId}; {@code false} the input method with {@code imeId} is not available
95      * to be switched.
96      */
switchToInputMethod(String imeId, @UserIdInt int userId)97     public abstract boolean switchToInputMethod(String imeId, @UserIdInt int userId);
98 
99     /**
100      * Force enable or disable the input method associated with {@code imeId} for given user. If
101      * the input method associated with {@code imeId} is not installed, do nothing.
102      *
103      * @param imeId  The input method ID to be enabled or disabled.
104      * @param enabled {@code true} if the input method associated with {@code imeId} should be
105      *                enabled.
106      * @param userId The user ID to be queried.
107      * @return {@code true} if the input method associated with {@code imeId} was successfully
108      *         enabled or disabled, {@code false} if the input method specified is not installed
109      *         or was unable to be enabled/disabled for some other reason.
110      */
setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId)111     public abstract boolean setInputMethodEnabled(String imeId, boolean enabled,
112             @UserIdInt int userId);
113 
114     /**
115      * Registers a new {@link InputMethodListListener}.
116      */
registerInputMethodListListener(InputMethodListListener listener)117     public abstract void registerInputMethodListListener(InputMethodListListener listener);
118 
119     /**
120      * Transfers input focus from a given input token to that of the IME window.
121      *
122      * @param sourceInputToken The source token.
123      * @param displayId The display hosting the IME window.
124      * @return {@code true} if the transfer is successful.
125      */
transferTouchFocusToImeWindow(@onNull IBinder sourceInputToken, int displayId)126     public abstract boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
127             int displayId);
128 
129     /**
130      * Reports that IME control has transferred to the given window token, or if null that
131      * control has been taken away from client windows (and is instead controlled by the policy
132      * or SystemUI).
133      *
134      * @param windowToken the window token that is now in control, or {@code null} if no client
135      *                   window is in control of the IME.
136      */
reportImeControl(@ullable IBinder windowToken)137     public abstract void reportImeControl(@Nullable IBinder windowToken);
138 
139     /**
140      * Indicates that the IME window has re-parented to the new target when the IME control changed.
141      */
onImeParentChanged()142     public abstract void onImeParentChanged();
143 
144     /**
145      * Destroys the IME surface.
146      */
removeImeSurface()147     public abstract void removeImeSurface();
148 
149     /**
150      * Updates the IME visibility, back disposition and show IME picker status for SystemUI.
151      * TODO(b/189923292): Making SystemUI to be true IME icon controller vs. presenter that
152      *     controlled by IMMS.
153      */
updateImeWindowStatus(boolean disableImeIcon)154     public abstract void updateImeWindowStatus(boolean disableImeIcon);
155 
156     /**
157      * Finish stylus handwriting by calling {@link InputMethodService#finishStylusHandwriting()} if
158      * there is an ongoing handwriting session.
159      */
maybeFinishStylusHandwriting()160     public abstract void maybeFinishStylusHandwriting();
161 
162     /**
163      * Callback when the IInputMethodSession from the accessibility service with the specified
164      * accessibilityConnectionId is created.
165      *
166      * @param accessibilityConnectionId The connection id of the accessibility service.
167      * @param session The session passed back from the accessibility service.
168      */
onSessionForAccessibilityCreated(int accessibilityConnectionId, IAccessibilityInputMethodSession session)169     public abstract void onSessionForAccessibilityCreated(int accessibilityConnectionId,
170             IAccessibilityInputMethodSession session);
171 
172     /**
173      * Unbind the accessibility service with the specified accessibilityConnectionId from current
174      * client.
175      *
176      * @param accessibilityConnectionId The connection id of the accessibility service.
177      */
unbindAccessibilityFromCurrentClient(int accessibilityConnectionId)178     public abstract void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId);
179 
180     /**
181      * Switch the keyboard layout in response to a keyboard shortcut.
182      *
183      * @param direction {@code 1} to switch to the next subtype, {@code -1} to switch to the
184      *                           previous subtype.
185      */
switchKeyboardLayout(int direction)186     public abstract void switchKeyboardLayout(int direction);
187 
188     /**
189      * Returns true if any InputConnection is currently active.
190      * {@hide}
191      */
isAnyInputConnectionActive()192     public abstract boolean isAnyInputConnectionActive();
193 
194     /**
195      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
196      */
197     private static final InputMethodManagerInternal NOP =
198             new InputMethodManagerInternal() {
199                 @Override
200                 public void setInteractive(boolean interactive) {
201                 }
202 
203                 @Override
204                 public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
205                 }
206 
207                 @Override
208                 public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
209                     return Collections.emptyList();
210                 }
211 
212                 @Override
213                 public List<InputMethodInfo> getEnabledInputMethodListAsUser(
214                         @UserIdInt int userId) {
215                     return Collections.emptyList();
216                 }
217 
218                 @Override
219                 public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
220                         InlineSuggestionsRequestInfo requestInfo,
221                         IInlineSuggestionsRequestCallback cb) {
222                 }
223 
224                 @Override
225                 public boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
226                     return false;
227                 }
228 
229                 @Override
230                 public boolean setInputMethodEnabled(String imeId, boolean enabled,
231                         @UserIdInt int userId) {
232                     return false;
233                 }
234 
235                 @Override
236                 public void registerInputMethodListListener(InputMethodListListener listener) {
237                 }
238 
239                 @Override
240                 public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
241                         int displayId) {
242                     return false;
243                 }
244 
245                 @Override
246                 public void reportImeControl(@Nullable IBinder windowToken) {
247                 }
248 
249                 @Override
250                 public void onImeParentChanged() {
251                 }
252 
253                 @Override
254                 public void removeImeSurface() {
255                 }
256 
257                 @Override
258                 public void updateImeWindowStatus(boolean disableImeIcon) {
259                 }
260 
261                 @Override
262                 public void onSessionForAccessibilityCreated(int accessibilityConnectionId,
263                         IAccessibilityInputMethodSession session) {
264                 }
265 
266                 @Override
267                 public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
268                 }
269 
270                 @Override
271                 public void maybeFinishStylusHandwriting() {
272                 }
273 
274                 @Override
275                 public void switchKeyboardLayout(int direction) {
276                 }
277 
278                 @Override
279                 public boolean isAnyInputConnectionActive() {
280                     return false;
281                 }
282             };
283 
284     /**
285      * @return Global instance if exists.  Otherwise, a fallback no-op instance.
286      */
287     @NonNull
get()288     public static InputMethodManagerInternal get() {
289         final InputMethodManagerInternal instance =
290                 LocalServices.getService(InputMethodManagerInternal.class);
291         return instance != null ? instance : NOP;
292     }
293 }
294