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:
@@ -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>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
package android.service.credentials;
|
||||
|
||||
parcelable GetCredentialsRequest;
|
||||
parcelable BeginGetCredentialsRequest;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package android.service.credentials;
|
||||
|
||||
parcelable BeginGetCredentialsResponse;
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package android.service.credentials;
|
||||
|
||||
parcelable GetCredentialsResponse;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user