AutofillService.java revision 2ac463e3f5c3b757ecbc7e30e0fc1e8e0d878272
1/*
2 * Copyright (C) 2017 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 */
16package android.service.autofill;
17
18import android.annotation.NonNull;
19import android.annotation.Nullable;
20import android.os.RemoteException;
21import com.android.internal.os.HandlerCaller;
22import android.annotation.SdkConstant;
23import android.app.Activity;
24import android.app.Service;
25import android.app.assist.AssistStructure;
26import android.content.Intent;
27import android.os.Bundle;
28import android.os.CancellationSignal;
29import android.os.IBinder;
30import android.os.ICancellationSignal;
31import android.os.Looper;
32import android.util.Log;
33import android.view.autofill.AutofillManager;
34
35import com.android.internal.os.SomeArgs;
36
37//TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
38//life-cycle (and how state could be maintained on server-side) is well documented.
39
40/**
41 * Top-level service of the current autofill service for a given user.
42 *
43 * <p>Apps providing autofill capabilities must extend this service.
44 */
45public abstract class AutofillService extends Service {
46    private static final String TAG = "AutofillService";
47
48    /**
49     * The {@link Intent} that must be declared as handled by the service.
50     * To be supported, the service must also require the
51     * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so
52     * that other applications can not abuse it.
53     *
54     * @hide
55     * @deprecated TODO(b/35956626): remove once clients use AutofillService
56     */
57    @Deprecated
58    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
59    public static final String OLD_SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
60
61    /**
62     * The {@link Intent} that must be declared as handled by the service.
63     * To be supported, the service must also require the
64     * {@link android.Manifest.permission#BIND_AUTOFILL} permission so
65     * that other applications can not abuse it.
66     */
67    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
68    public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
69
70    /**
71     * Name under which a AutoFillService component publishes information about itself.
72     * This meta-data should reference an XML resource containing a
73     * <code>&lt;{@link
74     * android.R.styleable#AutoFillService autofill-service}&gt;</code> tag.
75     * This is a a sample XML file configuring an AutoFillService:
76     * <pre> &lt;autofill-service
77     *     android:settingsActivity="foo.bar.SettingsActivity"
78     *     . . .
79     * /&gt;</pre>
80     */
81    public static final String SERVICE_META_DATA = "android.autofill";
82
83    // Internal extras
84    /** @hide */
85    public static final String EXTRA_ACTIVITY_TOKEN =
86            "android.service.autofill.extra.ACTIVITY_TOKEN";
87
88    // Handler messages.
89    private static final int MSG_CONNECT = 1;
90    private static final int MSG_DISCONNECT = 2;
91    private static final int MSG_ON_FILL_REQUEST = 3;
92    private static final int MSG_ON_SAVE_REQUEST = 4;
93
94    private static final int UNUSED_ARG = -1;
95
96    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
97        @Override
98        public void onInit(IAutoFillServiceConnection connection) {
99            if (connection != null) {
100                mHandlerCaller.obtainMessageO(MSG_CONNECT, connection).sendToTarget();
101            } else {
102                mHandlerCaller.obtainMessage(MSG_DISCONNECT).sendToTarget();
103            }
104        }
105
106        @Override
107        public void onFillRequest(AssistStructure structure, Bundle extras,
108                IFillCallback callback, int flags) {
109            ICancellationSignal transport = CancellationSignal.createTransport();
110            try {
111                callback.onCancellable(transport);
112            } catch (RemoteException e) {
113                e.rethrowFromSystemServer();
114            }
115            mHandlerCaller.obtainMessageIIOOOO(MSG_ON_FILL_REQUEST, flags, UNUSED_ARG, structure,
116                    CancellationSignal.fromTransport(transport), extras, callback)
117                    .sendToTarget();
118        }
119
120        @Override
121        public void onSaveRequest(AssistStructure structure, Bundle extras,
122                ISaveCallback callback) {
123            mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
124                    extras, callback).sendToTarget();
125        }
126    };
127
128    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
129        switch (msg.what) {
130            case MSG_CONNECT: {
131                mConnection = (IAutoFillServiceConnection) msg.obj;
132                onConnected();
133                break;
134            } case MSG_ON_FILL_REQUEST: {
135                final SomeArgs args = (SomeArgs) msg.obj;
136                final AssistStructure structure = (AssistStructure) args.arg1;
137                final CancellationSignal cancellation = (CancellationSignal) args.arg2;
138                final Bundle extras = (Bundle) args.arg3;
139                final IFillCallback callback = (IFillCallback) args.arg4;
140                final FillCallback fillCallback = new FillCallback(callback);
141                final int flags = msg.arg1;
142                args.recycle();
143                onFillRequest(structure, extras, flags, cancellation, fillCallback);
144                break;
145            } case MSG_ON_SAVE_REQUEST: {
146                final SomeArgs args = (SomeArgs) msg.obj;
147                final AssistStructure structure = (AssistStructure) args.arg1;
148                final Bundle extras = (Bundle) args.arg2;
149                final ISaveCallback callback = (ISaveCallback) args.arg3;
150                final SaveCallback saveCallback = new SaveCallback(callback);
151                args.recycle();
152                onSaveRequest(structure, extras, saveCallback);
153                break;
154            } case MSG_DISCONNECT: {
155                onDisconnected();
156                mConnection = null;
157                break;
158            } default: {
159                Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
160            }
161        }
162    };
163
164    private HandlerCaller mHandlerCaller;
165
166    private IAutoFillServiceConnection mConnection;
167
168    /**
169     * {@inheritDoc}
170     *
171     * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
172     */
173    @Override
174    public void onCreate() {
175        super.onCreate();
176        mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
177    }
178
179    @Override
180    public final IBinder onBind(Intent intent) {
181        if (SERVICE_INTERFACE.equals(intent.getAction())
182                || OLD_SERVICE_INTERFACE.equals(intent.getAction())) {
183            return mInterface.asBinder();
184        }
185        Log.w(TAG, "Tried to bind to wrong intent: " + intent);
186        return null;
187    }
188
189    /**
190     * Called when the Android system connects to service.
191     *
192     * <p>You should generally do initialization here rather than in {@link #onCreate}.
193     */
194    public void onConnected() {
195    }
196
197    /**
198     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
199     * service.
200     *
201     * <p>Service must call one of the {@link FillCallback} methods (like
202     * {@link FillCallback#onSuccess(FillResponse)}
203     * or {@link FillCallback#onFailure(CharSequence)})
204     * to notify the result of the request.
205     *
206     * @param structure {@link Activity}'s view structure.
207     * @param data bundle containing data passed by the service on previous calls to fill.
208     *     This bundle allows your service to keep state between fill and save requests
209     *     as well as when filling different sections of the UI as the system will try to
210     *     aggressively unbind from the service to conserve resources. See {@link
211     *     FillResponse} Javadoc for examples of multiple-sections requests.
212     * @param flags either {@code 0} or {@link AutofillManager#FLAG_MANUAL_REQUEST}.
213     * @param cancellationSignal signal for observing cancellation requests. The system will use
214     *     this to notify you that the fill result is no longer needed and you should stop
215     *     handling this fill request in order to save resources.
216     * @param callback object used to notify the result of the request.
217     */
218    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data, int flags,
219            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
220        //TODO(b/33197203): make non-abstract once older method is removed
221        onFillRequest(structure, data, cancellationSignal, callback);
222    }
223
224    /**
225     * @hide
226     * @deprecated - use {@link #onFillRequest(AssistStructure, Bundle, int,
227     * CancellationSignal, FillCallback)} instead
228     */
229    //TODO(b/33197203): remove once clients are not using anymore
230    @Deprecated
231    public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
232            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
233
234    /**
235     * Called when user requests service to save the fields of an {@link Activity}.
236     *
237     * <p>Service must call one of the {@link SaveCallback} methods (like
238     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
239     * to notify the result of the request.
240     *
241     * @param structure {@link Activity}'s view structure.
242     * @param data bundle containing data passed by the service on previous calls to fill.
243     *     This bundle allows your service to keep state between fill and save requests
244     *     as well as when filling different sections of the UI as the system will try to
245     *     aggressively unbind from the service to conserve resources. See {@link
246     *     FillResponse} Javadoc for examples of multiple-sections requests.
247     * @param callback object used to notify the result of the request.
248     */
249    public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
250            @NonNull SaveCallback callback);
251
252    /**
253     * Called when the Android system disconnects from the service.
254     *
255     * <p> At this point this service may no longer be an active {@link AutofillService}.
256     */
257    public void onDisconnected() {
258    }
259
260    /**
261     * Disables the service. After calling this method, the service will
262     * be disabled and settings will show that it is turned off.
263     *
264     * <p>You should call this method only after a call to {@link #onConnected()}
265     * and before the corresponding call to {@link #onDisconnected()}. In other words
266     * you can disable your service only while the system is connected to it.</p>
267     */
268    public final void disableSelf() {
269        if (mConnection != null) {
270            try {
271                mConnection.disableSelf();
272            } catch (RemoteException re) {
273                throw re.rethrowFromSystemServer();
274            }
275        }
276    }
277}
278