diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java index b746784492a32..f48fc2c37aff5 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -16,6 +16,7 @@ package com.android.server.credentials; +import android.Manifest; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.ComponentName; @@ -28,17 +29,20 @@ import android.credentials.GetCredentialResponse; import android.credentials.IGetCredentialCallback; import android.credentials.IPrepareGetCredentialCallback; import android.credentials.PrepareGetCredentialResponseInternal; +import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderData; import android.credentials.ui.RequestInfo; import android.os.CancellationSignal; import android.os.RemoteException; import android.service.credentials.CallingAppInfo; +import android.service.credentials.PermissionUtils; import android.util.Log; import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ProviderStatusForMetrics; import java.util.ArrayList; +import java.util.Set; import java.util.stream.Collectors; /** @@ -222,32 +226,33 @@ public class PrepareGetRequestSession extends RequestSession providerData = getProviderDataForUi(); + if (!providerData.isEmpty()) { + constructPendingResponseAndInvokeCallback(hasQueryCandidatePermission, + getCredentialResultTypes(hasQueryCandidatePermission), + hasAuthenticationResults(providerData, hasQueryCandidatePermission), + hasRemoteResults(providerData, hasQueryCandidatePermission), + getUiIntent()); + } else { + constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission); } - mIsInitialQuery = false; } else { - getProviderDataAndInitiateUi(); + constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission); } + mIsInitialQuery = false; } else { - if (mIsInitialQuery) { - try { - mPrepareGetCredentialCallback.onResponse( - new PrepareGetCredentialResponseInternal( - false, null, false, false, null)); - } catch (Exception e) { - Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); - } - mIsInitialQuery = false; - // TODO(273308895): should also clear session here + // Not the first time. This could be a result of a user selection leading to a UI + // invocation again. + if (isUiInvocationNeeded()) { + getProviderDataAndInitiateUi(); } else { respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL, "No credentials available"); @@ -256,6 +261,68 @@ public class PrepareGetRequestSession extends RequestSession credentialTypes, + boolean hasAuthenticationResults, boolean hasRemoteResults, PendingIntent uiIntent) { + try { + mPrepareGetCredentialCallback.onResponse( + new PrepareGetCredentialResponseInternal( + hasPermission, + credentialTypes, hasAuthenticationResults, hasRemoteResults, uiIntent)); + } catch (RemoteException e) { + Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); + } + } + + private void constructEmptyPendingResponseAndInvokeCallback( + boolean hasQueryCandidatePermission) { + try { + mPrepareGetCredentialCallback.onResponse( + new PrepareGetCredentialResponseInternal( + hasQueryCandidatePermission, + /*credentialResultTypes=*/ null, + /*hasAuthenticationResults=*/false, + /*hasRemoteResults=*/ false, + /*pendingIntent=*/ null)); + } catch (RemoteException e) { + Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e); + } + } + + private boolean hasRemoteResults(ArrayList providerData, + boolean hasQueryCandidatePermission) { + if (!hasQueryCandidatePermission) { + return false; + } + return providerData.stream() + .map(data -> (GetCredentialProviderData) data) + .anyMatch(getCredentialProviderData -> + getCredentialProviderData.getRemoteEntry() != null); + } + + private boolean hasAuthenticationResults(ArrayList providerData, + boolean hasQueryCandidatePermission) { + if (!hasQueryCandidatePermission) { + return false; + } + return providerData.stream() + .map(data -> (GetCredentialProviderData) data) + .anyMatch(getCredentialProviderData -> + !getCredentialProviderData.getAuthenticationEntries().isEmpty()); + } + + @Nullable + private Set getCredentialResultTypes(boolean hasQueryCandidatePermission) { + if (!hasQueryCandidatePermission) { + return null; + } + return mProviders.values().stream() + .map(session -> (ProviderGetSession) session) + .flatMap(providerGetSession -> providerGetSession + .getCredentialEntryTypes().stream()) + .collect(Collectors.toSet()); + } + private PendingIntent getUiIntent() { ArrayList providerDataList = new ArrayList<>(); for (ProviderSession session : mProviders.values()) { diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index fcc0904922dbe..7d3c86b3ad127 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -47,9 +47,11 @@ import com.android.server.credentials.metrics.EntryEnum; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; /** @@ -338,6 +340,11 @@ public final class ProviderGetSession extends ProviderSession getCredentialEntryTypes() { + return mProviderResponseDataHandler.getCredentialEntryTypes(); + } + @Override // Call from request session to data to be shown on the UI @Nullable protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException { @@ -575,6 +582,9 @@ public final class ProviderGetSession extends ProviderSession> mUiAuthenticationEntries = new HashMap<>(); + @NonNull + private final Set mCredentialEntryTypes = new HashSet<>(); + @Nullable private Pair> mUiRemoteEntry = null; @@ -607,6 +617,7 @@ public final class ProviderGetSession extends ProviderSession(credentialEntry, entry)); + mCredentialEntryTypes.add(credentialEntry.getType()); } public void addAction(Action action) { @@ -703,6 +714,11 @@ public final class ProviderGetSession extends ProviderSession getCredentialEntryTypes() { + return mCredentialEntryTypes; + } + @Nullable public Action getAuthenticationAction(String entryKey) { return mUiAuthenticationEntries.get(entryKey) == null ? null : diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index 0aa080b3c7e6f..d4ad65e5b5671 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -236,16 +236,26 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan } void getProviderDataAndInitiateUi() { + ArrayList providerDataList = getProviderDataForUi(); + if (!providerDataList.isEmpty()) { + Log.i(TAG, "provider list not empty about to initiate ui"); + MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); + launchUiWithProviderData(providerDataList); + } + } + + @NonNull + protected ArrayList getProviderDataForUi() { Log.i(TAG, "In getProviderDataAndInitiateUi"); Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size()); + ArrayList providerDataList = new ArrayList<>(); if (isSessionCancelled()) { MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); finishSession(/*propagateCancellation=*/true); - return; + return providerDataList; } - ArrayList providerDataList = new ArrayList<>(); for (ProviderSession session : mProviders.values()) { Log.i(TAG, "preparing data for : " + session.getComponentName()); ProviderData providerData = session.prepareUiData(); @@ -254,11 +264,7 @@ abstract class RequestSession implements CredentialManagerUi.CredentialMan providerDataList.add(providerData); } } - if (!providerDataList.isEmpty()) { - Log.i(TAG, "provider list not empty about to initiate ui"); - MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter); - launchUiWithProviderData(providerDataList); - } + return providerDataList; } protected void collectFinalPhaseMetricStatus(boolean hasException,