Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This file is meant as an easy way for us to collate notes and change logs across
- Backing out of the PersonalID phone number screen while the app is contacting the server no longer crashes the app.
- When too many incorrect email or phone OTP codes are entered, the OTP code is now reported as no longer usable and the user is prompted to request a new one, instead of showing a generic error. The wait before a new OTP code can be requested is now shown accurately.
- Fixed an issue where the day and year fields of the date widget used by date questions with a `gregorian` appearance could not be edited with the keyboard in landscape.
- When a phone OTP code sent through Firebase expires or runs out of attempts, PersonalID now asks the user to request a new code instead of reporting the code as wrong.

#### Internal Release Notes

Expand All @@ -42,6 +43,8 @@ This file is meant as an easy way for us to collate notes and change logs across
- On an opportunity with no daily visit limit, confirm the delivery dashboard and the job tile on the app home screen show only today's visit count with no progress bar, and no daily-limit warning appears.
- Confirm the opportunity intro and learning-complete screens omit the "Up to N per day" text for such opportunities.
- On an opportunity that still has daily limits, confirm the daily progress bar and daily-limit warnings work as before.
- With a phone number that gets its OTP code through Firebase, enter a wrong code three times. Confirm the field clears, the message says the code is no longer valid, and Request Code is offered straight away.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- Rotate the device in that state and confirm the code field stays disabled.

## CommCare 2.64.1

Expand Down
25 changes: 16 additions & 9 deletions app/res/layout/screen_personalid_phone_verify.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,13 @@
android:layout_marginTop="@dimen/connect_space_xs"
tools:text="Resend OTP in 60s" />

<RelativeLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/connect_space_lg"
android:layout_marginTop="@dimen/connect_space_lg"
android:layout_marginEnd="@dimen/connect_space_lg"
android:layout_marginBottom="@dimen/connect_space_lg"
android:orientation="horizontal">
android:layout_marginBottom="@dimen/connect_space_lg">

<com.google.android.material.button.MaterialButton
android:id="@+id/connect_deactivate_button"
Expand All @@ -115,28 +114,36 @@
android:gravity="center"
android:text="@string/connect_deactivate_account"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

<com.google.android.material.button.MaterialButton
android:id="@+id/connect_resend_button"
style="@style/NegativeButtonStyle"
android:layout_width="150dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/connect_space_lg"
android:padding="@dimen/connect_space_md"
android:visibility="gone"
android:text="@string/connect_verify_phone_resend_code"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@id/connect_phone_verify_button"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

<com.google.android.material.button.MaterialButton
android:id="@+id/connect_phone_verify_button"
style="@style/ConnectPrimaryButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:text="@string/connect_verify_phone_verify" />
android:text="@string/connect_verify_phone_verify"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

