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

Commit 9c6fbe0c authored by Becca Hughes's avatar Becca Hughes Committed by Automerger Merge Worker
Browse files

Merge changes from topic "udc-settings-subtitle" into udc-dev am: b2e70aeb

parents 059e97f0 b2e70aeb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1112,6 +1112,7 @@ package android.credentials {
    method @Nullable public CharSequence getLabel(@NonNull android.content.Context);
    method @Nullable public android.graphics.drawable.Drawable getServiceIcon(@NonNull android.content.Context);
    method @NonNull public android.content.pm.ServiceInfo getServiceInfo();
    method @Nullable public CharSequence getSettingsSubtitle();
    method @NonNull public boolean hasCapability(@NonNull String);
    method public boolean isEnabled();
    method public boolean isSystemProvider();
@@ -1124,6 +1125,7 @@ package android.credentials {
    method @NonNull public android.credentials.CredentialProviderInfo.Builder addCapabilities(@NonNull java.util.List<java.lang.String>);
    method @NonNull public android.credentials.CredentialProviderInfo build();
    method @NonNull public android.credentials.CredentialProviderInfo.Builder setEnabled(boolean);
    method @NonNull public android.credentials.CredentialProviderInfo.Builder setSettingsSubtitle(@Nullable CharSequence);
    method @NonNull public android.credentials.CredentialProviderInfo.Builder setSystemProvider(boolean);
  }

+46 −5
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@ import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * {@link ServiceInfo} and meta-data about a credential provider.
@@ -39,8 +41,9 @@ import java.util.List;
@TestApi
public final class CredentialProviderInfo implements Parcelable {
    @NonNull private final ServiceInfo mServiceInfo;
    @NonNull private final List<String> mCapabilities = new ArrayList<>();
    @NonNull private final Set<String> mCapabilities = new HashSet<>();
    @Nullable private final CharSequence mOverrideLabel;
    @Nullable private CharSequence mSettingsSubtitle = null;
    private final boolean mIsSystemProvider;
    private final boolean mIsEnabled;

@@ -53,6 +56,7 @@ public final class CredentialProviderInfo implements Parcelable {
        mServiceInfo = builder.mServiceInfo;
        mCapabilities.addAll(builder.mCapabilities);
        mIsSystemProvider = builder.mIsSystemProvider;
        mSettingsSubtitle = builder.mSettingsSubtitle;
        mIsEnabled = builder.mIsEnabled;
        mOverrideLabel = builder.mOverrideLabel;
    }
@@ -92,7 +96,11 @@ public final class CredentialProviderInfo implements Parcelable {
    /** Returns a list of capabilities this provider service can support. */
    @NonNull
    public List<String> getCapabilities() {
        return Collections.unmodifiableList(mCapabilities);
        List<String> capabilities = new ArrayList<>();
        for (String capability : mCapabilities) {
            capabilities.add(capability);
        }
        return Collections.unmodifiableList(capabilities);
    }

    /** Returns whether the provider is enabled by the user. */
@@ -100,6 +108,12 @@ public final class CredentialProviderInfo implements Parcelable {
        return mIsEnabled;
    }

    /** Returns the settings subtitle. */
    @Nullable
    public CharSequence getSettingsSubtitle() {
        return mSettingsSubtitle;
    }

    /** Returns the component name for the service. */
    @NonNull
    public ComponentName getComponentName() {
@@ -110,9 +124,12 @@ public final class CredentialProviderInfo implements Parcelable {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeTypedObject(mServiceInfo, flags);
        dest.writeBoolean(mIsSystemProvider);
        dest.writeStringList(mCapabilities);
        dest.writeBoolean(mIsEnabled);
        TextUtils.writeToParcel(mOverrideLabel, dest, flags);
        TextUtils.writeToParcel(mSettingsSubtitle, dest, flags);

        List<String> capabilities = getCapabilities();
        dest.writeStringList(capabilities);
    }

    @Override
@@ -135,6 +152,9 @@ public final class CredentialProviderInfo implements Parcelable {
                + "overrideLabel="
                + mOverrideLabel
                + ", "
                + "settingsSubtitle="
                + mSettingsSubtitle
                + ", "
                + "capabilities="
                + String.join(",", mCapabilities)
                + "}";
@@ -143,9 +163,13 @@ public final class CredentialProviderInfo implements Parcelable {
    private CredentialProviderInfo(@NonNull Parcel in) {
        mServiceInfo = in.readTypedObject(ServiceInfo.CREATOR);
        mIsSystemProvider = in.readBoolean();
        in.readStringList(mCapabilities);
        mIsEnabled = in.readBoolean();
        mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
        mSettingsSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);

        List<String> capabilities = new ArrayList<>();
        in.readStringList(capabilities);
        mCapabilities.addAll(capabilities);
    }

    public static final @NonNull Parcelable.Creator<CredentialProviderInfo> CREATOR =
@@ -165,8 +189,9 @@ public final class CredentialProviderInfo implements Parcelable {
    public static final class Builder {

        @NonNull private ServiceInfo mServiceInfo;
        @NonNull private List<String> mCapabilities = new ArrayList<>();
        @NonNull private Set<String> mCapabilities = new HashSet<>();
        private boolean mIsSystemProvider = false;
        @Nullable private CharSequence mSettingsSubtitle = null;
        private boolean mIsEnabled = false;
        @Nullable private CharSequence mOverrideLabel = null;

@@ -195,12 +220,28 @@ public final class CredentialProviderInfo implements Parcelable {
            return this;
        }

        /** Sets the settings subtitle. */
        public @NonNull Builder setSettingsSubtitle(@Nullable CharSequence settingsSubtitle) {
            mSettingsSubtitle = settingsSubtitle;
            return this;
        }

        /** Sets a list of capabilities this provider service can support. */
        public @NonNull Builder addCapabilities(@NonNull List<String> capabilities) {
            mCapabilities.addAll(capabilities);
            return this;
        }

        /**
         * Sets a list of capabilities this provider service can support.
         *
         * @hide
         */
        public @NonNull Builder addCapabilities(@NonNull Set<String> capabilities) {
            mCapabilities.addAll(capabilities);
            return this;
        }

        /** Sets whether it is enabled by the user. */
        public @NonNull Builder setEnabled(boolean isEnabled) {
            mIsEnabled = isEnabled;
+159 −26
Original line number Diff line number Diff line
@@ -33,17 +33,28 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -58,6 +69,11 @@ import java.util.Set;
public final class CredentialProviderInfoFactory {
    private static final String TAG = "CredentialProviderInfoFactory";

    private static final String TAG_CREDENTIAL_PROVIDER = "credential-provider";
    private static final String TAG_CAPABILITIES = "capabilities";
    private static final String TAG_CAPABILITY = "capability";
    private static final String ATTR_NAME = "name";

    /**
     * Constructs an information instance of the credential provider.
     *
@@ -118,8 +134,8 @@ public final class CredentialProviderInfoFactory {
    }

    /**
     * Constructs an information instance of the credential provider for testing purposes. Does
     * not run any verifications and passes parameters as is.
     * Constructs an information instance of the credential provider for testing purposes. Does not
     * run any verifications and passes parameters as is.
     */
    @VisibleForTesting
    public static CredentialProviderInfo createForTests(
@@ -134,7 +150,6 @@ public final class CredentialProviderInfoFactory {
                .setSystemProvider(isSystemProvider)
                .addCapabilities(capabilities)
                .build();

    }

    private static void verifyProviderPermission(ServiceInfo serviceInfo) throws SecurityException {
@@ -194,10 +209,8 @@ public final class CredentialProviderInfoFactory {
    private static CredentialProviderInfo.Builder populateMetadata(
            @NonNull Context context, ServiceInfo serviceInfo) {
        requireNonNull(context, "context must not be null");

        final CredentialProviderInfo.Builder builder =
                new CredentialProviderInfo.Builder(serviceInfo);
        final PackageManager pm = context.getPackageManager();
        CredentialProviderInfo.Builder builder = new CredentialProviderInfo.Builder(serviceInfo);

        // 1. Get the metadata for the service.
        final Bundle metadata = serviceInfo.metaData;
@@ -206,46 +219,165 @@ public final class CredentialProviderInfoFactory {
            return builder;
        }

        // 2. Extract the capabilities from the bundle.
        // 2. Get the resources for the application.
        Resources resources = null;
        try {
            Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
            resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Failed to get app resources", e);
        }

        // 3. Stop if we are missing data.
        if (metadata == null || resources == null) {
            Log.i(TAG, "populateMetadata - resources is null");
            return builder;
        }

            builder.addCapabilities(populateProviderCapabilities(resources, metadata, serviceInfo));
        } catch (PackageManager.NameNotFoundException e) {
            Slog.e(TAG, e.getMessage());
        // 4. Extract the XML metadata.
        try {
            builder = extractXmlMetadata(context, builder, serviceInfo, pm, resources);
        } catch (Exception e) {
            Log.e(TAG, "Failed to get XML metadata", e);
        }

        // 5. Extract the legacy metadata.
        try {
            builder.addCapabilities(
                    populateLegacyProviderCapabilities(resources, metadata, serviceInfo));
        } catch (Exception e) {
            Log.e(TAG, "Failed to get legacy metadata ", e);
        }

        return builder;
    }

    private static CredentialProviderInfo.Builder extractXmlMetadata(
            @NonNull Context context,
            @NonNull CredentialProviderInfo.Builder builder,
            @NonNull ServiceInfo serviceInfo,
            @NonNull PackageManager pm,
            @NonNull Resources resources) {
        final XmlResourceParser parser =
                serviceInfo.loadXmlMetaData(pm, CredentialProviderService.SERVICE_META_DATA);
        if (parser == null) {
            return builder;
        }

        try {
            int type = 0;
            while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
                type = parser.next();
            }

            // This is matching a <credential-provider /> tag in the XML.
            if (TAG_CREDENTIAL_PROVIDER.equals(parser.getName())) {
                final AttributeSet allAttributes = Xml.asAttributeSet(parser);
                TypedArray afsAttributes = null;
                try {
                    afsAttributes =
                            resources.obtainAttributes(
                                    allAttributes,
                                    com.android.internal.R.styleable.CredentialProvider);
                    builder.setSettingsSubtitle(
                            afsAttributes.getString(
                                    R.styleable.CredentialProvider_settingsSubtitle));
                } catch (Exception e) {
                    Log.e(TAG, "Failed to get XML attr", e);
                } finally {
                    if (afsAttributes != null) {
                        afsAttributes.recycle();
                    }
                }
                builder.addCapabilities(parseXmlProviderOuterCapabilities(parser, resources));
            } else {
                Log.e(TAG, "Meta-data does not start with credential-provider-service tag");
            }
        } catch (IOException | XmlPullParserException e) {
            Log.e(TAG, "Error parsing credential provider service meta-data", e);
        }

        return builder;
    }

    private static List<String> populateProviderCapabilities(
    private static Set<String> parseXmlProviderOuterCapabilities(
            XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException {
        final Set<String> capabilities = new HashSet<>();
        final int outerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            if (TAG_CAPABILITIES.equals(parser.getName())) {
                capabilities.addAll(parseXmlProviderInnerCapabilities(parser, resources));
            }
        }

        return capabilities;
    }

    private static List<String> parseXmlProviderInnerCapabilities(
            XmlPullParser parser, Resources resources) throws IOException, XmlPullParserException {
        List<String> capabilities = new ArrayList<>();

        final int outerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            if (TAG_CAPABILITY.equals(parser.getName())) {
                String name = parser.getAttributeValue(null, ATTR_NAME);
                if (name != null && !TextUtils.isEmpty(name)) {
                    capabilities.add(name);
                }
            }
        }

        return capabilities;
    }

    private static Set<String> populateLegacyProviderCapabilities(
            Resources resources, Bundle metadata, ServiceInfo serviceInfo) {
        List<String> output = new ArrayList<>();
        String[] capabilities = new String[0];
        Set<String> output = new HashSet<>();
        Set<String> capabilities = new HashSet<>();

        try {
            capabilities =
            String[] discovered =
                    resources.getStringArray(
                            metadata.getInt(CredentialProviderService.CAPABILITY_META_DATA_KEY));
        } catch (Resources.NotFoundException e) {
            Slog.e(TAG, "Failed to get capabilities: " + e.getMessage());
            if (discovered != null) {
                capabilities.addAll(Arrays.asList(discovered));
            }
        } catch (Resources.NotFoundException | NullPointerException e) {
            Log.e(TAG, "Failed to get capabilities: ", e);
        }

        try {
            String[] discovered =
                    metadata.getStringArray(CredentialProviderService.CAPABILITY_META_DATA_KEY);
            if (discovered != null) {
                capabilities.addAll(Arrays.asList(discovered));
            }
        } catch (Resources.NotFoundException | NullPointerException e) {
            Log.e(TAG, "Failed to get capabilities: ", e);
        }

        if (capabilities == null || capabilities.length == 0) {
            Slog.e(TAG, "No capabilities found for provider:" + serviceInfo.packageName);
        if (capabilities.size() == 0) {
            Log.e(TAG, "No capabilities found for provider:" + serviceInfo);
            return output;
        }

        for (String capability : capabilities) {
            if (capability.isEmpty()) {
                Slog.e(TAG, "Skipping empty capability");
            if (capability == null || capability.isEmpty()) {
                Log.w(TAG, "Skipping empty/null capability");
                continue;
            }
            Slog.e(TAG, "Capabilities found for provider: " + capability);
            Log.i(TAG, "Capabilities found for provider: " + capability);
            output.add(capability);
        }
        return output;
@@ -361,7 +493,8 @@ public final class CredentialProviderInfoFactory {

        try {
            DevicePolicyManager dpm = newContext.getSystemService(DevicePolicyManager.class);
            return dpm.getCredentialManagerPolicy();
            PackagePolicy pp = dpm.getCredentialManagerPolicy();
            return pp;
        } catch (SecurityException e) {
            // If the current user is not enrolled in DPM then this can throw a security error.
            Log.e(TAG, "Failed to get device policy: " + e);
+0 −1
Original line number Diff line number Diff line
@@ -193,7 +193,6 @@ public abstract class CredentialProviderService extends Service {
      */
    public static final String SERVICE_META_DATA = "android.credentials.provider";


    /** @hide */
    public static final String TEST_SYSTEM_PROVIDER_META_DATA_KEY =
            "android.credentials.testsystemprovider";