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

Commit 9931d03f authored by Becca Hughes's avatar Becca Hughes
Browse files

Implement policy transparency for CredMan

This CL implements policy transparency for
Credential Manager settings.

Screenshots:
https://hsv.googleplex.com/5502938857340928
https://hsv.googleplex.com/4999933426925568

Test: on device w/ test dpc
Bug: 318552220
Change-Id: I78e1fa47541c81e6e2d2bf2c13159be01928e77c
parent 0c85e4bc
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -236,6 +239,31 @@ public final class CombinedProviderInfo {
        return null;
    }

    /** Returns whether this entry contains a system provider. */
    public boolean isCredentialManagerSystemProvider() {
        for (CredentialProviderInfo cpi : mCredentialProviderInfos) {
            if (cpi.isSystemProvider()) {
                return true;
            }
        }

        return false;
    }

    /** Returns whether this entry has device admin restrictions. */
    @Nullable
    public RestrictedLockUtils.EnforcedAdmin getDeviceAdminRestrictions(
            Context context, int userId) {
        final String packageName = getPackageName();
        if (TextUtils.isEmpty(packageName)) {
            return null;
        }

        return RestrictedLockUtilsInternal.checkIfApplicationCanBeCredentialManagerProvider(
                context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0),
                packageName);
    }

    /** Returns the provider that gets the top spot. */
    public static @Nullable CombinedProviderInfo getTopProvider(
            List<CombinedProviderInfo> providers) {
@@ -327,8 +355,7 @@ public final class CombinedProviderInfo {
    }

    public static @Nullable Intent createSettingsActivityIntent(
            @Nullable CharSequence packageName,
            @Nullable CharSequence settingsActivity) {
            @Nullable CharSequence packageName, @Nullable CharSequence settingsActivity) {
        if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(settingsActivity)) {
            return null;
        }
+16 −8
Original line number Diff line number Diff line
@@ -69,8 +69,9 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.TwoTargetPreference;

import java.util.ArrayList;
import java.util.HashMap;
@@ -328,7 +329,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl

        setAvailableServices(
                mCredentialManager.getCredentialProviderServices(
                        getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
                        getUser(),
                        CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN),
                null);
    }

@@ -355,7 +357,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        // Get the list of new providers and components.
        List<CredentialProviderInfo> newProviders =
                mCredentialManager.getCredentialProviderServices(
                        getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
                        getUser(),
                        CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN);
        Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
        Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);

@@ -548,7 +551,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
                            icon,
                            packageName,
                            combinedInfo.getSettingsSubtitle(),
                            combinedInfo.getSettingsActivity());
                            combinedInfo.getSettingsActivity(),
                            combinedInfo.getDeviceAdminRestrictions(context, getUser()));
            output.put(packageName, pref);
            group.addPreference(pref);
        }
