diff --git a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt
index 52427bba9..fcae3ea9c 100644
--- a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt
+++ b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt
@@ -14,10 +14,16 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.ShapeDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
+import androidx.compose.material3.TooltipAnchorPosition
+import androidx.compose.material3.TooltipBox
+import androidx.compose.material3.TooltipDefaults
+import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -57,6 +63,7 @@ class HighLevelApiDemoActivity : ComponentActivity() {
tosUrl = "https://policies.google.com/terms"
privacyPolicyUrl = "https://policies.google.com/privacy"
isAnonymousUpgradeEnabled = false
+ isMfaEnabled = false
transitions = AuthUITransitions(
enterTransition = { slideInHorizontally { it } },
exitTransition = { slideOutHorizontally { -it } },
@@ -193,12 +200,14 @@ class HighLevelApiDemoActivity : ComponentActivity() {
}
}
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AppAuthenticatedContent(
state: AuthState,
uiContext: AuthSuccessUiContext
) {
val stringProvider = uiContext.stringProvider
+ val configuration = uiContext.configuration
when (state) {
is AuthState.Success -> {
val user = uiContext.authUI.getCurrentUser()
@@ -226,8 +235,25 @@ private fun AppAuthenticatedContent(
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(16.dp))
- Button(onClick = uiContext.onManageMfa) {
- Text(stringProvider.manageMfaAction)
+ TooltipBox(
+ positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
+ TooltipAnchorPosition.Above
+ ),
+ tooltip = {
+ PlainTooltip {
+ Text(stringProvider.mfaDisabledTooltip)
+ }
+ },
+ state = rememberTooltipState(
+ initialIsVisible = !configuration.isMfaEnabled
+ )
+ ) {
+ Button(
+ onClick = uiContext.onManageMfa,
+ enabled = configuration.isMfaEnabled
+ ) {
+ Text(stringProvider.manageMfaAction)
+ }
}
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = uiContext.onSignOut) {
diff --git a/auth/README.md b/auth/README.md
index ecc3208aa..6061eea06 100644
--- a/auth/README.md
+++ b/auth/README.md
@@ -138,6 +138,7 @@ If using Facebook Login, add your Facebook App ID to `strings.xml`:
YOUR_FACEBOOK_APP_ID
fbYOUR_FACEBOOK_APP_ID
+ CHANGE-ME
```
@@ -489,9 +490,6 @@ Configure Facebook Login with optional permissions:
```kotlin
val facebookProvider = AuthProvider.Facebook(
- // Optional: Facebook application ID (reads from strings.xml if not provided)
- applicationId = "YOUR_FACEBOOK_APP_ID",
-
// Optional: Permissions to request (default: ["email", "public_profile"])
scopes = listOf("email", "public_profile", "user_friends"),
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt
index 1b659a8fc..5cf392a8c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt
@@ -485,7 +485,21 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
/**
* The OAuth 2.0 client ID for your server.
*/
- val serverClientId: String?,
+ var serverClientId: String?,
+
+ /**
+ * Whether to filter by authorized accounts.
+ * When true, only shows Google accounts that have previously authorized this app.
+ * Defaults to true, with automatic fallback to false if no authorized accounts found.
+ */
+ val filterByAuthorizedAccounts: Boolean = true,
+
+ /**
+ * Whether to enable auto-select for single account scenarios.
+ * When true, automatically selects the account if only one is available.
+ * Defaults to false for better user control.
+ */
+ val autoSelectEnabled: Boolean = false,
/**
* A map of custom OAuth parameters.
@@ -505,8 +519,9 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
" default_web_client_id string wasn't populated.",
R.string.default_web_client_id
)
+ serverClientId = context.getString(R.string.default_web_client_id)
} else {
- require(serverClientId.isNotBlank()) {
+ require(serverClientId!!.isNotBlank()) {
"Server client ID cannot be blank."
}
}
@@ -529,7 +544,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
val credential: AuthCredential,
val idToken: String,
val displayName: String?,
- val photoUrl: Uri?
+ val photoUrl: Uri?,
)
/**
@@ -567,7 +582,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
credentialManager: CredentialManager,
serverClientId: String,
filterByAuthorizedAccounts: Boolean,
- autoSelectEnabled: Boolean
+ autoSelectEnabled: Boolean,
): GoogleSignInResult
suspend fun clearCredentialState(
@@ -600,8 +615,10 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
.build()
val result = credentialManager.getCredential(context, request)
- val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(result.credential.data)
- val credential = GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null)
+ val googleIdTokenCredential =
+ GoogleIdTokenCredential.createFrom(result.credential.data)
+ val credential =
+ GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null)
return GoogleSignInResult(
credential = credential,
@@ -624,11 +641,6 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
* Facebook Login provider configuration.
*/
class Facebook(
- /**
- * The Facebook application ID.
- */
- val applicationId: String? = null,
-
/**
* The list of scopes (permissions) to request. Defaults to email and public_profile.
*/
@@ -653,18 +665,26 @@ abstract class AuthProvider(open val providerId: String, open val providerName:
)
}
- if (applicationId == null) {
- Preconditions.checkConfigured(
- context,
- "Facebook provider unconfigured. Make sure to " +
- "add a `facebook_application_id` string or provide applicationId parameter.",
- R.string.facebook_application_id
- )
- } else {
- require(applicationId.isNotBlank()) {
- "Facebook application ID cannot be blank"
- }
- }
+ Preconditions.checkConfigured(
+ context,
+ "Facebook provider unconfigured. Make sure to " +
+ "add a `facebook_application_id` string to your strings.xml",
+ R.string.facebook_application_id
+ )
+
+ Preconditions.checkConfigured(
+ context,
+ "Facebook provider unconfigured. Make sure to " +
+ "add a `facebook_login_protocol_scheme` string to your strings.xml",
+ R.string.facebook_login_protocol_scheme
+ )
+
+ Preconditions.checkConfigured(
+ context,
+ "Facebook provider unconfigured. Make sure to " +
+ "add a `facebook_client_token` string to your strings.xml",
+ R.string.facebook_client_token
+ )
}
/**
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
index 2afdb3599..4d18cb0a9 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
@@ -133,14 +133,48 @@ internal suspend fun FirebaseAuthUI.signInWithGoogle(
}
}
- val result =
+ // Try with configured filterByAuthorizedAccounts setting
+ // If default (true), fallback to false if no authorized accounts found
+ // See: https://developer.android.com/identity/sign-in/credential-manager-siwg#siwg-button
+ val result = if (provider.filterByAuthorizedAccounts) {
+ // Default behavior: Try authorized accounts first, fallback to all accounts
+ try {
+ (testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential(
+ context = context,
+ credentialManager = CredentialManager.create(context),
+ serverClientId = provider.serverClientId!!,
+ filterByAuthorizedAccounts = true,
+ autoSelectEnabled = provider.autoSelectEnabled
+ )
+ } catch (e: NoCredentialException) {
+ // No authorized accounts found, try again with all accounts for sign-up flow
+ Log.d("GoogleAuthProvider", "No authorized accounts found, showing all Google accounts for sign-up")
+ try {
+ (testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential(
+ context = context,
+ credentialManager = CredentialManager.create(context),
+ serverClientId = provider.serverClientId!!,
+ filterByAuthorizedAccounts = false,
+ autoSelectEnabled = provider.autoSelectEnabled
+ )
+ } catch (fallbackException: NoCredentialException) {
+ // No Google accounts available on device at all
+ throw AuthException.UnknownException(
+ message = "No Google accounts available.\n\nPlease add a Google account to your device and try again.",
+ cause = fallbackException
+ )
+ }
+ }
+ } else {
+ // Developer explicitly wants to show all accounts (no fallback needed)
(testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential(
context = context,
credentialManager = CredentialManager.create(context),
serverClientId = provider.serverClientId!!,
- filterByAuthorizedAccounts = true,
- autoSelectEnabled = false
+ filterByAuthorizedAccounts = false,
+ autoSelectEnabled = provider.autoSelectEnabled
)
+ }
idTokenFromResult = result.idToken
signInAndLinkWithCredential(
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
index df71966ab..a062debdd 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
@@ -539,4 +539,7 @@ interface AuthUIStringProvider {
/** Tooltip message shown when new account sign-up is disabled */
val newAccountsDisabledTooltip: String
+
+ /** Tooltip message shown when MFA is disabled */
+ val mfaDisabledTooltip: String
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
index a0e53e2a9..429d6d286 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
@@ -491,4 +491,7 @@ class DefaultAuthUIStringProvider(
override val newAccountsDisabledTooltip: String
get() = localizedContext.getString(R.string.fui_new_accounts_disabled_tooltip)
+
+ override val mfaDisabledTooltip: String
+ get() = localizedContext.getString(R.string.fui_mfa_disabled_tooltip)
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
index 6b3bf5d38..5a065400c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
@@ -28,10 +28,16 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
+import androidx.compose.material3.TooltipAnchorPosition
+import androidx.compose.material3.TooltipBox
+import androidx.compose.material3.TooltipDefaults
+import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@@ -348,6 +354,7 @@ fun FirebaseAuthScreen(
AuthSuccessUiContext(
authUI = authUI,
stringProvider = stringProvider,
+ configuration = configuration,
onSignOut = {
coroutineScope.launch {
try {
@@ -362,7 +369,15 @@ fun FirebaseAuthScreen(
}
},
onManageMfa = {
- navController.navigate(AuthRoute.MfaEnrollment.route)
+ if (configuration.isMfaEnabled) {
+ navController.navigate(AuthRoute.MfaEnrollment.route)
+ } else {
+ val exception = AuthException.AuthCancelledException(
+ message = "Multi-factor authentication is disabled in the configuration. " +
+ "Enable MFA in AuthUIConfiguration to use this feature."
+ )
+ authUI.updateAuthState(AuthState.Error(exception))
+ }
},
onReloadUser = {
coroutineScope.launch {
@@ -410,6 +425,7 @@ fun FirebaseAuthScreen(
SuccessDestination(
authState = authState,
stringProvider = stringProvider,
+ configuration = configuration,
uiContext = uiContext
)
}
@@ -654,6 +670,7 @@ sealed class AuthRoute(val route: String) {
data class AuthSuccessUiContext(
val authUI: FirebaseAuthUI,
val stringProvider: AuthUIStringProvider,
+ val configuration: AuthUIConfiguration,
val onSignOut: () -> Unit,
val onManageMfa: () -> Unit,
val onReloadUser: () -> Unit,
@@ -664,6 +681,7 @@ data class AuthSuccessUiContext(
private fun SuccessDestination(
authState: AuthState,
stringProvider: AuthUIStringProvider,
+ configuration: AuthUIConfiguration,
uiContext: AuthSuccessUiContext,
) {
when (authState) {
@@ -671,6 +689,7 @@ private fun SuccessDestination(
AuthSuccessContent(
authUI = uiContext.authUI,
stringProvider = stringProvider,
+ configuration = configuration,
onSignOut = uiContext.onSignOut,
onManageMfa = uiContext.onManageMfa
)
@@ -704,10 +723,12 @@ private fun SuccessDestination(
}
}
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AuthSuccessContent(
authUI: FirebaseAuthUI,
stringProvider: AuthUIStringProvider,
+ configuration: AuthUIConfiguration,
onSignOut: () -> Unit,
onManageMfa: () -> Unit,
) {
@@ -726,8 +747,25 @@ private fun AuthSuccessContent(
Spacer(modifier = Modifier.height(16.dp))
}
if (user != null && authUI.auth.app.options.projectId != null) {
- Button(onClick = onManageMfa) {
- Text(stringProvider.manageMfaAction)
+ TooltipBox(
+ positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
+ TooltipAnchorPosition.Above
+ ),
+ tooltip = {
+ PlainTooltip {
+ Text(stringProvider.mfaDisabledTooltip)
+ }
+ },
+ state = rememberTooltipState(
+ initialIsVisible = !configuration.isMfaEnabled
+ )
+ ) {
+ Button(
+ onClick = onManageMfa,
+ enabled = configuration.isMfaEnabled
+ ) {
+ Text(stringProvider.manageMfaAction)
+ }
}
Spacer(modifier = Modifier.height(8.dp))
}
diff --git a/auth/src/main/res/values-ar/strings.xml b/auth/src/main/res/values-ar/strings.xml
index dcf4ca88c..e6d6f9b96 100755
--- a/auth/src/main/res/values-ar/strings.xml
+++ b/auth/src/main/res/values-ar/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ المصادقة متعددة العوامل معطلة حاليًا
diff --git a/auth/src/main/res/values-b+es+419/strings.xml b/auth/src/main/res/values-b+es+419/strings.xml
index 017b893bd..0513671be 100755
--- a/auth/src/main/res/values-b+es+419/strings.xml
+++ b/auth/src/main/res/values-b+es+419/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-bg/strings.xml b/auth/src/main/res/values-bg/strings.xml
index 8b9db9839..08432527b 100755
--- a/auth/src/main/res/values-bg/strings.xml
+++ b/auth/src/main/res/values-bg/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Многофакторната автентификация в момента е деактивирана
diff --git a/auth/src/main/res/values-bn/strings.xml b/auth/src/main/res/values-bn/strings.xml
index 747f19c8c..18010598a 100755
--- a/auth/src/main/res/values-bn/strings.xml
+++ b/auth/src/main/res/values-bn/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ মাল্টি-ফ্যাক্টর প্রমাণীকরণ বর্তমানে নিষ্ক্রিয়
diff --git a/auth/src/main/res/values-ca/strings.xml b/auth/src/main/res/values-ca/strings.xml
index 5b56f2489..a4cb13b80 100755
--- a/auth/src/main/res/values-ca/strings.xml
+++ b/auth/src/main/res/values-ca/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ L\'autenticació multifactor està desactivada actualment
diff --git a/auth/src/main/res/values-cs/strings.xml b/auth/src/main/res/values-cs/strings.xml
index 57afae344..527ddce0f 100755
--- a/auth/src/main/res/values-cs/strings.xml
+++ b/auth/src/main/res/values-cs/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Vícefaktorové ověřování je aktuálně zakázáno
diff --git a/auth/src/main/res/values-da/strings.xml b/auth/src/main/res/values-da/strings.xml
index 0b91742aa..0fb15c8cf 100755
--- a/auth/src/main/res/values-da/strings.xml
+++ b/auth/src/main/res/values-da/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multifaktorgodkendelse er i øjeblikket deaktiveret
diff --git a/auth/src/main/res/values-de-rAT/strings.xml b/auth/src/main/res/values-de-rAT/strings.xml
index 427f52319..10ebb575b 100755
--- a/auth/src/main/res/values-de-rAT/strings.xml
+++ b/auth/src/main/res/values-de-rAT/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert
diff --git a/auth/src/main/res/values-de-rCH/strings.xml b/auth/src/main/res/values-de-rCH/strings.xml
index 316f26f09..f45895074 100755
--- a/auth/src/main/res/values-de-rCH/strings.xml
+++ b/auth/src/main/res/values-de-rCH/strings.xml
@@ -198,4 +198,5 @@
This button is currently disabled because new accounts are not allowed
+ Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert
diff --git a/auth/src/main/res/values-de/strings.xml b/auth/src/main/res/values-de/strings.xml
index e7c0a9bd4..01232ea04 100755
--- a/auth/src/main/res/values-de/strings.xml
+++ b/auth/src/main/res/values-de/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert
diff --git a/auth/src/main/res/values-el/strings.xml b/auth/src/main/res/values-el/strings.xml
index 7a1872d87..434a11268 100755
--- a/auth/src/main/res/values-el/strings.xml
+++ b/auth/src/main/res/values-el/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Ο έλεγχος ταυτότητας πολλαπλών παραγόντων είναι απενεργοποιημένος προς το παρόν
diff --git a/auth/src/main/res/values-en-rAU/strings.xml b/auth/src/main/res/values-en-rAU/strings.xml
index 33bd778b7..4f5b7581e 100755
--- a/auth/src/main/res/values-en-rAU/strings.xml
+++ b/auth/src/main/res/values-en-rAU/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rCA/strings.xml b/auth/src/main/res/values-en-rCA/strings.xml
index 9534d4b43..214a3d91f 100755
--- a/auth/src/main/res/values-en-rCA/strings.xml
+++ b/auth/src/main/res/values-en-rCA/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rGB/strings.xml b/auth/src/main/res/values-en-rGB/strings.xml
index f86d87442..c30f71c1d 100755
--- a/auth/src/main/res/values-en-rGB/strings.xml
+++ b/auth/src/main/res/values-en-rGB/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rIE/strings.xml b/auth/src/main/res/values-en-rIE/strings.xml
index 5d7f7b2f3..1a3b4860e 100755
--- a/auth/src/main/res/values-en-rIE/strings.xml
+++ b/auth/src/main/res/values-en-rIE/strings.xml
@@ -172,4 +172,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rIN/strings.xml b/auth/src/main/res/values-en-rIN/strings.xml
index 5d7f7b2f3..1a3b4860e 100755
--- a/auth/src/main/res/values-en-rIN/strings.xml
+++ b/auth/src/main/res/values-en-rIN/strings.xml
@@ -172,4 +172,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rSG/strings.xml b/auth/src/main/res/values-en-rSG/strings.xml
index 5d7f7b2f3..1a3b4860e 100755
--- a/auth/src/main/res/values-en-rSG/strings.xml
+++ b/auth/src/main/res/values-en-rSG/strings.xml
@@ -172,4 +172,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-en-rZA/strings.xml b/auth/src/main/res/values-en-rZA/strings.xml
index 5d7f7b2f3..1a3b4860e 100755
--- a/auth/src/main/res/values-en-rZA/strings.xml
+++ b/auth/src/main/res/values-en-rZA/strings.xml
@@ -172,4 +172,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/main/res/values-es-rAR/strings.xml b/auth/src/main/res/values-es-rAR/strings.xml
index df6acc012..8bf944c45 100755
--- a/auth/src/main/res/values-es-rAR/strings.xml
+++ b/auth/src/main/res/values-es-rAR/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rBO/strings.xml b/auth/src/main/res/values-es-rBO/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rBO/strings.xml
+++ b/auth/src/main/res/values-es-rBO/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rCL/strings.xml b/auth/src/main/res/values-es-rCL/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rCL/strings.xml
+++ b/auth/src/main/res/values-es-rCL/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rCO/strings.xml b/auth/src/main/res/values-es-rCO/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rCO/strings.xml
+++ b/auth/src/main/res/values-es-rCO/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rCR/strings.xml b/auth/src/main/res/values-es-rCR/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rCR/strings.xml
+++ b/auth/src/main/res/values-es-rCR/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rDO/strings.xml b/auth/src/main/res/values-es-rDO/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rDO/strings.xml
+++ b/auth/src/main/res/values-es-rDO/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rEC/strings.xml b/auth/src/main/res/values-es-rEC/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rEC/strings.xml
+++ b/auth/src/main/res/values-es-rEC/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rGT/strings.xml b/auth/src/main/res/values-es-rGT/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rGT/strings.xml
+++ b/auth/src/main/res/values-es-rGT/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rHN/strings.xml b/auth/src/main/res/values-es-rHN/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rHN/strings.xml
+++ b/auth/src/main/res/values-es-rHN/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rMX/strings.xml b/auth/src/main/res/values-es-rMX/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rMX/strings.xml
+++ b/auth/src/main/res/values-es-rMX/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rNI/strings.xml b/auth/src/main/res/values-es-rNI/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rNI/strings.xml
+++ b/auth/src/main/res/values-es-rNI/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rPA/strings.xml b/auth/src/main/res/values-es-rPA/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rPA/strings.xml
+++ b/auth/src/main/res/values-es-rPA/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rPE/strings.xml b/auth/src/main/res/values-es-rPE/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rPE/strings.xml
+++ b/auth/src/main/res/values-es-rPE/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rPR/strings.xml b/auth/src/main/res/values-es-rPR/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rPR/strings.xml
+++ b/auth/src/main/res/values-es-rPR/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rPY/strings.xml b/auth/src/main/res/values-es-rPY/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rPY/strings.xml
+++ b/auth/src/main/res/values-es-rPY/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rSV/strings.xml b/auth/src/main/res/values-es-rSV/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rSV/strings.xml
+++ b/auth/src/main/res/values-es-rSV/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rUS/strings.xml b/auth/src/main/res/values-es-rUS/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rUS/strings.xml
+++ b/auth/src/main/res/values-es-rUS/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rUY/strings.xml b/auth/src/main/res/values-es-rUY/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rUY/strings.xml
+++ b/auth/src/main/res/values-es-rUY/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es-rVE/strings.xml b/auth/src/main/res/values-es-rVE/strings.xml
index 9ebc9ee65..95195a514 100755
--- a/auth/src/main/res/values-es-rVE/strings.xml
+++ b/auth/src/main/res/values-es-rVE/strings.xml
@@ -190,4 +190,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-es/strings.xml b/auth/src/main/res/values-es/strings.xml
index 5f8895314..ba0a84efe 100755
--- a/auth/src/main/res/values-es/strings.xml
+++ b/auth/src/main/res/values-es/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ La autenticación multifactor está actualmente desactivada
diff --git a/auth/src/main/res/values-fa/strings.xml b/auth/src/main/res/values-fa/strings.xml
index 2215781c2..16f3338fc 100755
--- a/auth/src/main/res/values-fa/strings.xml
+++ b/auth/src/main/res/values-fa/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ احراز هویت چند مرحلهای در حال حاضر غیرفعال است
diff --git a/auth/src/main/res/values-fi/strings.xml b/auth/src/main/res/values-fi/strings.xml
index 7c45770a8..9cfb2ce03 100755
--- a/auth/src/main/res/values-fi/strings.xml
+++ b/auth/src/main/res/values-fi/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Monivaiheinen todennus on tällä hetkellä poistettu käytöstä
diff --git a/auth/src/main/res/values-fil/strings.xml b/auth/src/main/res/values-fil/strings.xml
index fc2474b26..1db48118c 100755
--- a/auth/src/main/res/values-fil/strings.xml
+++ b/auth/src/main/res/values-fil/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Kasalukuyang naka-disable ang multi-factor authentication
diff --git a/auth/src/main/res/values-fr-rCH/strings.xml b/auth/src/main/res/values-fr-rCH/strings.xml
index dd6c99b1b..173450749 100755
--- a/auth/src/main/res/values-fr-rCH/strings.xml
+++ b/auth/src/main/res/values-fr-rCH/strings.xml
@@ -191,4 +191,5 @@
This button is currently disabled because new accounts are not allowed
+ L\'authentification multifacteur est actuellement désactivée
diff --git a/auth/src/main/res/values-fr/strings.xml b/auth/src/main/res/values-fr/strings.xml
index ceaf93d6e..d92ef24e1 100755
--- a/auth/src/main/res/values-fr/strings.xml
+++ b/auth/src/main/res/values-fr/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ L\'authentification multifacteur est actuellement désactivée
diff --git a/auth/src/main/res/values-gsw/strings.xml b/auth/src/main/res/values-gsw/strings.xml
index 2b586c600..0b97606b8 100755
--- a/auth/src/main/res/values-gsw/strings.xml
+++ b/auth/src/main/res/values-gsw/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ D\'Multi-Faktor-Authentifizierig isch zurziit deaktiviert
diff --git a/auth/src/main/res/values-gu/strings.xml b/auth/src/main/res/values-gu/strings.xml
index f331a75d3..d83ee4813 100755
--- a/auth/src/main/res/values-gu/strings.xml
+++ b/auth/src/main/res/values-gu/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ મલ્ટિ-ફેક્ટર પ્રમાણીકરણ હાલમાં અક્ષમ છે
diff --git a/auth/src/main/res/values-hi/strings.xml b/auth/src/main/res/values-hi/strings.xml
index 847f6c169..53339be6e 100755
--- a/auth/src/main/res/values-hi/strings.xml
+++ b/auth/src/main/res/values-hi/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ मल्टी-फैक्टर प्रमाणीकरण वर्तमान में अक्षम है
diff --git a/auth/src/main/res/values-hr/strings.xml b/auth/src/main/res/values-hr/strings.xml
index 4a481d5b3..e2516dfe0 100755
--- a/auth/src/main/res/values-hr/strings.xml
+++ b/auth/src/main/res/values-hr/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Višefaktorska autentifikacija trenutno je onemogućena
diff --git a/auth/src/main/res/values-hu/strings.xml b/auth/src/main/res/values-hu/strings.xml
index 6f8f96e28..e10f495b4 100755
--- a/auth/src/main/res/values-hu/strings.xml
+++ b/auth/src/main/res/values-hu/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ A többfaktoros hitelesítés jelenleg le van tiltva
diff --git a/auth/src/main/res/values-in/strings.xml b/auth/src/main/res/values-in/strings.xml
index 5e125242a..cc6b13419 100755
--- a/auth/src/main/res/values-in/strings.xml
+++ b/auth/src/main/res/values-in/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Autentikasi multifaktor saat ini dinonaktifkan
diff --git a/auth/src/main/res/values-it/strings.xml b/auth/src/main/res/values-it/strings.xml
index dd6ab26a7..a0efdc6d3 100755
--- a/auth/src/main/res/values-it/strings.xml
+++ b/auth/src/main/res/values-it/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ L\'autenticazione a più fattori è attualmente disabilitata
diff --git a/auth/src/main/res/values-iw/strings.xml b/auth/src/main/res/values-iw/strings.xml
index 712bfec7d..10f0db9c1 100755
--- a/auth/src/main/res/values-iw/strings.xml
+++ b/auth/src/main/res/values-iw/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ אימות רב-גורמי מושבת כעת
diff --git a/auth/src/main/res/values-ja/strings.xml b/auth/src/main/res/values-ja/strings.xml
index dc900e2d8..620c2cb11 100755
--- a/auth/src/main/res/values-ja/strings.xml
+++ b/auth/src/main/res/values-ja/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ 多要素認証は現在無効になっています
diff --git a/auth/src/main/res/values-kn/strings.xml b/auth/src/main/res/values-kn/strings.xml
index 31f780a6a..12f649a31 100755
--- a/auth/src/main/res/values-kn/strings.xml
+++ b/auth/src/main/res/values-kn/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ ಮಲ್ಟಿ-ಫ್ಯಾಕ್ಟರ್ ದೃಢೀಕರಣವು ಪ್ರಸ್ತುತ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ
diff --git a/auth/src/main/res/values-ko/strings.xml b/auth/src/main/res/values-ko/strings.xml
index eb6e1d22b..d829ffe62 100755
--- a/auth/src/main/res/values-ko/strings.xml
+++ b/auth/src/main/res/values-ko/strings.xml
@@ -178,4 +178,5 @@
This button is currently disabled because new accounts are not allowed
+ 다단계 인증이 현재 비활성화되어 있습니다
diff --git a/auth/src/main/res/values-ln/strings.xml b/auth/src/main/res/values-ln/strings.xml
index 0ee345992..6304e1f10 100755
--- a/auth/src/main/res/values-ln/strings.xml
+++ b/auth/src/main/res/values-ln/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Bondimisami ya makambo mingi ezali sikoyo te
diff --git a/auth/src/main/res/values-lt/strings.xml b/auth/src/main/res/values-lt/strings.xml
index cef70d317..b08c4dbb1 100755
--- a/auth/src/main/res/values-lt/strings.xml
+++ b/auth/src/main/res/values-lt/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Daugiafaktoris tapatybės nustatymas šiuo metu išjungtas
diff --git a/auth/src/main/res/values-lv/strings.xml b/auth/src/main/res/values-lv/strings.xml
index fbba1e17a..21aa5fc1d 100755
--- a/auth/src/main/res/values-lv/strings.xml
+++ b/auth/src/main/res/values-lv/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Daudzfaktoru autentifikācija pašlaik ir atspējota
diff --git a/auth/src/main/res/values-mo/strings.xml b/auth/src/main/res/values-mo/strings.xml
index 73ac609a4..717eb65ca 100755
--- a/auth/src/main/res/values-mo/strings.xml
+++ b/auth/src/main/res/values-mo/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Autentificarea cu mai mulți factori este dezactivată în prezent
diff --git a/auth/src/main/res/values-mr/strings.xml b/auth/src/main/res/values-mr/strings.xml
index 00b6ee391..c95fef12a 100755
--- a/auth/src/main/res/values-mr/strings.xml
+++ b/auth/src/main/res/values-mr/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ मल्टी-फॅक्टर ऑथेंटिकेशन सध्या अक्षम आहे
diff --git a/auth/src/main/res/values-ms/strings.xml b/auth/src/main/res/values-ms/strings.xml
index be8b30ccc..e35e22476 100755
--- a/auth/src/main/res/values-ms/strings.xml
+++ b/auth/src/main/res/values-ms/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Pengesahan berbilang faktor dilumpuhkan buat masa ini
diff --git a/auth/src/main/res/values-nb/strings.xml b/auth/src/main/res/values-nb/strings.xml
index 5cc9c83ac..5018c1952 100755
--- a/auth/src/main/res/values-nb/strings.xml
+++ b/auth/src/main/res/values-nb/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Flerfaktorautentisering er for øyeblikket deaktivert
diff --git a/auth/src/main/res/values-nl/strings.xml b/auth/src/main/res/values-nl/strings.xml
index 8d011cc4f..328497cf5 100755
--- a/auth/src/main/res/values-nl/strings.xml
+++ b/auth/src/main/res/values-nl/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factorauthenticatie is momenteel uitgeschakeld
diff --git a/auth/src/main/res/values-no/strings.xml b/auth/src/main/res/values-no/strings.xml
index 6afe11726..7833bccd9 100755
--- a/auth/src/main/res/values-no/strings.xml
+++ b/auth/src/main/res/values-no/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Flerfaktorautentisering er for øyeblikket deaktivert
diff --git a/auth/src/main/res/values-pl/strings.xml b/auth/src/main/res/values-pl/strings.xml
index 7fd45ad4e..9c4bcadbf 100755
--- a/auth/src/main/res/values-pl/strings.xml
+++ b/auth/src/main/res/values-pl/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Uwierzytelnianie wieloskładnikowe jest obecnie wyłączone
diff --git a/auth/src/main/res/values-pt-rBR/strings.xml b/auth/src/main/res/values-pt-rBR/strings.xml
index 7e805ba3e..f576f884c 100755
--- a/auth/src/main/res/values-pt-rBR/strings.xml
+++ b/auth/src/main/res/values-pt-rBR/strings.xml
@@ -198,4 +198,5 @@
This button is currently disabled because new accounts are not allowed
+ A autenticação multifator está atualmente desativada
diff --git a/auth/src/main/res/values-pt-rPT/strings.xml b/auth/src/main/res/values-pt-rPT/strings.xml
index 3844841bc..bc6c216d4 100755
--- a/auth/src/main/res/values-pt-rPT/strings.xml
+++ b/auth/src/main/res/values-pt-rPT/strings.xml
@@ -198,4 +198,5 @@
This button is currently disabled because new accounts are not allowed
+ A autenticação multifator está atualmente desativada
diff --git a/auth/src/main/res/values-pt/strings.xml b/auth/src/main/res/values-pt/strings.xml
index 54473de13..fbd9e7b37 100755
--- a/auth/src/main/res/values-pt/strings.xml
+++ b/auth/src/main/res/values-pt/strings.xml
@@ -197,4 +197,5 @@
This button is currently disabled because new accounts are not allowed
+ A autenticação multifator está atualmente desativada
diff --git a/auth/src/main/res/values-ro/strings.xml b/auth/src/main/res/values-ro/strings.xml
index c91b2199c..1b5b8cafb 100755
--- a/auth/src/main/res/values-ro/strings.xml
+++ b/auth/src/main/res/values-ro/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Autentificarea cu mai mulți factori este dezactivată în prezent
diff --git a/auth/src/main/res/values-ru/strings.xml b/auth/src/main/res/values-ru/strings.xml
index f41c29527..e2d654da9 100755
--- a/auth/src/main/res/values-ru/strings.xml
+++ b/auth/src/main/res/values-ru/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Многофакторная аутентификация в настоящее время отключена
diff --git a/auth/src/main/res/values-sk/strings.xml b/auth/src/main/res/values-sk/strings.xml
index 2643ea9d2..49c93e6e1 100755
--- a/auth/src/main/res/values-sk/strings.xml
+++ b/auth/src/main/res/values-sk/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Viacfaktorové overovanie je momentálne zakázané
diff --git a/auth/src/main/res/values-sl/strings.xml b/auth/src/main/res/values-sl/strings.xml
index 12c7fee84..be839d41b 100755
--- a/auth/src/main/res/values-sl/strings.xml
+++ b/auth/src/main/res/values-sl/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Večfaktorska avtentikacija je trenutno onemogočena
diff --git a/auth/src/main/res/values-sr/strings.xml b/auth/src/main/res/values-sr/strings.xml
index 666d446ad..be4fd78b2 100755
--- a/auth/src/main/res/values-sr/strings.xml
+++ b/auth/src/main/res/values-sr/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Вишефакторска аутентификација је тренутно онемогућена
diff --git a/auth/src/main/res/values-sv/strings.xml b/auth/src/main/res/values-sv/strings.xml
index 79c33bf9d..616d43dd2 100755
--- a/auth/src/main/res/values-sv/strings.xml
+++ b/auth/src/main/res/values-sv/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Multifaktorautentisering är för närvarande inaktiverad
diff --git a/auth/src/main/res/values-ta/strings.xml b/auth/src/main/res/values-ta/strings.xml
index a01ca8e42..378ced01f 100755
--- a/auth/src/main/res/values-ta/strings.xml
+++ b/auth/src/main/res/values-ta/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ பல-காரணி அங்கீகாரம் தற்போது முடக்கப்பட்டுள்ளது
diff --git a/auth/src/main/res/values-th/strings.xml b/auth/src/main/res/values-th/strings.xml
index 9dc12174b..859b5fc36 100755
--- a/auth/src/main/res/values-th/strings.xml
+++ b/auth/src/main/res/values-th/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ การรับรองความถูกต้องแบบหลายปัจจัยถูกปิดใช้งานในขณะนี้
diff --git a/auth/src/main/res/values-tl/strings.xml b/auth/src/main/res/values-tl/strings.xml
index bcafcca5e..e5f5b11e5 100755
--- a/auth/src/main/res/values-tl/strings.xml
+++ b/auth/src/main/res/values-tl/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ Kasalukuyang naka-disable ang multi-factor authentication
diff --git a/auth/src/main/res/values-tr/strings.xml b/auth/src/main/res/values-tr/strings.xml
index 59b2ba45b..7885d361e 100755
--- a/auth/src/main/res/values-tr/strings.xml
+++ b/auth/src/main/res/values-tr/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Çok faktörlü kimlik doğrulama şu anda devre dışı
diff --git a/auth/src/main/res/values-uk/strings.xml b/auth/src/main/res/values-uk/strings.xml
index 2361de7c4..5c99137d3 100755
--- a/auth/src/main/res/values-uk/strings.xml
+++ b/auth/src/main/res/values-uk/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Багатофакторна автентифікація наразі вимкнена
diff --git a/auth/src/main/res/values-ur/strings.xml b/auth/src/main/res/values-ur/strings.xml
index 9e4268e6c..f73956b29 100755
--- a/auth/src/main/res/values-ur/strings.xml
+++ b/auth/src/main/res/values-ur/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ ملٹی فیکٹر تصدیق فی الحال غیر فعال ہے
diff --git a/auth/src/main/res/values-vi/strings.xml b/auth/src/main/res/values-vi/strings.xml
index f67c4b703..e77e08e6d 100755
--- a/auth/src/main/res/values-vi/strings.xml
+++ b/auth/src/main/res/values-vi/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ Xác thực đa yếu tố hiện đang bị vô hiệu hóa
diff --git a/auth/src/main/res/values-zh-rCN/strings.xml b/auth/src/main/res/values-zh-rCN/strings.xml
index 64f584490..a4b5e61ff 100755
--- a/auth/src/main/res/values-zh-rCN/strings.xml
+++ b/auth/src/main/res/values-zh-rCN/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ 多重身份验证当前已禁用
diff --git a/auth/src/main/res/values-zh-rHK/strings.xml b/auth/src/main/res/values-zh-rHK/strings.xml
index a2b6f9530..f002ae7b6 100755
--- a/auth/src/main/res/values-zh-rHK/strings.xml
+++ b/auth/src/main/res/values-zh-rHK/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ 多重身份验证当前已禁用
diff --git a/auth/src/main/res/values-zh-rTW/strings.xml b/auth/src/main/res/values-zh-rTW/strings.xml
index 97939b4c9..094052f93 100755
--- a/auth/src/main/res/values-zh-rTW/strings.xml
+++ b/auth/src/main/res/values-zh-rTW/strings.xml
@@ -180,4 +180,5 @@
This button is currently disabled because new accounts are not allowed
+ 多重身份验证当前已禁用
diff --git a/auth/src/main/res/values-zh/strings.xml b/auth/src/main/res/values-zh/strings.xml
index a845558c9..55f8cb92b 100755
--- a/auth/src/main/res/values-zh/strings.xml
+++ b/auth/src/main/res/values-zh/strings.xml
@@ -179,4 +179,5 @@
This button is currently disabled because new accounts are not allowed
+ 多重身份验证当前已禁用
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index ee88a98a5..bb4b4e813 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -249,4 +249,5 @@
This button is currently disabled because new accounts are not allowed
+ Multi-factor authentication is currently disabled
diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt
index 80cf85ad6..4afcfa84b 100644
--- a/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt
+++ b/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt
@@ -294,12 +294,13 @@ class AuthUIConfigurationTest {
}
@Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
fun `validation accepts all supported providers`() {
val config = authUIConfiguration {
context = applicationContext
providers {
provider(AuthProvider.Google(scopes = listOf(), serverClientId = "test_client_id"))
- provider(AuthProvider.Facebook(applicationId = "test_app_id"))
+ provider(AuthProvider.Facebook())
provider(AuthProvider.Twitter(customParameters = mapOf()))
provider(AuthProvider.Github(customParameters = mapOf()))
provider(AuthProvider.Microsoft(customParameters = mapOf(), tenant = null))
diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt
index f64bfc2a6..718d38ad3 100644
--- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt
+++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt
@@ -2,6 +2,7 @@ package com.firebase.ui.auth.configuration.auth_provider
import android.content.Context
import androidx.test.core.app.ApplicationProvider
+import com.firebase.ui.auth.R
import com.google.common.truth.Truth.assertThat
import com.google.firebase.auth.actionCodeSettings
import org.junit.Before
@@ -264,32 +265,34 @@ class AuthProviderTest {
}
}
+ @Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
+ fun `google provider assigns default_web_client_id to serverClientId when null`() {
+ val provider = AuthProvider.Google(
+ scopes = listOf("email"),
+ serverClientId = null
+ )
+
+ provider.validate(applicationContext)
+
+ assertThat(provider.serverClientId)
+ .isEqualTo(applicationContext.getString(R.string.default_web_client_id))
+ }
+
// =============================================================================================
// Facebook Provider Tests
// =============================================================================================
@Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
fun `facebook provider with valid configuration should succeed`() {
- val provider = AuthProvider.Facebook(applicationId = "application_id")
+ val provider = AuthProvider.Facebook()
provider.validate(applicationContext)
}
@Test
- fun `facebook provider with empty application id throws`() {
- val provider = AuthProvider.Facebook(applicationId = "")
-
- try {
- provider.validate(applicationContext)
- assertThat(false).isTrue() // Should not reach here
- } catch (e: Exception) {
- assertThat(e).isInstanceOf(IllegalArgumentException::class.java)
- assertThat(e.message).isEqualTo("Facebook application ID cannot be blank")
- }
- }
-
- @Test
- fun `facebook provider validates facebook_application_id when applicationId is null`() {
+ fun `facebook provider validates facebook_application_id`() {
val provider = AuthProvider.Facebook()
try {
@@ -299,7 +302,7 @@ class AuthProviderTest {
assertThat(e).isInstanceOf(IllegalStateException::class.java)
assertThat(e.message).isEqualTo(
"Facebook provider unconfigured. Make sure to " +
- "add a `facebook_application_id` string or provide applicationId parameter."
+ "add a `facebook_application_id` string to your strings.xml"
)
}
}
@@ -400,4 +403,4 @@ class AuthProviderTest {
assertThat(e.message).isEqualTo("Button label cannot be null or empty")
}
}
-}
\ No newline at end of file
+}
diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt
index 155de1f82..1e48bae90 100644
--- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt
+++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt
@@ -103,6 +103,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
}
@Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - successful sign in signs user in and emits Success authState`() = runTest {
val authStateListeners = mutableListOf()
doAnswer { invocation ->
@@ -118,9 +119,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
whenever(mockFirebaseAuth.currentUser).thenReturn(null)
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
- val provider = spy(AuthProvider.Facebook(
- applicationId = "000000000000"
- ))
+ val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
@@ -175,6 +174,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
}
@Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - handles account collision by saving credential and emitting error`() = runTest {
EmailLinkPersistenceManager.default.clear(applicationContext)
EmailLinkPersistenceManager.default.saveEmail(
@@ -185,9 +185,7 @@ class FacebookAuthProviderFirebaseAuthUITest {
)
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
- val provider = spy(AuthProvider.Facebook(
- applicationId = "000000000000"
- ))
+ val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
@@ -238,11 +236,10 @@ class FacebookAuthProviderFirebaseAuthUITest {
}
@Test
+ @Config(manifest = Config.NONE, qualifiers = "night")
fun `signInWithFacebook - converts FacebookException into AuthException`() = runTest {
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
- val provider = spy(AuthProvider.Facebook(
- applicationId = "000000000000"
- ))
+ val provider = spy(AuthProvider.Facebook())
val config = authUIConfiguration {
context = applicationContext
providers {
diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt
index 9091e7d7c..2fd855c37 100644
--- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt
+++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt
@@ -602,6 +602,200 @@ class GoogleAuthProviderFirebaseAuthUITest {
verify(mockFirebaseAuth, never()).signInWithCredential(any())
}
+ // =============================================================================================
+ // signInWithGoogle - Configuration Properties
+ // =============================================================================================
+
+ @Test
+ fun `Sign in with Google with default settings passes filterByAuthorizedAccounts=true`() = runTest {
+ val mockCredential = mock(AuthCredential::class.java)
+ val mockUser = mock(FirebaseUser::class.java)
+ val mockAuthResult = mock(AuthResult::class.java)
+ `when`(mockAuthResult.user).thenReturn(mockUser)
+
+ val googleSignInResult = AuthProvider.Google.GoogleSignInResult(
+ credential = mockCredential,
+ idToken = "test-id-token",
+ displayName = "Test User",
+ photoUrl = null
+ )
+
+ `when`(
+ mockCredentialManagerProvider.getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(true),
+ autoSelectEnabled = eq(false)
+ )
+ ).thenReturn(googleSignInResult)
+
+ val taskCompletionSource = TaskCompletionSource()
+ taskCompletionSource.setResult(mockAuthResult)
+ `when`(mockFirebaseAuth.signInWithCredential(mockCredential))
+ .thenReturn(taskCompletionSource.task)
+ `when`(mockFirebaseAuth.currentUser).thenReturn(null)
+
+ val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
+ val googleProvider = AuthProvider.Google(
+ serverClientId = "test-client-id",
+ scopes = emptyList()
+ // filterByAuthorizedAccounts defaults to true
+ // autoSelectEnabled defaults to false
+ )
+ val config = authUIConfiguration {
+ context = applicationContext
+ providers {
+ provider(googleProvider)
+ }
+ }
+
+ instance.signInWithGoogle(
+ context = applicationContext,
+ config = config,
+ provider = googleProvider,
+ authorizationProvider = mockAuthorizationProvider,
+ credentialManagerProvider = mockCredentialManagerProvider
+ )
+
+ // Verify correct parameters were passed
+ verify(mockCredentialManagerProvider).getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(true),
+ autoSelectEnabled = eq(false)
+ )
+
+ verify(mockFirebaseAuth).signInWithCredential(mockCredential)
+ }
+
+ @Test
+ fun `Sign in with Google with filterByAuthorizedAccounts=false passes correct parameter`() = runTest {
+ val mockCredential = mock(AuthCredential::class.java)
+ val mockUser = mock(FirebaseUser::class.java)
+ val mockAuthResult = mock(AuthResult::class.java)
+ `when`(mockAuthResult.user).thenReturn(mockUser)
+
+ val googleSignInResult = AuthProvider.Google.GoogleSignInResult(
+ credential = mockCredential,
+ idToken = "test-id-token",
+ displayName = "Test User",
+ photoUrl = null
+ )
+
+ `when`(
+ mockCredentialManagerProvider.getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(false),
+ autoSelectEnabled = eq(false)
+ )
+ ).thenReturn(googleSignInResult)
+
+ val taskCompletionSource = TaskCompletionSource()
+ taskCompletionSource.setResult(mockAuthResult)
+ `when`(mockFirebaseAuth.signInWithCredential(mockCredential))
+ .thenReturn(taskCompletionSource.task)
+ `when`(mockFirebaseAuth.currentUser).thenReturn(null)
+
+ val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
+ val googleProvider = AuthProvider.Google(
+ serverClientId = "test-client-id",
+ scopes = emptyList(),
+ filterByAuthorizedAccounts = false
+ )
+ val config = authUIConfiguration {
+ context = applicationContext
+ providers {
+ provider(googleProvider)
+ }
+ }
+
+ instance.signInWithGoogle(
+ context = applicationContext,
+ config = config,
+ provider = googleProvider,
+ authorizationProvider = mockAuthorizationProvider,
+ credentialManagerProvider = mockCredentialManagerProvider
+ )
+
+ // Verify filterByAuthorizedAccounts=false was passed
+ verify(mockCredentialManagerProvider).getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(false),
+ autoSelectEnabled = eq(false)
+ )
+
+ verify(mockFirebaseAuth).signInWithCredential(mockCredential)
+ }
+
+ @Test
+ fun `Sign in with Google with autoSelectEnabled=true passes correct parameter`() = runTest {
+ val mockCredential = mock(AuthCredential::class.java)
+ val mockUser = mock(FirebaseUser::class.java)
+ val mockAuthResult = mock(AuthResult::class.java)
+ `when`(mockAuthResult.user).thenReturn(mockUser)
+
+ val googleSignInResult = AuthProvider.Google.GoogleSignInResult(
+ credential = mockCredential,
+ idToken = "test-id-token",
+ displayName = "Test User",
+ photoUrl = null
+ )
+
+ `when`(
+ mockCredentialManagerProvider.getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(true),
+ autoSelectEnabled = eq(true)
+ )
+ ).thenReturn(googleSignInResult)
+
+ val taskCompletionSource = TaskCompletionSource()
+ taskCompletionSource.setResult(mockAuthResult)
+ `when`(mockFirebaseAuth.signInWithCredential(mockCredential))
+ .thenReturn(taskCompletionSource.task)
+ `when`(mockFirebaseAuth.currentUser).thenReturn(null)
+
+ val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
+ val googleProvider = AuthProvider.Google(
+ serverClientId = "test-client-id",
+ scopes = emptyList(),
+ autoSelectEnabled = true
+ )
+ val config = authUIConfiguration {
+ context = applicationContext
+ providers {
+ provider(googleProvider)
+ }
+ }
+
+ instance.signInWithGoogle(
+ context = applicationContext,
+ config = config,
+ provider = googleProvider,
+ authorizationProvider = mockAuthorizationProvider,
+ credentialManagerProvider = mockCredentialManagerProvider
+ )
+
+ // Verify autoSelectEnabled=true was passed
+ verify(mockCredentialManagerProvider).getGoogleCredential(
+ context = eq(applicationContext),
+ credentialManager = any(),
+ serverClientId = eq("test-client-id"),
+ filterByAuthorizedAccounts = eq(true),
+ autoSelectEnabled = eq(true)
+ )
+
+ verify(mockFirebaseAuth).signInWithCredential(mockCredential)
+ }
+
// =============================================================================================
// signInWithGoogle - State Management
// =============================================================================================
diff --git a/auth/src/test/res/values-night/config.xml b/auth/src/test/res/values-night/config.xml
new file mode 100644
index 000000000..0b31fe015
--- /dev/null
+++ b/auth/src/test/res/values-night/config.xml
@@ -0,0 +1,7 @@
+
+
+ test_client_id
+ test_app_id
+ test_login_scheme
+ test_client_token
+
diff --git a/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt b/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt
new file mode 100644
index 000000000..307f79bc6
--- /dev/null
+++ b/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt
@@ -0,0 +1,229 @@
+package com.firebase.ui.auth.ui.screens
+
+import android.content.Context
+import android.os.Looper
+import androidx.compose.material3.Text
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import com.firebase.ui.auth.AuthException
+import com.firebase.ui.auth.AuthState
+import com.firebase.ui.auth.FirebaseAuthUI
+import com.firebase.ui.auth.configuration.authUIConfiguration
+import com.firebase.ui.auth.configuration.auth_provider.AuthProvider
+import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider
+import com.firebase.ui.auth.configuration.string_provider.DefaultAuthUIStringProvider
+import com.firebase.ui.auth.testutil.AUTH_STATE_WAIT_TIMEOUT_MS
+import com.firebase.ui.auth.testutil.EmulatorAuthApi
+import com.google.common.truth.Truth.assertThat
+import com.google.firebase.FirebaseApp
+import com.google.firebase.FirebaseOptions
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows.shadowOf
+import org.robolectric.annotation.Config
+
+/**
+ * E2E tests for MFA disabled functionality.
+ *
+ * Tests that when isMfaEnabled is false, the Manage MFA button is disabled
+ * and attempting to access MFA enrollment shows an AuthCancelledException.
+ */
+@Config(sdk = [34])
+@RunWith(RobolectricTestRunner::class)
+class MfaDisabledTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
+
+ private lateinit var applicationContext: Context
+ private lateinit var stringProvider: AuthUIStringProvider
+ private lateinit var authUI: FirebaseAuthUI
+ private lateinit var emulatorApi: EmulatorAuthApi
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.openMocks(this)
+
+ applicationContext = ApplicationProvider.getApplicationContext()
+ stringProvider = DefaultAuthUIStringProvider(applicationContext)
+
+ // Clear any existing Firebase apps
+ FirebaseApp.getApps(applicationContext).forEach { app ->
+ app.delete()
+ }
+
+ // Initialize default FirebaseApp
+ val firebaseApp = FirebaseApp.initializeApp(
+ applicationContext,
+ FirebaseOptions.Builder()
+ .setApiKey("fake-api-key")
+ .setApplicationId("fake-app-id")
+ .setProjectId("fake-project-id")
+ .build()
+ )
+
+ authUI = FirebaseAuthUI.getInstance()
+ authUI.auth.useEmulator("127.0.0.1", 9099)
+
+ emulatorApi = EmulatorAuthApi(
+ projectId = firebaseApp.options.projectId
+ ?: throw IllegalStateException("Project ID is required for emulator interactions"),
+ emulatorHost = "127.0.0.1",
+ emulatorPort = 9099
+ )
+
+ // Clear emulator data
+ emulatorApi.clearEmulatorData()
+ }
+
+ @After
+ fun tearDown() {
+ // Clean up after each test to prevent test pollution
+ FirebaseAuthUI.clearInstanceCache()
+
+ // Clear emulator data
+ emulatorApi.clearEmulatorData()
+ }
+
+ @Test
+ fun `Manage MFA button is disabled when isMfaEnabled is false`() {
+ val configuration = authUIConfiguration {
+ context = applicationContext
+ isMfaEnabled = false // MFA disabled
+ providers {
+ provider(AuthProvider.Anonymous)
+ provider(
+ AuthProvider.Email(
+ emailLinkActionCodeSettings = null,
+ passwordValidationRules = emptyList()
+ )
+ )
+ }
+ }
+
+ var currentAuthState: AuthState = AuthState.Idle
+
+ composeTestRule.setContent {
+ FirebaseAuthScreen(
+ authUI = authUI,
+ configuration = configuration,
+ onSignInSuccess = {},
+ onSignInFailure = {},
+ onSignInCancelled = {}
+ )
+ val authState by authUI.authStateFlow().collectAsState(AuthState.Idle)
+ currentAuthState = authState
+ }
+
+ // Wait for the navigation to settle and UI to be ready
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Sign in anonymously to get to the success screen
+ composeTestRule.onNodeWithText(stringProvider.signInAnonymously)
+ .assertIsDisplayed ()
+ .performClick()
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Wait for auth state to transition to Success
+ composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) {
+ shadowOf(Looper.getMainLooper()).idle()
+ currentAuthState is AuthState.Success
+ }
+
+ // Wait for UI to update
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Verify the Manage MFA button is displayed but disabled
+ composeTestRule.onNodeWithText(stringProvider.manageMfaAction)
+ .assertIsDisplayed()
+ .assertIsNotEnabled()
+ }
+
+ @Test
+ @Ignore("Flaky in CI due to timing issues")
+ fun `onManageMfa throws AuthCancelledException when MFA is disabled`() {
+ val configuration = authUIConfiguration {
+ context = applicationContext
+ isMfaEnabled = false // MFA disabled
+ providers {
+ provider(AuthProvider.Anonymous)
+ provider(
+ AuthProvider.Email(
+ emailLinkActionCodeSettings = null,
+ passwordValidationRules = emptyList()
+ )
+ )
+ }
+ }
+
+ var currentAuthState: AuthState = AuthState.Idle
+ var capturedUiContext: AuthSuccessUiContext? = null
+
+ composeTestRule.setContent {
+ FirebaseAuthScreen(
+ authUI = authUI,
+ configuration = configuration,
+ onSignInSuccess = {},
+ onSignInFailure = {},
+ onSignInCancelled = {},
+ authenticatedContent = { _, uiContext ->
+ // Custom content that captures the uiContext
+ capturedUiContext = uiContext
+ Text("Custom authenticated content")
+ }
+ )
+ val authState by authUI.authStateFlow().collectAsState(AuthState.Idle)
+ currentAuthState = authState
+ }
+
+ // Wait for the navigation to settle and UI to be ready
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Sign in anonymously to get to the success screen
+ composeTestRule.onNodeWithText(stringProvider.signInAnonymously)
+ .assertIsDisplayed()
+ .performClick()
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Wait for auth state to transition to Success
+ composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) {
+ shadowOf(Looper.getMainLooper()).idle()
+ currentAuthState is AuthState.Success
+ }
+
+ // Now call onManageMfa directly (simulating custom content calling it)
+ assertThat(capturedUiContext).isNotNull()
+ capturedUiContext?.onManageMfa?.invoke()
+
+ // Wait for auth state to update
+ composeTestRule.waitForIdle()
+ shadowOf(Looper.getMainLooper()).idle()
+
+ // Verify that auth state is now Error with AuthCancelledException
+ composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) {
+ shadowOf(Looper.getMainLooper()).idle()
+ currentAuthState is AuthState.Error &&
+ (currentAuthState as AuthState.Error).exception is AuthException.AuthCancelledException
+ }
+
+ val errorState = currentAuthState as AuthState.Error
+ assertThat(errorState.exception).isInstanceOf(AuthException.AuthCancelledException::class.java)
+ assertThat(errorState.exception.message).contains("Multi-factor authentication is disabled")
+ }
+}