Add error propagation piping for get & create

Test: Built & deployed locally

Change-Id: I67b57b228722ffce8a10e9269ef53ffa35fc18fc
This commit is contained in:
Reema Bajwa
2022-11-25 07:06:45 +00:00
parent 71d7b807bc
commit 61ae713373
11 changed files with 357 additions and 192 deletions

View File

@@ -0,0 +1,51 @@
/*
* 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;
/**
* Contains custom error codes to be used internally for various credential
* provider error states.
*
* @hide
*/
public class CredentialProviderErrors {
public static final int ERROR_UNKNOWN = 0;
/**
* For internal use only.
* Error code to be used when the provider request times out.
*
* @hide
*/
public static final int ERROR_TIMEOUT = 1;
/**
* For internal use only.
* Error code to be used when the async task is canceled internally.
*
* @hide
*/
public static final int ERROR_TASK_CANCELED = 2;
/**
* For internal use only.
* Error code to be used when an exception is received from the provider.
*
* @hide
*/
public static final int ERROR_PROVIDER_FAILURE = 3;
}

View File

@@ -1,96 +0,0 @@
/*
* 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.IntDef;
import android.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Contains custom exceptions to be used by credential providers on failure.
*
* @hide
*/
public class CredentialProviderException extends Exception {
public static final int ERROR_UNKNOWN = 0;
/**
* For internal use only.
* Error code to be used when the provider request times out.
*
* @hide
*/
public static final int ERROR_TIMEOUT = 1;
/**
* For internal use only.
* Error code to be used when the async task is canceled internally.
*
* @hide
*/
public static final int ERROR_TASK_CANCELED = 2;
/**
* For internal use only.
* Error code to be used when the provider encounters a failure while processing the request.
*
* @hide
*/
public static final int ERROR_PROVIDER_FAILURE = 3;
private final int mErrorCode;
/**
* @hide
*/
@IntDef(prefix = {"ERROR_"}, value = {
ERROR_UNKNOWN,
ERROR_TIMEOUT,
ERROR_TASK_CANCELED
})
@Retention(RetentionPolicy.SOURCE)
public @interface CredentialProviderError { }
public CredentialProviderException(@CredentialProviderError int errorCode,
@NonNull String message, @NonNull Throwable cause) {
super(message, cause);
mErrorCode = errorCode;
}
public CredentialProviderException(@CredentialProviderError int errorCode,
@NonNull String message) {
super(message);
mErrorCode = errorCode;
}
public CredentialProviderException(@CredentialProviderError int errorCode,
@NonNull Throwable cause) {
super(cause);
mErrorCode = errorCode;
}
public CredentialProviderException(@CredentialProviderError int errorCode) {
super();
mErrorCode = errorCode;
}
public @CredentialProviderError int getErrorCode() {
return mErrorCode;
}
}

View File

@@ -83,16 +83,6 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
}
}
private void respondToClientAndFinish(CreateCredentialResponse response) {
Log.i(TAG, "respondToClientAndFinish");
try {
mClientCallback.onResponse(response);
} catch (RemoteException e) {
e.printStackTrace();
}
finishSession();
}
@Override
public void onProviderStatusChanged(ProviderSession.Status status,
ComponentName componentName) {
@@ -101,10 +91,47 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
@Override
public void onFinalResponseReceived(ComponentName componentName,
CreateCredentialResponse response) {
@Nullable CreateCredentialResponse response) {
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
if (response != null) {
respondToClientAndFinish(response);
respondToClientWithResponseAndFinish(response);
} else {
// TODO("Replace with properly defined error type)
respondToClientWithErrorAndFinish("unknown_type",
"Invalid response");
}
}
@Override
public void onFinalErrorReceived(ComponentName componentName, String errorType,
String message) {
respondToClientWithErrorAndFinish(errorType, message);
}
@Override
public void onUiCancellation() {
// TODO("Replace with properly defined error type")
respondToClientWithErrorAndFinish("user_cancelled",
"User cancelled the selector");
}
private void respondToClientWithResponseAndFinish(CreateCredentialResponse response) {
Log.i(TAG, "respondToClientWithResponseAndFinish");
try {
mClientCallback.onResponse(response);
} catch (RemoteException e) {
Log.i(TAG, "Issue while responding to client: " + e.getMessage());
}
finishSession();
}
private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) {
Log.i(TAG, "respondToClientWithErrorAndFinish");
try {
mClientCallback.onError(errorType, errorMsg);
} catch (RemoteException e) {
Log.i(TAG, "Issue while responding to client: " + e.getMessage());
}
finishSession();
}
}

