AutofillService.java revision 121e526476fb226cabf400c55a0bbfdd0781e772
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
37import java.util.ArrayList;
38import java.util.List;
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_AUTOFILL} permission so
52     * that other applications can not abuse it.
53     */
54    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
55    public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
56
57    /**
58     * Name under which a AutoFillService component publishes information about itself.
59     * This meta-data should reference an XML resource containing a
60     * <code>&lt;{@link
61     * android.R.styleable#AutofillService autofill-service}&gt;</code> tag.
62     * This is a a sample XML file configuring an AutoFillService:
63     * <pre> &lt;autofill-service
64     *     android:settingsActivity="foo.bar.SettingsActivity"
65     *     . . .
66     * /&gt;</pre>
67     */
68    public static final String SERVICE_META_DATA = "android.autofill";
69
70    // Handler messages.
71    private static final int MSG_CONNECT = 1;
72    private static final int MSG_DISCONNECT = 2;
73    private static final int MSG_ON_FILL_REQUEST = 3;
74    private static final int MSG_ON_SAVE_REQUEST = 4;
75
76    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
77        @Override
78        public void onConnectedStateChanged(boolean connected) {
79            if (connected) {
80                mHandlerCaller.obtainMessage(MSG_CONNECT).sendToTarget();
81            } else {
82                mHandlerCaller.obtainMessage(MSG_DISCONNECT).sendToTarget();
83            }
84        }
85
86        @Override
87        public void onFillRequest(FillRequest request, IFillCallback callback) {
88            ICancellationSignal transport = CancellationSignal.createTransport();
89            try {
90                callback.onCancellable(transport);
91            } catch (RemoteException e) {
92                e.rethrowFromSystemServer();
93            }
94            mHandlerCaller.obtainMessageOOO(MSG_ON_FILL_REQUEST, request,
95                    CancellationSignal.fromTransport(transport), callback)
96                    .sendToTarget();
97        }
98
99        @Override
100        public void onSaveRequest(SaveRequest request, ISaveCallback callback) {
101            mHandlerCaller.obtainMessageOO(MSG_ON_SAVE_REQUEST, request,
102                    callback).sendToTarget();
103        }
104    };
105
106    private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
107        switch (msg.what) {
108            case MSG_CONNECT: {
109                onConnected();
110                break;
111            } case MSG_ON_FILL_REQUEST: {
112                final SomeArgs args = (SomeArgs) msg.obj;
113                final FillRequest request = (FillRequest) args.arg1;
114                final CancellationSignal cancellation = (CancellationSignal) args.arg2;
115                final IFillCallback callback = (IFillCallback) args.arg3;
116                final FillCallback fillCallback = new FillCallback(callback, request.getId());
117                args.recycle();
118                // TODO(b/37563972): temporary try-catch hack to support old method
119                try {
120                    onFillRequest(request, cancellation, fillCallback);
121                } catch (AbstractMethodError e) {
122                    final ArrayList<FillContext> contexts = request.getFillContexts();
123                    onFillRequest(contexts.get(contexts.size() - 1).getStructure(),
124                            request.getClientState(), request.getFlags(), cancellation,
125                            fillCallback);
126                }
127                break;
128            } case MSG_ON_SAVE_REQUEST: {
129                final SomeArgs args = (SomeArgs) msg.obj;
130                final SaveRequest request = (SaveRequest) args.arg1;
131                final ISaveCallback callback = (ISaveCallback) args.arg2;
132                final SaveCallback saveCallback = new SaveCallback(callback);
133                args.recycle();
134                // TODO(b/37563972): temporary try-catch hack to support old method
135                try {
136                    onSaveRequest(request, saveCallback);
137                } catch (AbstractMethodError e) {
138                    final List<FillContext> contexts = request.getFillContexts();
139                    onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
140                            request.getClientState(), saveCallback);
141                }
142                break;
143            } case MSG_DISCONNECT: {
144                onDisconnected();
145                break;
146            } default: {
147                Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
148            }
149        }
150    };
151
152    private HandlerCaller mHandlerCaller;
153
154    /**
155     * {@inheritDoc}
156     *
157     * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
158     */
159    @Override
160    public void onCreate() {
161        super.onCreate();
162        mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
163    }
164
165    @Override
166    public final IBinder onBind(Intent intent) {
167        if (SERVICE_INTERFACE.equals(intent.getAction())) {
168            return mInterface.asBinder();
169        }
170        Log.w(TAG, "Tried to bind to wrong intent: " + intent);
171        return null;
172    }
173
174    /**
175     * Called when the Android system connects to service.
176     *
177     * <p>You should generally do initialization here rather than in {@link #onCreate}.
178     */
179    public void onConnected() {
180    }
181
182    /**
183     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
184     * service.
185     *
186     * <p>Service must call one of the {@link FillCallback} methods (like
187     * {@link FillCallback#onSuccess(FillResponse)}
188     * or {@link FillCallback#onFailure(CharSequence)})
189     * to notify the result of the request.
190     *
191     * @param request the {@link FillRequest request} to handle.
192     *        See {@link FillResponse} for examples of multiple-sections requests.
193     * @param cancellationSignal signal for observing cancellation requests. The system will use
194     *     this to notify you that the fill result is no longer needed and you should stop
195     *     handling this fill request in order to save resources.
196     * @param callback object used to notify the result of the request.
197     */
198    public abstract void onFillRequest(@NonNull FillRequest request,
199            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
200
201    /**
202     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
203     * service.
204     *
205     * <p>Service must call one of the {@link FillCallback} methods (like
206     * {@link FillCallback#onSuccess(FillResponse)}
207     * or {@link FillCallback#onFailure(CharSequence)})
208     * to notify the result of the request.
209     *
210     * @param structure {@link Activity}'s view structure.
211     * @param data bundle containing data passed by the service in a last call to
212     *        {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
213     *        service to keep state between fill and save requests as well as when filling different
214     *        sections of the UI as the system will try to aggressively unbind from the service to
215     *        conserve resources.
216     *        See {@link FillResponse} for examples of multiple-sections requests.
217     * @param flags either {@code 0} or {@link AutofillManager#FLAG_MANUAL_REQUEST}.
218     * @param cancellationSignal signal for observing cancellation requests. The system will use
219     *     this to notify you that the fill result is no longer needed and you should stop
220     *     handling this fill request in order to save resources.
221     * @param callback object used to notify the result of the request.
222     *
223     * @hide
224     */
225    @Deprecated
226    public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
227            int flags, @NonNull CancellationSignal cancellationSignal,
228            @NonNull FillCallback callback);
229
230    /**
231     * Called when user requests service to save the fields of an {@link Activity}.
232     *
233     * <p>Service must call one of the {@link SaveCallback} methods (like
234     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
235     * to notify the result of the request.
236     *
237     * @param request the {@link SaveRequest request} to handle.
238     *        See {@link FillResponse} for examples of multiple-sections requests.
239     * @param callback object used to notify the result of the request.
240     */
241    public abstract void onSaveRequest(@NonNull SaveRequest request,
242            @NonNull SaveCallback callback);
243
244    /**
245     * Called when user requests service to save the fields of an {@link Activity}.
246     *
247     * <p>Service must call one of the {@link SaveCallback} methods (like
248     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
249     * to notify the result of the request.
250     *
251     * @param structure {@link Activity}'s view structure.
252     * @param data bundle containing data passed by the service in a last call to
253     *        {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
254     *        service to keep state between fill and save requests as well as when filling different
255     *        sections of the UI as the system will try to aggressively unbind from the service to
256     *        conserve resources.
257     *        See {@link FillResponse} for examples of multiple-sections requests.
258     * @param callback object used to notify the result of the request.
259     *
260     * @hide
261     */
262    @Deprecated
263    public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
264            @NonNull SaveCallback callback);
265
266    /**
267     * Called when the Android system disconnects from the service.
268     *
269     * <p> At this point this service may no longer be an active {@link AutofillService}.
270     */
271    public void onDisconnected() {
272    }
273
274    /** @hide */
275    @Deprecated
276    public final void disableSelf() {
277        getSystemService(AutofillManager.class).disableOwnedAutofillServices();
278    }
279
280    /**
281     * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was
282     * returned.
283     *
284     * <p>The history is not persisted over reboots.
285     *
286     * @return The history or {@code null} if there are not events.
287     */
288    @Nullable public final FillEventHistory getFillEventHistory() {
289        AutofillManager afm = getSystemService(AutofillManager.class);
290
291        if (afm == null) {
292            return null;
293        } else {
294            return afm.getFillEventHistory();
295        }
296    }
297}
298