diff --git a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthError.java b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthError.java new file mode 100644 index 000000000..45ad781fa --- /dev/null +++ b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthError.java @@ -0,0 +1,109 @@ +package com.firebase.ui.auth; + +import android.support.annotation.RestrictTo; + +import com.google.firebase.auth.FirebaseAuthException; + +/** + * List of all possible results of {@link FirebaseAuthException#getErrorCode()} and their meanings. + * + * This is a temporary band-aid until we have better documentation and exposure for these + * error codes in the real Firebase Auth SDK. + */ +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public enum FirebaseAuthError { + + ERROR_INVALID_CUSTOM_TOKEN("The custom token format is incorrect. Please check the documentation."), + + ERROR_CUSTOM_TOKEN_MISMATCH("Invalid configuration. Ensure your app's SHA1 is correct in the Firebase console."), + + ERROR_INVALID_CREDENTIAL("The supplied auth credential is malformed or has expired."), + + ERROR_INVALID_EMAIL("The email address is badly formatted."), + + ERROR_WRONG_PASSWORD("The password is invalid or the user does not have a password."), + + ERROR_USER_MISMATCH("The supplied credentials do not correspond to the previously signed in user."), + + ERROR_REQUIRES_RECENT_LOGIN("This operation is sensitive and requires recent authentication. Log in again before retrying this request."), + + ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL("An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address."), + + ERROR_EMAIL_ALREADY_IN_USE("The email address is already in use by another account."), + + ERROR_CREDENTIAL_ALREADY_IN_USE("This credential is already associated with a different user account."), + + ERROR_USER_DISABLED( "The user account has been disabled by an administrator."), + + ERROR_USER_TOKEN_EXPIRED("The user's credential has expired. The user must sign in again."), + + ERROR_USER_NOT_FOUND("There is no user record corresponding to this identifier. The user may have been deleted."), + + ERROR_INVALID_USER_TOKEN("The user's credential is no longer valid. The user must sign in again."), + + ERROR_OPERATION_NOT_ALLOWED("This operation is not allowed. Enable the sign-in method in the Authentication tab of the Firebase console"), + + ERROR_TOO_MANY_REQUESTS("We have blocked all requests from this device due to unusual activity. Try again later."), + + ERROR_WEAK_PASSWORD("The given password is too weak, please choose a stronger password."), + + ERROR_EXPIRED_ACTION_CODE("The out of band code has expired."), + + ERROR_INVALID_ACTION_CODE("The out of band code is invalid. This can happen if the code is malformed, expired, or has already been used."), + + ERROR_INVALID_MESSAGE_PAYLOAD("The email template corresponding to this action contains invalid characters in its message. Please fix by going to the Auth email templates section in the Firebase Console."), + + ERROR_INVALID_RECIPIENT_EMAIL("The email corresponding to this action failed to send as the provided recipient email address is invalid."), + + ERROR_INVALID_SENDER("The email template corresponding to this action contains an invalid sender email or name. Please fix by going to the Auth email templates section in the Firebase Console."), + + ERROR_MISSING_EMAIL("An email address must be provided."), + + ERROR_MISSING_PASSWORD("A password must be provided."), + + ERROR_MISSING_PHONE_NUMBER("To send verification codes, provide a phone number for the recipient."), + + ERROR_INVALID_PHONE_NUMBER("The format of the phone number provided is incorrect. Please enter the phone number in a format that can be parsed into E.164 format. E.164 phone numbers are written in the format [+][country code][subscriber number including area code]."), + + ERROR_MISSING_VERIFICATION_CODE("The phone auth credential was created with an empty sms verification code"), + + ERROR_INVALID_VERIFICATION_CODE("The sms verification code used to create the phone auth credential is invalid. Please resend the verification code sms and be sure use the verification code provided by the user."), + + ERROR_MISSING_VERIFICATION_ID("The phone auth credential was created with an empty verification ID"), + + ERROR_INVALID_VERIFICATION_ID("The verification ID used to create the phone auth credential is invalid."), + + ERROR_RETRY_PHONE_AUTH("An error occurred during authentication using the PhoneAuthCredential. Please retry authentication."), + + ERROR_SESSION_EXPIRED("The sms code has expired. Please re-send the verification code to try again."), + + ERROR_QUOTA_EXCEEDED("The sms quota for this project has been exceeded."), + + ERROR_APP_NOT_AUTHORIZED("This app is not authorized to use Firebase Authentication. Please verify that the correct package name and SHA-1 are configured in the Firebase Console."), + + ERROR_API_NOT_AVAILABLE("The API that you are calling is not available on devices without Google Play Services."), + + ERROR_UNKNOWN("An unknown error occurred."); + + /** + * Get an {@link FirebaseAuthError} from an exception, returning {@link #ERROR_UNKNOWN} as + * a default. + */ + public static FirebaseAuthError fromException(FirebaseAuthException ex) { + try { + return FirebaseAuthError.valueOf(ex.getErrorCode()); + } catch (IllegalArgumentException e) { + return FirebaseAuthError.ERROR_UNKNOWN; + } + } + + private final String description; + + FirebaseAuthError(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivity.java b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivity.java index 76579825b..deb59e20a 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivity.java +++ b/auth/src/main/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivity.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.util.Log; +import com.firebase.ui.auth.FirebaseAuthError; import com.firebase.ui.auth.IdpResponse; import com.firebase.ui.auth.R; import com.firebase.ui.auth.ResultCodes; @@ -60,11 +61,7 @@ private enum VerificationState { private static final long SHORT_DELAY_MILLIS = 750; @VisibleForTesting static final long AUTO_RETRIEVAL_TIMEOUT_MILLIS = 120000; - @VisibleForTesting static final String ERROR_INVALID_PHONE = "ERROR_INVALID_PHONE_NUMBER"; - @VisibleForTesting static final String ERROR_INVALID_VERIFICATION = "ERROR_INVALID_VERIFICATION_CODE"; - private static final String ERROR_TOO_MANY_REQUESTS = "ERROR_TOO_MANY_REQUESTS"; - private static final String ERROR_QUOTA_EXCEEDED = "ERROR_QUOTA_EXCEEDED"; - private static final String ERROR_SESSION_EXPIRED = "ERROR_SESSION_EXPIRED"; + private static final String KEY_VERIFICATION_PHONE = "KEY_VERIFICATION_PHONE"; private static final String KEY_STATE = "KEY_STATE"; @@ -202,9 +199,10 @@ private void onVerificationFailed(@NonNull FirebaseException ex) { return; } if (ex instanceof FirebaseAuthException) { - FirebaseAuthException firebaseAuthException = (FirebaseAuthException) ex; - switch (firebaseAuthException.getErrorCode()) { - case ERROR_INVALID_PHONE: + FirebaseAuthError error = FirebaseAuthError.fromException((FirebaseAuthException) ex); + + switch (error) { + case ERROR_INVALID_PHONE_NUMBER: verifyPhoneNumberFragment.showError(getString(R.string.invalid_phone_number)); dismissLoadingDialog(); break; @@ -217,9 +215,9 @@ private void onVerificationFailed(@NonNull FirebaseException ex) { dismissLoadingDialog(); break; default: - Log.w(PHONE_VERIFICATION_LOG_TAG, ex.getLocalizedMessage()); + Log.w(PHONE_VERIFICATION_LOG_TAG, error.getDescription(), ex); dismissLoadingDialog(); - showAlertDialog(ex.getLocalizedMessage(), null); + showAlertDialog(error.getDescription(), null); } } else { Log.w(PHONE_VERIFICATION_LOG_TAG, ex.getLocalizedMessage()); @@ -331,10 +329,11 @@ public void onFailure(@NonNull Exception e) { dismissLoadingDialog(); //incorrect confirmation code if (e instanceof FirebaseAuthInvalidCredentialsException) { - FirebaseAuthInvalidCredentialsException firebaseAuthInvalidCredentialsException - = (FirebaseAuthInvalidCredentialsException) e; - switch (firebaseAuthInvalidCredentialsException.getErrorCode()) { - case ERROR_INVALID_VERIFICATION: + FirebaseAuthError error = FirebaseAuthError.fromException( + (FirebaseAuthInvalidCredentialsException) e); + + switch (error) { + case ERROR_INVALID_VERIFICATION_CODE: showAlertDialog( getString(R.string.incorrect_code_dialog_body), new DialogInterface.OnClickListener() { @@ -357,7 +356,8 @@ public void onClick(DialogInterface dialog, int which) { }); break; default: - showAlertDialog(e.getLocalizedMessage(), null); + Log.w(PHONE_VERIFICATION_LOG_TAG, error.getDescription(), e); + showAlertDialog(error.getDescription(), null); } } else { showAlertDialog(e.getLocalizedMessage(), null); diff --git a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivityTest.java b/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivityTest.java index b7d827017..3f8c7d1ed 100644 --- a/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivityTest.java +++ b/auth/src/test/java/com/firebase/ui/auth/ui/phone/PhoneVerificationActivityTest.java @@ -24,6 +24,7 @@ import com.firebase.ui.auth.AuthUI; import com.firebase.ui.auth.BuildConfig; +import com.firebase.ui.auth.FirebaseAuthError; import com.firebase.ui.auth.R; import com.firebase.ui.auth.testhelpers.AuthHelperShadow; import com.firebase.ui.auth.testhelpers.AutoCompleteTask; @@ -58,8 +59,6 @@ import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.YE_COUNTRY_CODE; import static com.firebase.ui.auth.ui.phone.PhoneTestConstants.YE_RAW_PHONE; import static com.firebase.ui.auth.ui.phone.PhoneVerificationActivity.AUTO_RETRIEVAL_TIMEOUT_MILLIS; -import static com.firebase.ui.auth.ui.phone.PhoneVerificationActivity.ERROR_INVALID_PHONE; -import static com.firebase.ui.auth.ui.phone.PhoneVerificationActivity.ERROR_INVALID_VERIFICATION; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; @@ -173,7 +172,9 @@ public void testVerifyPhoneNumberInvalidPhoneException_showsInlineError() { PhoneAuthProvider.OnVerificationStateChangedCallbacks onVerificationStateChangedCallbacks = callbacksArgumentCaptor.getValue(); onVerificationStateChangedCallbacks.onVerificationFailed( - new FirebaseAuthException(ERROR_INVALID_PHONE, "any_message")); + new FirebaseAuthException( + FirebaseAuthError.ERROR_INVALID_PHONE_NUMBER.toString(), + "any_message")); //was error displayed assertEquals(mErrorEditText.getText(), mActivity.getString(R.string.invalid_phone_number)); @@ -199,7 +200,7 @@ public void testVerifyPhoneNumberNoMsgException_showsAlertDialog() { onVerificationStateChangedCallbacks.onVerificationFailed( new FirebaseAuthException("some_code", "custom_message")); assertTrue(mActivity.getAlertDialog().isShowing()); - assertEquals("custom_message", getAlertDialogMessage()); + assertEquals(FirebaseAuthError.ERROR_UNKNOWN.getDescription(), getAlertDialogMessage()); } @Test @@ -217,7 +218,7 @@ public void testSubmitCode_badCodeShowsAlertDialog() { .thenReturn(new AutoCompleteTask( null, true, new FirebaseAuthInvalidCredentialsException( - ERROR_INVALID_VERIFICATION, + FirebaseAuthError.ERROR_INVALID_VERIFICATION_CODE.toString(), "any_msg"))); testSendConfirmationCode(); SpacedEditText mConfirmationCodeEditText = (SpacedEditText) mActivity.findViewById(R.id.confirmation_code);