From 6939babc977d061a8787179578a8df3bfa858541 Mon Sep 17 00:00:00 2001 From: Omer Ozer Date: Tue, 21 Mar 2023 22:49:18 +0000 Subject: [PATCH] Changing flat request string to a set of element keys. Bug: 274667622 Test: local Change-Id: I719483380d86f12b17fec2d1ca58bb1b8ac56a64 --- core/api/current.txt | 6 +- .../credentials/CredentialDescription.java | 33 ++++---- .../android/credentials/CredentialOption.java | 6 +- .../credentials/CredentialManagerTest.java | 5 +- .../CredentialDescriptionRegistry.java | 48 +++++------- .../credentials/CredentialManagerService.java | 75 +++++++------------ .../ProviderRegistryGetSession.java | 13 ++-- .../CredentialDescriptionRegistryTest.java | 11 ++- .../ProviderRegistryGetSessionTest.java | 17 +++-- 9 files changed, 98 insertions(+), 116 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 4332d21b297ca..b0b04fa4cc3ea 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -13645,10 +13645,10 @@ package android.credentials { } public final class CredentialDescription implements android.os.Parcelable { - ctor public CredentialDescription(@NonNull String, @NonNull String, @NonNull java.util.List); + ctor public CredentialDescription(@NonNull String, @NonNull java.util.Set, @NonNull java.util.List); method public int describeContents(); method @NonNull public java.util.List getCredentialEntries(); - method @NonNull public String getFlattenedRequestString(); + method @NonNull public java.util.Set getSupportedElementKeys(); method @NonNull public String getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -13675,7 +13675,7 @@ package android.credentials { method public boolean isSystemProviderRequired(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; - field public static final String FLATTENED_REQUEST = "android.credentials.GetCredentialOption.FLATTENED_REQUEST_STRING"; + field public static final String SUPPORTED_ELEMENT_KEYS = "android.credentials.GetCredentialOption.SUPPORTED_ELEMENT_KEYS"; } public static final class CredentialOption.Builder { diff --git a/core/java/android/credentials/CredentialDescription.java b/core/java/android/credentials/CredentialDescription.java index a23d7e4027687..db71624cbe894 100644 --- a/core/java/android/credentials/CredentialDescription.java +++ b/core/java/android/credentials/CredentialDescription.java @@ -25,8 +25,10 @@ import com.android.internal.util.AnnotationValidations; import com.android.internal.util.Preconditions; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Represents the type and contained data fields of a {@link Credential}. @@ -42,10 +44,10 @@ public final class CredentialDescription implements Parcelable { private final String mType; /** - * Flattened semicolon separated keys of JSON values to match with requests. + * Keys of elements to match with Credential requests. */ @NonNull - private final String mFlattenedRequestString; + private final Set mSupportedElementKeys; /** * The credential entries to be used in the UI. @@ -57,8 +59,7 @@ public final class CredentialDescription implements Parcelable { * Constructs a {@link CredentialDescription}. * * @param type the type of the credential returned. - * @param flattenedRequestString flattened semicolon separated keys of JSON values - * to match with requests. + * @param supportedElementKeys Keys of elements to match with Credential requests. * @param credentialEntries a list of {@link CredentialEntry}s that are to be shown on the * account selector if a credential matches with this description. * Each entry contains information to be displayed within an @@ -68,10 +69,10 @@ public final class CredentialDescription implements Parcelable { * @throws IllegalArgumentException If type is empty. */ public CredentialDescription(@NonNull String type, - @NonNull String flattenedRequestString, + @NonNull Set supportedElementKeys, @NonNull List credentialEntries) { mType = Preconditions.checkStringNotEmpty(type, "type must not be empty"); - mFlattenedRequestString = Preconditions.checkStringNotEmpty(flattenedRequestString); + mSupportedElementKeys = Objects.requireNonNull(supportedElementKeys); mCredentialEntries = Objects.requireNonNull(credentialEntries); Preconditions.checkArgument(credentialEntries.size() <= MAX_ALLOWED_ENTRIES_PER_DESCRIPTION, @@ -82,15 +83,15 @@ public final class CredentialDescription implements Parcelable { private CredentialDescription(@NonNull Parcel in) { String type = in.readString8(); - String flattenedRequestString = in.readString(); + List descriptions = in.createStringArrayList(); List entries = new ArrayList<>(); in.readTypedList(entries, CredentialEntry.CREATOR); mType = type; AnnotationValidations.validate(android.annotation.NonNull.class, null, mType); - mFlattenedRequestString = flattenedRequestString; + mSupportedElementKeys = new HashSet<>(descriptions); AnnotationValidations.validate(android.annotation.NonNull.class, null, - mFlattenedRequestString); + mSupportedElementKeys); mCredentialEntries = entries; AnnotationValidations.validate(android.annotation.NonNull.class, null, mCredentialEntries); @@ -125,7 +126,7 @@ public final class CredentialDescription implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); - dest.writeString(mFlattenedRequestString); + dest.writeStringList(mSupportedElementKeys.stream().toList()); dest.writeTypedList(mCredentialEntries, flags); } @@ -141,8 +142,8 @@ public final class CredentialDescription implements Parcelable { * Returns the flattened JSON string that will be matched with requests. */ @NonNull - public String getFlattenedRequestString() { - return mFlattenedRequestString; + public Set getSupportedElementKeys() { + return new HashSet<>(mSupportedElementKeys); } /** @@ -155,18 +156,18 @@ public final class CredentialDescription implements Parcelable { /** * {@link CredentialDescription#mType} and - * {@link CredentialDescription#mFlattenedRequestString} are enough for hashing. Constructor + * {@link CredentialDescription#mSupportedElementKeys} are enough for hashing. Constructor * enforces {@link CredentialEntry} to have the same type and * {@link android.app.slice.Slice} contained by the entry can not be hashed. */ @Override public int hashCode() { - return Objects.hash(mType, mFlattenedRequestString); + return Objects.hash(mType, mSupportedElementKeys); } /** * {@link CredentialDescription#mType} and - * {@link CredentialDescription#mFlattenedRequestString} are enough for equality check. + * {@link CredentialDescription#mSupportedElementKeys} are enough for equality check. */ @Override public boolean equals(Object obj) { @@ -175,6 +176,6 @@ public final class CredentialDescription implements Parcelable { } CredentialDescription other = (CredentialDescription) obj; return mType.equals(other.mType) - && mFlattenedRequestString.equals(other.mFlattenedRequestString); + && mSupportedElementKeys.equals(other.mSupportedElementKeys); } } diff --git a/core/java/android/credentials/CredentialOption.java b/core/java/android/credentials/CredentialOption.java index da6656a0222ff..e933123d08b85 100644 --- a/core/java/android/credentials/CredentialOption.java +++ b/core/java/android/credentials/CredentialOption.java @@ -43,12 +43,12 @@ import java.util.Set; public final class CredentialOption implements Parcelable { /** - * Bundle key to the flattened version of the JSON request string. Framework will use this key + * Bundle key to the list of elements keys supported/requested. Framework will use this key * to determine which types of Credentials will utilize Credential Registry when filtering * Credential Providers to ping. */ - public static final String FLATTENED_REQUEST = "android.credentials" - + ".GetCredentialOption.FLATTENED_REQUEST_STRING"; + public static final String SUPPORTED_ELEMENT_KEYS = "android.credentials" + + ".GetCredentialOption.SUPPORTED_ELEMENT_KEYS"; /** * The requested credential type. diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java index 6f0c3d306bd5f..c7e0261234870 100644 --- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java +++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java @@ -49,6 +49,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; @@ -126,11 +127,11 @@ public class CredentialManagerTest { null, List.of(Slice.HINT_TITLE)).build(); mRegisterRequest = new RegisterCredentialDescriptionRequest( new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, - "{ \"foo\": \"bar\" }", + new HashSet<>(List.of("{ \"foo\": \"bar\" }")), List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); mUnregisterRequest = new UnregisterCredentialDescriptionRequest( new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL, - "{ \"foo\": \"bar\" }", + new HashSet<>(List.of("{ \"foo\": \"bar\" }")), List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice)))); final Context context = InstrumentationRegistry.getInstrumentation().getContext(); diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java index 8ccc61b70f459..1164516b2eb8f 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java +++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java @@ -25,19 +25,16 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; /** Contains information on what CredentialProvider has what provisioned Credential. */ public class CredentialDescriptionRegistry { - private static final String FLAT_STRING_SPLIT_REGEX = ";"; private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128; private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16; @GuardedBy("sLock") @@ -53,15 +50,15 @@ public class CredentialDescriptionRegistry { /** Represents the results of a given query into the registry. */ public static final class FilterResult { final String mPackageName; - final String mFlattenedRequest; + final Set mElementKeys; final List mCredentialEntries; @VisibleForTesting FilterResult(String packageName, - String flattenedRequest, + Set elementKeys, List credentialEntries) { mPackageName = packageName; - mFlattenedRequest = flattenedRequest; + mElementKeys = elementKeys; mCredentialEntries = credentialEntries; } } @@ -166,18 +163,17 @@ public class CredentialDescriptionRegistry { /** Returns package names and entries of a CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ public Set getFilteredResultForProvider(String packageName, - String flatRequestString) { + Set requestedKeyElements) { Set result = new HashSet<>(); if (!mCredentialDescriptions.containsKey(packageName)) { return result; } Set currentSet = mCredentialDescriptions.get(packageName); - Set unflattenedRequestString = flatStringToSet(flatRequestString); for (CredentialDescription containedDescription: currentSet) { - if (checkForMatch(flatStringToSet(containedDescription.getFlattenedRequestString()), - unflattenedRequestString)) { + if (checkForMatch(containedDescription.getSupportedElementKeys(), + requestedKeyElements)) { result.add(new FilterResult(packageName, - containedDescription.getFlattenedRequestString(), containedDescription + containedDescription.getSupportedElementKeys(), containedDescription .getCredentialEntries())); } } @@ -186,18 +182,15 @@ public class CredentialDescriptionRegistry { /** Returns package names of CredentialProviders that can satisfy a given * {@link CredentialDescription}. */ - public Set getMatchingProviders(Set flatRequestStrings) { + public Set getMatchingProviders(Set> supportedElementKeys) { Set result = new HashSet<>(); - Set> unflattenedRequestStrings = flatRequestStrings.stream().map( - CredentialDescriptionRegistry::flatStringToSet).collect(Collectors.toSet()); for (String packageName: mCredentialDescriptions.keySet()) { Set currentSet = mCredentialDescriptions.get(packageName); for (CredentialDescription containedDescription : currentSet) { - if (canProviderSatisfyAny(flatStringToSet(containedDescription - .getFlattenedRequestString()), - unflattenedRequestStrings)) { + if (canProviderSatisfyAny(containedDescription.getSupportedElementKeys(), + supportedElementKeys)) { result.add(new FilterResult(packageName, - containedDescription.getFlattenedRequestString(), containedDescription + containedDescription.getSupportedElementKeys(), containedDescription .getCredentialEntries())); } } @@ -211,24 +204,19 @@ public class CredentialDescriptionRegistry { } } - private static boolean canProviderSatisfyAny(Set registeredUnflattenedStrings, - Set> requestedUnflattenedStrings) { - for (Set requestedUnflattenedString : requestedUnflattenedStrings) { - if (registeredUnflattenedStrings.containsAll(requestedUnflattenedString)) { + private static boolean canProviderSatisfyAny(Set registeredElementKeys, + Set> requestedElementKeys) { + for (Set requestedUnflattenedString : requestedElementKeys) { + if (registeredElementKeys.containsAll(requestedUnflattenedString)) { return true; } } return false; } - static boolean checkForMatch(Set registeredUnflattenedStrings, - Set requestedUnflattenedString) { - return registeredUnflattenedStrings.containsAll(requestedUnflattenedString); - } - - static Set flatStringToSet(String flatString) { - return new HashSet<>(Arrays - .asList(flatString.split(FLAT_STRING_SPLIT_REGEX))); + static boolean checkForMatch(Set registeredElementKeys, + Set requestedElementKeys) { + return registeredElementKeys.containsAll(requestedElementKeys); } } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 90b92f43d80f9..06da76e50c294 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -339,13 +339,14 @@ public final class CredentialManagerService CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId()); // All requested credential descriptions based on the given request. - Set requestedCredentialDescriptions = + Set> requestedCredentialDescriptions = options.stream() .map( getCredentialOption -> - getCredentialOption + new HashSet<>(getCredentialOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST)) + .getStringArrayList( + CredentialOption.SUPPORTED_ELEMENT_KEYS))) .collect(Collectors.toSet()); // All requested credential descriptions based on the given request. @@ -356,15 +357,13 @@ public final class CredentialManagerService new HashSet<>(); for (CredentialDescriptionRegistry.FilterResult filterResult : filterResults) { - Set registeredUnflattenedStrings = CredentialDescriptionRegistry - .flatStringToSet(filterResult.mFlattenedRequest); for (CredentialOption credentialOption : options) { - Set requestedUnflattenedStrings = CredentialDescriptionRegistry - .flatStringToSet(credentialOption + Set requestedElementKeys = new HashSet<>( + credentialOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST)); - if (CredentialDescriptionRegistry.checkForMatch(registeredUnflattenedStrings, - requestedUnflattenedStrings)) { + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); + if (CredentialDescriptionRegistry.checkForMatch(filterResult.mElementKeys, + requestedElementKeys)) { result.add(new Pair<>(credentialOption, filterResult)); } } @@ -511,28 +510,20 @@ public final class CredentialManagerService if (isCredentialDescriptionApiEnabled()) { List optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - !TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) != null) .toList(); List optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) == null) .toList(); List sessionsWithoutRemoteService = @@ -590,28 +581,20 @@ public final class CredentialManagerService if (isCredentialDescriptionApiEnabled()) { List optionsThatRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - !TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) != null) .toList(); List optionsThatDoNotRequireActiveCredentials = request.getCredentialOptions().stream() - .filter( - getCredentialOption -> - TextUtils.isEmpty( - getCredentialOption - .getCredentialRetrievalData() - .getString( - CredentialOption - .FLATTENED_REQUEST, - null))) + .filter(credentialOption -> credentialOption + .getCredentialRetrievalData() + .getStringArrayList( + CredentialOption + .SUPPORTED_ELEMENT_KEYS) == null) .toList(); List sessionsWithoutRemoteService = diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java index 85c78445e66b1..8b14757bafed7 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -103,7 +104,7 @@ public class ProviderRegistryGetSession extends ProviderSession mElementKeys; @VisibleForTesting List mCredentialEntries; @@ -119,9 +120,9 @@ public class ProviderRegistryGetSession extends ProviderSession(requestOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST); + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); } protected ProviderRegistryGetSession(@NonNull Context context, @@ -136,9 +137,9 @@ public class ProviderRegistryGetSession extends ProviderSession(requestOption .getCredentialRetrievalData() - .getString(CredentialOption.FLATTENED_REQUEST); + .getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS)); } private List prepareUiCredentialEntries( @@ -257,7 +258,7 @@ public class ProviderRegistryGetSession extends ProviderSession>) filterResult diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java index 169210f627b85..ab2749e14094d 100644 --- a/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java +++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialDescriptionRegistryTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -52,10 +53,12 @@ public class CredentialDescriptionRegistryTest { private static final String CALLING_PACKAGE_NAME_2 = "com.credman.app2"; private static final String MDOC_CREDENTIAL_TYPE = "MDOC"; private static final String PASSKEY_CREDENTIAL_TYPE = "PASSKEY"; - private static final String FLATTENED_REGISTRY = - "FLATTENED_REQ;FLATTENED_REQ123;FLATTENED_REQa"; - private static final String FLATTENED_REGISTRY_2 = "FLATTENED_REQ_2"; - private static final String FLATTENED_REQUEST = "FLATTENED_REQ;FLATTENED_REQ123"; + private static final HashSet FLATTENED_REGISTRY = new HashSet<>(List.of( + "FLATTENED_REQ", "FLATTENED_REQ123", "FLATTENED_REQa")); + private static final HashSet FLATTENED_REGISTRY_2 = + new HashSet<>(List.of("FLATTENED_REQ_2")); + private static final HashSet FLATTENED_REQUEST = + new HashSet<>(List.of("FLATTENED_REQ;FLATTENED_REQ123")); private CredentialDescriptionRegistry mCredentialDescriptionRegistry; private CredentialEntry mEntry; diff --git a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java index 4c8e70ae5109d..13d49aa687a8e 100644 --- a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java @@ -18,6 +18,7 @@ package com.android.server.credentials; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -59,6 +60,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -74,7 +76,8 @@ public class ProviderRegistryGetSessionTest { private static final String CALLING_PACKAGE_NAME = "com.credman.app"; private static final int USER_ID_1 = 1; - private static final String FLATTENED_REQUEST = "FLATTENED_REQ"; + private static final ArrayList FLATTENED_REQUEST = + new ArrayList<>(List.of("FLATTENED_REQ")); private static final String CP_SERVICE_NAME = "CredentialProvider"; private static final ComponentName CREDENTIAL_PROVIDER_COMPONENT = new ComponentName(CALLING_PACKAGE_NAME, CP_SERVICE_NAME); @@ -102,7 +105,8 @@ public class ProviderRegistryGetSessionTest { MockitoAnnotations.initMocks(this); final Context context = ApplicationProvider.getApplicationContext(); mRetrievalData = new Bundle(); - mRetrievalData.putString(CredentialOption.FLATTENED_REQUEST, FLATTENED_REQUEST); + mRetrievalData.putStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS, + FLATTENED_REQUEST); mCallingAppInfo = createCallingAppInfo(); mGetCredentialOption = new CredentialOption(CREDENTIAL_TYPE, mRetrievalData, new Bundle(), false); @@ -114,10 +118,10 @@ public class ProviderRegistryGetSessionTest { when(mEntry.getSlice()).thenReturn(mSlice); when(mEntry2.getSlice()).thenReturn(mSlice2); mResult = new CredentialDescriptionRegistry.FilterResult(CALLING_PACKAGE_NAME, - FLATTENED_REQUEST, + new HashSet<>(FLATTENED_REQUEST), List.of(mEntry, mEntry2)); mResponse.add(mResult); - when(mCredentialDescriptionRegistry.getFilteredResultForProvider(anyString(), anyString())) + when(mCredentialDescriptionRegistry.getFilteredResultForProvider(anyString(), anySet())) .thenReturn(mResponse); mProviderRegistryGetSession = ProviderRegistryGetSession .createNewSession(context, USER_ID_1, mGetRequestSession, @@ -129,7 +133,8 @@ public class ProviderRegistryGetSessionTest { @Test public void testInvokeSession_existingProvider_setsResults() { final ArgumentCaptor packageNameCaptor = ArgumentCaptor.forClass(String.class); - final ArgumentCaptor flattenedRequestCaptor = ArgumentCaptor.forClass(String.class); + final ArgumentCaptor> flattenedRequestCaptor = + ArgumentCaptor.forClass(Set.class); final ArgumentCaptor statusCaptor = ArgumentCaptor.forClass(ProviderSession.Status.class); final ArgumentCaptor cpComponentNameCaptor = @@ -141,7 +146,7 @@ public class ProviderRegistryGetSessionTest { packageNameCaptor.capture(), flattenedRequestCaptor.capture()); assertThat(packageNameCaptor.getValue()).isEqualTo(CALLING_PACKAGE_NAME); - assertThat(flattenedRequestCaptor.getValue()).isEqualTo(FLATTENED_REQUEST); + assertThat(flattenedRequestCaptor.getValue()).containsExactly(FLATTENED_REQUEST); verify(mGetRequestSession).onProviderStatusChanged(statusCaptor.capture(), cpComponentNameCaptor.capture()); assertThat(statusCaptor.getValue()).isEqualTo(ProviderSession.Status.CREDENTIALS_RECEIVED);