</LinearLayout>
</layout>
1 change: 1 addition & 0 deletions app/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
<string name="personalid_email_otp_failed_wait">Esperar</string>
<string name="personalid_email_otp_failed_skip">Continuar sin correo</string>
<string name="personalid_otp_limit_exceeded">Ha utilizado todos los intentos para este código, por lo que ya no es válido. Solicite un código nuevo para continuar.</string>
<string name="personalid_otp_session_expired">Este código ya no es válido. Solicite un código nuevo para continuar.</string>
<string name="personalid_rate_limited_retry_after">Demasiados intentos. Vuelva a intentarlo en %1$s.</string>
<string name="personalid_otp_resend_wait">¿No recibió su código? Reenviar en %1$s</string>
<string name="personalid_otp_request_new_code_wait">Espere %1$s para solicitar un código nuevo</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ License.
<string name="personalid_email_otp_failed_wait">Attendre</string>
<string name="personalid_email_otp_failed_skip">Continuer sans e-mail</string>
<string name="personalid_otp_limit_exceeded">Vous avez utilisé toutes les tentatives pour ce code, il n\'est donc plus valide. Demandez un nouveau code pour continuer.</string>
<string name="personalid_otp_session_expired">Ce code n\'est plus valide. Demandez un nouveau code pour continuer.</string>
<string name="personalid_rate_limited_retry_after">Trop de tentatives. Veuillez réessayer dans %1$s.</string>
<string name="personalid_otp_resend_wait">Vous n\'avez pas reçu votre code ? Renvoyer dans %1$s</string>
<string name="personalid_otp_request_new_code_wait">Attendez %1$s pour demander un nouveau code</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-ha/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Don cikakken aiki na wurin zama na aikace-aikace da yawa, da fatan za a yi sabon
<string name="personalid_email_otp_failed_wait">Jira</string>
<string name="personalid_email_otp_failed_skip">Ci gaba ba tare da imel ba</string>
<string name="personalid_otp_limit_exceeded">Ka yi amfani da dukkan yunƙurin wannan lambar, don haka ba ta da inganci. Nemi sabuwar lamba don ci gaba.</string>
<string name="personalid_otp_session_expired">Wannan lambar ba ta da inganci yanzu. Nemi sabuwar lamba don ci gaba.</string>
<string name="personalid_rate_limited_retry_after">Yunƙuri da yawa. Don Allah sake gwadawa cikin %1$s.</string>
<string name="personalid_otp_resend_wait">Ba ka karɓi lambarka ba? Sake aikawa cikin %1$s</string>
<string name="personalid_otp_request_new_code_wait">Jira %1$s don neman sabuwar lamba</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-hi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ License.
<string name="personalid_email_otp_failed_wait">प्रतीक्षा करें</string>
<string name="personalid_email_otp_failed_skip">ईमेल के बिना आगे बढ़ें</string>
<string name="personalid_otp_limit_exceeded">आपने इस कोड के सभी प्रयास उपयोग कर लिए हैं, इसलिए यह अब मान्य नहीं है। जारी रखने के लिए नया कोड माँगें।</string>
<string name="personalid_otp_session_expired">यह कोड अब मान्य नहीं है। जारी रखने के लिए नया कोड माँगें।</string>
<string name="personalid_rate_limited_retry_after">बहुत अधिक प्रयास। कृपया %1$s में पुनः प्रयास करें।</string>
<string name="personalid_otp_resend_wait">आपको अपना कोड नहीं मिला? %1$s में पुनः भेजें</string>
<string name="personalid_otp_request_new_code_wait">नया कोड माँगने के लिए %1$s प्रतीक्षा करें</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-lt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@
<string name="personalid_email_otp_failed_wait">Palaukti</string>
<string name="personalid_email_otp_failed_skip">Tęsti be el. pašto</string>
<string name="personalid_otp_limit_exceeded">Išnaudojote visus šio kodo bandymus, todėl jis nebegalioja. Norėdami tęsti, užsisakykite naują kodą.</string>
<string name="personalid_otp_session_expired">Šis kodas nebegalioja. Norėdami tęsti, užsisakykite naują kodą.</string>
<string name="personalid_rate_limited_retry_after">Per daug bandymų. Bandykite dar kartą po %1$s.</string>
<string name="personalid_otp_resend_wait">Negavote kodo? Siųsti iš naujo po %1$s</string>
<string name="personalid_otp_request_new_code_wait">Palaukite %1$s, kad galėtumėte užsisakyti naują kodą</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-no/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
<string name="personalid_email_otp_failed_wait">Vent</string>
<string name="personalid_email_otp_failed_skip">Fortsett uten e-post</string>
<string name="personalid_otp_limit_exceeded">Du har brukt alle forsøkene for denne koden, så den er ikke lenger gyldig. Be om en ny kode for å fortsette.</string>
<string name="personalid_otp_session_expired">Denne koden er ikke lenger gyldig. Be om en ny kode for å fortsette.</string>
<string name="personalid_rate_limited_retry_after">For mange forsøk. Prøv igjen om %1$s.</string>
<string name="personalid_otp_resend_wait">Fikk du ikke koden? Send på nytt om %1$s</string>
<string name="personalid_otp_request_new_code_wait">Vent %1$s for å be om en ny kode</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@
<string name="personalid_email_otp_failed_wait">Aguardar</string>
<string name="personalid_email_otp_failed_skip">Continuar sem e-mail</string>
<string name="personalid_otp_limit_exceeded">Você usou todas as tentativas deste código, por isso ele não é mais válido. Solicite um novo código para continuar.</string>
<string name="personalid_otp_session_expired">Este código não é mais válido. Solicite um novo código para continuar.</string>
<string name="personalid_rate_limited_retry_after">Muitas tentativas. Tente novamente em %1$s.</string>
<string name="personalid_otp_resend_wait">Não recebeu seu código? Reenviar em %1$s</string>
<string name="personalid_otp_request_new_code_wait">Aguarde %1$s para solicitar um novo código</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-sw/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@
<string name="personalid_email_otp_failed_wait">Subiri</string>
<string name="personalid_email_otp_failed_skip">Endelea bila barua pepe</string>
<string name="personalid_otp_limit_exceeded">Umetumia majaribio yote ya msimbo huu, kwa hivyo hauna tena uhalali. Omba msimbo mpya ili kuendelea.</string>
<string name="personalid_otp_session_expired">Msimbo huu hauna tena uhalali. Omba msimbo mpya ili kuendelea.</string>
<string name="personalid_rate_limited_retry_after">Majaribio mengi mno. Tafadhali jaribu tena baada ya %1$s.</string>
<string name="personalid_otp_resend_wait">Hukupokea msimbo wako? Tuma tena baada ya %1$s</string>
<string name="personalid_otp_request_new_code_wait">Subiri %1$s ili kuomba msimbo mpya</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values-ti/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@
<string name="personalid_email_otp_failed_wait">ተጸበዩ</string>
<string name="personalid_email_otp_failed_skip">ብዘይ ኢመይል ቅፀል</string>
<string name="personalid_otp_limit_exceeded">ንዚ ኮድ እዚ ኩሉ ፈተነታት ተጠቒምኩምሉ ኢኹም፣ ስለዚ ደጊም ኣይሰርሕን እዩ። ንምቕጻል ሓድሽ ኮድ ሕተቱ።</string>
<string name="personalid_otp_session_expired">እዚ ኮድ እዚ ደጊም ኣይሰርሕን እዩ። ንምቕጻል ሓድሽ ኮድ ሕተቱ።</string>
<string name="personalid_rate_limited_retry_after">ብዙሕ ፈተነታት። በጃኹም ድሕሪ %1$s ደጊምኩም ፈትኑ።</string>
<string name="personalid_otp_resend_wait">ኮድኩም ኣይበጽሐኩምን ድዩ? ድሕሪ %1$s ደጊምኩም ስደዱ</string>
<string name="personalid_otp_request_new_code_wait">ሓድሽ ኮድ ንምሕታት %1$s ተጸበዩ</string>
Expand Down
1 change: 1 addition & 0 deletions app/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@
<string name="personalid_email_otp_failed_wait">Wait</string>
<string name="personalid_email_otp_failed_skip">Proceed without email</string>
<string name="personalid_otp_limit_exceeded">You have used all the attempts for this code, so it is no longer valid. Request a new code to continue.</string>
<string name="personalid_otp_session_expired">This code is no longer valid. Request a new code to continue.</string>
<string name="personalid_rate_limited_retry_after">Too many attempts. Please try again in %1$s.</string>
<string name="personalid_otp_resend_wait">Didn\'t receive your code? Resend in %1$s</string>
<string name="personalid_otp_request_new_code_wait">Wait %1$s to request a new code</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ abstract class BasePersonalIdPhoneVerificationFragment : BasePersonalIdFragment(
return
}

