diff options
| author | 2022-12-11 05:03:18 +0000 | |
|---|---|---|
| committer | 2022-12-11 05:03:18 +0000 | |
| commit | 4a51535c33de7c812a6ac35c947243945ff70682 (patch) | |
| tree | f73d9768cc001035b44940d77ab4a8fa96a6ec92 | |
| parent | 016f2243f92ac33dd7c547ac1c51d709c4746c88 (diff) | |
| parent | 9e3565b68ac88620e912ce1ff18f1e77844c7275 (diff) | |
Merge "Split credential manager get flow to two phases, similar to the create flow Test: Built & deployed locally Bug: 253155222 CTS-Coverage-Bug: 247549381"
19 files changed, 564 insertions, 200 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c539c3446c64..bedd6eeb365f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39497,6 +39497,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(); @@ -39518,8 +39552,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(); @@ -39529,7 +39562,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);    } @@ -39546,14 +39578,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";    } @@ -39576,29 +39610,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(  |