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

Commit 94d25016 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add service link when no providers are present" into udc-dev

parents 8dc3e775 f9f3309f
Loading
Loading
Loading
Loading
+74 −3
Original line number Diff line number Diff line
@@ -29,13 +29,16 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
@@ -48,6 +51,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
@@ -69,6 +73,7 @@ import java.util.concurrent.Executor;
/** Queries available credential manager providers and adds preferences for them. */
public class CredentialManagerPreferenceController extends BasePreferenceController
        implements LifecycleObserver {
    public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
    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";
@@ -85,6 +90,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl

    private @Nullable FragmentManager mFragmentManager = null;
    private @Nullable Delegate mDelegate = null;
    private @Nullable String mFlagOverrideForTest = null;

    public CredentialManagerPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
@@ -237,12 +243,16 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        setAvailableServices(
                lifecycleOwner,
                mCredentialManager.getCredentialProviderServices(
                        getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
                        getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
                null);
    }

    @VisibleForTesting
    void setAvailableServices(
            LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) {
            LifecycleOwner lifecycleOwner,
            List<CredentialProviderInfo> availableServices,
            String flagOverrideForTest) {
        mFlagOverrideForTest = flagOverrideForTest;
        mServices.clear();
        mServices.addAll(availableServices);

@@ -276,6 +286,65 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
        PreferenceGroup group = screen.findPreference(getPreferenceKey());
        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());
    }

    /**
     * Gets the preference that allows to add a new cred man service.
     *
     * @return the pref to be added
     */
    @VisibleForTesting
    public Preference newAddServicePreference(String searchUri, Context context) {
        final Intent addNewServiceIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
        final Preference preference = new Preference(context);
        preference.setOnPreferenceClickListener(
                p -> {
                    context.startActivityAsUser(addNewServiceIntent, UserHandle.of(getUser()));
                    return true;
                });
        preference.setTitle(R.string.print_menu_item_add_service);
        preference.setOrder(Integer.MAX_VALUE - 1);
        preference.setPersistent(false);

        // Try to set the icon this should fail in a test environment but work
        // in the actual app.
        try {
            preference.setIcon(R.drawable.ic_add_24dp);
        } catch (Resources.NotFoundException e) {
            Log.e(TAG, "Failed to find icon for add services link", e);
        }
        return preference;
    }

    /** Aggregates the list of services and builds a list of UI prefs to show. */
@@ -317,7 +386,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
            }

            // Build the pref and add it to the output & group.
            SwitchPreference pref = addProviderPreference(context, title, icon, packageName, firstInfo.getSettingsSubtitle());
            SwitchPreference pref =
                    addProviderPreference(
                            context, title, icon, packageName, firstInfo.getSettingsSubtitle());
            output.put(packageName, pref);
            group.addPreference(pref);
        }
+46 −4
Original line number Diff line number Diff line
@@ -33,9 +33,11 @@ import android.content.pm.ServiceInfo;
import android.credentials.CredentialProviderInfo;
import android.net.Uri;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;

import androidx.lifecycle.Lifecycle;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -121,11 +123,42 @@ public class CredentialManagerPreferenceControllerTest {
    }

    @Test
    public void displayPreference_noServices_noPreferencesAdded() {
    public void displayPreference_noServices_noPreferencesAdded_useAutofillUri() {
        Settings.Secure.putStringForUser(
                mContext.getContentResolver(),
                Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
                "test",
                UserHandle.myUserId());

        CredentialManagerPreferenceController controller =
                createControllerWithServices(Collections.emptyList());
        controller.displayPreference(mScreen);
        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);

        Preference pref = mCredentialsPreferenceCategory.getPreference(0);
        assertThat(pref.getTitle()).isEqualTo("Add service");

        assertThat(controller.getAddServiceUri(mContext)).isEqualTo("test");
    }

    @Test
    public void displayPreference_noServices_noPreferencesAdded_useCredManUri() {
        Settings.Secure.putStringForUser(
                mContext.getContentResolver(),
                Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
                "test",
                UserHandle.myUserId());

        CredentialManagerPreferenceController controller =
                createControllerWithServicesAndAddServiceOverride(
                        Collections.emptyList(), "credman");
        controller.displayPreference(mScreen);
        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);

        Preference pref = mCredentialsPreferenceCategory.getPreference(0);
        assertThat(pref.getTitle()).isEqualTo("Add service");

        assertThat(controller.getAddServiceUri(mContext)).isEqualTo("credman");
    }

    @Test
@@ -135,6 +168,9 @@ public class CredentialManagerPreferenceControllerTest {
        controller.displayPreference(mScreen);
        assertThat(controller.isConnected()).isFalse();
        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);

        Preference pref = mCredentialsPreferenceCategory.getPreference(0);
        assertThat(pref.getTitle()).isNotEqualTo("Add account");
    }

    @Test
@@ -317,7 +353,8 @@ public class CredentialManagerPreferenceControllerTest {

        Map<String, SwitchPreference> prefs =
                controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory);
        assertThat(prefs.keySet()).containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C);
        assertThat(prefs.keySet())
                .containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C);
        assertThat(prefs.size()).isEqualTo(3);
        assertThat(prefs.containsKey(TEST_PACKAGE_NAME_A)).isTrue();
        assertThat(prefs.get(TEST_PACKAGE_NAME_A).getTitle()).isEqualTo(TEST_TITLE_APP_A);
@@ -439,10 +476,15 @@ public class CredentialManagerPreferenceControllerTest {

    private CredentialManagerPreferenceController createControllerWithServices(
            List<CredentialProviderInfo> availableServices) {
        return createControllerWithServicesAndAddServiceOverride(availableServices, null);
    }

    private CredentialManagerPreferenceController createControllerWithServicesAndAddServiceOverride(
            List<CredentialProviderInfo> availableServices, String addServiceOverride) {
        CredentialManagerPreferenceController controller =
                new CredentialManagerPreferenceController(
                        mContext, mCredentialsPreferenceCategory.getKey());
        controller.setAvailableServices(() -> mock(Lifecycle.class), availableServices);
        controller.setAvailableServices(() -> mock(Lifecycle.class), availableServices, addServiceOverride);
        controller.setDelegate(mDelegate);
        return controller;
    }