View File

@@ -175,12 +175,20 @@ public final class CredentialManagerService
// Initiate all provider sessions
List<ProviderSession> providerSessions =
initiateProviderSessions(
session,
request.getGetCredentialOptions().stream()
.map(GetCredentialOption::getType)
.collect(Collectors.toList()));
// TODO : Return error when no providers available
initiateProviderSessions(session, request.getGetCredentialOptions()
.stream().map(GetCredentialOption::getType)
.collect(Collectors.toList()));
if (providerSessions.isEmpty()) {
try {
// TODO("Replace with properly defined error type")
callback.onError("unknown_type",
"No providers available to fulfill request.");
} catch (RemoteException e) {
Log.i(TAG, "Issue invoking onError on IGetCredentialCallback "
+ "callback: " + e.getMessage());
}
}
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(providerGetSession -> {
@@ -212,7 +220,17 @@ public final class CredentialManagerService
// Initiate all provider sessions
List<ProviderSession> providerSessions =
initiateProviderSessions(session, List.of(request.getType()));
// TODO : Return error when no providers available
if (providerSessions.isEmpty()) {
try {
// TODO("Replace with properly defined error type")
callback.onError("unknown_type",
"No providers available to fulfill request.");
} catch (RemoteException e) {
Log.i(TAG, "Issue invoking onError on ICreateCredentialCallback "
+ "callback: " + e.getMessage());
}
}
// Iterate over all provider sessions and invoke the request
providerSessions.forEach(

View File

@@ -88,15 +88,27 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
@Override
public void onFinalResponseReceived(ComponentName componentName,
GetCredentialResponse response) {
@Nullable GetCredentialResponse response) {
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
if (response != null) {
respondToClientAndFinish(response);
respondToClientWithResponseAndFinish(response);
} else {
// TODO("Replace with no credentials/unknown type when ready)
respondToClientWithErrorAndFinish("unknown_type",
"Invalid response from provider");
}
}
private void respondToClientAndFinish(GetCredentialResponse response) {
Log.i(TAG, "respondToClientAndFinish");
//TODO: Try moving the three error & response methods below to RequestSession to be shared
// between get & create.
@Override
public void onFinalErrorReceived(ComponentName componentName, String errorType,
String message) {
respondToClientWithErrorAndFinish(errorType, message);
}
private void respondToClientWithResponseAndFinish(GetCredentialResponse response) {
Log.i(TAG, "respondToClientWithResponseAndFinish");
try {
mClientCallback.onResponse(response);
} catch (RemoteException e) {
@@ -104,4 +116,21 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
}
finishSession();
}
private void respondToClientWithErrorAndFinish(String errorType, String errorMsg) {
Log.i(TAG, "respondToClientWithErrorAndFinish");
try {
mClientCallback.onError(errorType, errorMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
finishSession();
}
@Override
public void onUiCancellation() {
// TODO("Replace with properly defined error type")
respondToClientWithErrorAndFinish("user_canceled",
"User cancelled the selector");
}
}

View File

@@ -18,7 +18,9 @@ package com.android.server.credentials;
import android.app.Activity;
import android.content.Intent;
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialResponse;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.CredentialProviderService;
@@ -31,7 +33,7 @@ import android.service.credentials.CredentialsResponseContent;
*/
public class PendingIntentResultHandler {
/** Returns true if the result is successful and may contain result extras. */
public static boolean isSuccessfulResponse(
public static boolean isValidResponse(
ProviderPendingIntentResponse pendingIntentResponse) {
//TODO: Differentiate based on extra_error in the resultData
return pendingIntentResponse.getResultCode() == Activity.RESULT_OK;
@@ -66,4 +68,28 @@ public class PendingIntentResultHandler {
CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
GetCredentialResponse.class);
}
/** Extract the {@link CreateCredentialException} from the
* given pending intent . */
public static CreateCredentialException extractCreateCredentialException(
Intent resultData) {
if (resultData == null) {
return null;
}
return resultData.getParcelableExtra(
CredentialProviderService.EXTRA_CREATE_CREDENTIAL_EXCEPTION,
CreateCredentialException.class);
}
/** Extract the {@link GetCredentialException} from the
* given pending intent . */
public static GetCredentialException extractGetCredentialException(
Intent resultData) {
if (resultData == null) {
return null;
}
return resultData.getParcelableExtra(
CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
GetCredentialException.class);
}
}

View File

@@ -23,6 +23,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.Signature;
import android.credentials.CreateCredentialException;
import android.credentials.ui.CreateCredentialProviderData;
import android.credentials.ui.Entry;
import android.credentials.ui.ProviderPendingIntentResponse;
@@ -58,6 +59,8 @@ public final class ProviderCreateSession extends ProviderSession<
/** The complete request to be used in the second round. */
private final CreateCredentialRequest mCompleteRequest;
private CreateCredentialException mProviderException;
/** Creates a new provider session to be used by the request session. */
@Nullable public static ProviderCreateSession createNewSession(
Context context,
@@ -124,8 +127,11 @@ public final class ProviderCreateSession extends ProviderSession<
/** Called when the provider response resulted in a failure. */
@Override
public void onProviderResponseFailure(int errorCode, @Nullable String errorType,
@Nullable CharSequence message) {
public void onProviderResponseFailure(int errorCode, @Nullable Exception exception) {
if (exception instanceof CreateCredentialException) {
// Store query phase exception for aggregation with final response
mProviderException = (CreateCredentialException) exception;
}
updateStatusAndInvokeCallback(toStatus(errorCode));
}
@@ -177,16 +183,20 @@ public final class ProviderCreateSession extends ProviderSession<
if (mUiSaveEntries.containsKey(entryKey)) {
onSaveEntrySelected(providerPendingIntentResponse);
} else {
//TODO: Handle properly
Log.i(TAG, "Unexpected save entry key");
// TODO("Replace with no credentials error type");
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
}
break;
case REMOTE_ENTRY_KEY:
if (mUiRemoteEntry.first.equals(entryKey)) {
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
//TODO: Handle properly
Log.i(TAG, "Unexpected remote entry key");
// TODO("Replace with unknown/no credentials exception")
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
}
break;
default:
@@ -227,19 +237,53 @@ public final class ProviderCreateSession extends ProviderSession<
}
private void onSaveEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
CreateCredentialException exception = maybeGetPendingIntentException(
pendingIntentResponse);
if (exception != null) {
invokeCallbackWithError(
exception.errorType,
exception.getMessage());
return;
//TODO: Handle failure if pending intent is null
}
if (PendingIntentResultHandler.isSuccessfulResponse(pendingIntentResponse)) {
android.credentials.CreateCredentialResponse credentialResponse =
PendingIntentResultHandler.extractCreateCredentialResponse(
pendingIntentResponse.getResultData());
if (credentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
return;
android.credentials.CreateCredentialResponse credentialResponse =
PendingIntentResultHandler.extractCreateCredentialResponse(
pendingIntentResponse.getResultData());
if (credentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
return;
} else {
Log.i(TAG, "onSaveEntrySelected - no response or error found in pending "
+ "intent response");
invokeCallbackWithError(
// TODO("Replace with unknown/no credentials exception")
"unknown",
"Issue encountered while retrieving the credential");
}
}
private void invokeCallbackWithError(String errorType, @Nullable String message) {
mCallbacks.onFinalErrorReceived(mComponentName, errorType, message);
}
@Nullable
private CreateCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
return null;
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
CreateCredentialException exception = PendingIntentResultHandler
.extractCreateCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else {
Log.i(TAG, "Pending intent result code not Activity.RESULT_OK");
// TODO("Update with unknown exception when ready")
return new CreateCredentialException("unknown");
}
//TODO: Handle failure case is pending intent response does not have a credential
return null;
}
}

View File

@@ -22,7 +22,7 @@ import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.Signature;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialOption;
import android.credentials.GetCredentialResponse;
import android.credentials.ui.Entry;
@@ -80,6 +80,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
/** The complete request to be used in the second round. */
private final GetCredentialRequest mCompleteRequest;
private GetCredentialException mProviderException;
/** Creates a new provider session to be used by the request session. */
@Nullable public static ProviderGetSession createNewSession(
Context context,
@@ -131,7 +133,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
if (!filteredOptions.isEmpty()) {
return new GetCredentialRequest.Builder(
new CallingAppInfo(clientCallingPackage,
new ArraySet<Signature>())).setGetCredentialOptions(
new ArraySet<>())).setGetCredentialOptions(
filteredOptions).build();
}
Log.i(TAG, "In createProviderRequest - returning null");
@@ -164,8 +166,10 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
/** Called when the provider response resulted in a failure. */
@Override // Callback from the remote provider
public void onProviderResponseFailure(int errorCode, @Nullable String errorType,
@Nullable CharSequence message) {
public void onProviderResponseFailure(int errorCode, Exception exception) {
if (exception instanceof GetCredentialException) {
mProviderException = (GetCredentialException) exception;
}
updateStatusAndInvokeCallback(toStatus(errorCode));
}
@@ -187,8 +191,10 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
case CREDENTIAL_ENTRY_KEY:
CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
if (credentialEntry == null) {
Log.i(TAG, "Credential entry not found");
//TODO: Handle properly
Log.i(TAG, "Unexpected credential entry key");
// TODO("Replace with no credentials/unknown exception")
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
return;
}
onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
@@ -196,8 +202,10 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
case ACTION_ENTRY_KEY:
Action actionEntry = mUiActionsEntries.get(entryKey);
if (actionEntry == null) {
Log.i(TAG, "Action entry not found");
//TODO: Handle properly
Log.i(TAG, "Unexpected action entry key");
// TODO("Replace with no credentials/unknown exception")
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
return;
}
onActionEntrySelected(providerPendingIntentResponse);
@@ -206,16 +214,20 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
if (mUiAuthenticationAction.first.equals(entryKey)) {
onAuthenticationEntrySelected(providerPendingIntentResponse);
} else {
//TODO: Handle properly
Log.i(TAG, "Authentication entry not found");
Log.i(TAG, "Unexpected authentication entry key");
// TODO("Replace with no credentials/unknown exception")
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
}
break;
case REMOTE_ENTRY_KEY:
if (mUiRemoteEntry.first.equals(entryKey)) {
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
//TODO: Handle properly
Log.i(TAG, "Remote entry not found");
Log.i(TAG, "Unexpected remote entry key");
// TODO("Replace with no credentials/unknown exception")
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
}
break;
default:
@@ -223,6 +235,11 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
}
}
private void invokeCallbackWithError(String errorType, @Nullable String errorMessage) {
// TODO: Determine what the error message should be
mCallbacks.onFinalErrorReceived(mComponentName, errorType, errorMessage);
}
@Override // Call from request session to data to be shown on the UI
@Nullable protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
Log.i(TAG, "In prepareUiData");
@@ -330,39 +347,61 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
private void onCredentialEntrySelected(CredentialEntry credentialEntry,
ProviderPendingIntentResponse providerPendingIntentResponse) {
if (providerPendingIntentResponse != null) {
if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
// TODO: Remove credential extraction when flow is fully transitioned
GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
.extractGetCredentialResponse(
providerPendingIntentResponse.getResultData());
if (getCredentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName, getCredentialResponse);
return;
}
// Check if pending intent has an error
GetCredentialException exception = maybeGetPendingIntentException(
providerPendingIntentResponse);
if (exception != null) {
invokeCallbackWithError(exception.errorType,
exception.getMessage());
return;
}
// TODO: Handle other pending intent statuses
// Check if pending intent has a credential
GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
.extractGetCredentialResponse(
providerPendingIntentResponse.getResultData());
if (getCredentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName,
getCredentialResponse);
return;
}
Log.i(TAG, "Pending intent response contains no credential, or error");
// TODO("Replace with no credentials/unknown error when ready)
invokeCallbackWithError("unknown_type",
"Issue while retrieving credential");
}
Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
// TODO: Propagate failure to client
// TODO("Replace with no credentials/unknown error when ready)
invokeCallbackWithError("unknown_type",
"Error encountered while retrieving the credential");
}
private void onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
if (providerPendingIntentResponse != null) {
if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
CredentialsResponseContent content = PendingIntentResultHandler
.extractResponseContent(providerPendingIntentResponse
.getResultData());
if (content != null) {
onUpdateResponse(
BeginGetCredentialResponse.createWithResponseContent(content));
return;
}
}
//TODO: Other provider intent statuses
// Check if pending intent has an error
GetCredentialException exception = maybeGetPendingIntentException(
providerPendingIntentResponse);
if (exception != null) {
invokeCallbackWithError(exception.errorType,
exception.getMessage());
return;
}
Log.i(TAG, "Display content not present in pending intent result");
// TODO: Propagate error to client
// Check if pending intent has the content
CredentialsResponseContent content = PendingIntentResultHandler
.extractResponseContent(providerPendingIntentResponse
.getResultData());
if (content != null) {
onUpdateResponse(BeginGetCredentialResponse.createWithResponseContent(content));
return;
}
Log.i(TAG, "No error or respond found in pending intent response");
// TODO("Replace with no credentials/unknown error when ready)
invokeCallbackWithError("unknown type", "Issue"
+ " while retrieving credential");
}
private void onActionEntrySelected(ProviderPendingIntentResponse
@@ -383,4 +422,26 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
}
}
@Nullable
private GetCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
return null;
}
if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
GetCredentialException exception = PendingIntentResultHandler
.extractGetCredentialException(pendingIntentResponse.getResultData());
if (exception != null) {
Log.i(TAG, "Pending intent contains provider exception");
return exception;
}
} else {
Log.i(TAG, "Pending intent result code not Activity.RESULT_OK");
// TODO("Update with unknown exception when ready")
return new GetCredentialException("unknown");
}
return null;
}
}

