• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.internal.inputmethod;
18 
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.Nullable;
23 import android.content.ComponentName;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.graphics.Matrix;
27 import android.os.IBinder;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.util.SparseArray;
31 import android.view.InputChannel;
32 
33 import com.android.internal.view.IInputMethodSession;
34 
35 import java.lang.annotation.Retention;
36 
37 /**
38  * Bundle of information returned by input method manager about a successful
39  * binding to an input method.
40  */
41 public final class InputBindResult implements Parcelable {
42 
43     @Retention(SOURCE)
44     @IntDef({
45             ResultCode.SUCCESS_WITH_IME_SESSION,
46             ResultCode.SUCCESS_WAITING_IME_SESSION,
47             ResultCode.SUCCESS_WAITING_IME_BINDING,
48             ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
49             ResultCode.ERROR_NULL,
50             ResultCode.ERROR_NO_IME,
51             ResultCode.ERROR_INVALID_PACKAGE_NAME,
52             ResultCode.ERROR_SYSTEM_NOT_READY,
53             ResultCode.ERROR_IME_NOT_CONNECTED,
54             ResultCode.ERROR_INVALID_USER,
55             ResultCode.ERROR_NULL_EDITOR_INFO,
56             ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
57             ResultCode.ERROR_NO_EDITOR,
58             ResultCode.ERROR_DISPLAY_ID_MISMATCH,
59             ResultCode.ERROR_INVALID_DISPLAY_ID,
60             ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION
61     })
62     public @interface ResultCode {
63         /**
64          * Indicates that everything in this result object including {@link #method} is valid.
65          */
66         int SUCCESS_WITH_IME_SESSION = 0;
67         /**
68          * Indicates that this is a temporary binding until the
69          * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session
70          * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS).
71          *
72          * <p>Note that in this state the IMS is already bound to IMMS but the logical session
73          * is not yet established on top of the IPC channel.</p>
74          *
75          * <p>Some of fields such as {@link #channel} is not yet available.</p>
76          *
77          * @see android.inputmethodservice.InputMethodService#onCreateInputMethodSessionInterface()
78          **/
79         int SUCCESS_WAITING_IME_SESSION = 1;
80         /**
81          * Indicates that this is a temporary binding until the
82          * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session
83          * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS).
84          *
85          * <p>Note that in this state the IMMS has already initiated a connection to the IMS but
86          * the binding process is not completed yet.</p>
87          *
88          * <p>Some of fields such as {@link #channel} is not yet available.</p>
89          * @see android.content.ServiceConnection#onServiceConnected(ComponentName, IBinder)
90          */
91         int SUCCESS_WAITING_IME_BINDING = 2;
92         /**
93          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} has a
94          * pending operation to switch to a different user.
95          *
96          * <p>Note that in this state even what would be the next current IME is not determined.</p>
97          */
98         int SUCCESS_WAITING_USER_SWITCHING = 3;
99         /**
100          * Indicates that this is not intended for starting input but just for reporting window
101          * focus change from the application process.
102          *
103          * <p>All other fields do not have meaningful value.</p>
104          */
105         int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 4;
106         /**
107          * Indicates somehow
108          * {@link
109          * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus}
110          * is trying to return null {@link InputBindResult}, which must never happen.
111          */
112         int ERROR_NULL = 5;
113         /**
114          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService}
115          * recognizes no IME.
116          */
117         int ERROR_NO_IME = 6;
118         /**
119          * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match
120          * the caller UID.
121          *
122          * @see android.view.inputmethod.EditorInfo#packageName
123          */
124         int ERROR_INVALID_PACKAGE_NAME = 7;
125         /**
126          * Indicates that the system is still in an early stage of the boot process and any 3rd
127          * party application is not allowed to run.
128          *
129          * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START
130          */
131         int ERROR_SYSTEM_NOT_READY = 8;
132         /**
133          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to
134          * connect to an {@link android.inputmethodservice.InputMethodService} but failed.
135          *
136          * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int,
137          *      android.os.UserHandle)
138          */
139         int ERROR_IME_NOT_CONNECTED = 9;
140         /**
141          * Indicates that the caller is not the foreground user, does not have
142          * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user
143          * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not
144          * running.
145          */
146         int ERROR_INVALID_USER = 10;
147         /**
148          * Indicates that the caller should have specified non-null
149          * {@link android.view.inputmethod.EditorInfo}.
150          */
151         int ERROR_NULL_EDITOR_INFO = 11;
152         /**
153          * Indicates that the target window the client specified cannot be the IME target right now.
154          *
155          * <p>Due to the asynchronous nature of Android OS, we cannot completely avoid this error.
156          * The client should try to restart input when its {@link android.view.Window} is focused
157          * again.</p>
158          *
159          * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
160          */
161         int ERROR_NOT_IME_TARGET_WINDOW = 12;
162         /**
163          * Indicates that focused view in the current window is not an editor.
164          */
165         int ERROR_NO_EDITOR = 13;
166         /**
167          * Indicates that there is a mismatch in display ID between IME client and focused Window.
168          */
169         int ERROR_DISPLAY_ID_MISMATCH = 14;
170         /**
171          * Indicates that current IME client is no longer allowed to access to the associated
172          * display.
173          */
174         int ERROR_INVALID_DISPLAY_ID = 15;
175         int SUCCESS_WITH_ACCESSIBILITY_SESSION = 16;
176     }
177 
178     @ResultCode
179     public final int result;
180 
181     /**
182      * The input method service.
183      */
184     public final IInputMethodSession method;
185 
186     /**
187      * The accessibility services.
188      */
189     public SparseArray<IAccessibilityInputMethodSession> accessibilitySessions;
190 
191     /**
192      * The input channel used to send input events to this IME.
193      */
194     public final InputChannel channel;
195 
196     /**
197      * The ID for this input method, as found in InputMethodInfo; null if
198      * no input method will be bound.
199      */
200     public final String id;
201 
202     /**
203      * Sequence number of this binding.
204      */
205     public final int sequence;
206 
207     @Nullable
208     private final float[] mVirtualDisplayToScreenMatrixValues;
209 
210     /**
211      * {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
212      */
213     public final boolean isInputMethodSuppressingSpellChecker;
214 
215     /**
216      * @return {@link Matrix} that corresponds to {@link #mVirtualDisplayToScreenMatrixValues}.
217      *         {@code null} if {@link #mVirtualDisplayToScreenMatrixValues} is {@code null}.
218      */
219     @Nullable
getVirtualDisplayToScreenMatrix()220     public Matrix getVirtualDisplayToScreenMatrix() {
221         if (mVirtualDisplayToScreenMatrixValues == null) {
222             return null;
223         }
224         final Matrix matrix = new Matrix();
225         matrix.setValues(mVirtualDisplayToScreenMatrixValues);
226         return matrix;
227     }
228 
229     /**
230      * Creates a new instance of {@link InputBindResult}.
231      *
232      * @param result A result code defined in {@link ResultCode}.
233      * @param method {@link IInputMethodSession} to interact with the IME.
234      * @param accessibilitySessions {@link IAccessibilityInputMethodSession} to interact with
235      *                              accessibility services.
236      * @param channel {@link InputChannel} to forward input events to the IME.
237      * @param id The {@link String} representations of the IME, which is the same as
238      *           {@link android.view.inputmethod.InputMethodInfo#getId()} and
239      *           {@link android.content.ComponentName#flattenToShortString()}.
240      * @param sequence A sequence number of this binding.
241      * @param isInputMethodSuppressingSpellChecker {@code true} if the IME explicitly specifies
242      *                                             {@code suppressesSpellChecker="true"}.
243      */
InputBindResult(@esultCode int result, IInputMethodSession method, SparseArray<IAccessibilityInputMethodSession> accessibilitySessions, InputChannel channel, String id, int sequence, @Nullable Matrix virtualDisplayToScreenMatrix, boolean isInputMethodSuppressingSpellChecker)244     public InputBindResult(@ResultCode int result,
245             IInputMethodSession method,
246             SparseArray<IAccessibilityInputMethodSession> accessibilitySessions,
247             InputChannel channel, String id, int sequence,
248             @Nullable Matrix virtualDisplayToScreenMatrix,
249             boolean isInputMethodSuppressingSpellChecker) {
250         this.result = result;
251         this.method = method;
252         this.accessibilitySessions = accessibilitySessions;
253         this.channel = channel;
254         this.id = id;
255         this.sequence = sequence;
256         if (virtualDisplayToScreenMatrix == null) {
257             mVirtualDisplayToScreenMatrixValues = null;
258         } else {
259             mVirtualDisplayToScreenMatrixValues = new float[9];
260             virtualDisplayToScreenMatrix.getValues(mVirtualDisplayToScreenMatrixValues);
261         }
262         this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
263     }
264 
InputBindResult(Parcel source)265     private InputBindResult(Parcel source) {
266         result = source.readInt();
267         method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
268         int n = source.readInt();
269         if (n < 0) {
270             accessibilitySessions = null;
271         } else {
272             accessibilitySessions = new SparseArray<>(n);
273             while (n > 0) {
274                 int key = source.readInt();
275                 IAccessibilityInputMethodSession value =
276                         IAccessibilityInputMethodSession.Stub.asInterface(
277                                 source.readStrongBinder());
278                 accessibilitySessions.append(key, value);
279                 n--;
280             }
281         }
282         if (source.readInt() != 0) {
283             channel = InputChannel.CREATOR.createFromParcel(source);
284         } else {
285             channel = null;
286         }
287         id = source.readString();
288         sequence = source.readInt();
289         mVirtualDisplayToScreenMatrixValues = source.createFloatArray();
290         isInputMethodSuppressingSpellChecker = source.readBoolean();
291     }
292 
293     /**
294      * {@inheritDoc}
295      */
296     @Override
toString()297     public String toString() {
298         return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
299                 + " sequence=" + sequence
300                 + " virtualDisplayToScreenMatrix=" + getVirtualDisplayToScreenMatrix()
301                 + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
302                 + "}";
303     }
304 
305     /**
306      * {@inheritDoc}
307      */
308     @Override
writeToParcel(Parcel dest, int flags)309     public void writeToParcel(Parcel dest, int flags) {
310         dest.writeInt(result);
311         dest.writeStrongInterface(method);
312         if (accessibilitySessions == null) {
313             dest.writeInt(-1);
314         } else {
315             int n = accessibilitySessions.size();
316             dest.writeInt(n);
317             int i = 0;
318             while (i < n) {
319                 dest.writeInt(accessibilitySessions.keyAt(i));
320                 dest.writeStrongInterface(accessibilitySessions.valueAt(i));
321                 i++;
322             }
323         }
324         if (channel != null) {
325             dest.writeInt(1);
326             channel.writeToParcel(dest, flags);
327         } else {
328             dest.writeInt(0);
329         }
330         dest.writeString(id);
331         dest.writeInt(sequence);
332         dest.writeFloatArray(mVirtualDisplayToScreenMatrixValues);
333         dest.writeBoolean(isInputMethodSuppressingSpellChecker);
334     }
335 
336     /**
337      * Used to make this class parcelable.
338      */
339     public static final Parcelable.Creator<InputBindResult> CREATOR =
340             new Parcelable.Creator<InputBindResult>() {
341         @Override
342         public InputBindResult createFromParcel(Parcel source) {
343             return new InputBindResult(source);
344         }
345 
346         @Override
347         public InputBindResult[] newArray(int size) {
348             return new InputBindResult[size];
349         }
350     };
351 
352     /**
353      * {@inheritDoc}
354      */
355     @Override
describeContents()356     public int describeContents() {
357         return channel != null ? channel.describeContents() : 0;
358     }
359 
getResultString()360     private String getResultString() {
361         switch (result) {
362             case ResultCode.SUCCESS_WITH_IME_SESSION:
363                 return "SUCCESS_WITH_IME_SESSION";
364             case ResultCode.SUCCESS_WAITING_IME_SESSION:
365                 return "SUCCESS_WAITING_IME_SESSION";
366             case ResultCode.SUCCESS_WAITING_IME_BINDING:
367                 return "SUCCESS_WAITING_IME_BINDING";
368             case ResultCode.SUCCESS_WAITING_USER_SWITCHING:
369                 return "SUCCESS_WAITING_USER_SWITCHING";
370             case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY:
371                 return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY";
372             case ResultCode.ERROR_NULL:
373                 return "ERROR_NULL";
374             case ResultCode.ERROR_NO_IME:
375                 return "ERROR_NO_IME";
376             case ResultCode.ERROR_NO_EDITOR:
377                 return "ERROR_NO_EDITOR";
378             case ResultCode.ERROR_INVALID_PACKAGE_NAME:
379                 return "ERROR_INVALID_PACKAGE_NAME";
380             case ResultCode.ERROR_SYSTEM_NOT_READY:
381                 return "ERROR_SYSTEM_NOT_READY";
382             case ResultCode.ERROR_IME_NOT_CONNECTED:
383                 return "ERROR_IME_NOT_CONNECTED";
384             case ResultCode.ERROR_INVALID_USER:
385                 return "ERROR_INVALID_USER";
386             case ResultCode.ERROR_NULL_EDITOR_INFO:
387                 return "ERROR_NULL_EDITOR_INFO";
388             case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
389                 return "ERROR_NOT_IME_TARGET_WINDOW";
390             case ResultCode.ERROR_DISPLAY_ID_MISMATCH:
391                 return "ERROR_DISPLAY_ID_MISMATCH";
392             case ResultCode.ERROR_INVALID_DISPLAY_ID:
393                 return "ERROR_INVALID_DISPLAY_ID";
394             default:
395                 return "Unknown(" + result + ")";
396         }
397     }
398 
error(@esultCode int result)399     private static InputBindResult error(@ResultCode int result) {
400         return new InputBindResult(result, null, null, null, null, -1, null, false);
401     }
402 
403     /**
404      * Predefined error object for {@link ResultCode#ERROR_NULL}.
405      */
406     public static final InputBindResult NULL = error(ResultCode.ERROR_NULL);
407     /**
408      * Predefined error object for {@link ResultCode#NO_IME}.
409      */
410     public static final InputBindResult NO_IME = error(ResultCode.ERROR_NO_IME);
411     /**
412      * Predefined error object for {@link ResultCode#NO_EDITOR}.
413      */
414     public static final InputBindResult NO_EDITOR = error(ResultCode.ERROR_NO_EDITOR);
415     /**
416      * Predefined error object for {@link ResultCode#ERROR_INVALID_PACKAGE_NAME}.
417      */
418     public static final InputBindResult INVALID_PACKAGE_NAME =
419             error(ResultCode.ERROR_INVALID_PACKAGE_NAME);
420     /**
421      * Predefined error object for {@link ResultCode#ERROR_NULL_EDITOR_INFO}.
422      */
423     public static final InputBindResult NULL_EDITOR_INFO = error(ResultCode.ERROR_NULL_EDITOR_INFO);
424     /**
425      * Predefined error object for {@link ResultCode#ERROR_NOT_IME_TARGET_WINDOW}.
426      */
427     public static final InputBindResult NOT_IME_TARGET_WINDOW =
428             error(ResultCode.ERROR_NOT_IME_TARGET_WINDOW);
429     /**
430      * Predefined error object for {@link ResultCode#ERROR_IME_NOT_CONNECTED}.
431      */
432     public static final InputBindResult IME_NOT_CONNECTED =
433             error(ResultCode.ERROR_IME_NOT_CONNECTED);
434     /**
435      * Predefined error object for {@link ResultCode#ERROR_INVALID_USER}.
436      */
437     public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);
438 
439     /**
440      * Predefined error object for {@link ResultCode#ERROR_DISPLAY_ID_MISMATCH}.
441      */
442     public static final InputBindResult DISPLAY_ID_MISMATCH =
443             error(ResultCode.ERROR_DISPLAY_ID_MISMATCH);
444 
445     /**
446      * Predefined error object for {@link ResultCode#ERROR_INVALID_DISPLAY_ID}.
447      */
448     public static final InputBindResult INVALID_DISPLAY_ID =
449             error(ResultCode.ERROR_INVALID_DISPLAY_ID);
450 
451     /**
452      * Predefined <strong>success</strong> object for
453      * {@link ResultCode#SUCCESS_WAITING_USER_SWITCHING}.
454      */
455     public static final InputBindResult USER_SWITCHING =
456             error(ResultCode.SUCCESS_WAITING_USER_SWITCHING);
457 }
458