Merge "Support setting primary provider" into udc-dev am: d07c89db48 am: 23c6f5e306

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22963326

Change-Id: I0a255b6bf837c4fd0f144e2205d7bc59395c8f4e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Guangjie (Jerry) Shi
2023-05-04 18:39:36 +00:00
committed by Automerger Merge Worker
7 changed files with 365 additions and 238 deletions

View File

@@ -355,7 +355,11 @@ public final class CredentialManager {
* Sets a list of all user configurable credential providers registered on the system. This API * Sets a list of all user configurable credential providers registered on the system. This API
* is intended for settings apps. * is intended for settings apps.
* *
* @param providers the list of enabled providers * @param primaryProviders the primary providers that user selected for saving credentials. In
* the most case, there should be only one primary provider, However,
* if there are more than one CredentialProviderService in the same APK,
* they should be passed in altogether.
* @param providers the list of enabled providers.
* @param userId the user ID to configure credential manager for * @param userId the user ID to configure credential manager for
* @param executor the callback will take place on this {@link Executor} * @param executor the callback will take place on this {@link Executor}
* @param callback the callback invoked when the request succeeds or fails * @param callback the callback invoked when the request succeeds or fails
@@ -363,6 +367,7 @@ public final class CredentialManager {
*/ */
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public void setEnabledProviders( public void setEnabledProviders(
@NonNull List<String> primaryProviders,
@NonNull List<String> providers, @NonNull List<String> providers,
int userId, int userId,
@CallbackExecutor @NonNull Executor executor, @CallbackExecutor @NonNull Executor executor,
@@ -370,9 +375,11 @@ public final class CredentialManager {
requireNonNull(executor, "executor must not be null"); requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null"); requireNonNull(callback, "callback must not be null");
requireNonNull(providers, "providers must not be null"); requireNonNull(providers, "providers must not be null");
requireNonNull(primaryProviders, "primaryProviders must not be null");
try { try {
mService.setEnabledProviders( mService.setEnabledProviders(
primaryProviders,
providers, userId, new SetEnabledProvidersTransport(executor, callback)); providers, userId, new SetEnabledProvidersTransport(executor, callback));
} catch (RemoteException e) { } catch (RemoteException e) {
e.rethrowFromSystemServer(); e.rethrowFromSystemServer();

View File

@@ -46,6 +46,7 @@ public final class CredentialProviderInfo implements Parcelable {
@Nullable private CharSequence mSettingsSubtitle = null; @Nullable private CharSequence mSettingsSubtitle = null;
private final boolean mIsSystemProvider; private final boolean mIsSystemProvider;
private final boolean mIsEnabled; private final boolean mIsEnabled;
private final boolean mIsPrimary;
/** /**
* Constructs an information instance of the credential provider. * Constructs an information instance of the credential provider.
@@ -58,6 +59,7 @@ public final class CredentialProviderInfo implements Parcelable {
mIsSystemProvider = builder.mIsSystemProvider; mIsSystemProvider = builder.mIsSystemProvider;
mSettingsSubtitle = builder.mSettingsSubtitle; mSettingsSubtitle = builder.mSettingsSubtitle;
mIsEnabled = builder.mIsEnabled; mIsEnabled = builder.mIsEnabled;
mIsPrimary = builder.mIsPrimary;
mOverrideLabel = builder.mOverrideLabel; mOverrideLabel = builder.mOverrideLabel;
} }
@@ -108,6 +110,15 @@ public final class CredentialProviderInfo implements Parcelable {
return mIsEnabled; return mIsEnabled;
} }
/**
* Returns whether the provider is set as primary by the user.
*
* @hide
*/
public boolean isPrimary() {
return mIsPrimary;
}
/** Returns the settings subtitle. */ /** Returns the settings subtitle. */
@Nullable @Nullable
public CharSequence getSettingsSubtitle() { public CharSequence getSettingsSubtitle() {
@@ -125,6 +136,7 @@ public final class CredentialProviderInfo implements Parcelable {
dest.writeTypedObject(mServiceInfo, flags); dest.writeTypedObject(mServiceInfo, flags);
dest.writeBoolean(mIsSystemProvider); dest.writeBoolean(mIsSystemProvider);
dest.writeBoolean(mIsEnabled); dest.writeBoolean(mIsEnabled);
dest.writeBoolean(mIsPrimary);
TextUtils.writeToParcel(mOverrideLabel, dest, flags); TextUtils.writeToParcel(mOverrideLabel, dest, flags);
TextUtils.writeToParcel(mSettingsSubtitle, dest, flags); TextUtils.writeToParcel(mSettingsSubtitle, dest, flags);
@@ -149,6 +161,9 @@ public final class CredentialProviderInfo implements Parcelable {
+ "isEnabled=" + "isEnabled="
+ mIsEnabled + mIsEnabled
+ ", " + ", "
+ "isPrimary="
+ mIsPrimary
+ ", "
+ "overrideLabel=" + "overrideLabel="
+ mOverrideLabel + mOverrideLabel
+ ", " + ", "
@@ -164,6 +179,7 @@ public final class CredentialProviderInfo implements Parcelable {
mServiceInfo = in.readTypedObject(ServiceInfo.CREATOR); mServiceInfo = in.readTypedObject(ServiceInfo.CREATOR);
mIsSystemProvider = in.readBoolean(); mIsSystemProvider = in.readBoolean();
mIsEnabled = in.readBoolean(); mIsEnabled = in.readBoolean();
mIsPrimary = in.readBoolean();
mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mOverrideLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mSettingsSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mSettingsSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -193,6 +209,7 @@ public final class CredentialProviderInfo implements Parcelable {
private boolean mIsSystemProvider = false; private boolean mIsSystemProvider = false;
@Nullable private CharSequence mSettingsSubtitle = null; @Nullable private CharSequence mSettingsSubtitle = null;
private boolean mIsEnabled = false; private boolean mIsEnabled = false;
private boolean mIsPrimary = false;
@Nullable private CharSequence mOverrideLabel = null; @Nullable private CharSequence mOverrideLabel = null;
/** /**
@@ -248,6 +265,20 @@ public final class CredentialProviderInfo implements Parcelable {
return this; return this;
} }
/**
* Sets whether it is set as primary by the user.
*
* <p>Primary provider will be used for saving credentials by default. In most cases, there
* should only one primary provider exist. However, if there are multiple credential
* providers exist in the same package, all of them will be marked as primary.
*
* @hide
*/
public @NonNull Builder setPrimary(boolean isPrimary) {
mIsPrimary = isPrimary;
return this;
}
/** Builds a new {@link CredentialProviderInfo} instance. */ /** Builds a new {@link CredentialProviderInfo} instance. */
public @NonNull CredentialProviderInfo build() { public @NonNull CredentialProviderInfo build() {
return new CredentialProviderInfo(this); return new CredentialProviderInfo(this);

View File

@@ -47,7 +47,7 @@ interface ICredentialManager {
@nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage); @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
void setEnabledProviders(in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback); void setEnabledProviders(in List<String> primaryProviders, in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback);
void registerCredentialDescription(in RegisterCredentialDescriptionRequest request, String callingPackage); void registerCredentialDescription(in RegisterCredentialDescriptionRequest request, String callingPackage);

View File

@@ -80,8 +80,7 @@ public final class CredentialProviderInfoFactory {
* @param userId the android userId for which the current process is running * @param userId the android userId for which the current process is running
* @param isSystemProvider whether this provider is a system provider * @param isSystemProvider whether this provider is a system provider
* @throws PackageManager.NameNotFoundException If provider service is not found * @throws PackageManager.NameNotFoundException If provider service is not found
* @throws SecurityException If provider does not require the relevant * @throws SecurityException If provider does not require the relevant permission
* permission
*/ */
public static CredentialProviderInfo create( public static CredentialProviderInfo create(
@NonNull Context context, @NonNull Context context,
@@ -94,20 +93,19 @@ public final class CredentialProviderInfoFactory {
getServiceInfoOrThrow(serviceComponent, userId), getServiceInfoOrThrow(serviceComponent, userId),
isSystemProvider, isSystemProvider,
/* disableSystemAppVerificationForTests= */ false, /* disableSystemAppVerificationForTests= */ false,
/* isEnabled= */ false); /* isEnabled= */ false,
/* isPrimary= */ false);
} }
/** /**
* Constructs an information instance of the credential provider. * Constructs an information instance of the credential provider.
* *
* @param context the context object * @param context the context object
* @param serviceInfo the service info for the provider app. This must * @param serviceInfo the service info for the provider app. This must be retrieved from the
* be retrieved from the
* {@code PackageManager} * {@code PackageManager}
* @param isSystemProvider whether the provider app is a system provider * @param isSystemProvider whether the provider app is a system provider
* @param disableSystemAppVerificationForTests whether to disable system app permission * @param disableSystemAppVerificationForTests whether to disable system app permission
* verification so that tests can install system * verification so that tests can install system providers
* providers
* @param isEnabled whether the user enabled this provider * @param isEnabled whether the user enabled this provider
* @throws SecurityException If provider does not require the relevant permission * @throws SecurityException If provider does not require the relevant permission
*/ */
@@ -116,7 +114,8 @@ public final class CredentialProviderInfoFactory {
@NonNull ServiceInfo serviceInfo, @NonNull ServiceInfo serviceInfo,
boolean isSystemProvider, boolean isSystemProvider,
boolean disableSystemAppVerificationForTests, boolean disableSystemAppVerificationForTests,
boolean isEnabled) boolean isEnabled,
boolean isPrimary)
throws SecurityException { throws SecurityException {
verifyProviderPermission(serviceInfo); verifyProviderPermission(serviceInfo);
if (isSystemProvider) { if (isSystemProvider) {
@@ -131,6 +130,7 @@ public final class CredentialProviderInfoFactory {
return populateMetadata(context, serviceInfo) return populateMetadata(context, serviceInfo)
.setSystemProvider(isSystemProvider) .setSystemProvider(isSystemProvider)
.setEnabled(isEnabled) .setEnabled(isEnabled)
.setPrimary(isPrimary)
.build(); .build();
} }
@@ -168,7 +168,9 @@ public final class CredentialProviderInfoFactory {
Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission"); Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission");
return false; return false;
} }
return PermissionUtils.hasPermission(context, serviceInfo.packageName, return PermissionUtils.hasPermission(
context,
serviceInfo.packageName,
Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE); Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE);
} }
@@ -181,8 +183,11 @@ public final class CredentialProviderInfoFactory {
if (disableSystemAppVerificationForTests) { if (disableSystemAppVerificationForTests) {
Bundle metadata = serviceInfo.metaData; Bundle metadata = serviceInfo.metaData;
if (metadata == null) { if (metadata == null) {
Slog.w(TAG, "metadata is null while reading " Slog.w(
+ "TEST_SYSTEM_PROVIDER_META_DATA_KEY: " + serviceInfo); TAG,
"metadata is null while reading "
+ "TEST_SYSTEM_PROVIDER_META_DATA_KEY: "
+ serviceInfo);
return false; return false;
} }
return metadata.getBoolean( return metadata.getBoolean(
@@ -215,7 +220,9 @@ public final class CredentialProviderInfoFactory {
// 3. Stop if we are missing data. // 3. Stop if we are missing data.
if (resources == null) { if (resources == null) {
Slog.w(TAG, "Resources are null for the serviceInfo being processed: " Slog.w(
TAG,
"Resources are null for the serviceInfo being processed: "
+ serviceInfo.getComponentName()); + serviceInfo.getComponentName());
return builder; return builder;
} }
@@ -408,7 +415,7 @@ public final class CredentialProviderInfoFactory {
si, si,
/* isSystemProvider= */ true, /* isSystemProvider= */ true,
disableSystemAppVerificationForTests, disableSystemAppVerificationForTests,
enabledServices.contains(si.getComponentName())); enabledServices.contains(si.getComponentName()), false);
if (cpi.isSystemProvider()) { if (cpi.isSystemProvider()) {
providerInfos.add(cpi); providerInfos.add(cpi);
} else { } else {
@@ -446,7 +453,8 @@ public final class CredentialProviderInfoFactory {
@NonNull Context context, @NonNull Context context,
int userId, int userId,
int providerFilter, int providerFilter,
Set<ComponentName> enabledServices) { Set<ComponentName> enabledServices,
Set<String> primaryServices) {
requireNonNull(context, "context must not be null"); requireNonNull(context, "context must not be null");
// Get the device policy. // Get the device policy.
@@ -459,7 +467,11 @@ public final class CredentialProviderInfoFactory {
context, pp, disableSystemAppVerificationForTests, providerFilter); context, pp, disableSystemAppVerificationForTests, providerFilter);
generator.addUserProviders( generator.addUserProviders(
getUserProviders( getUserProviders(
context, userId, disableSystemAppVerificationForTests, enabledServices)); context,
userId,
disableSystemAppVerificationForTests,
enabledServices,
primaryServices));
generator.addSystemProviders( generator.addSystemProviders(
getAvailableSystemServices( getAvailableSystemServices(
context, userId, disableSystemAppVerificationForTests, enabledServices)); context, userId, disableSystemAppVerificationForTests, enabledServices));
@@ -475,7 +487,8 @@ public final class CredentialProviderInfoFactory {
@NonNull Context context, @NonNull Context context,
int userId, int userId,
int providerFilter, int providerFilter,
Set<ComponentName> enabledServices) { Set<ComponentName> enabledServices,
Set<String> primaryServices) {
requireNonNull(context, "context must not be null"); requireNonNull(context, "context must not be null");
// Get the device policy. // Get the device policy.
@@ -488,7 +501,11 @@ public final class CredentialProviderInfoFactory {
context, pp, disableSystemAppVerificationForTests, providerFilter); context, pp, disableSystemAppVerificationForTests, providerFilter);
generator.addUserProviders( generator.addUserProviders(
getUserProviders( getUserProviders(
context, userId, disableSystemAppVerificationForTests, enabledServices)); context,
userId,
disableSystemAppVerificationForTests,
enabledServices,
primaryServices));
generator.addSystemProviders( generator.addSystemProviders(
getAvailableSystemServices( getAvailableSystemServices(
context, userId, disableSystemAppVerificationForTests, enabledServices)); context, userId, disableSystemAppVerificationForTests, enabledServices));
@@ -581,7 +598,8 @@ public final class CredentialProviderInfoFactory {
@NonNull Context context, @NonNull Context context,
@UserIdInt int userId, @UserIdInt int userId,
boolean disableSystemAppVerificationForTests, boolean disableSystemAppVerificationForTests,
Set<ComponentName> enabledServices) { Set<ComponentName> enabledServices,
Set<String> primaryServices) {
final List<CredentialProviderInfo> services = new ArrayList<>(); final List<CredentialProviderInfo> services = new ArrayList<>();
final List<ResolveInfo> resolveInfos = final List<ResolveInfo> resolveInfos =
context.getPackageManager() context.getPackageManager()
@@ -603,7 +621,9 @@ public final class CredentialProviderInfoFactory {
serviceInfo, serviceInfo,
/* isSystemProvider= */ false, /* isSystemProvider= */ false,
disableSystemAppVerificationForTests, disableSystemAppVerificationForTests,
enabledServices.contains(serviceInfo.getComponentName())); enabledServices.contains(serviceInfo.getComponentName()),
primaryServices.contains(
serviceInfo.getComponentName().flattenToString()));
if (!cpi.isSystemProvider()) { if (!cpi.isSystemProvider()) {
services.add(cpi); services.add(cpi);
} }

View File

@@ -56,11 +56,9 @@ import java.util.concurrent.Executor;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class CredentialManagerTest { public class CredentialManagerTest {
@Mock @Mock private ICredentialManager mMockCredentialManagerService;
private ICredentialManager mMockCredentialManagerService;
@Mock @Mock private Activity mMockActivity;
private Activity mMockActivity;
private static final int TEST_USER_ID = 1; private static final int TEST_USER_ID = 1;
private static final CredentialProviderInfo TEST_CREDENTIAL_PROVIDER_INFO = private static final CredentialProviderInfo TEST_CREDENTIAL_PROVIDER_INFO =
@@ -112,27 +110,43 @@ public class CredentialManagerTest {
@Before @Before
public void setup() { public void setup() {
mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption( mGetRequest =
new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY, new GetCredentialRequest.Builder(Bundle.EMPTY)
Bundle.EMPTY, false)).build(); .addCredentialOption(
mCreateRequest = new CreateCredentialRequest.Builder( new CredentialOption(
Credential.TYPE_PASSWORD_CREDENTIAL, Credential.TYPE_PASSWORD_CREDENTIAL,
Bundle.EMPTY, Bundle.EMPTY) Bundle.EMPTY,
Bundle.EMPTY,
false))
.build();
mCreateRequest =
new CreateCredentialRequest.Builder(
Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY, Bundle.EMPTY)
.setIsSystemProviderRequired(false) .setIsSystemProviderRequired(false)
.setAlwaysSendAppInfoToProvider(false) .setAlwaysSendAppInfoToProvider(false)
.build(); .build();
mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY); mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY);
final Slice slice = new Slice.Builder(Uri.parse("foo://bar"), null).addText("some text", final Slice slice =
null, List.of(Slice.HINT_TITLE)).build(); new Slice.Builder(Uri.parse("foo://bar"), null)
mRegisterRequest = new RegisterCredentialDescriptionRequest( .addText("some text", null, List.of(Slice.HINT_TITLE))
new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, .build();
mRegisterRequest =
new RegisterCredentialDescriptionRequest(
new CredentialDescription(
Credential.TYPE_PASSWORD_CREDENTIAL,
new HashSet<>(List.of("{ \"foo\": \"bar\" }")), new HashSet<>(List.of("{ \"foo\": \"bar\" }")),
List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); List.of(
mUnregisterRequest = new UnregisterCredentialDescriptionRequest( new CredentialEntry(
new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
mUnregisterRequest =
new UnregisterCredentialDescriptionRequest(
new CredentialDescription(
Credential.TYPE_PASSWORD_CREDENTIAL,
new HashSet<>(List.of("{ \"foo\": \"bar\" }")), new HashSet<>(List.of("{ \"foo\": \"bar\" }")),
List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); List.of(
new CredentialEntry(
Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
final Context context = InstrumentationRegistry.getInstrumentation().getContext(); final Context context = InstrumentationRegistry.getInstrumentation().getContext();
mCredentialManager = new CredentialManager(context, mMockCredentialManagerService); mCredentialManager = new CredentialManager(context, mMockCredentialManagerService);
@@ -143,56 +157,63 @@ public class CredentialManagerTest {
@Test @Test
public void testGetCredential_nullRequest() { public void testGetCredential_nullRequest() {
GetCredentialRequest nullRequest = null; GetCredentialRequest nullRequest = null;
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.getCredential(mMockActivity, nullRequest, null, mExecutor, NullPointerException.class,
result -> { () ->
})); mCredentialManager.getCredential(
mMockActivity, nullRequest, null, mExecutor, result -> {}));
} }
@Test @Test
public void testGetCredential_nullActivity() { public void testGetCredential_nullActivity() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.getCredential(null, mGetRequest, null, mExecutor, NullPointerException.class,
result -> { () ->
})); mCredentialManager.getCredential(
null, mGetRequest, null, mExecutor, result -> {}));
} }
@Test @Test
public void testGetCredential_nullExecutor() { public void testGetCredential_nullExecutor() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, NullPointerException.class,
result -> { () ->
})); mCredentialManager.getCredential(
mMockActivity, mGetRequest, null, null, result -> {}));
} }
@Test @Test
public void testGetCredential_nullCallback() { public void testGetCredential_nullCallback() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, NullPointerException.class,
null)); () ->
mCredentialManager.getCredential(
mMockActivity, mGetRequest, null, null, null));
} }
@Test @Test
public void testGetCredential_noCredential() throws RemoteException { public void testGetCredential_noCredential() throws RemoteException {
ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<IGetCredentialCallback> callbackCaptor =
IGetCredentialCallback.class); ArgumentCaptor.forClass(IGetCredentialCallback.class);
ArgumentCaptor<GetCredentialException> errorCaptor = ArgumentCaptor.forClass( ArgumentCaptor<GetCredentialException> errorCaptor =
GetCredentialException.class); ArgumentCaptor.forClass(GetCredentialException.class);
OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock( OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.executeGetCredential(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
.thenReturn(mock(ICancellationSignal.class));
mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback);
verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
callbackCaptor.getValue().onError(GetCredentialException.TYPE_NO_CREDENTIAL, callbackCaptor
"no credential found"); .getValue()
.onError(GetCredentialException.TYPE_NO_CREDENTIAL, "no credential found");
verify(callback).onError(errorCaptor.capture()); verify(callback).onError(errorCaptor.capture());
assertThat(errorCaptor.getValue().getType()).isEqualTo( assertThat(errorCaptor.getValue().getType())
GetCredentialException.TYPE_NO_CREDENTIAL); .isEqualTo(GetCredentialException.TYPE_NO_CREDENTIAL);
} }
@Test @Test
@@ -200,9 +221,8 @@ public class CredentialManagerTest {
final CancellationSignal cancellation = new CancellationSignal(); final CancellationSignal cancellation = new CancellationSignal();
cancellation.cancel(); cancellation.cancel();
mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, mCredentialManager.getCredential(
result -> { mMockActivity, mGetRequest, cancellation, mExecutor, result -> {});
});
verify(mMockCredentialManagerService, never()).executeGetCredential(any(), any(), any()); verify(mMockCredentialManagerService, never()).executeGetCredential(any(), any(), any());
} }
@@ -212,14 +232,14 @@ public class CredentialManagerTest {
final ICancellationSignal serviceSignal = mock(ICancellationSignal.class); final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
final CancellationSignal cancellation = new CancellationSignal(); final CancellationSignal cancellation = new CancellationSignal();
OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock( OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeGetCredential(any(), any(), any())).thenReturn( when(mMockCredentialManagerService.executeGetCredential(any(), any(), any()))
serviceSignal); .thenReturn(serviceSignal);
mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, mCredentialManager.getCredential(
callback); mMockActivity, mGetRequest, cancellation, mExecutor, callback);
verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
@@ -231,16 +251,17 @@ public class CredentialManagerTest {
public void testGetCredential_success() throws RemoteException { public void testGetCredential_success() throws RemoteException {
final Credential cred = new Credential(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY); final Credential cred = new Credential(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY);
ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<IGetCredentialCallback> callbackCaptor =
IGetCredentialCallback.class); ArgumentCaptor.forClass(IGetCredentialCallback.class);
ArgumentCaptor<GetCredentialResponse> responseCaptor = ArgumentCaptor.forClass( ArgumentCaptor<GetCredentialResponse> responseCaptor =
GetCredentialResponse.class); ArgumentCaptor.forClass(GetCredentialResponse.class);
OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock( OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.executeGetCredential(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
.thenReturn(mock(ICancellationSignal.class));
mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback);
verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
@@ -252,33 +273,38 @@ public class CredentialManagerTest {
@Test @Test
public void testCreateCredential_nullRequest() { public void testCreateCredential_nullRequest() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.createCredential(mMockActivity, null, null, mExecutor, NullPointerException.class,
result -> { () ->
})); mCredentialManager.createCredential(
mMockActivity, null, null, mExecutor, result -> {}));
} }
@Test @Test
public void testCreateCredential_nullActivity() { public void testCreateCredential_nullActivity() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.createCredential(null, mCreateRequest, null, mExecutor, NullPointerException.class,
result -> { () ->
})); mCredentialManager.createCredential(
null, mCreateRequest, null, mExecutor, result -> {}));
} }
@Test @Test
public void testCreateCredential_nullExecutor() { public void testCreateCredential_nullExecutor() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, null, NullPointerException.class,
result -> { () ->
})); mCredentialManager.createCredential(
mMockActivity, mCreateRequest, null, null, result -> {}));
} }
@Test @Test
public void testCreateCredential_nullCallback() { public void testCreateCredential_nullCallback() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, NullPointerException.class,
mExecutor, null)); () ->
mCredentialManager.createCredential(
mMockActivity, mCreateRequest, null, mExecutor, null));
} }
@Test @Test
@@ -286,9 +312,8 @@ public class CredentialManagerTest {
final CancellationSignal cancellation = new CancellationSignal(); final CancellationSignal cancellation = new CancellationSignal();
cancellation.cancel(); cancellation.cancel();
mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, mCredentialManager.createCredential(
result -> { mMockActivity, mCreateRequest, cancellation, mExecutor, result -> {});
});
verify(mMockCredentialManagerService, never()).executeCreateCredential(any(), any(), any()); verify(mMockCredentialManagerService, never()).executeCreateCredential(any(), any(), any());
} }
@@ -298,17 +323,17 @@ public class CredentialManagerTest {
final ICancellationSignal serviceSignal = mock(ICancellationSignal.class); final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
final CancellationSignal cancellation = new CancellationSignal(); final CancellationSignal cancellation = new CancellationSignal();
OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock( OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any())).thenReturn( when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any()))
serviceSignal); .thenReturn(serviceSignal);
mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, mCredentialManager.createCredential(
callback); mMockActivity, mCreateRequest, cancellation, mExecutor, callback);
verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), verify(mMockCredentialManagerService)
eq(mPackageName)); .executeCreateCredential(any(), any(), eq(mPackageName));
cancellation.cancel(); cancellation.cancel();
verify(serviceSignal).cancel(); verify(serviceSignal).cancel();
@@ -316,26 +341,27 @@ public class CredentialManagerTest {
@Test @Test
public void testCreateCredential_failed() throws RemoteException { public void testCreateCredential_failed() throws RemoteException {
ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<ICreateCredentialCallback> callbackCaptor =
ICreateCredentialCallback.class); ArgumentCaptor.forClass(ICreateCredentialCallback.class);
ArgumentCaptor<CreateCredentialException> errorCaptor = ArgumentCaptor.forClass( ArgumentCaptor<CreateCredentialException> errorCaptor =
CreateCredentialException.class); ArgumentCaptor.forClass(CreateCredentialException.class);
OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock( OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.executeCreateCredential(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, .thenReturn(mock(ICancellationSignal.class));
callback); mCredentialManager.createCredential(
verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), mMockActivity, mCreateRequest, null, mExecutor, callback);
eq(mPackageName)); verify(mMockCredentialManagerService)
.executeCreateCredential(any(), any(), eq(mPackageName));
callbackCaptor.getValue().onError(CreateCredentialException.TYPE_UNKNOWN, "unknown error"); callbackCaptor.getValue().onError(CreateCredentialException.TYPE_UNKNOWN, "unknown error");
verify(callback).onError(errorCaptor.capture()); verify(callback).onError(errorCaptor.capture());
assertThat(errorCaptor.getValue().getType()).isEqualTo( assertThat(errorCaptor.getValue().getType())
CreateCredentialException.TYPE_UNKNOWN); .isEqualTo(CreateCredentialException.TYPE_UNKNOWN);
} }
@Test @Test
@@ -343,20 +369,21 @@ public class CredentialManagerTest {
final Bundle responseData = new Bundle(); final Bundle responseData = new Bundle();
responseData.putString("foo", "bar"); responseData.putString("foo", "bar");
ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<ICreateCredentialCallback> callbackCaptor =
ICreateCredentialCallback.class); ArgumentCaptor.forClass(ICreateCredentialCallback.class);
ArgumentCaptor<CreateCredentialResponse> responseCaptor = ArgumentCaptor.forClass( ArgumentCaptor<CreateCredentialResponse> responseCaptor =
CreateCredentialResponse.class); ArgumentCaptor.forClass(CreateCredentialResponse.class);
OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock( OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
OutcomeReceiver.class); mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.executeCreateCredential(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, .thenReturn(mock(ICancellationSignal.class));
callback); mCredentialManager.createCredential(
verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), mMockActivity, mCreateRequest, null, mExecutor, callback);
eq(mPackageName)); verify(mMockCredentialManagerService)
.executeCreateCredential(any(), any(), eq(mPackageName));
callbackCaptor.getValue().onResponse(new CreateCredentialResponse(responseData)); callbackCaptor.getValue().onResponse(new CreateCredentialResponse(responseData));
verify(callback).onResult(responseCaptor.capture()); verify(callback).onResult(responseCaptor.capture());
@@ -366,23 +393,27 @@ public class CredentialManagerTest {
@Test @Test
public void testClearCredentialState_nullRequest() { public void testClearCredentialState_nullRequest() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.clearCredentialState(null, null, mExecutor, result -> { NullPointerException.class,
})); () -> mCredentialManager.clearCredentialState(null, null, mExecutor, result -> {}));
} }
@Test @Test
public void testClearCredentialState_nullExecutor() { public void testClearCredentialState_nullExecutor() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.clearCredentialState(mClearRequest, null, null, result -> { NullPointerException.class,
})); () ->
mCredentialManager.clearCredentialState(
mClearRequest, null, null, result -> {}));
} }
@Test @Test
public void testClearCredentialState_nullCallback() { public void testClearCredentialState_nullCallback() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, NullPointerException.class,
null)); () ->
mCredentialManager.clearCredentialState(
mClearRequest, null, mExecutor, null));
} }
@Test @Test
@@ -390,8 +421,8 @@ public class CredentialManagerTest {
final CancellationSignal cancellation = new CancellationSignal(); final CancellationSignal cancellation = new CancellationSignal();
cancellation.cancel(); cancellation.cancel();
mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, result -> { mCredentialManager.clearCredentialState(
}); mClearRequest, cancellation, mExecutor, result -> {});
verify(mMockCredentialManagerService, never()).clearCredentialState(any(), any(), any()); verify(mMockCredentialManagerService, never()).clearCredentialState(any(), any(), any());
} }
@@ -403,8 +434,8 @@ public class CredentialManagerTest {
OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class); OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.clearCredentialState(any(), any(), any())).thenReturn( when(mMockCredentialManagerService.clearCredentialState(any(), any(), any()))
serviceSignal); .thenReturn(serviceSignal);
mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, callback); mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, callback);
@@ -416,35 +447,38 @@ public class CredentialManagerTest {
@Test @Test
public void testClearCredential_failed() throws RemoteException { public void testClearCredential_failed() throws RemoteException {
ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor =
IClearCredentialStateCallback.class); ArgumentCaptor.forClass(IClearCredentialStateCallback.class);
ArgumentCaptor<ClearCredentialStateException> errorCaptor = ArgumentCaptor.forClass( ArgumentCaptor<ClearCredentialStateException> errorCaptor =
ClearCredentialStateException.class); ArgumentCaptor.forClass(ClearCredentialStateException.class);
OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class); OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.clearCredentialState(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
.thenReturn(mock(ICancellationSignal.class));
mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback); mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName)); verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
callbackCaptor.getValue().onError(ClearCredentialStateException.TYPE_UNKNOWN, callbackCaptor
"unknown error"); .getValue()
.onError(ClearCredentialStateException.TYPE_UNKNOWN, "unknown error");
verify(callback).onError(errorCaptor.capture()); verify(callback).onError(errorCaptor.capture());
assertThat(errorCaptor.getValue().getType()).isEqualTo( assertThat(errorCaptor.getValue().getType())
ClearCredentialStateException.TYPE_UNKNOWN); .isEqualTo(ClearCredentialStateException.TYPE_UNKNOWN);
} }
@Test @Test
public void testClearCredential_success() throws RemoteException { public void testClearCredential_success() throws RemoteException {
ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor =
IClearCredentialStateCallback.class); ArgumentCaptor.forClass(IClearCredentialStateCallback.class);
OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class); OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(), when(mMockCredentialManagerService.clearCredentialState(
any())).thenReturn(mock(ICancellationSignal.class)); any(), callbackCaptor.capture(), any()))
.thenReturn(mock(ICancellationSignal.class));
mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback); mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName)); verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
@@ -464,27 +498,32 @@ public class CredentialManagerTest {
@Test @Test
public void testGetCredentialProviderServices_systemProviders() throws RemoteException { public void testGetCredentialProviderServices_systemProviders() throws RemoteException {
verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY); verifyGetCredentialProviderServices(
CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
} }
@Test @Test
public void testGetCredentialProviderServicesForTesting_allProviders() throws RemoteException { public void testGetCredentialProviderServicesForTesting_allProviders() throws RemoteException {
verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS); verifyGetCredentialProviderServicesForTesting(
CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
} }
@Test @Test
public void testGetCredentialProviderServicesForTesting_userProviders() throws RemoteException { public void testGetCredentialProviderServicesForTesting_userProviders() throws RemoteException {
verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY); verifyGetCredentialProviderServicesForTesting(
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
} }
@Test @Test
public void testGetCredentialProviderServicesForTesting_systemProviders() throws RemoteException { public void testGetCredentialProviderServicesForTesting_systemProviders()
verifyGetCredentialProviderServicesForTesting(CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY); throws RemoteException {
verifyGetCredentialProviderServicesForTesting(
CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
} }
private void verifyGetCredentialProviderServices(int testFilter) throws RemoteException { private void verifyGetCredentialProviderServices(int testFilter) throws RemoteException {
when(mMockCredentialManagerService.getCredentialProviderServices( when(mMockCredentialManagerService.getCredentialProviderServices(TEST_USER_ID, testFilter))
TEST_USER_ID, testFilter)).thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST); .thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
List<CredentialProviderInfo> output = List<CredentialProviderInfo> output =
mCredentialManager.getCredentialProviderServices(TEST_USER_ID, testFilter); mCredentialManager.getCredentialProviderServices(TEST_USER_ID, testFilter);
@@ -492,9 +531,10 @@ public class CredentialManagerTest {
assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST); assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
} }
private void verifyGetCredentialProviderServicesForTesting(int testFilter) throws RemoteException { private void verifyGetCredentialProviderServicesForTesting(int testFilter)
when(mMockCredentialManagerService.getCredentialProviderServicesForTesting( throws RemoteException {
testFilter)).thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST); when(mMockCredentialManagerService.getCredentialProviderServicesForTesting(testFilter))
.thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
List<CredentialProviderInfo> output = List<CredentialProviderInfo> output =
mCredentialManager.getCredentialProviderServicesForTesting(testFilter); mCredentialManager.getCredentialProviderServicesForTesting(testFilter);
@@ -504,41 +544,45 @@ public class CredentialManagerTest {
@Test @Test
public void testSetEnabledProviders_nullProviders() { public void testSetEnabledProviders_nullProviders() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.setEnabledProviders(null, 0, mExecutor, response -> { NullPointerException.class,
})); () ->
mCredentialManager.setEnabledProviders(
null, null, 0, mExecutor, response -> {}));
} }
@Test @Test
public void testSetEnabledProviders_nullExecutor() { public void testSetEnabledProviders_nullExecutor() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, null, response -> { NullPointerException.class,
})); () ->
mCredentialManager.setEnabledProviders(
List.of("foo"), List.of("foo"), 0, null, response -> {}));
} }
@Test @Test
public void testSetEnabledProviders_nullCallback() { public void testSetEnabledProviders_nullCallback() {
assertThrows(NullPointerException.class, assertThrows(
() -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, mExecutor, null)); NullPointerException.class,
() ->
mCredentialManager.setEnabledProviders(
List.of("foo"), List.of("foo"), 0, mExecutor, null));
} }
@Test @Test
public void testSetEnabledProviders_failed() throws RemoteException { public void testSetEnabledProviders_failed() throws RemoteException {
OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class); OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor =
ISetEnabledProvidersCallback.class); ArgumentCaptor.forClass(ISetEnabledProvidersCallback.class);
ArgumentCaptor<SetEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass( ArgumentCaptor<SetEnabledProvidersException> errorCaptor =
SetEnabledProvidersException.class); ArgumentCaptor.forClass(SetEnabledProvidersException.class);
final List<String> providers = List.of("foo", "bar"); final List<String> providers = List.of("foo", "bar");
final int userId = 0; final int userId = 0;
mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback); mCredentialManager.setEnabledProviders(providers, providers, userId, mExecutor, callback);
verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0), verify(mMockCredentialManagerService)
callbackCaptor.capture()); .setEnabledProviders(eq(providers), eq(providers), eq(0), callbackCaptor.capture());
final String errorType = "unknown"; final String errorType = "unknown";
final String errorMessage = "Unknown error"; final String errorMessage = "Unknown error";
@@ -553,15 +597,18 @@ public class CredentialManagerTest {
public void testSetEnabledProviders_success() throws RemoteException { public void testSetEnabledProviders_success() throws RemoteException {
OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class); OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass( ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor =
ISetEnabledProvidersCallback.class); ArgumentCaptor.forClass(ISetEnabledProvidersCallback.class);
final List<String> providers = List.of("foo", "bar"); final List<String> providers = List.of("foo", "bar");
final List<String> primaryProviders = List.of("foo");
final int userId = 0; final int userId = 0;
mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback); mCredentialManager.setEnabledProviders(
primaryProviders, providers, userId, mExecutor, callback);
verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0), verify(mMockCredentialManagerService)
callbackCaptor.capture()); .setEnabledProviders(
eq(primaryProviders), eq(providers), eq(0), callbackCaptor.capture());
callbackCaptor.getValue().onResponse(); callbackCaptor.getValue().onResponse();
verify(callback).onResult(any()); verify(callback).onResult(any());
@@ -569,27 +616,29 @@ public class CredentialManagerTest {
@Test @Test
public void testRegisterCredentialDescription_nullRequest() { public void testRegisterCredentialDescription_nullRequest() {
assertThrows(NullPointerException.class, assertThrows(
NullPointerException.class,
() -> mCredentialManager.registerCredentialDescription(null)); () -> mCredentialManager.registerCredentialDescription(null));
} }
@Test @Test
public void testRegisterCredentialDescription_success() throws RemoteException { public void testRegisterCredentialDescription_success() throws RemoteException {
mCredentialManager.registerCredentialDescription(mRegisterRequest); mCredentialManager.registerCredentialDescription(mRegisterRequest);
verify(mMockCredentialManagerService).registerCredentialDescription(same(mRegisterRequest), verify(mMockCredentialManagerService)
eq(mPackageName)); .registerCredentialDescription(same(mRegisterRequest), eq(mPackageName));
} }
@Test @Test
public void testUnregisterCredentialDescription_nullRequest() { public void testUnregisterCredentialDescription_nullRequest() {
assertThrows(NullPointerException.class, assertThrows(
NullPointerException.class,
() -> mCredentialManager.unregisterCredentialDescription(null)); () -> mCredentialManager.unregisterCredentialDescription(null));
} }
@Test @Test
public void testUnregisterCredentialDescription_success() throws RemoteException { public void testUnregisterCredentialDescription_success() throws RemoteException {
mCredentialManager.unregisterCredentialDescription(mUnregisterRequest); mCredentialManager.unregisterCredentialDescription(mUnregisterRequest);
verify(mMockCredentialManagerService).unregisterCredentialDescription( verify(mMockCredentialManagerService)
same(mUnregisterRequest), eq(mPackageName)); .unregisterCredentialDescription(same(mUnregisterRequest), eq(mPackageName));
} }
} }