View File

@@ -24,7 +24,6 @@ import android.credentials.Credential;
import android.credentials.ui.ProviderData;
import android.credentials.ui.ProviderPendingIntentResponse;
import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderException;
import android.service.credentials.CredentialProviderInfo;
import android.util.Pair;
@@ -37,6 +36,8 @@ import java.util.UUID;
*/
public abstract class ProviderSession<T, R>
implements RemoteCredentialService.ProviderCallbacks<R> {
private static final String TAG = "ProviderSession";
// Key to be used as an entry key for a remote entry
protected static final String REMOTE_ENTRY_KEY = "remote_entry_key";
@@ -52,6 +53,7 @@ public abstract class ProviderSession<T, R>
@Nullable protected R mProviderResponse;
@Nullable protected Pair<String, CredentialEntry> mUiRemoteEntry;
/**
* Returns true if the given status reflects that the provider state is ready to be shown
* on the credMan UI.
@@ -95,8 +97,12 @@ public abstract class ProviderSession<T, R>
/** Called when status changes. */
void onProviderStatusChanged(Status status, ComponentName componentName);
/** Called when the final credential to be returned to the client has been received. */
/** Called when the final credential is received through an entry selection. */
void onFinalResponseReceived(ComponentName componentName, V response);
/** Called when an error is received through an entry selection. */
void onFinalErrorReceived(ComponentName componentName, String errorType,
@Nullable String message);
}
protected ProviderSession(@NonNull Context context, @NonNull CredentialProviderInfo info,
@@ -129,8 +135,7 @@ public abstract class ProviderSession<T, R>
/** Converts exception to a provider session status. */
@NonNull
public static Status toStatus(
@CredentialProviderException.CredentialProviderError int errorCode) {
public static Status toStatus(int errorCode) {
// TODO : Add more mappings as more flows are supported
return Status.CANCELED;
}

View File

@@ -30,7 +30,7 @@ import android.service.credentials.BeginCreateCredentialRequest;
import android.service.credentials.BeginCreateCredentialResponse;
import android.service.credentials.BeginGetCredentialRequest;
import android.service.credentials.BeginGetCredentialResponse;
import android.service.credentials.CredentialProviderException;
import android.service.credentials.CredentialProviderErrors;
import android.service.credentials.CredentialProviderService;
import android.service.credentials.IBeginCreateCredentialCallback;
import android.service.credentials.IBeginGetCredentialCallback;
@@ -72,8 +72,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
/** Called when a successful response is received from the remote provider. */
void onProviderResponseSuccess(@Nullable T response);
/** Called when a failure response is received from the remote provider. */
void onProviderResponseFailure(int errorCode, @Nullable String errorType,
@Nullable CharSequence message);
void onProviderResponseFailure(int internalErrorCode, @Nullable Exception e);
/** Called when the remote provider service dies. */
void onProviderServiceDied(RemoteCredentialService service);
}
@@ -208,36 +207,31 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
Log.i(TAG, "In RemoteCredentialService execute error is timeout");
dispatchCancellationSignal(cancellationSink.get());
callback.onProviderResponseFailure(
CredentialProviderException.ERROR_TIMEOUT,
null,
error.getMessage());
CredentialProviderErrors.ERROR_TIMEOUT,
null);
} else if (error instanceof CancellationException) {
Log.i(TAG, "In RemoteCredentialService execute error is cancellation");
dispatchCancellationSignal(cancellationSink.get());
callback.onProviderResponseFailure(
CredentialProviderException.ERROR_TASK_CANCELED,
null,
error.getMessage());
CredentialProviderErrors.ERROR_TASK_CANCELED,
null);
} else if (error instanceof GetCredentialException) {
Log.i(TAG, "In RemoteCredentialService execute error is provider get"
+ "error");
callback.onProviderResponseFailure(
CredentialProviderException.ERROR_PROVIDER_FAILURE,
((GetCredentialException) error).errorType,
error.getMessage());
CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
(GetCredentialException) error);
} else if (error instanceof CreateCredentialException) {
Log.i(TAG, "In RemoteCredentialService execute error is provider create "
+ "error");
callback.onProviderResponseFailure(
CredentialProviderException.ERROR_PROVIDER_FAILURE,
((CreateCredentialException) error).errorType,
error.getMessage());
CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
(CreateCredentialException) error);
} else {
Log.i(TAG, "In RemoteCredentialService execute error is unknown");
callback.onProviderResponseFailure(
CredentialProviderException.ERROR_UNKNOWN,
null,
error.getMessage());
CredentialProviderErrors.ERROR_UNKNOWN,
(Exception) error);
}
}
}

View File

@@ -93,6 +93,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
@Override // from CredentialManagerUiCallbacks
public void onUiCancellation() {
Log.i(TAG, "Ui canceled");
// User canceled the activity
finishSession();
}
@@ -133,10 +134,12 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
}
protected void finishSession() {
Log.i(TAG, "finishing session");
clearProviderSessions();
}
protected void clearProviderSessions() {
Log.i(TAG, "Clearing sessions");
//TODO: Implement
mProviders.clear();
}
@@ -151,6 +154,9 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
}
private void getProviderDataAndInitiateUi() {
Log.i(TAG, "In getProviderDataAndInitiateUi");
Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
ArrayList<ProviderData> providerDataList = new ArrayList<>();
for (ProviderSession session : mProviders.values()) {
Log.i(TAG, "preparing data for : " + session.getComponentName());