15381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme/*
25381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * Copyright (C) 2016 The Android Open Source Project
35381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme *
45381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * Licensed under the Apache License, Version 2.0 (the "License");
55381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * you may not use this file except in compliance with the License.
65381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * You may obtain a copy of the License at
75381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme *
85381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme *      http://www.apache.org/licenses/LICENSE-2.0
95381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme *
105381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * Unless required by applicable law or agreed to in writing, software
115381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * distributed under the License is distributed on an "AS IS" BASIS,
125381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * See the License for the specific language governing permissions and
145381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme * limitations under the License.
155381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme */
165381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemepackage android.service.autofill;
175381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
185381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.Manifest;
190f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganovimport android.annotation.NonNull;
204b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.annotation.Nullable;
215381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.app.AppGlobals;
225381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.content.ComponentName;
235381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.content.pm.PackageManager;
245381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.content.pm.ServiceInfo;
254b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.content.res.Resources;
264b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.content.res.TypedArray;
274b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.content.res.XmlResourceParser;
285381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Lemeimport android.os.RemoteException;
294b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.util.AttributeSet;
304b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.util.Log;
314b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport android.util.Xml;
324b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport org.xmlpull.v1.XmlPullParser;
334b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport org.xmlpull.v1.XmlPullParserException;
344b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long
35c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Longimport com.android.internal.R;
36c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long
374b93f46130ab9a972773ebf2be9839109d5c6a08Jason Longimport java.io.IOException;
385381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
39c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long/**
40640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme * {@link ServiceInfo} and meta-data about an {@link AutofillService}.
41c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long *
42c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long * @hide
43c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long */
44640f30a7763b0a4b80c767acb84c740aac04768bFelipe Lemepublic final class AutofillServiceInfo {
45640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    private static final String TAG = "AutofillServiceInfo";
465381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
475381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
485381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme            throws PackageManager.NameNotFoundException {
495381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        try {
504b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(
514b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long                    comp,
524b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long                    PackageManager.GET_META_DATA,
534b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long                    userHandle);
545381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme            if (si != null) {
555381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme                return si;
565381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme            }
575381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        } catch (RemoteException e) {
585381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        }
595381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        throw new PackageManager.NameNotFoundException(comp.toString());
605381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme    }
615381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
620f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    @NonNull
63c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long    private final ServiceInfo mServiceInfo;
640f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov
654b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long    @Nullable
66c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long    private final String mSettingsActivity;
675381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
68640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    public AutofillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
694b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long            throws PackageManager.NameNotFoundException {
704b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long        this(pm, getServiceInfoOrThrow(comp, userHandle));
714b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long    }
724b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long
73640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    public AutofillServiceInfo(PackageManager pm, ServiceInfo si) {
74c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        mServiceInfo = si;
750f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        final TypedArray metaDataArray = getMetaDataArray(pm, si);
76c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        if (metaDataArray != null) {
77f78e952d8df7074aa7380c5998826a4dffe335e7Felipe Leme            mSettingsActivity = metaDataArray
78f78e952d8df7074aa7380c5998826a4dffe335e7Felipe Leme                    .getString(R.styleable.AutofillService_settingsActivity);
79c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            metaDataArray.recycle();
80c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        } else {
81c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            mSettingsActivity = null;
82c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        }
83c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long    }
84c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long
85c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long    /**
86decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme     * Gets the meta-data as a {@link TypedArray}, or {@code null} if not provided,
87decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme     * or throws if invalid.
88c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long     */
89c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long    @Nullable
900f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) {
91c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        // Check for permissions.
92decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme        // TODO(b/37563972): remove support to BIND_AUTOFILL once clients use BIND_AUTOFILL_SERVICE
93decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme        if (!Manifest.permission.BIND_AUTOFILL_SERVICE.equals(si.permission)
94decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme                && !Manifest.permission.BIND_AUTOFILL.equals(si.permission)) {
95decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme            Log.w(TAG, "AutofillService from '" + si.packageName + "' does not require permission "
96decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme                    + Manifest.permission.BIND_AUTOFILL_SERVICE);
97decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme            throw new SecurityException("Service does not require permission "
98decd887f012f0c39bba855c8878eb5d8255595c4Felipe Leme                    + Manifest.permission.BIND_AUTOFILL_SERVICE);
995381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        }
1005381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
101c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        // Get the AutoFill metadata, if declared.
102640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        XmlResourceParser parser = si.loadXmlMetaData(pm, AutofillService.SERVICE_META_DATA);
103c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        if (parser == null) {
104c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            return null;
105c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        }
106c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long
107c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        // Parse service info and get the <autofill-service> tag as an AttributeSet.
108c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long        AttributeSet attrs;
1094b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long        try {
110c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            // Move the XML parser to the first tag.
111c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            try {
112c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long                int type;
113c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
114c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long                        && type != XmlPullParser.START_TAG) {
115c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long                }
116c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            } catch (XmlPullParserException | IOException e) {
1170f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                Log.e(TAG, "Error parsing auto fill service meta-data", e);
1180f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                return null;
1194b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long            }
1205381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
121c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            if (!"autofill-service".equals(parser.getName())) {
1220f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                Log.e(TAG, "Meta-data does not start with autofill-service tag");
1230f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                return null;
1244b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long            }
125c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            attrs = Xml.asAttributeSet(parser);
126c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long
127c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            // Get resources required to read the AttributeSet.
128c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            Resources res;
129c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            try {
130c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long                res = pm.getResourcesForApplication(si.applicationInfo);
131c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            } catch (PackageManager.NameNotFoundException e) {
1320f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                Log.e(TAG, "Error getting application resources", e);
1330f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                return null;
1344b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long            }
1354b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long
136f78e952d8df7074aa7380c5998826a4dffe335e7Felipe Leme            return res.obtainAttributes(attrs, R.styleable.AutofillService);
1374b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long        } finally {
138c121dda89a0df1c174d63fa9c50f8924365fefe4Jason Long            parser.close();
1394b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long        }
1405381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme    }
1415381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme
1425381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme    public ServiceInfo getServiceInfo() {
1435381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme        return mServiceInfo;
1445381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme    }
1454b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long
1464b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long    @Nullable
1474b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long    public String getSettingsActivity() {
1484b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long        return mSettingsActivity;
1494b93f46130ab9a972773ebf2be9839109d5c6a08Jason Long    }
1505381aa4b585f3fa2a315d88e910111173e2ef77dFelipe Leme}
151