summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/credentials/CredentialManager.java65
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsException.java95
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsRequest.aidl19
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsRequest.java147
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsResponse.aidl19
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsResponse.java55
-rw-r--r--core/java/android/credentials/ICredentialManager.aidl4
-rw-r--r--core/java/android/credentials/IGetCandidateCredentialsCallback.aidl30
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java13
9 files changed, 447 insertions, 0 deletions
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index eedb25b1aa8f..408869ec76bc 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -19,6 +19,7 @@ package android.credentials;
import static java.util.Objects.requireNonNull;
import android.annotation.CallbackExecutor;
+import android.annotation.Hide;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -117,6 +118,32 @@ public final class CredentialManager {
}
/**
+ * Returns a list of candidate credentials returned from credential manager providers
+ *
+ * @param request the request specifying type(s) of credentials to get from the
+ * credential providers
+ * @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
+ *
+ * @hide
+ */
+ @Hide
+ public void getCandidateCredentials(
+ @NonNull GetCredentialRequest request,
+ @Nullable CancellationSignal cancellationSignal,
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> 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, "getCredential already canceled");
+ }
+ }
+
+ /**
* 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
@@ -641,6 +668,44 @@ public final class CredentialManager {
}
}
+ private static class GetCandidateCredentialsTransport
+ extends IGetCandidateCredentialsCallback.Stub {
+
+ private final Executor mExecutor;
+ private final OutcomeReceiver<GetCandidateCredentialsResponse,
+ GetCandidateCredentialsException> mCallback;
+
+ private GetCandidateCredentialsTransport(
+ Executor executor,
+ OutcomeReceiver<GetCandidateCredentialsResponse,
+ GetCandidateCredentialsException> callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResponse(GetCandidateCredentialsResponse response) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onResult(response));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void onError(String errorType, String message) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(
+ () -> mCallback.onError(new GetCandidateCredentialsException(
+ errorType, message)));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
// TODO: listen for cancellation to release callback.
diff --git a/core/java/android/credentials/GetCandidateCredentialsException.java b/core/java/android/credentials/GetCandidateCredentialsException.java
new file mode 100644
index 000000000000..40650d02a93e
--- /dev/null
+++ b/core/java/android/credentials/GetCandidateCredentialsException.java
@@ -0,0 +1,95 @@
+/*
+ * 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.Hide;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents an error encountered during the
+ * {@link CredentialManager#getCandidateCredentials} operation.
+ *
+ * @hide
+ */
+@Hide
+public class GetCandidateCredentialsException extends Exception {
+ /**
+ * The error type value for when the given operation failed due to an unknown reason.
+ */
+ @NonNull
+ public static final String TYPE_UNKNOWN =
+ "android.credentials.GetCandidateCredentialsException.TYPE_UNKNOWN";
+
+ /**
+ * The error type value for when no credential is found available for the given {@link
+ * CredentialManager#getCandidateCredentials} request.
+ */
+ @NonNull
+ public static final String TYPE_NO_CREDENTIAL =
+ "android.credentials.GetCandidateCredentialsException.TYPE_NO_CREDENTIAL";
+
+ @NonNull
+ private final String mType;
+
+ /** Returns the specific exception type. */
+ @NonNull
+ public String getType() {
+ return mType;
+ }
+
+ /**
+ * Constructs a {@link GetCandidateCredentialsException}.
+ *
+ * @throws IllegalArgumentException If type is empty.
+ */
+ public GetCandidateCredentialsException(@NonNull String type, @Nullable String message) {
+ this(type, message, null);
+ }
+
+ /**
+ * Constructs a {@link GetCandidateCredentialsException}.
+ *
+ * @throws IllegalArgumentException If type is empty.
+ */
+ public GetCandidateCredentialsException(
+ @NonNull String type, @Nullable String message, @Nullable Throwable cause) {
+ super(message, cause);
+ this.mType = Preconditions.checkStringNotEmpty(type,
+ "type must not be empty");
+ }
+
+ /**
+ * Constructs a {@link GetCandidateCredentialsException}.
+ *
+ * @throws IllegalArgumentException If type is empty.
+ */
+ public GetCandidateCredentialsException(@NonNull String type, @Nullable Throwable cause) {
+ this(type, null, cause);
+ }
+
+ /**
+ * Constructs a {@link GetCandidateCredentialsException}.
+ *
+ * @throws IllegalArgumentException If type is empty.
+ */
+ public GetCandidateCredentialsException(@NonNull String type) {
+ this(type, null, null);
+ }
+}
diff --git a/core/java/android/credentials/GetCandidateCredentialsRequest.aidl b/core/java/android/credentials/GetCandidateCredentialsRequest.aidl
new file mode 100644
index 000000000000..d3610894b418
--- /dev/null
+++ b/core/java/android/credentials/GetCandidateCredentialsRequest.aidl
@@ -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 GetCandidateCredentialsRequest; \ No newline at end of file
diff --git a/core/java/android/credentials/GetCandidateCredentialsRequest.java b/core/java/android/credentials/GetCandidateCredentialsRequest.java
new file mode 100644
index 000000000000..7f0dcaf060b8
--- /dev/null
+++ b/core/java/android/credentials/GetCandidateCredentialsRequest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.Hide;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+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 a list of candidate credentials against the list of credential
+ * options
+ *
+ * @hide
+ */
+@Hide
+public final class GetCandidateCredentialsRequest implements Parcelable {
+
+ /**
+ * The list of credential requests.
+ */
+ @NonNull
+ private final List<CredentialOption> mCredentialOptions;
+
+ /**
+ * The top request level data.
+ */
+ @NonNull
+ private final Bundle mData;
+
+ /**
+ * The origin of the calling app. Callers of this special API (e.g. browsers)
+ * can set this origin for an app different from their own, to be able to get credentials
+ * on behalf of that app.
+ */
+ @Nullable
+ private String mOrigin;
+
+ /**
+ * Returns the list of credential options to be requested.
+ */
+ @NonNull
+ public List<CredentialOption> getCredentialOptions() {
+ return mCredentialOptions;
+ }
+
+ /**
+ * Returns the top request level data.
+ */
+ @NonNull
+ public Bundle getData() {
+ return mData;
+ }
+
+ /**
+ * Returns the origin of the calling app if set otherwise returns null.
+ */
+ @Nullable
+ public String getOrigin() {
+ return mOrigin;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedList(mCredentialOptions, flags);
+ dest.writeBundle(mData);
+ dest.writeString8(mOrigin);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "GetCandidateCredentialsRequest {credentialOption=" + mCredentialOptions
+ + ", data=" + mData
+ + ", origin=" + mOrigin
+ + "}";
+ }
+
+ private GetCandidateCredentialsRequest(@NonNull List<CredentialOption> credentialOptions,
+ @NonNull Bundle data, String origin) {
+ Preconditions.checkCollectionNotEmpty(
+ credentialOptions,
+ /*valueName=*/ "credentialOptions");
+ Preconditions.checkCollectionElementsNotNull(
+ credentialOptions,
+ /*valueName=*/ "credentialOptions");
+ mCredentialOptions = credentialOptions;
+ mData = requireNonNull(data,
+ "data must not be null");
+ mOrigin = origin;
+ }
+
+ private GetCandidateCredentialsRequest(@NonNull Parcel in) {
+ List<CredentialOption> credentialOptions = new ArrayList<CredentialOption>();
+ in.readTypedList(credentialOptions, CredentialOption.CREATOR);
+ mCredentialOptions = credentialOptions;
+ AnnotationValidations.validate(NonNull.class, null, mCredentialOptions);
+
+ Bundle data = in.readBundle();
+ mData = data;
+ AnnotationValidations.validate(NonNull.class, null, mData);
+
+ mOrigin = in.readString8();
+ }
+
+ @NonNull
+ public static final Creator<GetCandidateCredentialsRequest> CREATOR =
+ new Creator<>() {
+ @Override
+ public GetCandidateCredentialsRequest[] newArray(int size) {
+ return new GetCandidateCredentialsRequest[size];
+ }
+
+ @Override
+ public GetCandidateCredentialsRequest createFromParcel(@NonNull Parcel in) {
+ return new GetCandidateCredentialsRequest(in);
+ }
+ };
+}
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.aidl b/core/java/android/credentials/GetCandidateCredentialsResponse.aidl
new file mode 100644
index 000000000000..ffcd3e7078e8
--- /dev/null
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.aidl
@@ -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 GetCandidateCredentialsResponse; \ No newline at end of file
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
new file mode 100644
index 000000000000..1d649eb92fde
--- /dev/null
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -0,0 +1,55 @@
+/*
+ * 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.Hide;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A list of candidate credentials.
+ *
+ * @hide
+ */
+@Hide
+public final class GetCandidateCredentialsResponse implements Parcelable {
+ // TODO(b/299321990): Add members
+ protected GetCandidateCredentialsResponse(Parcel in) {
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<GetCandidateCredentialsResponse> CREATOR =
+ new Creator<GetCandidateCredentialsResponse>() {
+ @Override
+ public GetCandidateCredentialsResponse createFromParcel(Parcel in) {
+ return new GetCandidateCredentialsResponse(in);
+ }
+
+ @Override
+ public GetCandidateCredentialsResponse[] newArray(int size) {
+ return new GetCandidateCredentialsResponse[size];
+ }
+ };
+}
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
index dec729f4a19f..42323d66e533 100644
--- a/core/java/android/credentials/ICredentialManager.aidl
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -21,12 +21,14 @@ import java.util.List;
import android.credentials.CredentialProviderInfo;
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialRequest;
+import android.credentials.GetCandidateCredentialsRequest;
import android.credentials.GetCredentialRequest;
import android.credentials.RegisterCredentialDescriptionRequest;
import android.credentials.UnregisterCredentialDescriptionRequest;
import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback;
import android.credentials.IGetCredentialCallback;
+import android.credentials.IGetCandidateCredentialsCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.ISetEnabledProvidersCallback;
import android.content.ComponentName;
@@ -45,6 +47,8 @@ interface ICredentialManager {
@nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage);
+ @nullable ICancellationSignal getCandidateCredentials(in GetCandidateCredentialsRequest request, in IGetCandidateCredentialsCallback callback, String callingPackage);
+
@nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
void setEnabledProviders(in List<String> primaryProviders, in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback);
diff --git a/core/java/android/credentials/IGetCandidateCredentialsCallback.aidl b/core/java/android/credentials/IGetCandidateCredentialsCallback.aidl
new file mode 100644
index 000000000000..729176a9919d
--- /dev/null
+++ b/core/java/android/credentials/IGetCandidateCredentialsCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.app.PendingIntent;
+import android.credentials.GetCandidateCredentialsResponse;
+
+/**
+ * Listener for a getCandidateCredentials request.
+ *
+ * @hide
+ */
+interface IGetCandidateCredentialsCallback {
+ oneway void onResponse(in GetCandidateCredentialsResponse response);
+ oneway void onError(String errorType, String message);
+} \ No newline at end of file
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index d8c684fb8c1e..c544b411b4b1 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -35,11 +35,13 @@ import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
+import android.credentials.GetCandidateCredentialsRequest;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialRequest;
import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback;
import android.credentials.ICredentialManager;
+import android.credentials.IGetCandidateCredentialsCallback;
import android.credentials.IGetCredentialCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.ISetEnabledProvidersCallback;
@@ -461,6 +463,17 @@ public final class CredentialManagerService
final class CredentialManagerServiceStub extends ICredentialManager.Stub {
@Override
+ public ICancellationSignal getCandidateCredentials(
+ GetCandidateCredentialsRequest request,
+ IGetCandidateCredentialsCallback callback,
+ final String callingPackage) {
+ Slog.i(TAG, "starting getCandidateCredentials with callingPackage: "
+ + callingPackage);
+ // TODO(): Implement
+ return CancellationSignal.createTransport();
+ }
+
+ @Override
public ICancellationSignal executeGetCredential(
GetCredentialRequest request,
IGetCredentialCallback callback,