Add CredentialDescription get impl.

Bug: 260629338
CTS-Coverage-Bug: 265212839
API-Coverage-Bug: 265212839
Test: Local Build & Deployment
Change-Id: I44b4fba89cee00b51455d3ddf8696477b98045e6
This commit is contained in:
Omer Ozer
2023-01-19 02:45:35 +00:00
parent 1ba51e8e6d
commit d6040afdf7
7 changed files with 465 additions and 110 deletions

View File

@@ -19,35 +19,72 @@ package com.android.server.credentials;
import android.credentials.CredentialDescription;
import android.credentials.RegisterCredentialDescriptionRequest;
import android.credentials.UnregisterCredentialDescriptionRequest;
import android.service.credentials.CredentialEntry;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
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;
/** Contains information on what CredentialProvider has what provisioned Credential. */
public class CredentialDescriptionRegistry {
public final class CredentialDescriptionRegistry {
private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128;
private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16;
private static SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser;
@GuardedBy("sLock")
private static final SparseArray<CredentialDescriptionRegistry>
sCredentialDescriptionSessionPerUser;
private static final ReentrantLock sLock;
static {
sCredentialDescriptionSessionPerUser = new SparseArray<>();
sLock = new ReentrantLock();
}
// TODO(b/265992655): add a way to update CredentialRegistry when a user is removed.
/** Get and/or create a {@link CredentialDescription} for the given user id. */
public static CredentialDescriptionRegistry forUser(int userId) {
CredentialDescriptionRegistry session =
sCredentialDescriptionSessionPerUser.get(userId, null);
/** Represents the results of a given query into the registry. */
public static final class FilterResult {
final String mPackageName;
final List<CredentialEntry> mCredentialEntries;
if (session == null) {
session = new CredentialDescriptionRegistry();
sCredentialDescriptionSessionPerUser.put(userId, session);
private FilterResult(String packageName,
List<CredentialEntry> credentialEntries) {
mPackageName = packageName;
mCredentialEntries = credentialEntries;
}
}
/** Get and/or create a {@link CredentialDescription} for the given user id. */
@GuardedBy("sLock")
public static CredentialDescriptionRegistry forUser(int userId) {
sLock.lock();
try {
CredentialDescriptionRegistry session =
sCredentialDescriptionSessionPerUser.get(userId, null);
if (session == null) {
session = new CredentialDescriptionRegistry();
sCredentialDescriptionSessionPerUser.put(userId, session);
}
return session;
} finally {
sLock.unlock();
}
}
/** Clears an existing session for a given user identifier. */
@GuardedBy("sLock")
public static void clearUserSession(int userId) {
sLock.lock();
try {
sCredentialDescriptionSessionPerUser.remove(userId);
} finally {
sLock.unlock();
}
return session;
}
private Map<String, Set<CredentialDescription>> mCredentialDescriptions;
@@ -74,7 +111,7 @@ public class CredentialDescriptionRegistry {
int size = mCredentialDescriptions.get(callingPackageName).size();
mCredentialDescriptions.get(callingPackageName)
.addAll(descriptions);
mTotalDescriptionCount += size - mCredentialDescriptions.get(callingPackageName).size();
mTotalDescriptionCount += mCredentialDescriptions.get(callingPackageName).size() - size;
}
}
@@ -93,21 +130,33 @@ public class CredentialDescriptionRegistry {
}
}
/** Returns package names and entries of a CredentialProviders that can satisfy a given
* {@link CredentialDescription}. */
public Set<FilterResult> getFilteredResultForProvider(String packageName,
List<String> flatRequestStrings) {
Set<FilterResult> result = new HashSet<>();
Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
for (CredentialDescription containedDescription: currentSet) {
if (flatRequestStrings.contains(containedDescription.getFlattenedRequestString())) {
result.add(new FilterResult(packageName, containedDescription
.getCredentialEntries()));
}
}
return result;
}
/** Returns package names of CredentialProviders that can satisfy a given
* {@link CredentialDescription}. */
public Set<String> filterCredentials(String flatRequestString) {
public Set<String> getMatchingProviders(Set<String> flatRequestString) {
Set<String> result = new HashSet<>();
for (String componentName: mCredentialDescriptions.keySet()) {
Set<CredentialDescription> currentSet = mCredentialDescriptions.get(componentName);
for (CredentialDescription containedDescription: currentSet) {
if (flatRequestString.equals(containedDescription.getFlattenedRequestString())) {
result.add(componentName);
for (String packageName: mCredentialDescriptions.keySet()) {
Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
for (CredentialDescription containedDescription : currentSet) {
if (flatRequestString.contains(containedDescription.getFlattenedRequestString())) {
result.add(packageName);
}
}
}
return result;
}

View File

@@ -61,13 +61,11 @@ import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.SecureSettingsServiceNameResolver;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Entry point service for credential management.
@@ -236,6 +234,7 @@ public final class CredentialManagerService
concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId));
return concatenatedServices;
}
public static boolean isCredentialDescriptionApiEnabled() {
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false);
@@ -244,44 +243,38 @@ public final class CredentialManagerService
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
// to be guarded by 'service.mLock', which is the same as mLock.
private List<ProviderSession> initiateProviderSessionsWithActiveContainers(
RequestSession session,
List<String> requestOptions, Set<ComponentName> activeCredentialContainers) {
GetRequestSession session,
List<String> requestOptions, Set<String> activeCredentialContainers) {
List<ProviderSession> providerSessions = new ArrayList<>();
// Invoke all services of a user to initiate a provider session
runForUser((service) -> {
if (activeCredentialContainers.contains(service.getComponentName())) {
ProviderSession providerSession = service
.initiateProviderSessionForRequestLocked(session, requestOptions);
if (providerSession != null) {
providerSessions.add(providerSession);
}
}
});
for (String packageName: activeCredentialContainers) {
providerSessions.add(ProviderRegistryGetSession.createNewSession(
mContext,
UserHandle.getCallingUserId(),
session,
packageName,
requestOptions));
}
return providerSessions;
}
@NonNull
private Set<String> getMatchingProviders(GetCredentialRequest request) {
private Set<String> getFilteredResultFromRegistry(List<CredentialOption> options) {
// Session for active/provisioned credential descriptions;
CredentialDescriptionRegistry registry = CredentialDescriptionRegistry
.forUser(UserHandle.getCallingUserId());
// All requested credential descriptions based on the given request.
Set<String> requestedCredentialDescriptions =
request.getCredentialOptions().stream().map(
credentialOption -> credentialOption
options.stream().map(
getCredentialOption -> getCredentialOption
.getCredentialRetrievalData()
.getString(CredentialOption
.FLATTENED_REQUEST))
.collect(Collectors.toSet());
// All requested credential descriptions based on the given request.
return requestedCredentialDescriptions.stream()
.map(registry::filterCredentials)
.flatMap(
(Function<Set<String>, Stream<String>>)
Collection::stream)
.collect(Collectors.toSet());
return registry.getMatchingProviders(requestedCredentialDescriptions);
}
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
@@ -304,6 +297,13 @@ public final class CredentialManagerService
return providerSessions;
}
@Override
@GuardedBy("CredentialDescriptionRegistry.sLock")
public void onUserStopped(@NonNull TargetUser user) {
super.onUserStopped(user);
CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier());
}
private CallingAppInfo constructCallingAppInfo(String packageName, int userId) {
final PackageInfo packageInfo;
try {
@@ -340,13 +340,57 @@ public final class CredentialManagerService
request,
constructCallingAppInfo(callingPackage, userId));
// Initiate all provider sessions
List<ProviderSession> providerSessions =
initiateProviderSessions(
session,
request.getCredentialOptions().stream()
.map(CredentialOption::getType)
.collect(Collectors.toList()));
List<ProviderSession> providerSessions;
if (isCredentialDescriptionApiEnabled()) {
List<CredentialOption> optionsThatRequireActiveCredentials =
request.getCredentialOptions().stream()
.filter(getCredentialOption ->
!TextUtils.isEmpty(getCredentialOption
.getCredentialRetrievalData().getString(
CredentialOption
.FLATTENED_REQUEST, null)))
.toList();
List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
request.getCredentialOptions().stream()
.filter(getCredentialOption ->
TextUtils.isEmpty(getCredentialOption
.getCredentialRetrievalData().getString(
CredentialOption
.FLATTENED_REQUEST, null)))
.toList();
List<ProviderSession> sessionsWithoutRemoteService =
initiateProviderSessionsWithActiveContainers(session,
optionsThatRequireActiveCredentials
.stream().map(getCredentialOption ->
getCredentialOption.getCredentialRetrievalData()
.getString(CredentialOption
.FLATTENED_REQUEST))
.collect(Collectors.toList()),
getFilteredResultFromRegistry(optionsThatRequireActiveCredentials));
List<ProviderSession> sessionsWithRemoteService = initiateProviderSessions(
session,
optionsThatDoNotRequireActiveCredentials.stream()
.map(CredentialOption::getType)
.collect(Collectors.toList()));
Set<ProviderSession> all = new LinkedHashSet<>();
all.addAll(sessionsWithRemoteService);
all.addAll(sessionsWithoutRemoteService);
providerSessions = new ArrayList<>(all);
} else {
// Initiate all provider sessions
providerSessions =
initiateProviderSessions(
session,
request.getCredentialOptions().stream()
.map(CredentialOption::getType)
.collect(Collectors.toList()));
}
if (providerSessions.isEmpty()) {
try {
@@ -363,6 +407,7 @@ public final class CredentialManagerService
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(ProviderSession::invokeSession);
return cancelTransport;
}

View File

@@ -118,8 +118,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
@Override
protected void invokeSession() {
this.mRemoteCredentialService.onClearCredentialState(
this.getProviderRequest(),
/*callback=*/this);
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
}
}
}

View File

@@ -51,6 +51,8 @@ public final class ProviderCreateSession extends ProviderSession<
// Key to be used as an entry key for a save entry
private static final String SAVE_ENTRY_KEY = "save_entry_key";
// Key to be used as an entry key for a remote entry
private static final String REMOTE_ENTRY_KEY = "remote_entry_key";
@NonNull
private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>();
@@ -199,9 +201,9 @@ public final class ProviderCreateSession extends ProviderSession<
@Override
protected void invokeSession() {
this.mRemoteCredentialService.onCreateCredential(
this.getProviderRequest(),
/*callback=*/this);
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
}
}
private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) {

View File

@@ -59,14 +59,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
implements
RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> {
private static final String TAG = "ProviderGetSession";
// Key to be used as an entry key for a credential entry
private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
// Key to be used as the entry key for an action entry
private static final String ACTION_ENTRY_KEY = "action_key";
// Key to be used as the entry key for the authentication entry
private static final String AUTHENTICATION_ACTION_ENTRY_KEY = "authentication_action_key";
// Key to be used as an entry key for a remote entry
private static final String REMOTE_ENTRY_KEY = "remote_entry_key";
// Key to be used as an entry key for a credential entry
private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
@NonNull
private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
@@ -101,23 +101,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
return null;
}
private static BeginGetCredentialRequest constructQueryPhaseRequest(
android.credentials.GetCredentialRequest filteredRequest,
CallingAppInfo callingAppInfo
) {
return new BeginGetCredentialRequest.Builder(callingAppInfo)
.setBeginGetCredentialOptions(
filteredRequest.getCredentialOptions().stream().map(
option -> {
return new BeginGetCredentialOption(
option.getType(),
option.getCandidateQueryData());
}).collect(Collectors.toList()))
.build();
}
@Nullable
private static android.credentials.GetCredentialRequest filterOptions(
protected static android.credentials.GetCredentialRequest filterOptions(
List<String> providerCapabilities,
android.credentials.GetCredentialRequest clientRequest
) {
@@ -142,6 +127,21 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
return null;
}
private static BeginGetCredentialRequest constructQueryPhaseRequest(
android.credentials.GetCredentialRequest filteredRequest,
CallingAppInfo callingAppInfo
) {
return new BeginGetCredentialRequest.Builder(callingAppInfo)
.setBeginGetCredentialOptions(
filteredRequest.getCredentialOptions().stream().map(
option -> {
return new BeginGetCredentialOption(
option.getType(),
option.getCandidateQueryData());
}).collect(Collectors.toList()))
.build();
}
public ProviderGetSession(Context context,
CredentialProviderInfo info,
ProviderInternalCallback<GetCredentialResponse> callbacks,
@@ -232,9 +232,9 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
@Override
protected void invokeSession() {
this.mRemoteCredentialService.onBeginGetCredential(
this.getProviderRequest(),
/*callback=*/this);
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
}
}
@Override // Call from request session to data to be shown on the UI
@@ -379,6 +379,28 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
invokeCallbackOnInternalInvalidState();
}
@Nullable
protected GetCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
return null;
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
GetCredentialException exception = PendingIntentResultHandler
.extractGetCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
} else {
return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
}
return null;
}
private void onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
//TODO: Other provider intent statuses
@@ -431,28 +453,6 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
updateStatusAndInvokeCallback(Status.NO_CREDENTIALS);
}
@Nullable
private GetCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
return null;
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
GetCredentialException exception = PendingIntentResultHandler
.extractGetCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
} else {
return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
}
return null;
}
/**
* When an invalid state occurs, e.g. entry mismatch or no response from provider,
* we send back a TYPE_UNKNOWN error as to the developer.

View File

@@ -0,0 +1,261 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.Intent;
import android.credentials.CredentialOption;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
import android.credentials.GetCredentialResponse;
import android.credentials.ui.Entry;
import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderService;
import android.telecom.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Central provider session that utilizes {@link CredentialDescriptionRegistry} and therefor is able
* to bypass having to use a {@link RemoteCredentialService}.
*
* @hide
*/
public class ProviderRegistryGetSession extends ProviderSession<GetCredentialRequest,
Set<CredentialDescriptionRegistry.FilterResult>> {
private static final String TAG = "ProviderRegistryGetSession";
private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
/** Creates a new provider session to be used by the request session. */
@Nullable
public static ProviderRegistryGetSession createNewSession(
@NonNull Context context,
@UserIdInt int userId,
@NonNull GetRequestSession getRequestSession,
@NonNull String credentialProviderPackageName,
@NonNull List<String> requestOptions) {
return new ProviderRegistryGetSession(
context,
userId,
getRequestSession,
getRequestSession.mClientRequest,
getRequestSession.mClientAppInfo,
credentialProviderPackageName,
requestOptions);
}
@NonNull
private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
@NonNull
private final CredentialDescriptionRegistry mCredentialDescriptionRegistry;
@NonNull
private final CallingAppInfo mCallingAppInfo;
@NonNull
private final String mCredentialProviderPackageName;
@NonNull
private final GetRequestSession mGetRequestSession;
@NonNull
private final List<String> mRequestOptions;
private List<CredentialEntry> mCredentialEntries;
protected ProviderRegistryGetSession(@NonNull Context context,
@NonNull int userId,
@NonNull GetRequestSession session,
@NonNull GetCredentialRequest request,
@NonNull CallingAppInfo callingAppInfo,
@NonNull String servicePackageName,
@NonNull List<String> requestOptions) {
super(context, null, request, session, userId, null);
mGetRequestSession = session;
mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
mCallingAppInfo = callingAppInfo;
mCredentialProviderPackageName = servicePackageName;
mRequestOptions = requestOptions;
}
private List<Entry> prepareUiCredentialEntries(
@NonNull List<CredentialEntry> credentialEntries) {
Log.i(TAG, "in prepareUiProviderDataWithCredentials");
List<Entry> credentialUiEntries = new ArrayList<>();
// Populate the credential entries
for (CredentialEntry credentialEntry : credentialEntries) {
String entryId = generateEntryId();
mUiCredentialEntries.put(entryId, credentialEntry);
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
credentialEntry.getSlice(),
setUpFillInIntent(credentialEntry.getType())));
}
return credentialUiEntries;
}
private Intent setUpFillInIntent(String type) {
Intent intent = new Intent();
for (CredentialOption option : mProviderRequest.getCredentialOptions()) {
if (option.getType().equals(type)) {
intent.putExtra(
CredentialProviderService
.EXTRA_GET_CREDENTIAL_REQUEST,
new android.service.credentials.GetCredentialRequest(
mCallingAppInfo, option));
return intent;
}
}
return intent;
}
@Override
protected ProviderData prepareUiData() {
Log.i(TAG, "In prepareUiData");
if (!ProviderSession.isUiInvokingStatus(getStatus())) {
Log.i(TAG, "In prepareUiData - provider does not want to show UI: "
+ mComponentName.flattenToString());
return null;
}
if (mProviderResponse == null) {
Log.i(TAG, "In prepareUiData response null");
throw new IllegalStateException("Response must be in completion mode");
}
return new GetCredentialProviderData.Builder(
mComponentName.flattenToString()).setActionChips(null)
.setCredentialEntries(prepareUiCredentialEntries(
mProviderResponse.stream().flatMap((Function<CredentialDescriptionRegistry
.FilterResult,
Stream<CredentialEntry>>) filterResult ->
filterResult.mCredentialEntries.stream())
.collect(Collectors.toList())))
.build();
}
@Override // Selection call from the request provider
protected void onUiEntrySelected(String entryType, String entryKey,
ProviderPendingIntentResponse providerPendingIntentResponse) {
switch (entryType) {
case CREDENTIAL_ENTRY_KEY:
CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
if (credentialEntry == null) {
Log.i(TAG, "Unexpected credential entry key");
return;
}
onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
break;
default:
Log.i(TAG, "Unsupported entry type selected");
}
}
private void onCredentialEntrySelected(CredentialEntry credentialEntry,
ProviderPendingIntentResponse providerPendingIntentResponse) {
if (!mCredentialEntries.contains(credentialEntry)) {
invokeCallbackWithError("",
"");
}
if (providerPendingIntentResponse != null) {
// Check if pending intent has an error
GetCredentialException exception = maybeGetPendingIntentException(
providerPendingIntentResponse);
if (exception != null) {
invokeCallbackWithError(exception.getType(),
exception.getMessage());
return;
}
// Check if pending intent has a credential
GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
.extractGetCredentialResponse(
providerPendingIntentResponse.getResultData());
if (getCredentialResponse != null) {
if (mCallbacks != null) {
mCallbacks.onFinalResponseReceived(mComponentName,
getCredentialResponse);
}
return;
}
Log.i(TAG, "Pending intent response contains no credential, or error");
}
Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
}
@Override
public void onProviderResponseSuccess(
@Nullable Set<CredentialDescriptionRegistry.FilterResult> response) {
// No need to do anything since this class does not rely on a remote service.
}
@Override
public void onProviderResponseFailure(int internalErrorCode, @Nullable Exception e) {
// No need to do anything since this class does not rely on a remote service.
}
@Override
public void onProviderServiceDied(RemoteCredentialService service) {
// No need to do anything since this class does not rely on a remote service.
}
@Override
protected void invokeSession() {
mProviderResponse = mCredentialDescriptionRegistry
.getFilteredResultForProvider(mCredentialProviderPackageName,
mRequestOptions);
mCredentialEntries = mProviderResponse.stream().flatMap(
(Function<CredentialDescriptionRegistry.FilterResult,
Stream<CredentialEntry>>) filterResult
-> filterResult.mCredentialEntries.stream())
.collect(Collectors.toList());
setStatus(Status.CREDENTIALS_RECEIVED);
}
@Nullable
protected GetCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
android.util.Log.i(TAG, "pendingIntentResponse is null");
return null;
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
GetCredentialException exception = PendingIntentResultHandler
.extractGetCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
android.util.Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
} else {
return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
}
return null;
}
}