@@ -569,7 +573,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
                service.getServiceIcon(mContext),
                service.getServiceInfo().packageName,
                service.getSettingsSubtitle(),
                service.getSettingsActivity());
                service.getSettingsActivity(),
                /* enforcedCredManAdmin= */ null);
    }

    /**
@@ -653,7 +658,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
            @Nullable Drawable icon,
            @NonNull String packageName,
            @Nullable CharSequence subtitle,
            @Nullable CharSequence settingsActivity) {
            @Nullable CharSequence settingsActivity,
            @Nullable RestrictedLockUtils.EnforcedAdmin enforcedCredManAdmin) {
        final CombiPreference pref =
                new CombiPreference(prefContext, mEnabledPackageNames.contains(packageName));
        pref.setTitle(title);
@@ -669,6 +675,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
            pref.setSummary(subtitle);
        }

        pref.setDisabledByAdmin(enforcedCredManAdmin);

        pref.setPreferenceListener(
                new CombiPreference.OnCombiPreferenceClickListener() {
                    @Override
@@ -1005,8 +1013,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        }
    }

    /** CombiPreference is a combination of TwoTargetPreference and SwitchPreference. */
    public static class CombiPreference extends TwoTargetPreference {
    /** CombiPreference is a combination of RestrictedPreference and SwitchPreference. */
    public static class CombiPreference extends RestrictedPreference {

        private final Listener mListener = new Listener();

+71 −18
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
@@ -39,14 +42,17 @@ import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.preference.Preference;

import com.android.internal.content.PackageMonitor;
import com.android.settings.R;
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
import com.android.settingslib.RestrictedSelectorWithWidgetPreference;
import com.android.settingslib.applications.DefaultAppInfo;
import com.android.settingslib.widget.CandidateInfo;
import com.android.settingslib.widget.SelectorWithWidgetPreference;

import java.util.ArrayList;
import java.util.List;
@@ -263,7 +269,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
        if (service != null) {
            credManProviders.addAll(
                    service.getCredentialProviderServices(
                            getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
                            getUser(),
                            CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN));
        }

        final String selectedAutofillProvider = getSelectedAutofillProvider(context, getUser());
@@ -283,30 +290,75 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {

        for (CombinedProviderInfo cpi : allProviders) {
            ServiceInfo brandingService = cpi.getBrandingService();
            if (brandingService == null) {
            ApplicationInfo appInfo = cpi.getApplicationInfo();

            if (brandingService != null) {
                candidates.add(
                        new DefaultAppInfo(
                                context,
                                mPm,
                                getUser(),
                                cpi.getApplicationInfo(),
                                cpi.getSettingsSubtitle(),
                                true));
            } else {
                        new CredentialManagerDefaultAppInfo(
                                context, mPm, getUser(), brandingService, cpi));
            } else if (appInfo != null) {
                candidates.add(
                        new DefaultAppInfo(
                                context,
                                mPm,
                                getUser(),
                                brandingService,
                                cpi.getSettingsSubtitle(),
                                true));
                        new CredentialManagerDefaultAppInfo(context, mPm, getUser(), appInfo, cpi));
            }
        }

        return candidates;
    }

    @Override
    public void bindPreferenceExtra(
            SelectorWithWidgetPreference pref,
            String key,
            CandidateInfo info,
            String defaultKey,
            String systemDefaultKey) {
        super.bindPreferenceExtra(pref, key, info, defaultKey, systemDefaultKey);

        if (!(info instanceof CredentialManagerDefaultAppInfo)) {
            Log.e(TAG, "Candidate info should be a subclass of CredentialManagerDefaultAppInfo");
            return;
        }

        if (!(pref instanceof RestrictedSelectorWithWidgetPreference)) {
            Log.e(TAG, "Preference should be a subclass of RestrictedSelectorWithWidgetPreference");
            return;
        }

        CredentialManagerDefaultAppInfo credmanAppInfo = (CredentialManagerDefaultAppInfo) info;
        RestrictedSelectorWithWidgetPreference rp = (RestrictedSelectorWithWidgetPreference) pref;

        // Apply policy transparency.
        rp.setDisabledByAdmin(
                credmanAppInfo
                        .getCombinedProviderInfo()
                        .getDeviceAdminRestrictions(getContext(), getUser()));
    }

    @Override
    protected SelectorWithWidgetPreference createPreference() {
        return new RestrictedSelectorWithWidgetPreference(getPrefContext());
    }

    /** This extends DefaultAppInfo with custom CredMan app info. */
    public static class CredentialManagerDefaultAppInfo extends DefaultAppInfo {

        private final CombinedProviderInfo mCombinedProviderInfo;

        CredentialManagerDefaultAppInfo(
                Context context,
                PackageManager pm,
                int uid,
                PackageItemInfo info,
                CombinedProviderInfo cpi) {
            super(context, pm, uid, info, cpi.getSettingsSubtitle(), /* enabled= */ true);
            mCombinedProviderInfo = cpi;
        }

        public @NonNull CombinedProviderInfo getCombinedProviderInfo() {
            return mCombinedProviderInfo;
        }
    }

    @Override
    protected String getDefaultKey() {
        final CombinedProviderInfo topProvider =
@@ -415,7 +467,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
        final List<String> credManProviders = new ArrayList<>();
        for (CredentialProviderInfo cpi :
                service.getCredentialProviderServices(
                        getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)) {
                        getUser(),
                        CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN)) {

            if (cpi.isEnabled() && !cpi.isPrimary()) {
                credManProviders.add(cpi.getServiceInfo().getComponentName().flattenToString());
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
            @Nullable CharSequence appName,
            @Nullable String appSubtitle,
            @Nullable Drawable appIcon,
            @Nullable CharSequence packageName,
            @Nullable String packageName,
            @Nullable CharSequence settingsActivity) {
        if (appName == null) {
            preference.setTitle(R.string.credman_app_list_preference_none);
+8 −2
Original line number Diff line number Diff line
@@ -159,6 +159,13 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme
            String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
    }

    /**
     * A chance for subclasses to create a custom preference instance.
     */
    protected SelectorWithWidgetPreference createPreference() {
        return new SelectorWithWidgetPreference(getPrefContext());
    }

    public void updateCandidates() {
        mCandidates.clear();
        final List<? extends CandidateInfo> candidateList = getCandidates();
@@ -193,8 +200,7 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme
        }
        if (candidateList != null) {
            for (CandidateInfo info : candidateList) {
                SelectorWithWidgetPreference pref =
                        new SelectorWithWidgetPreference(getPrefContext());
                SelectorWithWidgetPreference pref = createPreference();
                if (customLayoutResId > 0) {
                    pref.setLayoutResource(customLayoutResId);
                }