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

Commit 21733fa1 authored by Becca Hughes's avatar Becca Hughes Committed by Android (Google) Code Review
Browse files

Merge "Align settings with new mocks" into udc-dev

parents 8060347e b21df6c5
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -237,7 +237,10 @@ public final class CombinedProviderInfo {
            List<CredentialProviderInfo> cpi = credmanServices.get(packageName);

            // If there are multiple autofill services then pick the first one.
            AutofillServiceInfo selectedAsi = asi.isEmpty() ? null : asi.get(0);
            AutofillServiceInfo selectedAsi = null;
            if (asi != null && !asi.isEmpty()) {
                selectedAsi = asi.get(0);
            }

            // Check if we are the default autofill provider.
            boolean isDefaultAutofillProvider = false;
+64 −98
Original line number Diff line number Diff line
@@ -41,8 +41,8 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.autofill.AutofillServiceInfo;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -79,6 +79,15 @@ import java.util.concurrent.Executor;
public class CredentialManagerPreferenceController extends BasePreferenceController
        implements LifecycleObserver {
    public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";

    /**
     * In the settings logic we should hide the list of additional credman providers if there is no
     * provider selected at the top. The current logic relies on checking whether the autofill
     * provider is set which won't work for cred-man only providers. Therefore when a CM only
     * provider is set we will set the autofill setting to be this placeholder.
     */
    public static final String AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER = "credential-provider";

    private static final String TAG = "CredentialManagerPreferenceController";
    private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
    private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
@@ -99,6 +108,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
    private @Nullable String mFlagOverrideForTest = null;
    private @Nullable PreferenceScreen mPreferenceScreen = null;

    private boolean mVisibility = false;

    public CredentialManagerPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mPm = context.getPackageManager();
@@ -131,7 +142,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
            return UNSUPPORTED_ON_DEVICE;
        }

        if (!isAutofillPrefSelected()) {
        if (!mVisibility) {
            return CONDITIONALLY_UNAVAILABLE;
        }

@@ -271,7 +282,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl

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

@@ -287,6 +298,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        }
    }

    private void setVisibility(boolean newVisibility) {
        if (newVisibility == mVisibility) {
            return;
        }

        mVisibility = newVisibility;
        if (mDelegate != null) {
            mDelegate.forceDelegateRefresh();
        }
    }

    @VisibleForTesting
    void setAvailableServices(
            List<CredentialProviderInfo> availableServices, String flagOverrideForTest) {
@@ -320,48 +342,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        PreferenceGroup group = screen.findPreference(getPreferenceKey());
        group.removeAll();

        // Hide/show based on autofill pref.
        boolean isVisible = isAutofillPrefSelected();
        screen.setVisible(isVisible);
        group.setVisible(isVisible);

        if (!isVisible) {
            return;
        }

        Context context = screen.getContext();
        mPrefs.putAll(buildPreferenceList(context, group));

        // Add the "add service" button only when there are no providers.
        if (mPrefs.isEmpty()) {
            String searchUri = getAddServiceUri(context);
            if (!TextUtils.isEmpty(searchUri)) {
                group.addPreference(newAddServicePreference(searchUri, context));
            }
        }
    }

    /**
     * Returns the "add service" URI to show the play store. It will first try and use the
     * credential manager specific search URI and if that is null it will fallback to the autofill
     * one.
     */
    public @NonNull String getAddServiceUri(@NonNull Context context) {
        // Check the credential manager gflag for a link.
        String searchUri =
                DeviceConfig.getString(
                        DeviceConfig.NAMESPACE_CREDENTIAL,
                        ADD_SERVICE_DEVICE_CONFIG,
                        mFlagOverrideForTest);
        if (!TextUtils.isEmpty(searchUri)) {
            return searchUri;
        }

        // If not fall back on autofill.
        return Settings.Secure.getStringForUser(
                context.getContentResolver(),
                Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
                getUser());
    }

    /**
@@ -396,52 +378,59 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
    @VisibleForTesting
    public Map<String, SwitchPreference> buildPreferenceList(
            Context context, PreferenceGroup group) {
        // Group the services by package name.
        Map<String, List<CredentialProviderInfo>> groupedInfos = new HashMap<>();
        for (CredentialProviderInfo cpi : mServices) {
            String packageName = cpi.getServiceInfo().packageName;
            if (isProviderHiddenBecauseOfAutofill(packageName)) {
                continue;
        // Get the selected autofill provider. If it is the placeholder then replace it with an
        // empty string.
        String selectedAutofillProvider =
                DefaultCombinedPicker.getSelectedAutofillProvider(mContext, getUser());
        if (TextUtils.equals(
                selectedAutofillProvider, AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER)) {
            selectedAutofillProvider = "";
        }

        // Get the list of combined providers.
        List<CombinedProviderInfo> providers =
                CombinedProviderInfo.buildMergedList(
                        AutofillServiceInfo.getAvailableServices(context, getUser()),
                        mServices,
                        selectedAutofillProvider);

        // Get the provider that is displayed at the top. If there is none then hide
        // everything.
        CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
        if (topProvider == null) {
            setVisibility(false);
            return new HashMap<>();
        }

            if (!groupedInfos.containsKey(packageName)) {
                groupedInfos.put(packageName, new ArrayList<>());
            }
        Map<String, SwitchPreference> output = new HashMap<>();
        for (CombinedProviderInfo combinedInfo : providers) {
            final String packageName = combinedInfo.getApplicationInfo().packageName;

            groupedInfos.get(packageName).add(cpi);
            // If this provider is displayed at the top then we should not show it.
            if (topProvider != null
                    && topProvider.getApplicationInfo().packageName.equals(packageName)) {
                continue;
            }

        // Build the pref list.
        Map<String, SwitchPreference> output = new HashMap<>();
        for (String packageName : groupedInfos.keySet()) {
            List<CredentialProviderInfo> infos = groupedInfos.get(packageName);
            CredentialProviderInfo firstInfo = infos.get(0);
            ServiceInfo firstServiceInfo = firstInfo.getServiceInfo();
            CharSequence title = firstInfo.getLabel(context);
            Drawable icon = firstInfo.getServiceIcon(context);

            if (infos.size() > 1) {
                // If there is more than one then group them under the package.
                ApplicationInfo appInfo = firstServiceInfo.applicationInfo;
                if (appInfo.nonLocalizedLabel != null) {
                    title = appInfo.loadLabel(mPm);
                }
                icon = mIconFactory.getBadgedIcon(appInfo, getUser());
            // If this is an autofill provider then don't show it here.
            if (combinedInfo.getCredentialProviderInfos().isEmpty()) {
                continue;
            }

            // If there is no title then show the package manager.
            if (TextUtils.isEmpty(title)) {
                title = firstServiceInfo.packageName;
            }
            Drawable icon = combinedInfo.getAppIcon(context);
            CharSequence title = combinedInfo.getAppName(context);

            // Build the pref and add it to the output & group.
            SwitchPreference pref =
                    addProviderPreference(
                            context, title, icon, packageName, firstInfo.getSettingsSubtitle());
                            context, title, icon, packageName, combinedInfo.getSettingsSubtitle());
            output.put(packageName, pref);
            group.addPreference(pref);
        }

        // Set the visibility if we have services.
        setVisibility(!output.isEmpty());

        return output;
    }

@@ -607,29 +596,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        return new NewProviderConfirmationDialogFragment(host, packageName, appName);
    }

    /** If the provider is also the autofill provider then hide it. */
    @VisibleForTesting
    public boolean isProviderHiddenBecauseOfAutofill(String packageName) {
        final String autofillService =
                Settings.Secure.getStringForUser(
                        mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser());
        if (autofillService == null || TextUtils.isEmpty(autofillService)) {
            return false;
        }
        if (packageName == null || TextUtils.isEmpty(packageName)) {
            return false;
        }

        return autofillService.startsWith(packageName);
    }

    private boolean isAutofillPrefSelected() {
        final String autofillService =
                Settings.Secure.getStringForUser(
                        mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser());
        return !TextUtils.isEmpty(autofillService);
    }

    @VisibleForTesting
    void completeEnableProviderDialogBox(
            int whichButton, String packageName, boolean setActivityResult) {
+140 −24
Original line number Diff line number Diff line
@@ -16,21 +16,27 @@

package com.android.settings.applications.credentials;

import android.annotation.Nullable;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
import android.net.Uri;
import android.os.Bundle;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.content.ContextCompat;
import androidx.preference.Preference;

import com.android.internal.content.PackageMonitor;
@@ -47,8 +53,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {

    private static final String TAG = "DefaultCombinedPicker";

    public static final String SETTING = Settings.Secure.AUTOFILL_SERVICE;
    public static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
    public static final String AUTOFILL_SETTING = Settings.Secure.AUTOFILL_SERVICE;
    public static final String CREDENTIAL_SETTING = Settings.Secure.CREDENTIAL_SERVICE;

    /** Extra set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
    public static final String EXTRA_PACKAGE_NAME = "package_name";
@@ -56,6 +62,8 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
    /** Set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */
    private DialogInterface.OnClickListener mCancelListener;

    private CredentialManager mCredentialManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
@@ -71,6 +79,7 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
            // ACTION_REQUEST_SET_AUTOFILL_SERVICE and we should always use the calling uid.
            mUserId = UserHandle.myUserId();
        }

        mSettingsPackageMonitor.register(activity, activity.getMainLooper(), false);
        update();
    }
