[CredMan] Prefetch credential get api
Based on partner feedback, add a new prefetch get-credential api that supports first retrieving credential candidates and delaying the UI flows to finalize a credential to later using a separate api, GetPendingCredentialResponse.show(). Bug: 273308895 Test: local deployment (will add unit test with the unhiding change) Change-Id: I212a6066c71b8468c6d7bfc2df2d9dab737368e0
This commit is contained in:
@@ -166,6 +166,48 @@ public final class CredentialManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link GetPendingCredentialResponse} that can launch the credential retrieval UI flow
|
||||
* to request a user credential for your app.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void getPendingCredential(
|
||||
@NonNull GetCredentialRequest request,
|
||||
@Nullable CancellationSignal cancellationSignal,
|
||||
@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<
|
||||
GetPendingCredentialResponse, 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, "getPendingCredential already canceled");
|
||||
return;
|
||||
}
|
||||
|
||||
ICancellationSignal cancelRemote = null;
|
||||
try {
|
||||
cancelRemote =
|
||||
mService.executeGetPendingCredential(
|
||||
request,
|
||||
new GetPendingCredentialTransport(executor, callback),
|
||||
mContext.getOpPackageName());
|
||||
} 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.
|
||||
*
|
||||
@@ -442,6 +484,32 @@ public final class CredentialManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetPendingCredentialTransport extends IGetPendingCredentialCallback.Stub {
|
||||
// TODO: listen for cancellation to release callback.
|
||||
|
||||
private final Executor mExecutor;
|
||||
private final OutcomeReceiver<
|
||||
GetPendingCredentialResponse, GetCredentialException> mCallback;
|
||||
|
||||
private GetPendingCredentialTransport(
|
||||
Executor executor,
|
||||
OutcomeReceiver<GetPendingCredentialResponse, GetCredentialException> callback) {
|
||||
mExecutor = executor;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(GetPendingCredentialResponse response) {
|
||||
mExecutor.execute(() -> mCallback.onResult(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String errorType, String message) {
|
||||
mExecutor.execute(
|
||||
() -> mCallback.onError(new GetCredentialException(errorType, message)));
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
|
||||
// TODO: listen for cancellation to release callback.
|
||||
|
||||
|
||||
@@ -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 GetPendingCredentialResponse;
|
||||
127
core/java/android/credentials/GetPendingCredentialResponse.java
Normal file
127
core/java/android/credentials/GetPendingCredentialResponse.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
|
||||
/**
|
||||
* A response object that prefetches user app credentials and provides metadata about them. It can
|
||||
* then be used to issue the full credential retrieval flow via the
|
||||
* {@link #show(Activity, CancellationSignal, Executor, OutcomeReceiver)} method to perform the
|
||||
* necessary flows such as consent collection and officially retrieve a credential.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GetPendingCredentialResponse implements Parcelable {
|
||||
private final boolean mHasCredentialResults;
|
||||
private final boolean mHasAuthenticationResults;
|
||||
private final boolean mHasRemoteResults;
|
||||
|
||||
/** Returns true if the user has any candidate credentials, and false otherwise. */
|
||||
public boolean hasCredentialResults() {
|
||||
return mHasCredentialResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user has any candidate authentication actions (locked credential
|
||||
* supplier), and false otherwise.
|
||||
*/
|
||||
public boolean hasAuthenticationResults() {
|
||||
return mHasAuthenticationResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user has any candidate remote credential results, and false otherwise.
|
||||
*/
|
||||
public boolean hasRemoteResults() {
|
||||
return mHasRemoteResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the necessary flows such as consent collection and credential selection to
|
||||
* officially retrieve a credential among the pending credential candidates.
|
||||
*
|
||||
* @param activity the activity used to launch any UI needed
|
||||
* @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 show(@NonNull Activity activity, @Nullable CancellationSignal cancellationSignal,
|
||||
@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
|
||||
// TODO(b/273308895): implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeBoolean(mHasCredentialResults);
|
||||
dest.writeBoolean(mHasAuthenticationResults);
|
||||
dest.writeBoolean(mHasRemoteResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GetCredentialResponse {" + "credential=" + mHasCredentialResults + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link GetPendingCredentialResponse}.
|
||||
*
|
||||
* @param hasCredentialResults whether the user has any candidate credentials
|
||||
* @param hasAuthenticationResults whether the user has any candidate authentication actions
|
||||
* @param hasRemoteResults whether the user has any candidate remote options
|
||||
*/
|
||||
public GetPendingCredentialResponse(boolean hasCredentialResults,
|
||||
boolean hasAuthenticationResults, boolean hasRemoteResults) {
|
||||
mHasCredentialResults = hasCredentialResults;
|
||||
mHasAuthenticationResults = hasAuthenticationResults;
|
||||
mHasRemoteResults = hasRemoteResults;
|
||||
}
|
||||
|
||||
private GetPendingCredentialResponse(@NonNull Parcel in) {
|
||||
mHasCredentialResults = in.readBoolean();
|
||||
mHasAuthenticationResults = in.readBoolean();
|
||||
mHasRemoteResults = in.readBoolean();
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<GetPendingCredentialResponse> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public GetPendingCredentialResponse[] newArray(int size) {
|
||||
return new GetPendingCredentialResponse[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetPendingCredentialResponse createFromParcel(@NonNull Parcel in) {
|
||||
return new GetPendingCredentialResponse(in);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import android.credentials.UnregisterCredentialDescriptionRequest;
|
||||
import android.credentials.IClearCredentialStateCallback;
|
||||
import android.credentials.ICreateCredentialCallback;
|
||||
import android.credentials.IGetCredentialCallback;
|
||||
import android.credentials.IGetPendingCredentialCallback;
|
||||
import android.credentials.ISetEnabledProvidersCallback;
|
||||
import android.content.ComponentName;
|
||||
import android.os.ICancellationSignal;
|
||||
@@ -40,6 +41,8 @@ interface ICredentialManager {
|
||||
|
||||
@nullable ICancellationSignal executeGetCredential(in GetCredentialRequest request, in IGetCredentialCallback callback, String callingPackage);
|
||||
|
||||
@nullable ICancellationSignal executeGetPendingCredential(in GetCredentialRequest request, in IGetPendingCredentialCallback callback, String callingPackage);
|
||||
|
||||
@nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage);
|
||||
|
||||
@nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
|
||||
|
||||
@@ -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.GetPendingCredentialResponse;
|
||||
|
||||
/**
|
||||
* Listener for a executeGetPendingCredential request.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IGetPendingCredentialCallback {
|
||||
oneway void onResponse(in GetPendingCredentialResponse response);
|
||||
oneway void onError(String errorType, String message);
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import android.credentials.IClearCredentialStateCallback;
|
||||
import android.credentials.ICreateCredentialCallback;
|
||||
import android.credentials.ICredentialManager;
|
||||
import android.credentials.IGetCredentialCallback;
|
||||
import android.credentials.IGetPendingCredentialCallback;
|
||||
import android.credentials.ISetEnabledProvidersCallback;
|
||||
import android.credentials.RegisterCredentialDescriptionRequest;
|
||||
import android.credentials.UnregisterCredentialDescriptionRequest;
|
||||
@@ -438,6 +439,17 @@ public final class CredentialManagerService
|
||||
return cancelTransport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal executeGetPendingCredential(
|
||||
GetCredentialRequest request,
|
||||
IGetPendingCredentialCallback callback,
|
||||
final String callingPackage) {
|
||||
// TODO(b/273308895): implement
|
||||
|
||||
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
|
||||
return cancelTransport;
|
||||
}
|
||||
|
||||
private void processGetCredential(
|
||||
GetCredentialRequest request,
|
||||
IGetCredentialCallback callback,
|
||||
|
||||
Reference in New Issue
Block a user