Merge "Maintain auth entry status across providers" into udc-dev

This commit is contained in:
TreeHugger Robot
2023-02-25 00:13:31 +00:00
committed by Android (Google) Code Review
4 changed files with 71 additions and 8 deletions

View File

@@ -44,7 +44,6 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
IGetCredentialCallback>
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
private static final String TAG = "GetRequestSession";
public GetRequestSession(Context context, int userId, int callingUid,
IGetCredentialCallback callback, GetCredentialRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal) {
@@ -173,6 +172,12 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName) {
Log.i(TAG, "in onStatusChanged with status: " + status);
// Auth entry was selected, and it did not have any underlying credentials
if (status == ProviderSession.Status.NO_CREDENTIALS_FROM_AUTH_ENTRY) {
handleEmptyAuthenticationSelection(componentName);
return;
}
// For any other status, we check if all providers are done and then invoke UI if needed
if (!isAnyProviderPending()) {
// If all provider responses have been received, we can either need the UI,
// or we need to respond with error. The only other case is the entry being
@@ -186,4 +191,34 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
}
}
}
private void handleEmptyAuthenticationSelection(ComponentName componentName) {
// Update auth entry statuses across different provider sessions
mProviders.keySet().forEach(key -> {
ProviderGetSession session = (ProviderGetSession) mProviders.get(key);
if (!session.mComponentName.equals(componentName)) {
session.updateAuthEntriesStatusFromAnotherSession();
}
});
// Invoke UI since it needs to show a snackbar if last auth entry, or a status on each
// auth entries along with other valid entries
getProviderDataAndInitiateUi();
// Respond to client if all auth entries are empty and nothing else to show on the UI
if (providerDataContainsEmptyAuthEntriesOnly()) {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
"No credentials available");
}
}
private boolean providerDataContainsEmptyAuthEntriesOnly() {
for (String key : mProviders.keySet()) {
ProviderGetSession session = (ProviderGetSession) mProviders.get(key);
if (!session.containsEmptyAuthEntriesOnly()) {
return false;
}
}
return true;
}
}

View File

@@ -241,13 +241,14 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
if (additionalContentReceived) {
Log.i(TAG, "Additional content received - removing authentication entry");
mProviderResponseDataHandler.removeAuthenticationAction(entryKey);
if (!mProviderResponseDataHandler.isEmptyResponse()) {
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
}
} else {
Log.i(TAG, "Additional content not received");
mProviderResponseDataHandler
.updateAuthEntryWithNoCredentialsReceived(entryKey);
}
if (!mProviderResponseDataHandler.isEmptyResponse()) {
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
updateStatusAndInvokeCallback(Status.NO_CREDENTIALS_FROM_AUTH_ENTRY);
}
break;
case REMOTE_ENTRY_KEY:
@@ -456,6 +457,27 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
GetCredentialException.TYPE_UNKNOWN, null);
}
/** Update auth entries status based on an auth entry selected from a different session. */
public void updateAuthEntriesStatusFromAnotherSession() {
// Pass null for entryKey if the auth entry selected belongs to a different session
mProviderResponseDataHandler.updateAuthEntryWithNoCredentialsReceived(/*entryKey=*/null);
}
/** Returns true if the provider response contains empty auth entries only, false otherwise. **/
public boolean containsEmptyAuthEntriesOnly() {
// We do not consider action entries here because if actions are the only entries,
// we don't show the UI
return mProviderResponseDataHandler.mUiCredentialEntries.isEmpty()
&& mProviderResponseDataHandler.mUiRemoteEntry == null
&& mProviderResponseDataHandler.mUiAuthenticationEntries
.values().stream().allMatch(
e -> e.second.getStatus() == AuthenticationEntry
.STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT
|| e.second.getStatus()
== AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT
);
}
private class ProviderResponseDataHandler {
private final ComponentName mExpectedRemoteEntryProviderService;
@NonNull
@@ -610,7 +632,12 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
? null : mUiCredentialEntries.get(entryKey).first;
}
public void updateAuthEntryWithNoCredentialsReceived(String entryKey) {
public void updateAuthEntryWithNoCredentialsReceived(@Nullable String entryKey) {
if (entryKey == null) {
// Auth entry from a different provider was selected by the user.
updatePreviousMostRecentAuthEntry();
return;
}
updatePreviousMostRecentAuthEntry();
updateMostRecentAuthEntry(entryKey);
}

View File

@@ -66,7 +66,8 @@ public abstract class ProviderSession<T, R>
* on the credMan UI.
*/
public static boolean isUiInvokingStatus(Status status) {
return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED;
return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED
|| status == Status.NO_CREDENTIALS_FROM_AUTH_ENTRY;
}
/**
@@ -140,7 +141,7 @@ public abstract class ProviderSession<T, R>
PENDING_INTENT_INVOKED,
CREDENTIAL_RECEIVED_FROM_SELECTION,
SAVE_ENTRIES_RECEIVED, CANCELED,
NO_CREDENTIALS, EMPTY_RESPONSE, COMPLETE
NO_CREDENTIALS, EMPTY_RESPONSE, NO_CREDENTIALS_FROM_AUTH_ENTRY, COMPLETE
}
/** Converts exception to a provider session status. */

View File

@@ -216,7 +216,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
* Returns true if at least one provider is ready for UI invocation, and no
* provider is pending a response.
*/
boolean isUiInvocationNeeded() {
protected boolean isUiInvocationNeeded() {
for (ProviderSession session : mProviders.values()) {
if (ProviderSession.isUiInvokingStatus(session.getStatus())) {
return true;