View File

@@ -38,16 +38,14 @@ public abstract class ProviderSession<T, R>
implements RemoteCredentialService.ProviderCallbacks<R> {
private static final String TAG = "ProviderSession";
// Key to be used as an entry key for a remote entry
protected static final String REMOTE_ENTRY_KEY = "remote_entry_key";
@NonNull protected final Context mContext;
@NonNull protected final ComponentName mComponentName;
@NonNull protected final CredentialProviderInfo mProviderInfo;
@NonNull protected final RemoteCredentialService mRemoteCredentialService;
@Nullable protected final CredentialProviderInfo mProviderInfo;
@Nullable protected final RemoteCredentialService mRemoteCredentialService;
@NonNull protected final int mUserId;
@NonNull protected Status mStatus = Status.NOT_STARTED;
@NonNull protected final ProviderInternalCallback mCallbacks;
@Nullable protected final ProviderInternalCallback mCallbacks;
@Nullable protected Credential mFinalCredentialResponse;
@NonNull protected final T mProviderRequest;
@Nullable protected R mProviderResponse;
@@ -109,9 +107,9 @@ public abstract class ProviderSession<T, R>
protected ProviderSession(@NonNull Context context, @NonNull CredentialProviderInfo info,
@NonNull T providerRequest,
@NonNull ProviderInternalCallback callbacks,
@Nullable ProviderInternalCallback callbacks,
@NonNull int userId,
@NonNull RemoteCredentialService remoteCredentialService) {
@Nullable RemoteCredentialService remoteCredentialService) {
mContext = context;
mProviderInfo = info;
mProviderRequest = providerRequest;
@@ -165,7 +163,7 @@ public abstract class ProviderSession<T, R>
return mComponentName;
}
@NonNull
@Nullable
protected RemoteCredentialService getRemoteCredentialService() {
return mRemoteCredentialService;
}