Framework credential manager developer APIs definitions.

The CredentialManager module provides solution for developers to create
or get credential from a user that can be used to authenticate to the app.
It can potentially launch system level UI flows to collect user consent,
render a unified selector when more than one credential exists, and
perform anything else needed.

Check bug id for detailed design.

Note that this is still very early stage of productionizing the module
and proper test cases will be added subsequently when the service
gets more concrete business logic.

Bug: 246564035
CTS-Coverage-Bug: 246637346
Test: Local Build & Deployment
Change-Id: Ia5884a7f6a3908de3b8b4b29f154f98e25730bd7
This commit is contained in:
Helen Qin
2022-09-13 15:47:24 +00:00
parent 09ebd974fb
commit 20ff355163
19 changed files with 1180 additions and 6 deletions

View File

@@ -9820,6 +9820,7 @@ package android.content {
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
field public static final String CREDENTIAL_SERVICE = "credential";
field public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
field public static final String DEVICE_POLICY_SERVICE = "device_policy";
field public static final String DISPLAY_HASH_SERVICE = "display_hash";
@@ -12879,6 +12880,82 @@ package android.content.res.loader {
}
package android.credentials {
public final class CreateCredentialRequest implements android.os.Parcelable {
ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle);
method public int describeContents();
method @NonNull public android.os.Bundle getData();
method @NonNull public String getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CreateCredentialRequest> CREATOR;
}
public final class CreateCredentialResponse implements android.os.Parcelable {
ctor public CreateCredentialResponse(@NonNull android.os.Bundle);
method public int describeContents();
method @NonNull public android.os.Bundle getData();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CreateCredentialResponse> CREATOR;
}
public final class Credential implements android.os.Parcelable {
ctor public Credential(@NonNull String, @NonNull android.os.Bundle);
method public int describeContents();
method @NonNull public android.os.Bundle getData();
method @NonNull public String getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.Credential> CREATOR;
}
public final class CredentialManager {
method public void executeCreateCredential(@NonNull android.credentials.CreateCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CredentialManagerException>);
method public void executeGetCredential(@NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.CredentialManagerException>);
}
public class CredentialManagerException extends java.lang.Exception {
ctor public CredentialManagerException(int, @Nullable String);
ctor public CredentialManagerException(int, @Nullable String, @Nullable Throwable);
ctor public CredentialManagerException(int, @Nullable Throwable);
ctor public CredentialManagerException(int);
field public static final int ERROR_UNKNOWN = 0; // 0x0
field public final int errorCode;
}
public final class GetCredentialOption implements android.os.Parcelable {
ctor public GetCredentialOption(@NonNull String, @NonNull android.os.Bundle);
method public int describeContents();
method @NonNull public android.os.Bundle getData();
method @NonNull public String getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialOption> CREATOR;
}
public final class GetCredentialRequest implements android.os.Parcelable {
method public int describeContents();
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.credentials.GetCredentialRequest> CREATOR;
}
public static final class GetCredentialRequest.Builder {
ctor public GetCredentialRequest.Builder();
method @NonNull public android.credentials.GetCredentialRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption);
method @NonNull public android.credentials.GetCredentialRequest build();
method @NonNull public android.credentials.GetCredentialRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>);
}
public final class GetCredentialResponse implements android.os.Parcelable {
ctor public GetCredentialResponse(@NonNull android.credentials.Credential);
ctor public GetCredentialResponse();
method public int describeContents();
method @Nullable public android.credentials.Credential getCredential();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialResponse> CREATOR;
}
}
package android.database {
public abstract class AbstractCursor implements android.database.CrossProcessCursor {

View File

@@ -57,6 +57,7 @@ import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.credentials.CredentialManager;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -3933,6 +3934,7 @@ public abstract class Context {
//@hide: ATTESTATION_VERIFICATION_SERVICE,
//@hide: SAFETY_CENTER_SERVICE,
DISPLAY_HASH_SERVICE,
CREDENTIAL_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -6058,6 +6060,15 @@ public abstract class Context {
*/
public static final String HEALTHCONNECT_SERVICE = "healthconnect";
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.credentials.CredentialManager} to authenticate a user to your app.
*
* @see #getSystemService(String)
* @see CredentialManager
*/
public static final String CREDENTIAL_SERVICE = "credential";
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.

View File

@@ -0,0 +1,19 @@
/*
* 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.credentials;
parcelable CreateCredentialRequest;

View File

@@ -0,0 +1,114 @@
/*
* 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.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 request to register a specific type of user credential, potentially launching UI flows to
* collect user consent and any other operation needed.
*/
public final class CreateCredentialRequest implements Parcelable {
/**
* The requested credential type.
*/
@NonNull
private final String mType;
/**
* The request data.
*/
@NonNull
private final Bundle mData;
/**
* Returns the requested credential type.
*/
@NonNull
public String getType() {
return mType;
}
/**
* Returns the request data.
*/
@NonNull
public Bundle getData() {
return mData;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mType);
dest.writeBundle(mData);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "CreateCredentialRequest {" + "type=" + mType + ", data=" + mData + "}";
}
/**
* Constructs a {@link CreateCredentialRequest}.
*
* @param type the requested credential type.
* @param data the request data.
*
* @throws IllegalArgumentException If type is empty.
*/
public CreateCredentialRequest(@NonNull String type, @NonNull Bundle data) {
mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
mData = requireNonNull(data, "data must not be null");
}
private CreateCredentialRequest(@NonNull Parcel in) {
String type = in.readString8();
Bundle data = in.readBundle();
mType = type;
AnnotationValidations.validate(NonNull.class, null, mType);
mData = data;
AnnotationValidations.validate(NonNull.class, null, mData);
}
public static final @NonNull Parcelable.Creator<CreateCredentialRequest> CREATOR =
new Parcelable.Creator<CreateCredentialRequest>() {
@Override
public CreateCredentialRequest[] newArray(int size) {
return new CreateCredentialRequest[size];
}
@Override
public CreateCredentialRequest createFromParcel(@NonNull Parcel in) {
return new CreateCredentialRequest(in);
}
};
}

View File

@@ -0,0 +1,19 @@
/*
* 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.credentials;
parcelable CreateCredentialResponse;

View File

@@ -0,0 +1,89 @@
/*
* 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.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;
/**
* A response object that encapsulates the result of a successful credential creation execution.
*/
public final class CreateCredentialResponse implements Parcelable {
/**
* The response data.
*/
@NonNull
private final Bundle mData;
/**
* Returns the response data.
*/
@NonNull
public Bundle getData() {
return mData;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeBundle(mData);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "CreateCredentialResponse {data=" + mData + "}";
}
/**
* Constructs a {@link CreateCredentialResponse}.
*
* @param data the data associated with the credential created.
*/
public CreateCredentialResponse(@NonNull Bundle data) {
mData = requireNonNull(data, "data must not be null");
}
private CreateCredentialResponse(@NonNull Parcel in) {
Bundle data = in.readBundle();
mData = data;
AnnotationValidations.validate(NonNull.class, null, mData);
}
public static final @NonNull Parcelable.Creator<CreateCredentialResponse> CREATOR =
new Parcelable.Creator<CreateCredentialResponse>() {
@Override
public CreateCredentialResponse[] newArray(int size) {
return new CreateCredentialResponse[size];
}
@Override
public CreateCredentialResponse createFromParcel(@NonNull Parcel in) {
return new CreateCredentialResponse(in);
}
};
}

View File

@@ -0,0 +1,113 @@
/*
* 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.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;
/**
* Represents a user credential that can be used to authenticate to your app.
*/
public final class Credential implements Parcelable {
/**
* The credential type.
*/
@NonNull
private final String mType;
/**
* The credential data.
*/
@NonNull
private final Bundle mData;
/**
* Returns the credential type.
*/
@NonNull
public String getType() {
return mType;
}
/**
* Returns the credential data.
*/
@NonNull
public Bundle getData() {
return mData;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mType);
dest.writeBundle(mData);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "Credential {" + "type=" + mType + ", data=" + mData + "}";
}
/**
* Constructs a {@link Credential}.
*
* @param type the type of the credential returned.
* @param data the data associated with the credential returned.
*
* @throws IllegalArgumentException If type is empty.
*/
public Credential(@NonNull String type, @NonNull Bundle data) {
mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
mData = requireNonNull(data, "data must not be null");
}
private Credential(@NonNull Parcel in) {
String type = in.readString8();
Bundle data = in.readBundle();
mType = type;
AnnotationValidations.validate(NonNull.class, null, mType);
mData = data;
AnnotationValidations.validate(NonNull.class, null, mData);
}
public static final @NonNull Parcelable.Creator<Credential> CREATOR =
new Parcelable.Creator<Credential>() {
@Override
public Credential[] newArray(int size) {
return new Credential[size];
}
@Override
public Credential createFromParcel(@NonNull Parcel in) {
return new Credential(in);
}
};
}

View File

@@ -0,0 +1,186 @@
/*
* 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.credentials;
import static java.util.Objects.requireNonNull;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.util.Log;
import java.util.concurrent.Executor;
/**
* Manages user authentication flows.
*
* <p>Note that an application should call the Jetpack CredentialManager apis instead of directly
* calling these framework apis.
*
* <p>The CredentialManager apis launch framework UI flows for a user to
* register a new credential or to consent to a saved credential from supported credential
* providers, which can then be used to authenticate to the app.
*/
@SystemService(Context.CREDENTIAL_SERVICE)
public final class CredentialManager {
private static final String TAG = "CredentialManager";
private final Context mContext;
private final ICredentialManager mService;
/**
* @hide instantiated by ContextImpl.
*/
public CredentialManager(Context context, ICredentialManager service) {
mContext = context;
mService = service;
}
/**
* Launches the necessary flows to retrieve an app credential from the user.
*
* <p>The execution can potentially launch UI flows to collect user consent to using a
* credential, display a picker when multiple credentials exist, etc.
*
* @param request the request specifying type(s) of credentials to get from the user.
* @param cancellationSignal an optional signal that allows for cancelling this call.
* @param executor the callback will take place on this {@link Executor}.
* @param callback the callback invoked when the request succeeds or fails.
*/
public void executeGetCredential(
@NonNull GetCredentialRequest request,
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<
GetCredentialResponse, CredentialManagerException> callback) {
requireNonNull(request, "request must not be null");
requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null");
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
Log.w(TAG, "executeGetCredential already canceled");
return;
}
ICancellationSignal cancelRemote = null;
try {
cancelRemote = mService.executeGetCredential(request,
new GetCredentialTransport(executor, callback));
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
if (cancellationSignal != null && cancelRemote != null) {
cancellationSignal.setRemote(cancelRemote);
}
}
/**
* Launches the necessary flows to register an app credential for the user.
*
* <p>The execution can potentially launch UI flows to collect user consent to creating
* or storing the new credential, etc.
*
* @param request the request specifying type(s) of credentials to get from the user.
* @param cancellationSignal an optional signal that allows for cancelling this call.
* @param executor the callback will take place on this {@link Executor}.
* @param callback the callback invoked when the request succeeds or fails.
*/
public void executeCreateCredential(
@NonNull CreateCredentialRequest request,
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<
CreateCredentialResponse, CredentialManagerException> callback) {
requireNonNull(request, "request must not be null");
requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null");
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
Log.w(TAG, "executeCreateCredential already canceled");
return;
}
ICancellationSignal cancelRemote = null;
try {
cancelRemote = mService.executeCreateCredential(request,
new CreateCredentialTransport(executor, callback));
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
if (cancellationSignal != null && cancelRemote != null) {
cancellationSignal.setRemote(cancelRemote);
}
}
private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
// TODO: listen for cancellation to release callback.
private final Executor mExecutor;
private final OutcomeReceiver<
GetCredentialResponse, CredentialManagerException> mCallback;
private GetCredentialTransport(Executor executor,
OutcomeReceiver<GetCredentialResponse, CredentialManagerException> callback) {
mExecutor = executor;
mCallback = callback;
}
@Override
public void onResponse(GetCredentialResponse response) {
mExecutor.execute(() -> mCallback.onResult(response));
}
@Override
public void onError(int errorCode, String message) {
mExecutor.execute(
() -> mCallback.onError(new CredentialManagerException(errorCode, message)));
}
}
private static class CreateCredentialTransport extends ICreateCredentialCallback.Stub {
// TODO: listen for cancellation to release callback.
private final Executor mExecutor;
private final OutcomeReceiver<
CreateCredentialResponse, CredentialManagerException> mCallback;
private CreateCredentialTransport(Executor executor,
OutcomeReceiver<CreateCredentialResponse, CredentialManagerException> callback) {
mExecutor = executor;
mCallback = callback;
}
@Override
public void onResponse(CreateCredentialResponse response) {
mExecutor.execute(() -> mCallback.onResult(response));
}
@Override
public void onError(int errorCode, String message) {
mExecutor.execute(
() -> mCallback.onError(new CredentialManagerException(errorCode, message)));
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.credentials;
import android.annotation.Nullable;
/** Exception class for CredentialManager operations. */
public class CredentialManagerException extends Exception {
/** Indicates that an unknown error was encountered. */
public static final int ERROR_UNKNOWN = 0;
public final int errorCode;
public CredentialManagerException(int errorCode, @Nullable String message) {
super(message);
this.errorCode = errorCode;
}
public CredentialManagerException(
int errorCode, @Nullable String message, @Nullable Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public CredentialManagerException(int errorCode, @Nullable Throwable cause) {
super(cause);
this.errorCode = errorCode;
}
public CredentialManagerException(int errorCode) {
super();
this.errorCode = errorCode;
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.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.
*/
public final class GetCredentialOption implements Parcelable {
/**
* The requested credential type.
*/
@NonNull
private final String mType;
/**
* The request data.
*/
@NonNull
private final Bundle mData;
/**
* Returns the requested credential type.
*/
@NonNull
public String getType() {
return mType;
}
/**
* Returns the request data.
*/
@NonNull
public Bundle getData() {
return mData;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mType);
dest.writeBundle(mData);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "GetCredentialOption {" + "type=" + mType + ", data=" + mData + "}";
}
/**
* Constructs a {@link GetCredentialOption}.
*
* @param type the requested credential type.
* @param data the request data.
*
* @throws IllegalArgumentException If type is empty.
*/
public GetCredentialOption(@NonNull String type, @NonNull Bundle data) {
mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
mData = requireNonNull(data, "data must not be null");
}
private GetCredentialOption(@NonNull Parcel in) {
String type = in.readString8();
Bundle data = in.readBundle();
mType = type;
AnnotationValidations.validate(NonNull.class, null, mType);
mData = data;
AnnotationValidations.validate(NonNull.class, null, mData);
}
public static final @NonNull Parcelable.Creator<GetCredentialOption> CREATOR =
new Parcelable.Creator<GetCredentialOption>() {
@Override
public GetCredentialOption[] newArray(int size) {
return new GetCredentialOption[size];
}
@Override
public GetCredentialOption createFromParcel(@NonNull Parcel in) {
return new GetCredentialOption(in);
}
};
}

View File

@@ -0,0 +1,19 @@
/*
* 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.credentials;
parcelable GetCredentialRequest;

View File

@@ -0,0 +1,138 @@
/*
* 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.credentials;
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
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;
/**
* A request to retrieve the user credential, potentially launching UI flows to let the user pick
* from different credential sources.
*/
public final class GetCredentialRequest implements Parcelable {
/**
* The list of credential requests.
*/
@NonNull
private final List<GetCredentialOption> mGetCredentialOptions;
/**
* Returns the list of credential options to be requested.
*/
@NonNull
public List<GetCredentialOption> getGetCredentialOptions() {
return mGetCredentialOptions;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedList(mGetCredentialOptions, flags);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "GetCredentialRequest {getCredentialOption=" + mGetCredentialOptions + "}";
}
private GetCredentialRequest(@NonNull List<GetCredentialOption> getCredentialOptions) {
Preconditions.checkCollectionNotEmpty(
getCredentialOptions,
/*valueName=*/ "getCredentialOptions");
Preconditions.checkCollectionElementsNotNull(
getCredentialOptions,
/*valueName=*/ "getCredentialOptions");
mGetCredentialOptions = getCredentialOptions;
}
private GetCredentialRequest(@NonNull Parcel in) {
List<GetCredentialOption> getCredentialOptions = new ArrayList<GetCredentialOption>();
in.readTypedList(getCredentialOptions, GetCredentialOption.CREATOR);
mGetCredentialOptions = getCredentialOptions;
AnnotationValidations.validate(NonNull.class, null, mGetCredentialOptions);
}
public static final @NonNull Parcelable.Creator<GetCredentialRequest> CREATOR =
new Parcelable.Creator<GetCredentialRequest>() {
@Override
public GetCredentialRequest[] newArray(int size) {
return new GetCredentialRequest[size];
}
@Override
public GetCredentialRequest createFromParcel(@NonNull Parcel in) {
return new GetCredentialRequest(in);
}
};
/** A builder for {@link GetCredentialRequest}. */
public static final class Builder {
private @NonNull List<GetCredentialOption> mGetCredentialOptions = new ArrayList<>();
/**
* Adds a specific type of {@link GetCredentialOption}.
*/
public @NonNull Builder addGetCredentialOption(
@NonNull GetCredentialOption getCredentialOption) {
mGetCredentialOptions.add(requireNonNull(
getCredentialOption, "getCredentialOption must not be null"));
return this;
}
/**
* Sets the list of {@link GetCredentialOption}.
*/
public @NonNull Builder setGetCredentialOptions(
@NonNull List<GetCredentialOption> getCredentialOptions) {
Preconditions.checkCollectionElementsNotNull(
getCredentialOptions,
/*valueName=*/ "getCredentialOptions");
mGetCredentialOptions = new ArrayList<>(getCredentialOptions);
return this;
}
/**
* Builds a {@link GetCredentialRequest}.
*
* @throws IllegalArgumentException If getCredentialOptions is empty.
*/
public @NonNull GetCredentialRequest build() {
Preconditions.checkCollectionNotEmpty(
mGetCredentialOptions,
/*valueName=*/ "getCredentialOptions");
Preconditions.checkCollectionElementsNotNull(
mGetCredentialOptions,
/*valueName=*/ "getCredentialOptions");
return new GetCredentialRequest(mGetCredentialOptions);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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.credentials;
parcelable GetCredentialResponse;

View File

@@ -0,0 +1,97 @@
/*
* 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.credentials;
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
/**
* A response object that encapsulates the credential successfully retrieved from the user.
*/
public final class GetCredentialResponse implements Parcelable {
/**
* The credential that can be used to authenticate the user.
*/
@Nullable
private final Credential mCredential;
/**
* Returns the credential that can be used to authenticate the user, or {@code null} if no
* credential is available.
*/
@Nullable
public Credential getCredential() {
return mCredential;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mCredential, flags);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
return "GetCredentialResponse {" + "credential=" + mCredential + "}";
}
/**
* Constructs a {@link GetCredentialResponse}.
*
* @param credential the credential successfully retrieved from the user.
*/
public GetCredentialResponse(@NonNull Credential credential) {
mCredential = requireNonNull(credential, "credential must not be null");
}
/**
* Constructs a {@link GetCredentialResponse}.
*/
public GetCredentialResponse() {
mCredential = null;
}
private GetCredentialResponse(@NonNull Parcel in) {
Credential credential = in.readTypedObject(Credential.CREATOR);
mCredential = credential;
AnnotationValidations.validate(NonNull.class, null, mCredential);
}
public static final @NonNull Parcelable.Creator<GetCredentialResponse> CREATOR =
new Parcelable.Creator<GetCredentialResponse>() {
@Override
public GetCredentialResponse[] newArray(int size) {
return new GetCredentialResponse[size];
}
@Override
public GetCredentialResponse createFromParcel(@NonNull Parcel in) {
return new GetCredentialResponse(in);
}
};
}

View File

@@ -0,0 +1,29 @@
/*
* 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.credentials;
import android.credentials.CreateCredentialResponse;
/**
* Listener for an executeCreateCredential request.
*
* @hide
*/
interface ICreateCredentialCallback {
oneway void onResponse(in CreateCredentialResponse response);
oneway void onError(int errorCode, String message);
}

View File

@@ -1,10 +1,35 @@
/*
* 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.credentials;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
import android.credentials.ICreateCredentialCallback;
import android.credentials.IGetCredentialCallback;
import android.os.ICancellationSignal;
/**
* Mediator between apps and credential manager service implementations.
* System private interface for talking to the credential manager service.
*
* {@hide}
* @hide
*/
oneway interface ICredentialManager {
void getCredential();
}
interface ICredentialManager {
@nullable ICancellationSignal executeGetCredential(in GetCredentialRequest request, in IGetCredentialCallback callback);
@nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback);
}

View File

@@ -0,0 +1,29 @@
/*
* 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.credentials;
import android.credentials.GetCredentialResponse;
/**
* Listener for an executeGetCredential request.
*
* @hide
*/
interface IGetCredentialCallback {
oneway void onResponse(in GetCredentialResponse response);
oneway void onError(int errorCode, String message);
}

View File

@@ -93,6 +93,7 @@ filegroup {
":services.contentcapture-sources",
":services.contentsuggestions-sources",
":services.coverage-sources",
":services.credentials-sources",
":services.devicepolicy-sources",
":services.midi-sources",
":services.musicsearch-sources",
@@ -146,6 +147,7 @@ java_library {
"services.contentcapture",
"services.contentsuggestions",
"services.coverage",
"services.credentials",
"services.devicepolicy",
"services.midi",
"services.musicsearch",

View File

@@ -16,10 +16,18 @@
package com.android.server.credentials;
import static android.content.Context.CREDENTIAL_SERVICE;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
import android.credentials.ICreateCredentialCallback;
import android.credentials.ICredentialManager;
import android.credentials.IGetCredentialCallback;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -59,11 +67,17 @@ public final class CredentialManagerService extends
@Override
public void onStart() {
Log.i(TAG, "onStart");
publishBinderService(CREDENTIAL_SERVICE, new CredentialManagerServiceStub());
}
final class CredentialManagerServiceStub extends ICredentialManager.Stub {
@Override
public void getCredential() {
public ICancellationSignal executeGetCredential(
GetCredentialRequest request,
IGetCredentialCallback callback) {
// TODO: implement.
Log.i(TAG, "executeGetCredential");
final int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
final CredentialManagerServiceImpl service = peekServiceForUserLocked(userId);
@@ -72,6 +86,19 @@ public final class CredentialManagerService extends
service.getCredential();
}
}
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
return cancelTransport;
}
@Override
public ICancellationSignal executeCreateCredential(
CreateCredentialRequest request,
ICreateCredentialCallback callback) {
// TODO: implement.
Log.i(TAG, "executeCreateCredential");
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
return cancelTransport;
}
}
}