Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b04c54fd authored by Jason Long's avatar Jason Long Committed by Android (Google) Code Review
Browse files

Merge "Define contract for AutoFillServiceInfo more precisely."

parents e84ad491 c121dda8
Loading
Loading
Loading
Loading
+72 −42
Original line number Diff line number Diff line
@@ -25,15 +25,26 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.RemoteException;
import android.util.AndroidException;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import com.android.internal.R;

import java.io.IOException;

/** @hide */
// TODO(b/33197203 , b/33802548): add CTS tests
/**
 * {@link ServiceInfo} and meta-data about an {@link AutoFillService}.
 *
 * <p>Upon construction, if {@link #getParseError()} is {@code null}, then the service is configured
 * correctly. Otherwise, {@link #getParseError()} indicates the parsing error.
 *
 * @hide
 */
public final class AutoFillServiceInfo {
    static final String TAG = "AutoFillServiceInfo";

@@ -53,67 +64,87 @@ public final class AutoFillServiceInfo {
    }

    @Nullable
    private String mParseError;
    private final String mParseError;

    private final ServiceInfo mServiceInfo;
    @Nullable
    private ServiceInfo mServiceInfo;
    @Nullable
    private String mSettingsActivity;
    private final String mSettingsActivity;

    public AutoFillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
            throws PackageManager.NameNotFoundException {
        this(pm, getServiceInfoOrThrow(comp, userHandle));
    }

    public AutoFillServiceInfo(PackageManager pm, ServiceInfo si)
            throws PackageManager.NameNotFoundException{
        if (si == null) {
            mParseError = "Service not available";
    public AutoFillServiceInfo(PackageManager pm, ServiceInfo si) {
        mServiceInfo = si;
        TypedArray metaDataArray;
        try {
            metaDataArray = getMetaDataArray(pm, si);
        } catch (AndroidException e) {
            mParseError = e.getMessage();
            mSettingsActivity = null;
            Log.w(TAG, mParseError, e);
            return;
        }

        mParseError = null;
        if (metaDataArray != null) {
            mSettingsActivity =
                    metaDataArray.getString(R.styleable.AutoFillService_settingsActivity);
            metaDataArray.recycle();
        } else {
            mSettingsActivity = null;
        }
    }

    /**
     * Gets the meta-data as a TypedArray, or null if not provided, or throws if invalid.
     */
    @Nullable
    private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si)
            throws AndroidException {
        // Check for permissions.
        if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
            mParseError = "Service does not require permission "
                    + Manifest.permission.BIND_AUTO_FILL;
            return;
            throw new AndroidException(
                "Service does not require permission " + Manifest.permission.BIND_AUTO_FILL);
        }

        XmlResourceParser parser = null;
        try {
            parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
        // Get the AutoFill metadata, if declared.
        XmlResourceParser parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
        if (parser == null) {
                mParseError = "No " + AutoFillService.SERVICE_META_DATA
                        + " meta-data for " + si.packageName;
                return;
            return null;
        }

            Resources res = pm.getResourcesForApplication(si.applicationInfo);

            AttributeSet attrs = Xml.asAttributeSet(parser);

        // Parse service info and get the <autofill-service> tag as an AttributeSet.
        AttributeSet attrs;
        try {
            // Move the XML parser to the first tag.
            try {
                int type;
                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                        && type != XmlPullParser.START_TAG) {
                }
            } catch (XmlPullParserException | IOException e) {
                throw new AndroidException("Error parsing auto fill service meta-data: " + e, e);
            }

            String nodeName = parser.getName();
            if (!"autofill-service".equals(nodeName)) {
                mParseError = "Meta-data does not start with autofill-service tag";
                return;
            if (!"autofill-service".equals(parser.getName())) {
                throw new AndroidException("Meta-data does not start with autofill-service tag");
            }
            attrs = Xml.asAttributeSet(parser);

            TypedArray array = res.obtainAttributes(attrs,
                    com.android.internal.R.styleable.AutoFillService);
            mSettingsActivity = array.getString(
                    com.android.internal.R.styleable.AutoFillService_settingsActivity);
            array.recycle();
        } catch (XmlPullParserException | IOException | PackageManager.NameNotFoundException e) {
            mParseError = "Error parsing auto fill service meta-data: " + e;
            Log.w(TAG, "error parsing auto fill service meta-data", e);
            return;
            // Get resources required to read the AttributeSet.
            Resources res;
            try {
                res = pm.getResourcesForApplication(si.applicationInfo);
            } catch (PackageManager.NameNotFoundException e) {
                throw new AndroidException("Error getting application resources: " + e, e);
            }

            return res.obtainAttributes(attrs, R.styleable.AutoFillService);
        } finally {
            if (parser != null) parser.close();
            parser.close();
        }
        mServiceInfo = si;
    }

    @Nullable
@@ -121,7 +152,6 @@ public final class AutoFillServiceInfo {
        return mParseError;
    }

    @Nullable
    public ServiceInfo getServiceInfo() {
        return mServiceInfo;
    }