@@ -187,35 +196,76 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
        }
    }

    @Override
    /**
     * Get the Credential Manager service if we haven't already got it. We need to get the service
     * later because if we do it in onCreate it will fail.
     */
    private @Nullable CredentialManager getCredentialProviderService() {
        if (mCredentialManager == null) {
            mCredentialManager = getContext().getSystemService(CredentialManager.class);
        }
        return mCredentialManager;
    }

    private List<CombinedProviderInfo> getAllProviders() {
        final Context context = getContext();
        final List<AutofillServiceInfo> autofillProviders =
                AutofillServiceInfo.getAvailableServices(context, mUserId);

        final CredentialManager service = getCredentialProviderService();
        final List<CredentialProviderInfo> credManProviders = new ArrayList<>();
        if (service != null) {
            credManProviders.addAll(
                    service.getCredentialProviderServices(
                            mUserId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
        }

        final String selectedAutofillProvider = getSelectedAutofillProvider(context, mUserId);
        return CombinedProviderInfo.buildMergedList(
                autofillProviders, credManProviders, selectedAutofillProvider);
    }

    public static String getSelectedAutofillProvider(Context context, int userId) {
        return Settings.Secure.getStringForUser(
                context.getContentResolver(), AUTOFILL_SETTING, userId);
    }

    protected List<DefaultAppInfo> getCandidates() {
        final Context context = getContext();
        final List<CombinedProviderInfo> allProviders = getAllProviders();
        final List<DefaultAppInfo> candidates = new ArrayList<>();
        final List<AutofillServiceInfo> services =
                AutofillServiceInfo.getAvailableServices(getContext(), mUserId);
        for (AutofillServiceInfo asi : services) {

        for (CombinedProviderInfo cpi : allProviders) {
            ServiceInfo brandingService = cpi.getBrandingService();
            if (brandingService == null) {
                candidates.add(
                        new DefaultAppInfo(
                            getContext(), mPm, mUserId, asi.getServiceInfo().getComponentName()));
                                context,
                                mPm,
                                mUserId,
                                cpi.getApplicationInfo(),
                                cpi.getSettingsSubtitle(),
                                true));
            } else {
                candidates.add(
                        new DefaultAppInfo(
                                context,
                                mPm,
                                mUserId,
                                brandingService,
                                cpi.getSettingsSubtitle(),
                                true));
            }

        return candidates;
        }

    public static String getDefaultKey(Context context, int userId) {
        String setting =
                Settings.Secure.getStringForUser(context.getContentResolver(), SETTING, userId);
        if (setting != null) {
            ComponentName componentName = ComponentName.unflattenFromString(setting);
            if (componentName != null) {
                return componentName.flattenToString();
            }
        }
        return null;
        return candidates;
    }

    @Override
    protected String getDefaultKey() {
        return getDefaultKey(getContext(), mUserId);
        final CombinedProviderInfo topProvider =
                CombinedProviderInfo.getTopProvider(getAllProviders());
        return topProvider == null ? "" : topProvider.getApplicationInfo().packageName;
    }

    @Override
@@ -234,7 +284,39 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {

    @Override
    protected boolean setDefaultKey(String key) {
        Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING, key, mUserId);
        // Get the list of providers and see if any match the key (package name).
        final List<CombinedProviderInfo> allProviders = getAllProviders();
        CombinedProviderInfo matchedProvider = null;
        for (CombinedProviderInfo cpi : allProviders) {
            if (cpi.getApplicationInfo().packageName.equals(key)) {
                matchedProvider = cpi;
                break;
            }
        }

        // If there were none then clear the stored providers.
        if (matchedProvider == null) {
            setProviders(null, new ArrayList<>());
            return true;
        }

        // Get the component names and save them.
        final List<String> credManComponents = new ArrayList<>();
        for (CredentialProviderInfo pi : matchedProvider.getCredentialProviderInfos()) {
            credManComponents.add(pi.getServiceInfo().getComponentName().flattenToString());
        }

        String autofillValue = null;
        if (matchedProvider.getAutofillServiceInfo() != null) {
            autofillValue =
                    matchedProvider
                            .getAutofillServiceInfo()
                            .getServiceInfo()
                            .getComponentName()
                            .flattenToString();
        }

        setProviders(autofillValue, credManComponents);

        // Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
        // intent, and set proper result if so...
@@ -255,4 +337,38 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {

        return true;
    }

    private void setProviders(String autofillProvider, List<String> credManProviders) {
        if (TextUtils.isEmpty(autofillProvider)) {
            if (credManProviders.size() > 0) {
                autofillProvider =
                        CredentialManagerPreferenceController
                                .AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
            }
        }

        Settings.Secure.putStringForUser(
                getContext().getContentResolver(), AUTOFILL_SETTING, autofillProvider, mUserId);

        CredentialManager service = getCredentialProviderService();
        if (service == null) {
            return;
        }

        service.setEnabledProviders(
                credManProviders,
                mUserId,
                ContextCompat.getMainExecutor(getContext()),
                new OutcomeReceiver<Void, SetEnabledProvidersException>() {
                    @Override
                    public void onResult(Void result) {
                        Log.i(TAG, "setEnabledProviders success");
                    }

                    @Override
                    public void onError(SetEnabledProvidersException e) {
                        Log.e(TAG, "setEnabledProviders error: " + e.toString());
                    }
                });
    }
}
+49 −17
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -36,6 +38,9 @@ import java.util.List;

public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {

    private static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
    private static final String TAG = "DefaultCombinedPreferenceController";

    private final AutofillManager mAutofillManager;
    private final CredentialManager mCredentialManager;

@@ -76,26 +81,57 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon

    @Override
    protected DefaultAppInfo getDefaultAppInfo() {
        final String flattenComponent =
                Settings.Secure.getString(
                        mContext.getContentResolver(), DefaultCombinedPicker.SETTING);
        if (!TextUtils.isEmpty(flattenComponent)) {
            DefaultAppInfo appInfo =
                    new DefaultAppInfo(
        List<CombinedProviderInfo> providers = getAllProviders(mUserId);
        CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
        if (topProvider != null) {
            ServiceInfo brandingService = topProvider.getBrandingService();
            if (brandingService == null) {
                return new DefaultAppInfo(
                        mContext,
                        mPackageManager,
                        mUserId,
                            ComponentName.unflattenFromString(flattenComponent));
            return appInfo;
                        topProvider.getApplicationInfo(),
                        topProvider.getSettingsSubtitle(),
                        true);
            } else {
                return new DefaultAppInfo(
                        mContext,
                        mPackageManager,
                        mUserId,
                        brandingService,
                        topProvider.getSettingsSubtitle(),
                        true);
            }
        }
        return null;
    }

    private List<CombinedProviderInfo> getAllProviders(int userId) {
        final List<AutofillServiceInfo> autofillProviders =
                AutofillServiceInfo.getAvailableServices(mContext, userId);
        final List<CredentialProviderInfo> credManProviders =
                mCredentialManager.getCredentialProviderServices(
                        userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
        final String selectedAutofillProvider =
                Settings.Secure.getStringForUser(
                        mContext.getContentResolver(),
                        DefaultCombinedPicker.AUTOFILL_SETTING,
                        userId);

        return CombinedProviderInfo.buildMergedList(
                autofillProviders, credManProviders, selectedAutofillProvider);
    }

    @Override
    protected boolean showLabelAsTitle() {
        return true;
    }

    @Override
    protected boolean showAppSummary() {
        return true;
    }

    /** Provides Intent to setting activity for the specified autofill service. */
    static final class AutofillSettingIntentProvider {

@@ -113,9 +149,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
            final List<ResolveInfo> resolveInfos =
                    mContext.getPackageManager()
                            .queryIntentServicesAsUser(
                                    DefaultCombinedPicker.AUTOFILL_PROBE,
                                    PackageManager.GET_META_DATA,
                                    mUserId);
                                    AUTOFILL_PROBE, PackageManager.GET_META_DATA, mUserId);

            for (ResolveInfo resolveInfo : resolveInfos) {
                final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -130,9 +164,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
                                        .getSettingsActivity();
                    } catch (SecurityException e) {
                        // Service does not declare the proper permission, ignore it.
                        Log.w(
                                "AutofillSettingIntentProvider",
                                "Error getting info for " + serviceInfo + ": " + e);
                        Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
                        return null;
                    }
                    if (TextUtils.isEmpty(settingsActivity)) {
+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ public class DefaultWorkCombinedPreferenceController extends DefaultCombinedPref
        final String flattenComponent =
                Settings.Secure.getStringForUser(
                        mContext.getContentResolver(),
                        DefaultCombinedPicker.SETTING,
                        DefaultCombinedPicker.AUTOFILL_SETTING,
                        mUserHandle.getIdentifier());
        if (!TextUtils.isEmpty(flattenComponent)) {
            DefaultAppInfo appInfo =
Loading