if (errorType == OtpErrorType.SESSION_EXPIRED) {
showCodeNoLongerValid(getString(R.string.personalid_otp_session_expired), 0)
return
}

val userMessage =
when (errorType) {
OtpErrorType.INVALID_CREDENTIAL -> {
Expand Down Expand Up @@ -265,6 +270,7 @@ abstract class BasePersonalIdPhoneVerificationFragment : BasePersonalIdFragment(
otpRequestTime = DateTime.parse(otpRequestTimeString)
}
binding.connectPhoneVerifyButton.isEnabled = verifyButtonEnabled
binding.customOtpView.isEnabled = !otpLimitExceeded
}

private fun setupListeners() {
Expand Down Expand Up @@ -308,21 +314,28 @@ abstract class BasePersonalIdPhoneVerificationFragment : BasePersonalIdFragment(
}

private fun onOtpLimitExceeded(throwable: Throwable?) {
val retryAfterSeconds = (throwable as? RateLimitedException)?.retryAfterSeconds
val limitExceededMessage =
PersonalIdOrConnectApiErrorHandler.handle(
requireActivity(),
PersonalIdOrConnectApiErrorCodes.OTP_LIMIT_EXCEEDED_ERROR,
throwable,
)
showCodeNoLongerValid(limitExceededMessage, retryAfterSeconds ?: 0)
}

private fun showCodeNoLongerValid(
message: String?,
retryAfterSeconds: Int,
) {
otpLimitExceeded = true
binding.customOtpView.clearCode()
binding.customOtpView.isEnabled = false
binding.connectPhoneVerifyButton.isEnabled = false
val retryAfterSeconds = (throwable as? RateLimitedException)?.retryAfterSeconds
resendCooldownSeconds = retryAfterSeconds ?: 0
resendCooldownSeconds = retryAfterSeconds
otpRequestTime = DateTime()
updateResendButtonState()
displayOtpError(
PersonalIdOrConnectApiErrorHandler.handle(
requireActivity(),
PersonalIdOrConnectApiErrorCodes.OTP_LIMIT_EXCEEDED_ERROR,
throwable,
),
)
displayOtpError(message)
}

private fun clearOtpError() {
Expand Down Expand Up @@ -507,6 +520,8 @@ abstract class BasePersonalIdPhoneVerificationFragment : BasePersonalIdFragment(

binding.connectResendButton.setText(resendButtonLabel)
binding.connectResendButton.visibility = if (canResend) View.VISIBLE else View.GONE
binding.connectPhoneVerifyResend.visibility =
if (otpLimitExceeded && canResend) View.GONE else View.VISIBLE

val resendStatusText =
if (canResend) {
Expand Down
7 changes: 6 additions & 1 deletion app/src/org/commcare/utils/FirebaseAuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

public class FirebaseAuthService implements OtpAuthService {

private static final String ERROR_SESSION_EXPIRED = "ERROR_SESSION_EXPIRED";

private final FirebaseAuth firebaseAuth;
private final OtpVerificationCallback callback;
private final Activity activity;
Expand Down Expand Up @@ -129,7 +131,10 @@ private void firebaseAuthenticator(PhoneAuthCredential credential) {
@VisibleForTesting
static OtpErrorType errorTypeFrom(Exception e) {
if (e instanceof FirebaseAuthInvalidCredentialsException) {
return OtpErrorType.INVALID_CREDENTIAL;
String errorCode = ((FirebaseAuthInvalidCredentialsException) e).getErrorCode();
return ERROR_SESSION_EXPIRED.equals(errorCode)
? OtpErrorType.SESSION_EXPIRED
: OtpErrorType.INVALID_CREDENTIAL;
} else if (e instanceof FirebaseTooManyRequestsException) {
return OtpErrorType.TOO_MANY_REQUESTS;
} else if (e instanceof FirebaseAuthMissingActivityForRecaptchaException) {
Expand Down
12 changes: 7 additions & 5 deletions app/src/org/commcare/utils/OtpErrorType.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@

public enum OtpErrorType {
INVALID_CREDENTIAL,
SESSION_EXPIRED,
TOO_MANY_REQUESTS,
MISSING_ACTIVITY,
GENERIC_ERROR,
VERIFICATION_FAILED;

/**
* INVALID_CREDENTIAL is the only error the user can act on themselves; it means the phone
* number or the code they supplied was malformed, missing or expired. Everything else
* indicates Firebase cannot deliver an OTP at all, so we treat unrecognised errors as
* non-recoverable and let the caller fall back to PersonalID SMS.
* INVALID_CREDENTIAL and SESSION_EXPIRED are the only errors the user can act on themselves:
* the phone number or code they supplied was malformed or missing, or the code is no longer
* valid and a new one must be requested. Everything else indicates Firebase cannot deliver an
* OTP at all, so we treat unrecognized errors as non-recoverable and let the caller fall back
* to PersonalID SMS.
*/
public boolean isNonRecoverable() {
return this != OtpErrorType.INVALID_CREDENTIAL;
return this != OtpErrorType.INVALID_CREDENTIAL && this != OtpErrorType.SESSION_EXPIRED;
}
}
Loading
Loading