diff options
19 files changed, 564 insertions, 200 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c1c4c92237db..657bfef4c533 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39472,6 +39472,40 @@ package android.service.credentials { method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.CreateEntry); } + public final class BeginGetCredentialOption implements android.os.Parcelable { + ctor public BeginGetCredentialOption(@NonNull String, @NonNull android.os.Bundle); + method public int describeContents(); + method @NonNull public android.os.Bundle getCandidateQueryData(); + method @NonNull public String getType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialOption> CREATOR; + } + + public final class BeginGetCredentialsRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.service.credentials.BeginGetCredentialOption> getBeginGetCredentialOptions(); + method @NonNull public String getCallingPackage(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialsRequest> CREATOR; + } + + public static final class BeginGetCredentialsRequest.Builder { + ctor public BeginGetCredentialsRequest.Builder(@NonNull String); + method @NonNull public android.service.credentials.BeginGetCredentialsRequest.Builder addBeginGetCredentialOption(@NonNull android.service.credentials.BeginGetCredentialOption); + method @NonNull public android.service.credentials.BeginGetCredentialsRequest build(); + method @NonNull public android.service.credentials.BeginGetCredentialsRequest.Builder setBeginGetCredentialOptions(@NonNull java.util.List<android.service.credentials.BeginGetCredentialOption>); + } + + public final class BeginGetCredentialsResponse implements android.os.Parcelable { + method @NonNull public static android.service.credentials.BeginGetCredentialsResponse createWithAuthentication(@NonNull android.service.credentials.Action); + method @NonNull public static android.service.credentials.BeginGetCredentialsResponse createWithResponseContent(@NonNull android.service.credentials.CredentialsResponseContent); + method public int describeContents(); + method @Nullable public android.service.credentials.Action getAuthenticationAction(); + method @Nullable public android.service.credentials.CredentialsResponseContent getCredentialsResponseContent(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginGetCredentialsResponse> CREATOR; + } + public final class CreateCredentialRequest implements android.os.Parcelable { ctor public CreateCredentialRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle); method public int describeContents(); @@ -39493,8 +39527,7 @@ package android.service.credentials { public final class CredentialEntry implements android.os.Parcelable { method public int describeContents(); - method @Nullable public android.credentials.Credential getCredential(); - method @Nullable public android.app.PendingIntent getPendingIntent(); + method @NonNull public android.app.PendingIntent getPendingIntent(); method @NonNull public android.app.slice.Slice getSlice(); method @NonNull public String getType(); method public boolean isAutoSelectAllowed(); @@ -39504,7 +39537,6 @@ package android.service.credentials { public static final class CredentialEntry.Builder { ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent); - ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.credentials.Credential); method @NonNull public android.service.credentials.CredentialEntry build(); method @NonNull public android.service.credentials.CredentialEntry.Builder setAutoSelectAllowed(@NonNull boolean); } @@ -39521,14 +39553,16 @@ package android.service.credentials { public abstract class CredentialProviderService extends android.app.Service { ctor public CredentialProviderService(); method public abstract void onBeginCreateCredential(@NonNull android.service.credentials.BeginCreateCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.service.credentials.CredentialProviderException>); + method public abstract void onBeginGetCredentials(@NonNull android.service.credentials.BeginGetCredentialsRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialsResponse,android.service.credentials.CredentialProviderException>); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); - method public abstract void onGetCredentials(@NonNull android.service.credentials.GetCredentialsRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.GetCredentialsResponse,android.service.credentials.CredentialProviderException>); field public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities"; + field public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION"; field public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST"; - field public static final String EXTRA_CREATE_CREDENTIAL_RESULT = "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT"; - field public static final String EXTRA_CREDENTIAL_RESULT = "android.service.credentials.extra.CREDENTIAL_RESULT"; - field public static final String EXTRA_ERROR = "android.service.credentials.extra.ERROR"; - field public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT = "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT"; + field public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE = "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE"; + field public static final String EXTRA_CREDENTIALS_RESPONSE_CONTENT = "android.service.credentials.extra.CREDENTIALS_RESPONSE_CONTENT"; + field public static final String EXTRA_GET_CREDENTIAL_EXCEPTION = "android.service.credentials.extra.GET_CREDENTIAL_EXCEPTION"; + field public static final String EXTRA_GET_CREDENTIAL_REQUEST = "android.service.credentials.extra.GET_CREDENTIAL_REQUEST"; + field public static final String EXTRA_GET_CREDENTIAL_RESPONSE = "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE"; field public static final String SERVICE_INTERFACE = "android.service.credentials.CredentialProviderService"; } @@ -39551,29 +39585,19 @@ package android.service.credentials { method @NonNull public android.service.credentials.CredentialsResponseContent.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.CredentialEntry); } - public final class GetCredentialsRequest implements android.os.Parcelable { + public final class GetCredentialRequest implements android.os.Parcelable { method public int describeContents(); method @NonNull public String getCallingPackage(); method @NonNull public java.util.List<android.credentials.GetCredentialOption> getGetCredentialOptions(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsRequest> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialRequest> CREATOR; } - public static final class GetCredentialsRequest.Builder { - ctor public GetCredentialsRequest.Builder(@NonNull String); - method @NonNull public android.service.credentials.GetCredentialsRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption); - method @NonNull public android.service.credentials.GetCredentialsRequest build(); - method @NonNull public android.service.credentials.GetCredentialsRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>); - } - - public final class GetCredentialsResponse implements android.os.Parcelable { - method @NonNull public static android.service.credentials.GetCredentialsResponse createWithAuthentication(@NonNull android.service.credentials.Action); - method @NonNull public static android.service.credentials.GetCredentialsResponse createWithResponseContent(@NonNull android.service.credentials.CredentialsResponseContent); - method public int describeContents(); - method @Nullable public android.service.credentials.Action getAuthenticationAction(); - method @Nullable public android.service.credentials.CredentialsResponseContent getCredentialsResponseContent(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsResponse> CREATOR; + public static final class GetCredentialRequest.Builder { + ctor public GetCredentialRequest.Builder(@NonNull String); + method @NonNull public android.service.credentials.GetCredentialRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption); + method @NonNull public android.service.credentials.GetCredentialRequest build(); + method @NonNull public android.service.credentials.GetCredentialRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>); } } diff --git a/core/java/android/service/credentials/Action.java b/core/java/android/service/credentials/Action.java index 77570813e6c3..42dd52840575 100644 --- a/core/java/android/service/credentials/Action.java +++ b/core/java/android/service/credentials/Action.java @@ -42,7 +42,7 @@ public final class Action implements Parcelable { * level authentication before displaying any content etc. * * <p> See details on usage of {@code Action} for various actionable entries in - * {@link BeginCreateCredentialResponse} and {@link GetCredentialsResponse}. + * {@link BeginCreateCredentialResponse} and {@link BeginGetCredentialsResponse}. * * @param slice the display content to be displayed on the UI, along with this action * @param pendingIntent the intent to be invoked when the user selects this action diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java index 022678ea49bd..8ca3a1a2ec99 100644 --- a/core/java/android/service/credentials/BeginCreateCredentialResponse.java +++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java @@ -127,7 +127,7 @@ public final class BeginCreateCredentialResponse implements Parcelable { * * <p> Once the remote credential flow is complete, the {@link android.app.Activity} * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the - * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESULT} key should be populated + * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} key should be populated * with a {@link android.credentials.CreateCredentialResponse} object. */ public @NonNull Builder setRemoteCreateEntry(@Nullable CreateEntry remoteCreateEntry) { diff --git a/core/java/android/service/credentials/BeginGetCredentialOption.java b/core/java/android/service/credentials/BeginGetCredentialOption.java new file mode 100644 index 000000000000..c82b445d19e0 --- /dev/null +++ b/core/java/android/service/credentials/BeginGetCredentialOption.java @@ -0,0 +1,129 @@ +/* + * Copyright 2022 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 android.service.credentials; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; +import com.android.internal.util.Preconditions; + +/** + * A specific type of credential request to be sent to the provider during the query phase of + * a get flow. This request contains limited parameters needed to populate a list of + * {@link CredentialEntry} on the {@link BeginGetCredentialsResponse}. + */ +public final class BeginGetCredentialOption implements Parcelable { + + /** + * The requested credential type. + */ + @NonNull + private final String mType; + + /** + * The request candidateQueryData. + */ + @NonNull + private final Bundle mCandidateQueryData; + + /** + * Returns the requested credential type. + */ + @NonNull + public String getType() { + return mType; + } + + /** + * Returns the request candidate query data, denoting a set of parameters + * that can be used to populate a candidate list of credentials, as + * {@link CredentialEntry} on {@link BeginGetCredentialsResponse}. This list + * of entries is then presented to the user on a selector. + * + * <p>This data does not contain any sensitive parameters, and will be sent + * to all eligible providers. + * The complete set of parameters will only be set on the {@link android.app.PendingIntent} + * set on the {@link CredentialEntry} that is selected by the user. + */ + @NonNull + public Bundle getCandidateQueryData() { + return mCandidateQueryData; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mType); + dest.writeBundle(mCandidateQueryData); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "GetCredentialOption {" + + "type=" + mType + + ", candidateQueryData=" + mCandidateQueryData + + "}"; + } + + /** + * Constructs a {@link BeginGetCredentialOption}. + * + * @param type the requested credential type + * @param candidateQueryData the request candidateQueryData + * + * @throws IllegalArgumentException If type is empty. + */ + public BeginGetCredentialOption( + @NonNull String type, + @NonNull Bundle candidateQueryData) { + mType = Preconditions.checkStringNotEmpty(type, "type must not be empty"); + mCandidateQueryData = requireNonNull( + candidateQueryData, "candidateQueryData must not be null"); + } + + private BeginGetCredentialOption(@NonNull Parcel in) { + String type = in.readString8(); + Bundle candidateQueryData = in.readBundle(); + + mType = type; + AnnotationValidations.validate(NonNull.class, null, mType); + mCandidateQueryData = candidateQueryData; + AnnotationValidations.validate(NonNull.class, null, mCandidateQueryData); + } + + public static final @NonNull Creator<BeginGetCredentialOption> CREATOR = + new Creator<BeginGetCredentialOption>() { + @Override + public BeginGetCredentialOption[] newArray(int size) { + return new BeginGetCredentialOption[size]; + } + + @Override + public BeginGetCredentialOption createFromParcel(@NonNull Parcel in) { + return new BeginGetCredentialOption(in); + } + }; +} diff --git a/core/java/android/service/credentials/GetCredentialsRequest.aidl b/core/java/android/service/credentials/BeginGetCredentialsRequest.aidl index b309d698e7de..5e1fe8abc2aa 100644 --- a/core/java/android/service/credentials/GetCredentialsRequest.aidl +++ b/core/java/android/service/credentials/BeginGetCredentialsRequest.aidl @@ -1,3 +1,3 @@ package android.service.credentials; -parcelable GetCredentialsRequest;
\ No newline at end of file +parcelable BeginGetCredentialsRequest;
\ No newline at end of file diff --git a/core/java/android/service/credentials/BeginGetCredentialsRequest.java b/core/java/android/service/credentials/BeginGetCredentialsRequest.java new file mode 100644 index 000000000000..795840b42f2a --- /dev/null +++ b/core/java/android/service/credentials/BeginGetCredentialsRequest.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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 android.service.credentials; + +import android.annotation.NonNull; +import android.app.PendingIntent; +import android.content.Intent; +import android.credentials.GetCredentialOption; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Query stage request for getting user's credentials from a given credential provider. + * + * <p>This request contains a list of {@link GetCredentialOption} that have parameters + * to be used to query credentials, and return a list of {@link CredentialEntry} to be set + * on the {@link BeginGetCredentialsResponse}. This list is then shown to the user on a selector. + * + * If a {@link PendingIntent} is set on a {@link CredentialEntry}, and the user selects that + * entry, a {@link GetCredentialRequest} with all parameters needed to get the actual + * {@link android.credentials.Credential} will be sent as part of the {@link Intent} fired + * through the {@link PendingIntent}. + */ +public final class BeginGetCredentialsRequest implements Parcelable { + /** Calling package of the app requesting for credentials. */ + @NonNull private final String mCallingPackage; + + /** + * List of credential options. Each {@link BeginGetCredentialOption} object holds parameters to + * be used for populating a list of {@link CredentialEntry} for a specific type of credential. + * + * This request does not reveal sensitive parameters. Complete list of parameters + * is retrieved through the {@link PendingIntent} set on each {@link CredentialEntry} + * on {@link CredentialsResponseContent} set on {@link BeginGetCredentialsResponse}, + * when the user selects one of these entries. + */ + @NonNull private final List<BeginGetCredentialOption> mBeginGetCredentialOptions; + + private BeginGetCredentialsRequest(@NonNull String callingPackage, + @NonNull List<BeginGetCredentialOption> getBeginCredentialOptions) { + this.mCallingPackage = callingPackage; + this.mBeginGetCredentialOptions = getBeginCredentialOptions; + } + + private BeginGetCredentialsRequest(@NonNull Parcel in) { + mCallingPackage = in.readString8(); + List<BeginGetCredentialOption> getBeginCredentialOptions = new ArrayList<>(); + in.readTypedList(getBeginCredentialOptions, BeginGetCredentialOption.CREATOR); + mBeginGetCredentialOptions = getBeginCredentialOptions; + AnnotationValidations.validate(NonNull.class, null, mBeginGetCredentialOptions); + } + + public static final @NonNull Creator<BeginGetCredentialsRequest> CREATOR = + new Creator<BeginGetCredentialsRequest>() { + @Override + public BeginGetCredentialsRequest createFromParcel(Parcel in) { + return new BeginGetCredentialsRequest(in); + } + + @Override + public BeginGetCredentialsRequest[] newArray(int size) { + return new BeginGetCredentialsRequest[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mCallingPackage); + dest.writeTypedList(mBeginGetCredentialOptions); + } + + /** + * Returns the calling package of the app requesting credentials. + */ + public @NonNull String getCallingPackage() { + return mCallingPackage; + } + + /** + * Returns the list of type specific credential options to list credentials for in + * {@link BeginGetCredentialsResponse}. + */ + public @NonNull List<BeginGetCredentialOption> getBeginGetCredentialOptions() { + return mBeginGetCredentialOptions; + } + + /** + * Builder for {@link BeginGetCredentialsRequest}. + */ + public static final class Builder { + private String mCallingPackage; + private List<BeginGetCredentialOption> mBeginGetCredentialOptions = new ArrayList<>(); + + /** + * Creates a new builder. + * @param callingPackage the calling package of the app requesting credentials + * + * @throws IllegalArgumentException If {@code callingPackage} is null or empty. + */ + public Builder(@NonNull String callingPackage) { + mCallingPackage = Preconditions.checkStringNotEmpty(callingPackage); + } + + /** + * Sets the list of credential options. + * + * @throws NullPointerException If {@code getBeginCredentialOptions} itself or any of its + * elements is null. + * @throws IllegalArgumentException If {@code getBeginCredentialOptions} is empty. + */ + public @NonNull Builder setBeginGetCredentialOptions( + @NonNull List<BeginGetCredentialOption> getBeginCredentialOptions) { + Preconditions.checkCollectionNotEmpty(getBeginCredentialOptions, + "getBeginCredentialOptions"); + Preconditions.checkCollectionElementsNotNull(getBeginCredentialOptions, + "getBeginCredentialOptions"); + mBeginGetCredentialOptions = getBeginCredentialOptions; + return this; + } + + /** + * Adds a single {@link BeginGetCredentialOption} object to the list of credential options. + * + * @throws NullPointerException If {@code beginGetCredentialOption} is null. + */ + public @NonNull Builder addBeginGetCredentialOption( + @NonNull BeginGetCredentialOption beginGetCredentialOption) { + Objects.requireNonNull(beginGetCredentialOption, + "beginGetCredentialOption must not be null"); + mBeginGetCredentialOptions.add(beginGetCredentialOption); + return this; + } + + /** + * Builds a new {@link BeginGetCredentialsRequest} instance. + * + * @throws NullPointerException If {@code beginGetCredentialOptions} is null. + * @throws IllegalArgumentException If {@code beginGetCredentialOptions} is empty, or if + * {@code callingPackage} is null or empty. + */ + public @NonNull BeginGetCredentialsRequest build() { + Preconditions.checkStringNotEmpty(mCallingPackage, + "Must set the calling package"); + Preconditions.checkCollectionNotEmpty(mBeginGetCredentialOptions, + "beginGetCredentialOptions"); + return new BeginGetCredentialsRequest(mCallingPackage, mBeginGetCredentialOptions); + } + } +} diff --git a/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl b/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl new file mode 100644 index 000000000000..ca69bcaa866b --- /dev/null +++ b/core/java/android/service/credentials/BeginGetCredentialsResponse.aidl @@ -0,0 +1,3 @@ +package android.service.credentials; + +parcelable BeginGetCredentialsResponse;
\ No newline at end of file diff --git a/core/java/android/service/credentials/GetCredentialsResponse.java b/core/java/android/service/credentials/BeginGetCredentialsResponse.java index 5263141f982a..2cda56067ba8 100644 --- a/core/java/android/service/credentials/GetCredentialsResponse.java +++ b/core/java/android/service/credentials/BeginGetCredentialsResponse.java @@ -27,7 +27,7 @@ import java.util.Objects; * Response from a credential provider, containing credential entries and other associated * data to be shown on the account selector UI. */ -public final class GetCredentialsResponse implements Parcelable { +public final class BeginGetCredentialsResponse implements Parcelable { /** Content to be used for the UI. */ private final @Nullable CredentialsResponseContent mCredentialsResponseContent; @@ -38,14 +38,15 @@ public final class GetCredentialsResponse implements Parcelable { private final @Nullable Action mAuthenticationAction; /** - * Creates a {@link GetCredentialsResponse} instance with an authentication {@link Action} set. - * Providers must use this method when no content can be shown before authentication. + * Creates a {@link BeginGetCredentialsResponse} instance with an authentication + * {@link Action} set. Providers must use this method when no content can be shown + * before authentication. * * <p> When the user selects this {@code authenticationAction}, the system invokes the * corresponding {@code pendingIntent}. Once the authentication flow is complete, * the {@link android.app.Activity} result should be set * to {@link android.app.Activity#RESULT_OK} and the - * {@link CredentialProviderService#EXTRA_GET_CREDENTIALS_CONTENT_RESULT} extra should be set + * {@link CredentialProviderService#EXTRA_CREDENTIALS_RESPONSE_CONTENT} extra should be set * with a fully populated {@link CredentialsResponseContent} object. * the authentication action activity is launched, and the user is authenticated, providers * should create another response with {@link CredentialsResponseContent} using @@ -54,48 +55,49 @@ public final class GetCredentialsResponse implements Parcelable { * * @throws NullPointerException If {@code authenticationAction} is null. */ - public static @NonNull GetCredentialsResponse createWithAuthentication( + public static @NonNull BeginGetCredentialsResponse createWithAuthentication( @NonNull Action authenticationAction) { Objects.requireNonNull(authenticationAction, "authenticationAction must not be null"); - return new GetCredentialsResponse(null, authenticationAction); + return new BeginGetCredentialsResponse(null, authenticationAction); } /** - * Creates a {@link GetCredentialsRequest} instance with content to be shown on the UI. + * Creates a {@link BeginGetCredentialsRequest} instance with content to be shown on the UI. * Providers must use this method when there is content to be shown without top level * authentication required, including credential entries, action entries or a remote entry, * * @throws NullPointerException If {@code credentialsResponseContent} is null. */ - public static @NonNull GetCredentialsResponse createWithResponseContent( + public static @NonNull BeginGetCredentialsResponse createWithResponseContent( @NonNull CredentialsResponseContent credentialsResponseContent) { Objects.requireNonNull(credentialsResponseContent, "credentialsResponseContent must not be null"); - return new GetCredentialsResponse(credentialsResponseContent, null); + return new BeginGetCredentialsResponse(credentialsResponseContent, null); } - private GetCredentialsResponse(@Nullable CredentialsResponseContent credentialsResponseContent, + private BeginGetCredentialsResponse(@Nullable CredentialsResponseContent + credentialsResponseContent, @Nullable Action authenticationAction) { mCredentialsResponseContent = credentialsResponseContent; mAuthenticationAction = authenticationAction; } - private GetCredentialsResponse(@NonNull Parcel in) { + private BeginGetCredentialsResponse(@NonNull Parcel in) { mCredentialsResponseContent = in.readTypedObject(CredentialsResponseContent.CREATOR); mAuthenticationAction = in.readTypedObject(Action.CREATOR); } - public static final @NonNull Creator<GetCredentialsResponse> CREATOR = - new Creator<GetCredentialsResponse>() { + public static final @NonNull Creator<BeginGetCredentialsResponse> CREATOR = + new Creator<BeginGetCredentialsResponse>() { @Override - public GetCredentialsResponse createFromParcel(Parcel in) { - return new GetCredentialsResponse(in); + public BeginGetCredentialsResponse createFromParcel(Parcel in) { + return new BeginGetCredentialsResponse(in); } @Override - public GetCredentialsResponse[] newArray(int size) { - return new GetCredentialsResponse[size]; + public BeginGetCredentialsResponse[] newArray(int size) { + return new BeginGetCredentialsResponse[size]; } }; diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java index 941db02be8d1..3c399d26c2fb 100644 --- a/core/java/android/service/credentials/CredentialEntry.java +++ b/core/java/android/service/credentials/CredentialEntry.java @@ -17,10 +17,9 @@ package android.service.credentials; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.PendingIntent; import android.app.slice.Slice; -import android.credentials.Credential; +import android.credentials.GetCredentialResponse; import android.os.Parcel; import android.os.Parcelable; @@ -41,32 +40,23 @@ public final class CredentialEntry implements Parcelable { private final @NonNull Slice mSlice; /** The pending intent to be invoked when this credential entry is selected. */ - private final @Nullable PendingIntent mPendingIntent; - - /** - * The underlying credential to be returned to the app when the user selects - * this credential entry. - */ - private final @Nullable Credential mCredential; + private final @NonNull PendingIntent mPendingIntent; /** A flag denoting whether auto-select is enabled for this entry. */ private final @NonNull boolean mAutoSelectAllowed; private CredentialEntry(@NonNull String type, @NonNull Slice slice, - @Nullable PendingIntent pendingIntent, @Nullable Credential credential, - @NonNull boolean autoSeletAllowed) { + @NonNull PendingIntent pendingIntent, @NonNull boolean autoSelectAllowed) { mType = type; mSlice = slice; mPendingIntent = pendingIntent; - mCredential = credential; - mAutoSelectAllowed = autoSeletAllowed; + mAutoSelectAllowed = autoSelectAllowed; } private CredentialEntry(@NonNull Parcel in) { mType = in.readString8(); mSlice = in.readTypedObject(Slice.CREATOR); mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); - mCredential = in.readTypedObject(Credential.CREATOR); mAutoSelectAllowed = in.readBoolean(); } @@ -93,7 +83,6 @@ public final class CredentialEntry implements Parcelable { dest.writeString8(mType); dest.writeTypedObject(mSlice, flags); dest.writeTypedObject(mPendingIntent, flags); - dest.writeTypedObject(mCredential, flags); dest.writeBoolean(mAutoSelectAllowed); } @@ -114,18 +103,11 @@ public final class CredentialEntry implements Parcelable { /** * Returns the pending intent to be invoked if the user selects this entry. */ - public @Nullable PendingIntent getPendingIntent() { + public @NonNull PendingIntent getPendingIntent() { return mPendingIntent; } /** - * Returns the credential associated with this entry. - */ - public @Nullable Credential getCredential() { - return mCredential; - } - - /** * Returns whether this entry can be auto selected if it is the only option for the user. */ public boolean isAutoSelectAllowed() { @@ -138,8 +120,7 @@ public final class CredentialEntry implements Parcelable { public static final class Builder { private String mType; private Slice mSlice; - private PendingIntent mPendingIntent = null; - private Credential mCredential = null; + private PendingIntent mPendingIntent; private boolean mAutoSelectAllowed = false; /** @@ -152,8 +133,8 @@ public final class CredentialEntry implements Parcelable { * Once the activity fulfills the required user engagement, the * {@link android.app.Activity} result should be set to * {@link android.app.Activity#RESULT_OK}, and the - * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} must be set with a - * {@link Credential} object. + * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} must be set with a + * {@link GetCredentialResponse} object. * * @param type the type of credential underlying this credential entry * @param slice the content to be displayed with this entry on the UI @@ -179,26 +160,6 @@ public final class CredentialEntry implements Parcelable { } /** - * Creates a builder for a {@link CredentialEntry} that contains a {@link Credential}, - * and does not require further action. - * @param type the type of credential underlying this credential entry - * @param slice the content to be displayed with this entry on the UI - * @param credential the credential to be returned to the client app, when this entry is - * selected by the user - * - * @throws IllegalArgumentException If {@code type} is null or empty. - * @throws NullPointerException If {@code slice}, or {@code credential} is null. - */ - public Builder(@NonNull String type, @NonNull Slice slice, @NonNull Credential credential) { - mType = Preconditions.checkStringNotEmpty(type, "type must not be " - + "null, or empty"); - mSlice = Objects.requireNonNull(slice, - "slice must not be null"); - mCredential = Objects.requireNonNull(credential, - "credential must not be null"); - } - - /** * Sets whether the entry is allowed to be auto selected by the framework. * The default value is set to false. * @@ -219,12 +180,9 @@ public final class CredentialEntry implements Parcelable { * is set, or if both are set. */ public @NonNull CredentialEntry build() { - Preconditions.checkState(((mPendingIntent != null && mCredential == null) - || (mPendingIntent == null && mCredential != null)), - "Either pendingIntent or credential must be set, and both cannot" - + "be set at the same time"); - return new CredentialEntry(mType, mSlice, mPendingIntent, - mCredential, mAutoSelectAllowed); + Preconditions.checkState(mPendingIntent != null, + "pendingIntent must not be null"); + return new CredentialEntry(mType, mSlice, mPendingIntent, mAutoSelectAllowed); } } } diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java index 32646e6fd289..416ddf172616 100644 --- a/core/java/android/service/credentials/CredentialProviderService.java +++ b/core/java/android/service/credentials/CredentialProviderService.java @@ -21,6 +21,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.SdkConstant; +import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.CancellationSignal; @@ -45,12 +46,23 @@ public abstract class CredentialProviderService extends Service { * returned as part of the {@link BeginCreateCredentialResponse} * * <p> - * Type: {@link android.credentials.CreateCredentialRequest} + * Type: {@link android.service.credentials.CreateCredentialRequest} */ public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST"; /** + * Intent extra: The {@link GetCredentialRequest} attached with + * the {@code pendingIntent} that is invoked when the user selects a {@link CredentialEntry} + * returned as part of the {@link BeginGetCredentialsResponse} + * + * <p> + * Type: {@link GetCredentialRequest} + */ + public static final String EXTRA_GET_CREDENTIAL_REQUEST = + "android.service.credentials.extra.GET_CREDENTIAL_REQUEST"; + + /** * Intent extra: The result of a create flow operation, to be set on finish of the * {@link android.app.Activity} invoked through the {@code pendingIntent} set on * a {@link CreateEntry}. @@ -58,8 +70,8 @@ public abstract class CredentialProviderService extends Service { * <p> * Type: {@link android.credentials.CreateCredentialResponse} */ - public static final String EXTRA_CREATE_CREDENTIAL_RESULT = - "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT"; + public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE = + "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE"; /** * Intent extra: The result of a get credential flow operation, to be set on finish of the @@ -67,33 +79,48 @@ public abstract class CredentialProviderService extends Service { * a {@link CredentialEntry}. * * <p> - * Type: {@link android.credentials.Credential} + * Type: {@link android.credentials.GetCredentialResponse} */ - public static final String EXTRA_CREDENTIAL_RESULT = - "android.service.credentials.extra.CREDENTIAL_RESULT"; + public static final String EXTRA_GET_CREDENTIAL_RESPONSE = + "android.service.credentials.extra.GET_CREDENTIAL_RESPONSE"; /** * Intent extra: The result of an authentication flow, to be set on finish of the * {@link android.app.Activity} invoked through the {@link android.app.PendingIntent} set on - * a {@link GetCredentialsResponse}. This result should contain the actual content, including - * credential entries and action entries, to be shown on the selector. + * a {@link BeginGetCredentialsResponse}. This result should contain the actual content, + * including credential entries and action entries, to be shown on the selector. * * <p> * Type: {@link CredentialsResponseContent} */ - public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT = - "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT"; + public static final String EXTRA_CREDENTIALS_RESPONSE_CONTENT = + "android.service.credentials.extra.CREDENTIALS_RESPONSE_CONTENT"; /** - * Intent extra: The error result of any {@link android.app.PendingIntent} flow, to be set - * on finish of the corresponding {@link android.app.Activity}. This result should contain an - * error code, representing the error encountered by the provider. + * Intent extra: The failure exception set at the final stage of a get flow. + * This exception is set at the finishing result of the {@link android.app.Activity} + * invoked by the {@link PendingIntent} , when a user selects the {@link CredentialEntry} + * that contained the {@link PendingIntent} in question. + * + * <p>The result must be set through {@link android.app.Activity#setResult} as an intent extra * * <p> - * Type: {@link String} + * Type: {@link android.credentials.GetCredentialException} */ - public static final String EXTRA_ERROR = - "android.service.credentials.extra.ERROR"; + public static final String EXTRA_GET_CREDENTIAL_EXCEPTION = + "android.service.credentials.extra.GET_CREDENTIAL_EXCEPTION"; + + /** + * Intent extra: The failure exception set at the final stage of a create flow. + * This exception is set at the finishing result of the {@link android.app.Activity} + * invoked by the {@link PendingIntent} , when a user selects the {@link CreateEntry} + * that contained the {@link PendingIntent} in question. + * + * <p> + * Type: {@link android.credentials.CreateCredentialException} + */ + public static final String EXTRA_CREATE_CREDENTIAL_EXCEPTION = + "android.service.credentials.extra.CREATE_CREDENTIAL_EXCEPTION"; private static final String TAG = "CredProviderService"; @@ -128,20 +155,21 @@ public abstract class CredentialProviderService extends Service { private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() { @Override - public ICancellationSignal onGetCredentials(GetCredentialsRequest request, - IGetCredentialsCallback callback) { + public ICancellationSignal onBeginGetCredentials(BeginGetCredentialsRequest request, + IBeginGetCredentialsCallback callback) { Objects.requireNonNull(request); Objects.requireNonNull(callback); ICancellationSignal transport = CancellationSignal.createTransport(); mHandler.sendMessage(obtainMessage( - CredentialProviderService::onGetCredentials, + CredentialProviderService::onBeginGetCredentials, CredentialProviderService.this, request, CancellationSignal.fromTransport(transport), - new OutcomeReceiver<GetCredentialsResponse, CredentialProviderException>() { + new OutcomeReceiver<BeginGetCredentialsResponse, + CredentialProviderException>() { @Override - public void onResult(GetCredentialsResponse result) { + public void onResult(BeginGetCredentialsResponse result) { try { callback.onSuccess(result); } catch (RemoteException e) { @@ -200,14 +228,29 @@ public abstract class CredentialProviderService extends Service { /** * Called by the android system to retrieve user credentials from the connected provider * service. - * @param request the credential request for the provider to handle + * + * + * + * <p>This API denotes a query stage request for getting user's credentials from a given + * credential provider. The request contains a list of + * {@link android.credentials.GetCredentialOption} that have parameters to be used for + * populating candidate credentials, as a list of {@link CredentialEntry} to be set + * on the {@link BeginGetCredentialsResponse}. This list is then shown to the user on a + * selector. + * + * <p>If a {@link PendingIntent} is set on a {@link CredentialEntry}, and the user selects that + * entry, a {@link GetCredentialRequest} with all parameters needed to get the actual + * {@link android.credentials.Credential} will be sent as part of the {@link Intent} fired + * through the {@link PendingIntent}. + * @param request the request for the provider to handle * @param cancellationSignal signal for providers to listen to any cancellation requests from * the android system * @param callback object used to relay the response of the credentials request */ - public abstract void onGetCredentials(@NonNull GetCredentialsRequest request, + public abstract void onBeginGetCredentials(@NonNull BeginGetCredentialsRequest request, @NonNull CancellationSignal cancellationSignal, - @NonNull OutcomeReceiver<GetCredentialsResponse, CredentialProviderException> callback); + @NonNull OutcomeReceiver< + BeginGetCredentialsResponse, CredentialProviderException> callback); /** * Called by the android system to create a credential. diff --git a/core/java/android/service/credentials/CredentialsResponseContent.java b/core/java/android/service/credentials/CredentialsResponseContent.java index 32cab5004ac0..c2f28cb1204c 100644 --- a/core/java/android/service/credentials/CredentialsResponseContent.java +++ b/core/java/android/service/credentials/CredentialsResponseContent.java @@ -29,7 +29,7 @@ import java.util.Objects; /** * The content to be displayed on the account selector UI, including credential entries, - * actions etc. Returned as part of {@link GetCredentialsResponse} + * actions etc. Returned as part of {@link BeginGetCredentialsResponse} */ public final class CredentialsResponseContent implements Parcelable { /** List of credential entries to be displayed on the UI. */ @@ -124,7 +124,7 @@ public final class CredentialsResponseContent implements Parcelable { * * <p> Once the remote credential flow is complete, the {@link android.app.Activity} * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the - * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} key should be populated + * {@link CredentialProviderService#EXTRA_GET_CREDENTIAL_RESPONSE} key should be populated * with a {@link android.credentials.Credential} object. */ public @NonNull Builder setRemoteCredentialEntry(@Nullable CredentialEntry @@ -188,7 +188,7 @@ public final class CredentialsResponseContent implements Parcelable { } /** - * Builds a {@link GetCredentialsResponse} instance. + * Builds a {@link CredentialsResponseContent} instance. * * @throws IllegalStateException if {@code credentialEntries}, {@code actions} * and {@code remoteCredentialEntry} are all null or empty. diff --git a/core/java/android/service/credentials/GetCredentialsRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java index 9052b54c8291..1d6c83be0db1 100644 --- a/core/java/android/service/credentials/GetCredentialsRequest.java +++ b/core/java/android/service/credentials/GetCredentialRequest.java @@ -21,6 +21,7 @@ import android.credentials.GetCredentialOption; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.AnnotationValidations; import com.android.internal.util.Preconditions; import java.util.ArrayList; @@ -30,7 +31,7 @@ import java.util.Objects; /** * Request for getting user's credentials from a given credential provider. */ -public final class GetCredentialsRequest implements Parcelable { +public final class GetCredentialRequest implements Parcelable { /** Calling package of the app requesting for credentials. */ private final @NonNull String mCallingPackage; @@ -40,29 +41,30 @@ public final class GetCredentialsRequest implements Parcelable { */ private final @NonNull List<GetCredentialOption> mGetCredentialOptions; - private GetCredentialsRequest(@NonNull String callingPackage, + private GetCredentialRequest(@NonNull String callingPackage, @NonNull List<GetCredentialOption> getCredentialOptions) { this.mCallingPackage = callingPackage; this.mGetCredentialOptions = getCredentialOptions; } - private GetCredentialsRequest(@NonNull Parcel in) { + private GetCredentialRequest(@NonNull Parcel in) { mCallingPackage = in.readString8(); List<GetCredentialOption> getCredentialOptions = new ArrayList<>(); in.readTypedList(getCredentialOptions, GetCredentialOption.CREATOR); mGetCredentialOptions = getCredentialOptions; + AnnotationValidations.validate(NonNull.class, null, mGetCredentialOptions); } - public static final @NonNull Creator<GetCredentialsRequest> CREATOR = - new Creator<GetCredentialsRequest>() { + public static final @NonNull Creator<GetCredentialRequest> CREATOR = + new Creator<GetCredentialRequest>() { @Override - public GetCredentialsRequest createFromParcel(Parcel in) { - return new GetCredentialsRequest(in); + public GetCredentialRequest createFromParcel(Parcel in) { + return new GetCredentialRequest(in); } @Override - public GetCredentialsRequest[] newArray(int size) { - return new GetCredentialsRequest[size]; + public GetCredentialRequest[] newArray(int size) { + return new GetCredentialRequest[size]; } }; @@ -92,7 +94,7 @@ public final class GetCredentialsRequest implements Parcelable { } /** - * Builder for {@link GetCredentialsRequest}. + * Builder for {@link GetCredentialRequest}. */ public static final class Builder { private String mCallingPackage; @@ -139,18 +141,18 @@ public final class GetCredentialsRequest implements Parcelable { } /** - * Builds a new {@link GetCredentialsRequest} instance. + * Builds a new {@link GetCredentialRequest} instance. * * @throws NullPointerException If {@code getCredentialOptions} is null. * @throws IllegalArgumentException If {@code getCredentialOptions} is empty, or if * {@code callingPackage} is null or empty. */ - public @NonNull GetCredentialsRequest build() { + public @NonNull GetCredentialRequest build() { Preconditions.checkStringNotEmpty(mCallingPackage, "Must set the calling package"); Preconditions.checkCollectionNotEmpty(mGetCredentialOptions, "getCredentialOptions"); - return new GetCredentialsRequest(mCallingPackage, mGetCredentialOptions); + return new GetCredentialRequest(mCallingPackage, mGetCredentialOptions); } } } diff --git a/core/java/android/service/credentials/GetCredentialsResponse.aidl b/core/java/android/service/credentials/GetCredentialsResponse.aidl deleted file mode 100644 index 0d8c6357a715..000000000000 --- a/core/java/android/service/credentials/GetCredentialsResponse.aidl +++ /dev/null @@ -1,3 +0,0 @@ -package android.service.credentials; - -parcelable GetCredentialsResponse;
\ No newline at end of file diff --git a/core/java/android/service/credentials/IGetCredentialsCallback.aidl b/core/java/android/service/credentials/IBeginGetCredentialsCallback.aidl index 6e20c555af60..9ac28f26059b 100644 --- a/core/java/android/service/credentials/IGetCredentialsCallback.aidl +++ b/core/java/android/service/credentials/IBeginGetCredentialsCallback.aidl @@ -1,13 +1,13 @@ package android.service.credentials; -import android.service.credentials.GetCredentialsResponse; +import android.service.credentials.BeginGetCredentialsResponse; /** * Interface from the system to a credential provider service. * * @hide */ -oneway interface IGetCredentialsCallback { - void onSuccess(in GetCredentialsResponse response); +oneway interface IBeginGetCredentialsCallback { + void onSuccess(in BeginGetCredentialsResponse response); void onFailure(int errorCode, in CharSequence message); }
\ No newline at end of file diff --git a/core/java/android/service/credentials/ICredentialProviderService.aidl b/core/java/android/service/credentials/ICredentialProviderService.aidl index b9eb3ed9571a..130688291795 100644 --- a/core/java/android/service/credentials/ICredentialProviderService.aidl +++ b/core/java/android/service/credentials/ICredentialProviderService.aidl @@ -17,9 +17,9 @@ package android.service.credentials; import android.os.ICancellationSignal; -import android.service.credentials.GetCredentialsRequest; +import android.service.credentials.BeginGetCredentialsRequest; import android.service.credentials.BeginCreateCredentialRequest; -import android.service.credentials.IGetCredentialsCallback; +import android.service.credentials.IBeginGetCredentialsCallback; import android.service.credentials.IBeginCreateCredentialCallback; import android.os.ICancellationSignal; @@ -29,6 +29,6 @@ import android.os.ICancellationSignal; * @hide */ interface ICredentialProviderService { - ICancellationSignal onGetCredentials(in GetCredentialsRequest request, in IGetCredentialsCallback callback); + ICancellationSignal onBeginGetCredentials(in BeginGetCredentialsRequest request, in IBeginGetCredentialsCallback callback); ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback); } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index d3b9e10a436a..2f951ed63bb9 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -36,7 +36,7 @@ import android.os.ICancellationSignal; import android.os.UserHandle; import android.provider.Settings; import android.service.credentials.BeginCreateCredentialRequest; -import android.service.credentials.GetCredentialsRequest; +import android.service.credentials.BeginGetCredentialsRequest; import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -169,8 +169,8 @@ public final class CredentialManagerService extends // Iterate over all provider sessions and invoke the request providerSessions.forEach(providerGetSession -> { - providerGetSession.getRemoteCredentialService().onGetCredentials( - (GetCredentialsRequest) providerGetSession.getProviderRequest(), + providerGetSession.getRemoteCredentialService().onBeginGetCredentials( + (BeginGetCredentialsRequest) providerGetSession.getProviderRequest(), /*callback=*/providerGetSession); }); return cancelTransport; diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java index d0bc0744f8a5..7f9e57a5bdb6 100644 --- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java +++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java @@ -19,7 +19,7 @@ package com.android.server.credentials; import android.app.Activity; import android.content.Intent; import android.credentials.CreateCredentialResponse; -import android.credentials.Credential; +import android.credentials.GetCredentialResponse; import android.credentials.ui.ProviderPendingIntentResponse; import android.service.credentials.CredentialProviderService; import android.service.credentials.CredentialsResponseContent; @@ -43,8 +43,7 @@ public class PendingIntentResultHandler { return null; } return resultData.getParcelableExtra( - CredentialProviderService - .EXTRA_GET_CREDENTIALS_CONTENT_RESULT, + CredentialProviderService.EXTRA_CREDENTIALS_RESPONSE_CONTENT, CredentialsResponseContent.class); } @@ -54,17 +53,17 @@ public class PendingIntentResultHandler { return null; } return resultData.getParcelableExtra( - CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESULT, + CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESPONSE, CreateCredentialResponse.class); } - /** Extracts the {@link Credential} object added to the result data. */ - public static Credential extractCredential(Intent resultData) { + /** Extracts the {@link GetCredentialResponse} object added to the result data. */ + public static GetCredentialResponse extractGetCredentialResponse(Intent resultData) { if (resultData == null) { return null; } return resultData.getParcelableExtra( - CredentialProviderService.EXTRA_CREDENTIAL_RESULT, - Credential.class); + CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE, + GetCredentialResponse.class); } } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 6cd011b7a686..9888cc0a3732 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -19,19 +19,23 @@ package com.android.server.credentials; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.PendingIntent; import android.content.Context; -import android.credentials.Credential; +import android.content.Intent; import android.credentials.GetCredentialOption; import android.credentials.GetCredentialResponse; import android.credentials.ui.Entry; import android.credentials.ui.GetCredentialProviderData; import android.credentials.ui.ProviderPendingIntentResponse; import android.service.credentials.Action; +import android.service.credentials.BeginGetCredentialOption; +import android.service.credentials.BeginGetCredentialsRequest; +import android.service.credentials.BeginGetCredentialsResponse; import android.service.credentials.CredentialEntry; import android.service.credentials.CredentialProviderInfo; +import android.service.credentials.CredentialProviderService; import android.service.credentials.CredentialsResponseContent; -import android.service.credentials.GetCredentialsRequest; -import android.service.credentials.GetCredentialsResponse; +import android.service.credentials.GetCredentialRequest; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -41,6 +45,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; /** * Central provider session that listens for provider callbacks, and maintains provider state. @@ -48,10 +53,10 @@ import java.util.UUID; * * @hide */ -public final class ProviderGetSession extends ProviderSession<GetCredentialsRequest, - GetCredentialsResponse> +public final class ProviderGetSession extends ProviderSession<BeginGetCredentialsRequest, + BeginGetCredentialsResponse> implements - RemoteCredentialService.ProviderCallbacks<GetCredentialsResponse> { + RemoteCredentialService.ProviderCallbacks<BeginGetCredentialsResponse> { private static final String TAG = "ProviderGetSession"; // Key to be used as an entry key for a credential entry @@ -69,6 +74,9 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ @Nullable private Pair<String, Action> mUiAuthenticationAction = null; + /** The complete request to be used in the second round. */ + private final GetCredentialRequest mCompleteRequest; + /** Creates a new provider session to be used by the request session. */ @Nullable public static ProviderGetSession createNewSession( Context context, @@ -76,20 +84,34 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ CredentialProviderInfo providerInfo, GetRequestSession getRequestSession, RemoteCredentialService remoteCredentialService) { - GetCredentialsRequest providerRequest = + GetCredentialRequest completeRequest = createProviderRequest(providerInfo.getCapabilities(), getRequestSession.mClientRequest, getRequestSession.mClientCallingPackage); - if (providerRequest != null) { + if (completeRequest != null) { + // TODO: Update to using query data when ready + BeginGetCredentialsRequest beginGetCredentialsRequest = + new BeginGetCredentialsRequest.Builder( + completeRequest.getCallingPackage()) + .setBeginGetCredentialOptions( + completeRequest.getGetCredentialOptions().stream().map( + option -> { + //TODO : Replace with option.getCandidateQueryData + // when ready + return new BeginGetCredentialOption( + option.getType(), + option.getCandidateQueryData()); + }).collect(Collectors.toList())) + .build(); return new ProviderGetSession(context, providerInfo, getRequestSession, userId, - remoteCredentialService, providerRequest); + remoteCredentialService, beginGetCredentialsRequest, completeRequest); } Log.i(TAG, "Unable to create provider session"); return null; } @Nullable - private static GetCredentialsRequest createProviderRequest(List<String> providerCapabilities, + private static GetCredentialRequest createProviderRequest(List<String> providerCapabilities, android.credentials.GetCredentialRequest clientRequest, String clientCallingPackage) { List<GetCredentialOption> filteredOptions = new ArrayList<>(); @@ -104,7 +126,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ } } if (!filteredOptions.isEmpty()) { - return new GetCredentialsRequest.Builder(clientCallingPackage).setGetCredentialOptions( + return new GetCredentialRequest.Builder(clientCallingPackage).setGetCredentialOptions( filteredOptions).build(); } Log.i(TAG, "In createProviderRequest - returning null"); @@ -115,8 +137,10 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ CredentialProviderInfo info, ProviderInternalCallback callbacks, int userId, RemoteCredentialService remoteCredentialService, - GetCredentialsRequest request) { - super(context, info, request, callbacks, userId, remoteCredentialService); + BeginGetCredentialsRequest beginGetRequest, + GetCredentialRequest completeGetRequest) { + super(context, info, beginGetRequest, callbacks, userId, remoteCredentialService); + mCompleteRequest = completeGetRequest; setStatus(Status.PENDING); } @@ -128,7 +152,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ /** Called when the provider response has been updated by an external source. */ @Override // Callback from the remote provider - public void onProviderResponseSuccess(@Nullable GetCredentialsResponse response) { + public void onProviderResponseSuccess(@Nullable BeginGetCredentialsResponse response) { Log.i(TAG, "in onProviderResponseSuccess"); onUpdateResponse(response); } @@ -254,19 +278,26 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ mUiCredentialEntries.put(entryId, credentialEntry); Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId); if (credentialEntry.getPendingIntent() != null) { + setUpFillInIntent(credentialEntry.getPendingIntent()); credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId, credentialEntry.getSlice(), credentialEntry.getPendingIntent(), /*fillInIntent=*/null)); - } else if (credentialEntry.getCredential() != null) { - credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId, - credentialEntry.getSlice())); } else { - Log.i(TAG, "No credential or pending intent. Should not happen."); + Log.i(TAG, "No pending intent. Should not happen."); } } return credentialUiEntries; } + private Intent setUpFillInIntent(PendingIntent pendingIntent) { + Intent intent = pendingIntent.getIntent(); + intent.putExtra( + CredentialProviderService + .EXTRA_GET_CREDENTIAL_REQUEST, + mCompleteRequest); + return intent; + } + private List<Entry> prepareUiActionEntries(@Nullable List<Action> actions) { List<Entry> actionEntries = new ArrayList<>(); for (Action action : actions) { @@ -292,17 +323,14 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ private void onCredentialEntrySelected(CredentialEntry credentialEntry, ProviderPendingIntentResponse providerPendingIntentResponse) { - if (credentialEntry.getCredential() != null) { - mCallbacks.onFinalResponseReceived(mComponentName, new GetCredentialResponse( - credentialEntry.getCredential())); - return; - } else if (providerPendingIntentResponse != null) { + if (providerPendingIntentResponse != null) { if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) { - Credential credential = PendingIntentResultHandler.extractCredential( - providerPendingIntentResponse.getResultData()); - if (credential != null) { - mCallbacks.onFinalResponseReceived(mComponentName, - new GetCredentialResponse(credential)); + // TODO: Remove credential extraction when flow is fully transitioned + GetCredentialResponse getCredentialResponse = PendingIntentResultHandler + .extractGetCredentialResponse( + providerPendingIntentResponse.getResultData()); + if (getCredentialResponse != null) { + mCallbacks.onFinalResponseReceived(mComponentName, getCredentialResponse); return; } } @@ -320,7 +348,8 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ .extractResponseContent(providerPendingIntentResponse .getResultData()); if (content != null) { - onUpdateResponse(GetCredentialsResponse.createWithResponseContent(content)); + onUpdateResponse( + BeginGetCredentialsResponse.createWithResponseContent(content)); return; } } @@ -337,7 +366,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ /** Updates the response being maintained in state by this provider session. */ - private void onUpdateResponse(GetCredentialsResponse response) { + private void onUpdateResponse(BeginGetCredentialsResponse response) { mProviderResponse = response; if (response.getAuthenticationAction() != null) { Log.i(TAG , "updateResponse with authentication entry"); diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index e385bcb32201..7a883b359d9f 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -26,14 +26,14 @@ import android.os.ICancellationSignal; import android.os.RemoteException; import android.service.credentials.BeginCreateCredentialRequest; import android.service.credentials.BeginCreateCredentialResponse; +import android.service.credentials.BeginGetCredentialsRequest; +import android.service.credentials.BeginGetCredentialsResponse; import android.service.credentials.CredentialProviderException; import android.service.credentials.CredentialProviderException.CredentialProviderError; import android.service.credentials.CredentialProviderService; -import android.service.credentials.GetCredentialsRequest; -import android.service.credentials.GetCredentialsResponse; import android.service.credentials.IBeginCreateCredentialCallback; +import android.service.credentials.IBeginGetCredentialsCallback; import android.service.credentials.ICredentialProviderService; -import android.service.credentials.IGetCredentialsCallback; import android.text.format.DateUtils; import android.util.Log; import android.util.Slog; @@ -106,19 +106,21 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr * @param callback the callback to be used to send back the provider response to the * {@link ProviderGetSession} class that maintains provider state */ - public void onGetCredentials(@NonNull GetCredentialsRequest request, - ProviderCallbacks<GetCredentialsResponse> callback) { + public void onBeginGetCredentials(@NonNull BeginGetCredentialsRequest request, + ProviderCallbacks<BeginGetCredentialsResponse> callback) { Log.i(TAG, "In onGetCredentials in RemoteCredentialService"); AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); - AtomicReference<CompletableFuture<GetCredentialsResponse>> futureRef = + AtomicReference<CompletableFuture<BeginGetCredentialsResponse>> futureRef = new AtomicReference<>(); - CompletableFuture<GetCredentialsResponse> connectThenExecute = postAsync(service -> { - CompletableFuture<GetCredentialsResponse> getCredentials = new CompletableFuture<>(); + CompletableFuture<BeginGetCredentialsResponse> connectThenExecute = postAsync(service -> { + CompletableFuture<BeginGetCredentialsResponse> getCredentials = + new CompletableFuture<>(); ICancellationSignal cancellationSignal = - service.onGetCredentials(request, new IGetCredentialsCallback.Stub() { + service.onBeginGetCredentials(request, + new IBeginGetCredentialsCallback.Stub() { @Override - public void onSuccess(GetCredentialsResponse response) { + public void onSuccess(BeginGetCredentialsResponse response) { Log.i(TAG, "In onSuccess in RemoteCredentialService"); getCredentials.complete(response); } @@ -132,7 +134,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr errorCode, errorMsg)); } }); - CompletableFuture<GetCredentialsResponse> future = futureRef.get(); + CompletableFuture<BeginGetCredentialsResponse> future = futureRef.get(); if (future != null && future.isCancelled()) { dispatchCancellationSignal(cancellationSignal); } else { @@ -159,7 +161,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef = new AtomicReference<>(); - CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = postAsync(service -> { + CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = + postAsync(service -> { CompletableFuture<BeginCreateCredentialResponse> createCredentialFuture = new CompletableFuture<>(); ICancellationSignal cancellationSignal = service.onBeginCreateCredential( |