View File

@@ -18,7 +18,6 @@ package com.android.server.credentials;
import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS; import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS;
import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN; import static android.Manifest.permission.CREDENTIAL_MANAGER_SET_ORIGIN;
import static android.Manifest.permission.LAUNCH_CREDENTIAL_SELECTOR;
import static android.content.Context.CREDENTIAL_SERVICE; import static android.content.Context.CREDENTIAL_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -46,7 +45,6 @@ import android.credentials.ISetEnabledProvidersCallback;
import android.credentials.PrepareGetCredentialResponseInternal; import android.credentials.PrepareGetCredentialResponseInternal;
import android.credentials.RegisterCredentialDescriptionRequest; import android.credentials.RegisterCredentialDescriptionRequest;
import android.credentials.UnregisterCredentialDescriptionRequest; import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.ui.IntentFactory;
import android.os.Binder; import android.os.Binder;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.IBinder; import android.os.IBinder;
@@ -69,6 +67,7 @@ import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.SecureSettingsServiceNameResolver; import com.android.server.infra.SecureSettingsServiceNameResolver;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@@ -282,6 +281,18 @@ public final class CredentialManagerService
} }
} }
private Set<String> getPrimaryProvidersForUserId(int userId) {
final int resolvedUserId = ActivityManager.handleIncomingUser(
Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, false,
"getPrimaryProvidersForUserId", null);
SecureSettingsServiceNameResolver resolver = new SecureSettingsServiceNameResolver(
mContext, Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
/* isMultipleMode= */ true);
String[] serviceNames = resolver.readServiceNameList(resolvedUserId);
return new HashSet<String>(Arrays.asList(serviceNames));
}
@GuardedBy("mLock") @GuardedBy("mLock")
private List<CredentialManagerServiceImpl> getCredentialProviderServicesLocked(int userId) { private List<CredentialManagerServiceImpl> getCredentialProviderServicesLocked(int userId) {
List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>(); List<CredentialManagerServiceImpl> concatenatedServices = new ArrayList<>();
@@ -689,7 +700,8 @@ public final class CredentialManagerService
@Override @Override
public void setEnabledProviders( public void setEnabledProviders(
List<String> providers, int userId, ISetEnabledProvidersCallback callback) { List<String> primaryProviders, List<String> providers, int userId,
ISetEnabledProvidersCallback callback) {
if (!hasWriteSecureSettingsPermission()) { if (!hasWriteSecureSettingsPermission()) {
try { try {
callback.onError( callback.onError(
@@ -710,17 +722,24 @@ public final class CredentialManagerService
"setEnabledProviders", "setEnabledProviders",
null); null);
String storedValue = String.join(":", providers); boolean writeEnabledStatus =
if (!Settings.Secure.putStringForUser( Settings.Secure.putStringForUser(getContext().getContentResolver(),
getContext().getContentResolver(),
Settings.Secure.CREDENTIAL_SERVICE, Settings.Secure.CREDENTIAL_SERVICE,
storedValue, String.join(":", providers),
userId)) { userId);
Slog.e(TAG, "Failed to store setting containing enabled providers");
boolean writePrimaryStatus =
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
String.join(":", primaryProviders),
userId);
if (!writeEnabledStatus || !writePrimaryStatus) {
Slog.e(TAG, "Failed to store setting containing enabled or primary providers");
try { try {
callback.onError( callback.onError(
"failed_setting_store", "failed_setting_store",
"Failed to store setting containing enabled providers"); "Failed to store setting containing enabled or primary providers");
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Issue with invoking error response: ", e); Slog.e(TAG, "Issue with invoking error response: ", e);
return; return;
@@ -734,10 +753,6 @@ public final class CredentialManagerService
Slog.e(TAG, "Issue with invoking response: ", e); Slog.e(TAG, "Issue with invoking response: ", e);
// TODO: Propagate failure // TODO: Propagate failure
} }
// Send an intent to the UI that we have new enabled providers.
getContext().sendBroadcast(IntentFactory.createProviderUpdateIntent(),
LAUNCH_CREDENTIAL_SELECTOR);
} }
@Override @Override
@@ -785,7 +800,8 @@ public final class CredentialManagerService
verifyGetProvidersPermission(); verifyGetProvidersPermission();
return CredentialProviderInfoFactory.getCredentialProviderServices( return CredentialProviderInfoFactory.getCredentialProviderServices(
mContext, userId, providerFilter, getEnabledProviders()); mContext, userId, providerFilter, getEnabledProviders(),
getPrimaryProvidersForUserId(userId));
} }
@Override @Override
@@ -795,7 +811,8 @@ public final class CredentialManagerService
final int userId = UserHandle.getCallingUserId(); final int userId = UserHandle.getCallingUserId();
return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting( return CredentialProviderInfoFactory.getCredentialProviderServicesForTesting(
mContext, userId, providerFilter, getEnabledProviders()); mContext, userId, providerFilter, getEnabledProviders(),
getPrimaryProvidersForUserId(userId));
} }
@Override @Override

View File

@@ -36,6 +36,7 @@ import android.service.credentials.CredentialProviderInfoFactory;
import android.util.Slog; import android.util.Slog;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@@ -154,7 +155,9 @@ public class CredentialManagerUi {
mContext, mContext,
mUserId, mUserId,
CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY,
mEnabledProviders); mEnabledProviders,
// Don't need primary providers here.
new HashSet<String>());
List<DisabledProviderData> disabledProviderDataList = allProviders.stream() List<DisabledProviderData> disabledProviderDataList = allProviders.stream()
.filter(provider -> !provider.isEnabled()) .filter(provider -> !provider.isEnabled())