AutofillServiceInfo.java revision 640f30a7763b0a4b80c767acb84c740aac04768b
1/*
2 * Copyright (C) 2016 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.Manifest;
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.app.AppGlobals;
22import android.content.ComponentName;
23import android.content.pm.PackageManager;
24import android.content.pm.ServiceInfo;
25import android.content.res.Resources;
26import android.content.res.TypedArray;
27import android.content.res.XmlResourceParser;
28import android.os.RemoteException;
29import android.util.AttributeSet;
30import android.util.Log;
31import android.util.Xml;
32import org.xmlpull.v1.XmlPullParser;
33import org.xmlpull.v1.XmlPullParserException;
34
35import com.android.internal.R;
36
37import java.io.IOException;
38
39// TODO(b/33197203 , b/33802548): add CTS tests
40/**
41 * {@link ServiceInfo} and meta-data about an {@link AutofillService}.
42 *
43 * @hide
44 */
45public final class AutofillServiceInfo {
46    private static final String TAG = "AutofillServiceInfo";
47
48    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
49            throws PackageManager.NameNotFoundException {
50        try {
51            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(
52                    comp,
53                    PackageManager.GET_META_DATA,
54                    userHandle);
55            if (si != null) {
56                return si;
57            }
58        } catch (RemoteException e) {
59        }
60        throw new PackageManager.NameNotFoundException(comp.toString());
61    }
62
63    @NonNull
64    private final ServiceInfo mServiceInfo;
65
66    @Nullable
67    private final String mSettingsActivity;
68
69    public AutofillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
70            throws PackageManager.NameNotFoundException {
71        this(pm, getServiceInfoOrThrow(comp, userHandle));
72    }
73
74    public AutofillServiceInfo(PackageManager pm, ServiceInfo si) {
75        mServiceInfo = si;
76        final TypedArray metaDataArray = getMetaDataArray(pm, si);
77        if (metaDataArray != null) {
78            // TODO(b/35956626): inline newSettingsActivity once clients migrate
79            final String newSettingsActivity =
80                    metaDataArray.getString(R.styleable.AutofillService_settingsActivity);
81            System.out.println(">>> NEW CRAP MAN: " + newSettingsActivity); // TODO(felipeal): tmp
82            if (newSettingsActivity != null) {
83                mSettingsActivity = newSettingsActivity;
84            } else {
85                mSettingsActivity =
86                        metaDataArray.getString(R.styleable.AutoFillService_settingsActivity);
87            }
88            System.out.println(">>> FINAL CRAP MAN: " + mSettingsActivity); // TODO(felipeal): tmp
89            metaDataArray.recycle();
90        } else {
91            mSettingsActivity = null;
92        }
93    }
94
95    /**
96     * Gets the meta-data as a TypedArray, or null if not provided, or throws if invalid.
97     */
98    @Nullable
99    private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) {
100        // Check for permissions.
101        // TODO(b/35956626): remove check for BIND_AUTO_FILL once clients migrate
102        if (!Manifest.permission.BIND_AUTOFILL.equals(si.permission)
103                && !Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
104            Log.e(TAG, "Service does not require permission " + Manifest.permission.BIND_AUTOFILL);
105            return null;
106        }
107
108        // TODO(b/35956626): remove once clients migrate
109        final boolean oldStyle = !Manifest.permission.BIND_AUTOFILL.equals(si.permission);
110
111        // Get the AutoFill metadata, if declared.
112        XmlResourceParser parser = si.loadXmlMetaData(pm, AutofillService.SERVICE_META_DATA);
113        if (parser == null) {
114            return null;
115        }
116
117        // Parse service info and get the <autofill-service> tag as an AttributeSet.
118        AttributeSet attrs;
119        try {
120            // Move the XML parser to the first tag.
121            try {
122                int type;
123                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
124                        && type != XmlPullParser.START_TAG) {
125                }
126            } catch (XmlPullParserException | IOException e) {
127                Log.e(TAG, "Error parsing auto fill service meta-data", e);
128                return null;
129            }
130
131            if (!"autofill-service".equals(parser.getName())) {
132                Log.e(TAG, "Meta-data does not start with autofill-service tag");
133                return null;
134            }
135            attrs = Xml.asAttributeSet(parser);
136
137            // Get resources required to read the AttributeSet.
138            Resources res;
139            try {
140                res = pm.getResourcesForApplication(si.applicationInfo);
141            } catch (PackageManager.NameNotFoundException e) {
142                Log.e(TAG, "Error getting application resources", e);
143                return null;
144            }
145
146            return oldStyle ? res.obtainAttributes(attrs, R.styleable.AutoFillService)
147                    : res.obtainAttributes(attrs, R.styleable.AutofillService);
148        } finally {
149            parser.close();
150        }
151    }
152
153    public ServiceInfo getServiceInfo() {
154        return mServiceInfo;
155    }
156
157    @Nullable
158    public String getSettingsActivity() {
159        return mSettingsActivity;
160    }
161}
162