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