Merge "Add service link when no providers are present"
This commit is contained in:
@@ -29,13 +29,16 @@ import android.content.Intent;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.credentials.CredentialManager;
|
import android.credentials.CredentialManager;
|
||||||
import android.credentials.CredentialProviderInfo;
|
import android.credentials.CredentialProviderInfo;
|
||||||
import android.credentials.SetEnabledProvidersException;
|
import android.credentials.SetEnabledProvidersException;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.OutcomeReceiver;
|
import android.os.OutcomeReceiver;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.IconDrawableFactory;
|
import android.util.IconDrawableFactory;
|
||||||
@@ -48,6 +51,7 @@ import androidx.fragment.app.FragmentManager;
|
|||||||
import androidx.lifecycle.LifecycleObserver;
|
import androidx.lifecycle.LifecycleObserver;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.OnLifecycleEvent;
|
import androidx.lifecycle.OnLifecycleEvent;
|
||||||
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceGroup;
|
import androidx.preference.PreferenceGroup;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.preference.SwitchPreference;
|
import androidx.preference.SwitchPreference;
|
||||||
@@ -69,6 +73,7 @@ import java.util.concurrent.Executor;
|
|||||||
/** Queries available credential manager providers and adds preferences for them. */
|
/** Queries available credential manager providers and adds preferences for them. */
|
||||||
public class CredentialManagerPreferenceController extends BasePreferenceController
|
public class CredentialManagerPreferenceController extends BasePreferenceController
|
||||||
implements LifecycleObserver {
|
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 TAG = "CredentialManagerPreferenceController";
|
||||||
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
|
||||||
private static final int MAX_SELECTABLE_PROVIDERS = 5;
|
private static final int MAX_SELECTABLE_PROVIDERS = 5;
|
||||||
@@ -84,6 +89,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
|
|
||||||
private @Nullable FragmentManager mFragmentManager = null;
|
private @Nullable FragmentManager mFragmentManager = null;
|
||||||
private @Nullable Delegate mDelegate = null;
|
private @Nullable Delegate mDelegate = null;
|
||||||
|
private @Nullable String mFlagOverrideForTest = null;
|
||||||
|
|
||||||
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
|
public CredentialManagerPreferenceController(Context context, String preferenceKey) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
@@ -236,12 +242,16 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
setAvailableServices(
|
setAvailableServices(
|
||||||
lifecycleOwner,
|
lifecycleOwner,
|
||||||
mCredentialManager.getCredentialProviderServices(
|
mCredentialManager.getCredentialProviderServices(
|
||||||
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
|
getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setAvailableServices(
|
void setAvailableServices(
|
||||||
LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) {
|
LifecycleOwner lifecycleOwner,
|
||||||
|
List<CredentialProviderInfo> availableServices,
|
||||||
|
String flagOverrideForTest) {
|
||||||
|
mFlagOverrideForTest = flagOverrideForTest;
|
||||||
mServices.clear();
|
mServices.clear();
|
||||||
mServices.addAll(availableServices);
|
mServices.addAll(availableServices);
|
||||||
|
|
||||||
@@ -275,6 +285,65 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
|
|||||||
PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
PreferenceGroup group = screen.findPreference(getPreferenceKey());
|
||||||
Context context = screen.getContext();
|
Context context = screen.getContext();
|
||||||
mPrefs.putAll(buildPreferenceList(context, group));
|
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. */
|
/** Aggregates the list of services and builds a list of UI prefs to show. */
|
||||||
|
@@ -33,9 +33,11 @@ import android.content.pm.ServiceInfo;
|
|||||||
import android.credentials.CredentialProviderInfo;
|
import android.credentials.CredentialProviderInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
@@ -120,11 +122,42 @@ public class CredentialManagerPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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 =
|
CredentialManagerPreferenceController controller =
|
||||||
createControllerWithServices(Collections.emptyList());
|
createControllerWithServices(Collections.emptyList());
|
||||||
controller.displayPreference(mScreen);
|
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
|
@Test
|
||||||
@@ -134,6 +167,9 @@ public class CredentialManagerPreferenceControllerTest {
|
|||||||
controller.displayPreference(mScreen);
|
controller.displayPreference(mScreen);
|
||||||
assertThat(controller.isConnected()).isFalse();
|
assertThat(controller.isConnected()).isFalse();
|
||||||
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
|
||||||
|
|
||||||
|
Preference pref = mCredentialsPreferenceCategory.getPreference(0);
|
||||||
|
assertThat(pref.getTitle()).isNotEqualTo("Add account");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -400,10 +436,15 @@ public class CredentialManagerPreferenceControllerTest {
|
|||||||
|
|
||||||
private CredentialManagerPreferenceController createControllerWithServices(
|
private CredentialManagerPreferenceController createControllerWithServices(
|
||||||
List<CredentialProviderInfo> availableServices) {
|
List<CredentialProviderInfo> availableServices) {
|
||||||
|
return createControllerWithServicesAndAddServiceOverride(availableServices, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CredentialManagerPreferenceController createControllerWithServicesAndAddServiceOverride(
|
||||||
|
List<CredentialProviderInfo> availableServices, String addServiceOverride) {
|
||||||
CredentialManagerPreferenceController controller =
|
CredentialManagerPreferenceController controller =
|
||||||
new CredentialManagerPreferenceController(
|
new CredentialManagerPreferenceController(
|
||||||
mContext, mCredentialsPreferenceCategory.getKey());
|
mContext, mCredentialsPreferenceCategory.getKey());
|
||||||
controller.setAvailableServices(() -> mock(Lifecycle.class), availableServices);
|
controller.setAvailableServices(() -> mock(Lifecycle.class), availableServices, addServiceOverride);
|
||||||
controller.setDelegate(mDelegate);
|
controller.setDelegate(mDelegate);
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user