Loading core/java/android/credentials/GetCandidateCredentialsResponse.java +9 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,15 @@ public final class GetCandidateCredentialsResponse implements Parcelable { mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); } /** * Returns candidate provider data list. * * @hide */ public List<GetCredentialProviderData> getCandidateProviderDataList() { return mCandidateProviderDataList; } protected GetCandidateCredentialsResponse(Parcel in) { List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); Loading core/java/android/service/credentials/CredentialProviderService.java +12 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,18 @@ public abstract class CredentialProviderService extends Service { public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST"; /** * The key to autofillId associated with the requested credential option and the corresponding * credential entry. The associated autofillId will be contained inside the candidate query * bundle of {@link android.credentials.CredentialOption} if requested through the * {@link com.android.credentialmanager.autofill.CredentialAutofillService}. The resulting * credential entry will contain the autofillId inside its framework extras intent. * * @hide */ public static final String EXTRA_AUTOFILL_ID = "android.service.credentials.extra.AUTOFILL_ID"; private static final String TAG = "CredProviderService"; /** Loading packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +29 −18 Original line number Diff line number Diff line Loading @@ -18,21 +18,23 @@ package com.android.credentialmanager.autofill import android.app.assist.AssistStructure import android.content.Context import android.credentials.GetCredentialRequest import android.credentials.CredentialManager import android.credentials.GetCandidateCredentialsResponse import android.credentials.CredentialOption import android.credentials.GetCandidateCredentialsException import android.credentials.GetCandidateCredentialsResponse import android.credentials.GetCredentialRequest import android.os.Bundle import android.os.CancellationSignal import android.os.OutcomeReceiver import android.service.autofill.FillRequest import android.service.autofill.AutofillService import android.service.autofill.FillResponse import android.service.autofill.FillCallback import android.service.autofill.SaveRequest import android.service.autofill.FillRequest import android.service.autofill.FillResponse import android.service.autofill.SaveCallback import android.service.autofill.SaveRequest import android.service.credentials.CredentialProviderService import android.util.Log import android.view.autofill.AutofillId import org.json.JSONObject import java.util.concurrent.Executors Loading Loading @@ -129,27 +131,31 @@ class CredentialAutofillService : AutofillService() { } private fun traverseNode( viewNode: AssistStructure.ViewNode?, viewNode: AssistStructure.ViewNode, cmRequests: MutableList<CredentialOption> ) { val options = getCredentialOptionsFromViewNode(viewNode) viewNode.autofillId?.let { val options = getCredentialOptionsFromViewNode(viewNode, it) cmRequests.addAll(options) } val children: List<AssistStructure.ViewNode>? = viewNode?.run { val children: List<AssistStructure.ViewNode> = viewNode.run { (0 until childCount).map { getChildAt(it) } } children?.forEach { childNode: AssistStructure.ViewNode -> children.forEach { childNode: AssistStructure.ViewNode -> traverseNode(childNode, cmRequests) } } private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?): List<CredentialOption> { private fun getCredentialOptionsFromViewNode( viewNode: AssistStructure.ViewNode, autofillId: AutofillId ): List<CredentialOption> { // TODO(b/293945193) Replace with isCredential check from viewNode val credentialHints: MutableList<String> = mutableListOf() if (viewNode != null && viewNode.autofillHints != null) { if (viewNode.autofillHints != null) { for (hint in viewNode.autofillHints!!) { if (hint.startsWith(CRED_HINT_PREFIX)) { credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX)) Loading @@ -159,12 +165,14 @@ class CredentialAutofillService : AutofillService() { val credentialOptions: MutableList<CredentialOption> = mutableListOf() for (credentialHint in credentialHints) { convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) } convertJsonToCredentialOption(credentialHint, autofillId) .let { credentialOptions.addAll(it) } } return credentialOptions } private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> { private fun convertJsonToCredentialOption(jsonString: String, autofillId: AutofillId): List<CredentialOption> { // TODO(b/302000646) Move this logic to jetpack so that is consistent // with building the json val credentialOptions: MutableList<CredentialOption> = mutableListOf() Loading @@ -173,11 +181,14 @@ class CredentialAutofillService : AutofillService() { val options = json.getJSONArray(CRED_OPTIONS_KEY) for (i in 0 until options.length()) { val option = options.getJSONObject(i) val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)) candidateBundle.putParcelable( CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId) credentialOptions.add(CredentialOption( option.getString(TYPE_KEY), convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)), convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)), candidateBundle, option.getBoolean(SYS_PROVIDER_REQ_KEY), )) } Loading services/credentials/java/com/android/server/credentials/ProviderGetSession.java +16 −4 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.os.ICancellationSignal; import android.service.autofill.Flags; import android.service.credentials.Action; import android.service.credentials.BeginGetCredentialOption; import android.service.credentials.BeginGetCredentialRequest; Loading @@ -42,6 +43,7 @@ import android.service.credentials.GetCredentialRequest; import android.service.credentials.RemoteEntry; import android.util.Pair; import android.util.Slog; import android.view.autofill.AutofillId; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -379,13 +381,23 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential // but does not resolve to a valid option. For now, not skipping it because // it may be possible that the provider adds their own extras and expects to receive // those and complete the flow. if (mBeginGetOptionToCredentialOptionMap.get(id) == null) { Intent intent = new Intent(); CredentialOption credentialOption = mBeginGetOptionToCredentialOptionMap.get(id); if (credentialOption == null) { Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option"); return new Intent(); return intent; } return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, AutofillId autofillId = credentialOption .getCandidateQueryData() .getParcelable(CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); if (autofillId != null && Flags.autofillCredmanIntegration()) { intent.putExtra(CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId); } return intent.putExtra( CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, new GetCredentialRequest( mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id)))); mCallingAppInfo, List.of(credentialOption))); } private Intent setUpFillInIntentWithQueryRequest() { Loading Loading
core/java/android/credentials/GetCandidateCredentialsResponse.java +9 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,15 @@ public final class GetCandidateCredentialsResponse implements Parcelable { mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); } /** * Returns candidate provider data list. * * @hide */ public List<GetCredentialProviderData> getCandidateProviderDataList() { return mCandidateProviderDataList; } protected GetCandidateCredentialsResponse(Parcel in) { List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); in.readTypedList(candidateProviderDataList, GetCredentialProviderData.CREATOR); Loading
core/java/android/service/credentials/CredentialProviderService.java +12 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,18 @@ public abstract class CredentialProviderService extends Service { public static final String EXTRA_BEGIN_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.BEGIN_GET_CREDENTIAL_REQUEST"; /** * The key to autofillId associated with the requested credential option and the corresponding * credential entry. The associated autofillId will be contained inside the candidate query * bundle of {@link android.credentials.CredentialOption} if requested through the * {@link com.android.credentialmanager.autofill.CredentialAutofillService}. The resulting * credential entry will contain the autofillId inside its framework extras intent. * * @hide */ public static final String EXTRA_AUTOFILL_ID = "android.service.credentials.extra.AUTOFILL_ID"; private static final String TAG = "CredProviderService"; /** Loading
packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +29 −18 Original line number Diff line number Diff line Loading @@ -18,21 +18,23 @@ package com.android.credentialmanager.autofill import android.app.assist.AssistStructure import android.content.Context import android.credentials.GetCredentialRequest import android.credentials.CredentialManager import android.credentials.GetCandidateCredentialsResponse import android.credentials.CredentialOption import android.credentials.GetCandidateCredentialsException import android.credentials.GetCandidateCredentialsResponse import android.credentials.GetCredentialRequest import android.os.Bundle import android.os.CancellationSignal import android.os.OutcomeReceiver import android.service.autofill.FillRequest import android.service.autofill.AutofillService import android.service.autofill.FillResponse import android.service.autofill.FillCallback import android.service.autofill.SaveRequest import android.service.autofill.FillRequest import android.service.autofill.FillResponse import android.service.autofill.SaveCallback import android.service.autofill.SaveRequest import android.service.credentials.CredentialProviderService import android.util.Log import android.view.autofill.AutofillId import org.json.JSONObject import java.util.concurrent.Executors Loading Loading @@ -129,27 +131,31 @@ class CredentialAutofillService : AutofillService() { } private fun traverseNode( viewNode: AssistStructure.ViewNode?, viewNode: AssistStructure.ViewNode, cmRequests: MutableList<CredentialOption> ) { val options = getCredentialOptionsFromViewNode(viewNode) viewNode.autofillId?.let { val options = getCredentialOptionsFromViewNode(viewNode, it) cmRequests.addAll(options) } val children: List<AssistStructure.ViewNode>? = viewNode?.run { val children: List<AssistStructure.ViewNode> = viewNode.run { (0 until childCount).map { getChildAt(it) } } children?.forEach { childNode: AssistStructure.ViewNode -> children.forEach { childNode: AssistStructure.ViewNode -> traverseNode(childNode, cmRequests) } } private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?): List<CredentialOption> { private fun getCredentialOptionsFromViewNode( viewNode: AssistStructure.ViewNode, autofillId: AutofillId ): List<CredentialOption> { // TODO(b/293945193) Replace with isCredential check from viewNode val credentialHints: MutableList<String> = mutableListOf() if (viewNode != null && viewNode.autofillHints != null) { if (viewNode.autofillHints != null) { for (hint in viewNode.autofillHints!!) { if (hint.startsWith(CRED_HINT_PREFIX)) { credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX)) Loading @@ -159,12 +165,14 @@ class CredentialAutofillService : AutofillService() { val credentialOptions: MutableList<CredentialOption> = mutableListOf() for (credentialHint in credentialHints) { convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) } convertJsonToCredentialOption(credentialHint, autofillId) .let { credentialOptions.addAll(it) } } return credentialOptions } private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> { private fun convertJsonToCredentialOption(jsonString: String, autofillId: AutofillId): List<CredentialOption> { // TODO(b/302000646) Move this logic to jetpack so that is consistent // with building the json val credentialOptions: MutableList<CredentialOption> = mutableListOf() Loading @@ -173,11 +181,14 @@ class CredentialAutofillService : AutofillService() { val options = json.getJSONArray(CRED_OPTIONS_KEY) for (i in 0 until options.length()) { val option = options.getJSONObject(i) val candidateBundle = convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)) candidateBundle.putParcelable( CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId) credentialOptions.add(CredentialOption( option.getString(TYPE_KEY), convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)), convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)), candidateBundle, option.getBoolean(SYS_PROVIDER_REQ_KEY), )) } Loading
services/credentials/java/com/android/server/credentials/ProviderGetSession.java +16 −4 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.os.ICancellationSignal; import android.service.autofill.Flags; import android.service.credentials.Action; import android.service.credentials.BeginGetCredentialOption; import android.service.credentials.BeginGetCredentialRequest; Loading @@ -42,6 +43,7 @@ import android.service.credentials.GetCredentialRequest; import android.service.credentials.RemoteEntry; import android.util.Pair; import android.util.Slog; import android.view.autofill.AutofillId; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -379,13 +381,23 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential // but does not resolve to a valid option. For now, not skipping it because // it may be possible that the provider adds their own extras and expects to receive // those and complete the flow. if (mBeginGetOptionToCredentialOptionMap.get(id) == null) { Intent intent = new Intent(); CredentialOption credentialOption = mBeginGetOptionToCredentialOptionMap.get(id); if (credentialOption == null) { Slog.w(TAG, "Id from Credential Entry does not resolve to a valid option"); return new Intent(); return intent; } return new Intent().putExtra(CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, AutofillId autofillId = credentialOption .getCandidateQueryData() .getParcelable(CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); if (autofillId != null && Flags.autofillCredmanIntegration()) { intent.putExtra(CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId); } return intent.putExtra( CredentialProviderService.EXTRA_GET_CREDENTIAL_REQUEST, new GetCredentialRequest( mCallingAppInfo, List.of(mBeginGetOptionToCredentialOptionMap.get(id)))); mCallingAppInfo, List.of(credentialOption))); } private Intent setUpFillInIntentWithQueryRequest() { Loading