1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.credentials.selection; 18 19 import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.content.Intent; 27 import android.os.Bundle; 28 import android.os.ResultReceiver; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * Failure or cancellation result encountered during a UI flow. 35 * 36 * @hide 37 */ 38 @SystemApi 39 @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) 40 public final class FailureResult { 41 42 /** 43 * Sends the {@code failureResult} that caused the UI to stop back to the CredentialManager 44 * service. 45 * 46 * @param resultReceiver the ResultReceiver sent from the system service, that can be extracted 47 * from the launch intent via 48 * {@link IntentHelper#extractResultReceiver(Intent)} 49 */ sendFailureResult(@onNull ResultReceiver resultReceiver, @NonNull FailureResult failureResult)50 public static void sendFailureResult(@NonNull ResultReceiver resultReceiver, 51 @NonNull FailureResult failureResult) { 52 FailureDialogResult result = failureResult.toFailureDialogResult(); 53 Bundle resultData = new Bundle(); 54 FailureDialogResult.addToBundle(result, resultData); 55 resultReceiver.send(failureResult.errorCodeToResultCode(), 56 resultData); 57 } 58 59 @Nullable 60 private final String mErrorMessage; 61 @NonNull 62 private final int mErrorCode; 63 64 /** @hide **/ 65 @IntDef(prefix = {"ERROR_CODE_"}, value = { 66 ERROR_CODE_DIALOG_CANCELED_BY_USER, 67 ERROR_CODE_CANCELED_AND_LAUNCHED_SETTINGS, 68 ERROR_CODE_UI_FAILURE, 69 }) 70 @Retention(RetentionPolicy.SOURCE) 71 public @interface ErrorCode { 72 } 73 74 /** 75 * The UI was stopped due to a failure, e.g. because it failed to parse the incoming data, 76 * or it encountered an irrecoverable internal issue. 77 * 78 * This code also serves as a default value to use for failures that do not fall into any other 79 * error code category or for backward compatibility. 80 */ 81 public static final int ERROR_CODE_UI_FAILURE = 0; 82 /** The user intentionally canceled the dialog. */ 83 public static final int ERROR_CODE_DIALOG_CANCELED_BY_USER = 1; 84 /** 85 * The UI was stopped since the user has chosen to navigate to the Settings UI to reconfigure 86 * their providers. 87 */ 88 public static final int ERROR_CODE_CANCELED_AND_LAUNCHED_SETTINGS = 2; 89 90 /** 91 * Constructs a {@link FailureResult}. 92 * 93 * @throws IllegalArgumentException if {@code providerId} is empty 94 */ FailureResult(@rrorCode int errorCode, @Nullable String errorMessage)95 public FailureResult(@ErrorCode int errorCode, @Nullable String errorMessage) { 96 mErrorCode = errorCode; 97 mErrorMessage = errorMessage; 98 } 99 100 /** Returns the error code. */ 101 @ErrorCode getErrorCode()102 public int getErrorCode() { 103 return mErrorCode; 104 } 105 106 /** Returns the error message. */ 107 @Nullable getErrorMessage()108 public String getErrorMessage() { 109 return mErrorMessage; 110 } 111 toFailureDialogResult()112 FailureDialogResult toFailureDialogResult() { 113 return new FailureDialogResult(/*requestToken=*/null, mErrorMessage); 114 } 115 errorCodeToResultCode()116 int errorCodeToResultCode() { 117 switch (mErrorCode) { 118 case ERROR_CODE_DIALOG_CANCELED_BY_USER: 119 return BaseDialogResult.RESULT_CODE_DIALOG_USER_CANCELED; 120 case ERROR_CODE_CANCELED_AND_LAUNCHED_SETTINGS: 121 return BaseDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS; 122 default: 123 return BaseDialogResult.RESULT_CODE_DATA_PARSING_FAILURE; 124 } 125 } 126 } 127