Merge "Split credential manager get flow to two phases, similar to the create flow Test: Built & deployed locally Bug: 253155222 CTS-Coverage-Bug: 247549381"

This commit is contained in:
Reema Bajwa
2022-12-11 05:03:18 +00:00
committed by Android (Google) Code Review
19 changed files with 564 additions and 200 deletions

View File

@@ -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>);
}
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);
}
};
}

View File

@@ -1,3 +1,3 @@
package android.service.credentials;
parcelable GetCredentialsRequest;
parcelable BeginGetCredentialsRequest;

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,3 @@
package android.service.credentials;
parcelable BeginGetCredentialsResponse;

View File

@@ -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];
}
};

View File

@@ -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,17 +103,10 @@ 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.
*/
@@ -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
@@ -178,26 +159,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);
}
}
}

View File

@@ -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,11 +46,22 @@ 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
@@ -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.

View File

@@ -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.

View File

@@ -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);
}
}
}

View File

@@ -1,3 +0,0 @@
package android.service.credentials;
parcelable GetCredentialsResponse;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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");

View File

@@ -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(