1/*
2 * Copyright (C) 2007-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.android.internal.view;
18
19import static java.lang.annotation.RetentionPolicy.SOURCE;
20
21import android.annotation.IntDef;
22import android.content.ComponentName;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.IBinder;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.os.UserHandle;
29import android.view.InputChannel;
30
31import java.lang.annotation.Retention;
32
33/**
34 * Bundle of information returned by input method manager about a successful
35 * binding to an input method.
36 */
37public final class InputBindResult implements Parcelable {
38
39    @Retention(SOURCE)
40    @IntDef({
41            ResultCode.SUCCESS_WITH_IME_SESSION,
42            ResultCode.SUCCESS_WAITING_IME_SESSION,
43            ResultCode.SUCCESS_WAITING_IME_BINDING,
44            ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
45            ResultCode.ERROR_NULL,
46            ResultCode.ERROR_NO_IME,
47            ResultCode.ERROR_INVALID_PACKAGE_NAME,
48            ResultCode.ERROR_SYSTEM_NOT_READY,
49            ResultCode.ERROR_IME_NOT_CONNECTED,
50            ResultCode.ERROR_INVALID_USER,
51            ResultCode.ERROR_NULL_EDITOR_INFO,
52            ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
53    })
54    public @interface ResultCode {
55        /**
56         * Indicates that everything in this result object including {@link #method} is valid.
57         */
58        int SUCCESS_WITH_IME_SESSION = 0;
59        /**
60         * Indicates that this is a temporary binding until the
61         * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session
62         * to {@link com.android.server.InputMethodManagerService} (IMMS).
63         *
64         * <p>Note that in this state the IMS is already bound to IMMS but the logical session
65         * is not yet established on top of the IPC channel.</p>
66         *
67         * <p>Some of fields such as {@link #channel} is not yet available.</p>
68         *
69         * @see android.inputmethodservice.InputMethodService##onCreateInputMethodSessionInterface()
70         **/
71        int SUCCESS_WAITING_IME_SESSION = 1;
72        /**
73         * Indicates that this is a temporary binding until the
74         * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session
75         * to {@link com.android.server.InputMethodManagerService} (IMMS).
76         *
77         * <p>Note that in this state the IMMS has already initiated a connection to the IMS but
78         * the binding process is not completed yet.</p>
79         *
80         * <p>Some of fields such as {@link #channel} is not yet available.</p>
81         * @see android.content.ServiceConnection#onServiceConnected(ComponentName, IBinder)
82         */
83        int SUCCESS_WAITING_IME_BINDING = 2;
84        /**
85         * Indicates that this is not intended for starting input but just for reporting window
86         * focus change from the application process.
87         *
88         * <p>All other fields do not have meaningful value.</p>
89         */
90        int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3;
91        /**
92         * Indicates somehow
93         * {@link com.android.server.InputMethodManagerService#startInputOrWindowGainedFocus} is
94         * trying to return null {@link InputBindResult}, which must never happen.
95         */
96        int ERROR_NULL = 4;
97        /**
98         * Indicates that {@link com.android.server.InputMethodManagerService} recognizes no IME.
99         */
100        int ERROR_NO_IME = 5;
101        /**
102         * Indicates that {@link android.view.inputmethod.EditorInfo#packageName} does not match
103         * the caller UID.
104         *
105         * @see android.view.inputmethod.EditorInfo#packageName
106         */
107        int ERROR_INVALID_PACKAGE_NAME = 6;
108        /**
109         * Indicates that the system is still in an early stage of the boot process and any 3rd
110         * party application is not allowed to run.
111         *
112         * @see com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START
113         */
114        int ERROR_SYSTEM_NOT_READY = 7;
115        /**
116         * Indicates that {@link com.android.server.InputMethodManagerService} tried to connect to
117         * an {@link android.inputmethodservice.InputMethodService} but failed.
118         *
119         * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle)
120         */
121        int ERROR_IME_NOT_CONNECTED = 8;
122        /**
123         * Indicates that the caller is not the foreground user (or does not have
124         * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission).
125         */
126        int ERROR_INVALID_USER = 9;
127        /**
128         * Indicates that the caller should have specified non-null
129         * {@link android.view.inputmethod.EditorInfo}.
130         */
131        int ERROR_NULL_EDITOR_INFO = 10;
132        /**
133         * Indicates that the target window the client specified cannot be the IME target right now.
134         *
135         * <p>Due to the asynchronous nature of Android OS, we cannot completely avoid this error.
136         * The client should try to restart input when its {@link android.view.Window} is focused
137         * again.</p>
138         *
139         * @see com.android.server.wm.WindowManagerService#inputMethodClientHasFocus(IInputMethodClient)
140         */
141        int ERROR_NOT_IME_TARGET_WINDOW = 11;
142        /**
143         * Indicates that focused view in the current window is not an editor.
144         */
145        int ERROR_NO_EDITOR = 12;
146    }
147
148    @ResultCode
149    public final int result;
150
151    /**
152     * The input method service.
153     */
154    public final IInputMethodSession method;
155
156    /**
157     * The input channel used to send input events to this IME.
158     */
159    public final InputChannel channel;
160
161    /**
162     * The ID for this input method, as found in InputMethodInfo; null if
163     * no input method will be bound.
164     */
165    public final String id;
166
167    /**
168     * Sequence number of this binding.
169     */
170    public final int sequence;
171
172    /**
173     * Sequence number of user action notification.
174     */
175    public final int userActionNotificationSequenceNumber;
176
177    public InputBindResult(@ResultCode int _result,
178            IInputMethodSession _method, InputChannel _channel,
179            String _id, int _sequence, int _userActionNotificationSequenceNumber) {
180        result = _result;
181        method = _method;
182        channel = _channel;
183        id = _id;
184        sequence = _sequence;
185        userActionNotificationSequenceNumber = _userActionNotificationSequenceNumber;
186    }
187
188    InputBindResult(Parcel source) {
189        result = source.readInt();
190        method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
191        if (source.readInt() != 0) {
192            channel = InputChannel.CREATOR.createFromParcel(source);
193        } else {
194            channel = null;
195        }
196        id = source.readString();
197        sequence = source.readInt();
198        userActionNotificationSequenceNumber = source.readInt();
199    }
200
201    @Override
202    public String toString() {
203        return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
204                + " sequence=" + sequence
205                + " userActionNotificationSequenceNumber=" + userActionNotificationSequenceNumber
206                + "}";
207    }
208
209    /**
210     * Used to package this object into a {@link Parcel}.
211     *
212     * @param dest The {@link Parcel} to be written.
213     * @param flags The flags used for parceling.
214     */
215    @Override
216    public void writeToParcel(Parcel dest, int flags) {
217        dest.writeInt(result);
218        dest.writeStrongInterface(method);
219        if (channel != null) {
220            dest.writeInt(1);
221            channel.writeToParcel(dest, flags);
222        } else {
223            dest.writeInt(0);
224        }
225        dest.writeString(id);
226        dest.writeInt(sequence);
227        dest.writeInt(userActionNotificationSequenceNumber);
228    }
229
230    /**
231     * Used to make this class parcelable.
232     */
233    public static final Parcelable.Creator<InputBindResult> CREATOR =
234            new Parcelable.Creator<InputBindResult>() {
235        @Override
236        public InputBindResult createFromParcel(Parcel source) {
237            return new InputBindResult(source);
238        }
239
240        @Override
241        public InputBindResult[] newArray(int size) {
242            return new InputBindResult[size];
243        }
244    };
245
246    @Override
247    public int describeContents() {
248        return channel != null ? channel.describeContents() : 0;
249    }
250
251    public String getResultString() {
252        switch (result) {
253            case ResultCode.SUCCESS_WITH_IME_SESSION:
254                return "SUCCESS_WITH_IME_SESSION";
255            case ResultCode.SUCCESS_WAITING_IME_SESSION:
256                return "SUCCESS_WAITING_IME_SESSION";
257            case ResultCode.SUCCESS_WAITING_IME_BINDING:
258                return "SUCCESS_WAITING_IME_BINDING";
259            case ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY:
260                return "SUCCESS_REPORT_WINDOW_FOCUS_ONLY";
261            case ResultCode.ERROR_NULL:
262                return "ERROR_NULL";
263            case ResultCode.ERROR_NO_IME:
264                return "ERROR_NO_IME";
265            case ResultCode.ERROR_NO_EDITOR:
266                return "ERROR_NO_EDITOR";
267            case ResultCode.ERROR_INVALID_PACKAGE_NAME:
268                return "ERROR_INVALID_PACKAGE_NAME";
269            case ResultCode.ERROR_SYSTEM_NOT_READY:
270                return "ERROR_SYSTEM_NOT_READY";
271            case ResultCode.ERROR_IME_NOT_CONNECTED:
272                return "ERROR_IME_NOT_CONNECTED";
273            case ResultCode.ERROR_INVALID_USER:
274                return "ERROR_INVALID_USER";
275            case ResultCode.ERROR_NULL_EDITOR_INFO:
276                return "ERROR_NULL_EDITOR_INFO";
277            case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
278                return "ERROR_NOT_IME_TARGET_WINDOW";
279            default:
280                return "Unknown(" + result + ")";
281        }
282    }
283
284    private static InputBindResult error(@ResultCode int result) {
285        return new InputBindResult(result, null, null, null, -1, -1);
286    }
287
288    /**
289     * Predefined error object for {@link ResultCode#ERROR_NULL}.
290     */
291    public static final InputBindResult NULL = error(ResultCode.ERROR_NULL);
292    /**
293     * Predefined error object for {@link ResultCode#NO_IME}.
294     */
295    public static final InputBindResult NO_IME = error(ResultCode.ERROR_NO_IME);
296    /**
297     * Predefined error object for {@link ResultCode#NO_EDITOR}.
298     */
299    public static final InputBindResult NO_EDITOR = error(ResultCode.ERROR_NO_EDITOR);
300    /**
301     * Predefined error object for {@link ResultCode#ERROR_INVALID_PACKAGE_NAME}.
302     */
303    public static final InputBindResult INVALID_PACKAGE_NAME =
304            error(ResultCode.ERROR_INVALID_PACKAGE_NAME);
305    /**
306     * Predefined error object for {@link ResultCode#ERROR_NULL_EDITOR_INFO}.
307     */
308    public static final InputBindResult NULL_EDITOR_INFO = error(ResultCode.ERROR_NULL_EDITOR_INFO);
309    /**
310     * Predefined error object for {@link ResultCode#ERROR_NOT_IME_TARGET_WINDOW}.
311     */
312    public static final InputBindResult NOT_IME_TARGET_WINDOW =
313            error(ResultCode.ERROR_NOT_IME_TARGET_WINDOW);
314    /**
315     * Predefined error object for {@link ResultCode#ERROR_IME_NOT_CONNECTED}.
316     */
317    public static final InputBindResult IME_NOT_CONNECTED =
318            error(ResultCode.ERROR_IME_NOT_CONNECTED);
319    /**
320     * Predefined error object for {@link ResultCode#ERROR_INVALID_USER}.
321     */
322    public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);
323
324}
325