Skip to content

Commit d088871

Browse files
committed
feat: add "Continue as..." feature to enhance user experience with last-used sign-in preferences
1 parent 0182277 commit d088871

14 files changed

Lines changed: 556 additions & 22 deletions

File tree

app/src/main/java/com/firebaseui/android/demo/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import com.google.firebase.FirebaseApp
3636
*/
3737
class MainActivity : ComponentActivity() {
3838
companion object {
39-
private const val USE_AUTH_EMULATOR = false
39+
private const val USE_AUTH_EMULATOR = true
4040
private const val AUTH_EMULATOR_HOST = "10.0.2.2"
4141
private const val AUTH_EMULATOR_PORT = 9099
4242
}

auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.firebase.ui.auth.util.EmailLinkPersistenceManager
3131
import com.firebase.ui.auth.util.EmailLinkParser
3232
import com.firebase.ui.auth.util.PersistenceManager
3333
import com.firebase.ui.auth.util.SessionUtils
34+
import com.firebase.ui.auth.util.SignInPreferenceManager
3435
import com.google.firebase.FirebaseApp
3536
import com.google.firebase.auth.ActionCodeSettings
3637
import com.google.firebase.auth.AuthCredential
@@ -181,6 +182,21 @@ internal suspend fun FirebaseAuthUI.createOrLinkUserWithEmailAndPassword(
181182
}
182183
}
183184

185+
// Save sign-in preference for "Continue as..." feature
186+
if (result != null) {
187+
try {
188+
SignInPreferenceManager.saveLastSignIn(
189+
context = context,
190+
providerId = "password",
191+
identifier = email
192+
)
193+
Log.d(TAG, "Sign-in preference saved for: $email")
194+
} catch (e: Exception) {
195+
// Failed to save preference - log but don't break auth flow
196+
Log.w(TAG, "Failed to save sign-in preference for: $email", e)
197+
}
198+
}
199+
184200
updateAuthState(AuthState.Idle)
185201
return result
186202
} catch (e: FirebaseAuthUserCollisionException) {
@@ -400,6 +416,21 @@ internal suspend fun FirebaseAuthUI.signInWithEmailAndPassword(
400416
}
401417
}
402418

419+
// Save sign-in preference for "Continue as..." feature
420+
if (result != null) {
421+
try {
422+
SignInPreferenceManager.saveLastSignIn(
423+
context = context,
424+
providerId = "password",
425+
identifier = email
426+
)
427+
Log.d(TAG, "Sign-in preference saved for: $email")
428+
} catch (e: Exception) {
429+
// Failed to save preference - log but don't break auth flow
430+
Log.w(TAG, "Failed to save sign-in preference for: $email", e)
431+
}
432+
}
433+
403434
updateAuthState(AuthState.Idle)
404435
}
405436
} catch (e: FirebaseAuthMultiFactorException) {

auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProvider+FirebaseAuthUI.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.firebase.ui.auth.AuthState
3232
import com.firebase.ui.auth.FirebaseAuthUI
3333
import com.firebase.ui.auth.configuration.AuthUIConfiguration
3434
import com.firebase.ui.auth.util.EmailLinkPersistenceManager
35+
import com.firebase.ui.auth.util.SignInPreferenceManager
3536
import kotlinx.coroutines.CancellationException
3637
import kotlinx.coroutines.launch
3738

@@ -158,6 +159,23 @@ internal suspend fun FirebaseAuthUI.signInWithFacebook(
158159
displayName = profileData?.displayName,
159160
photoUrl = profileData?.photoUrl,
160161
)
162+
163+
// Save sign-in preference for "Continue as..." feature
164+
try {
165+
val user = auth.currentUser
166+
val identifier = user?.email
167+
if (identifier != null) {
168+
SignInPreferenceManager.saveLastSignIn(
169+
context = context,
170+
providerId = provider.providerId,
171+
identifier = identifier
172+
)
173+
android.util.Log.d("FacebookAuthProvider", "Sign-in preference saved for: $identifier")
174+
}
175+
} catch (e: Exception) {
176+
// Failed to save preference - log but don't break auth flow
177+
android.util.Log.w("FacebookAuthProvider", "Failed to save sign-in preference", e)
178+
}
161179
} catch (e: AuthException.AccountLinkingRequiredException) {
162180
// Account collision occurred - save Facebook credential for linking after email link sign-in
163181
// This happens when a user tries to sign in with Facebook but an email link account exists

auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.firebase.ui.auth.AuthState
1313
import com.firebase.ui.auth.FirebaseAuthUI
1414
import com.firebase.ui.auth.configuration.AuthUIConfiguration
1515
import com.firebase.ui.auth.util.EmailLinkPersistenceManager
16+
import com.firebase.ui.auth.util.SignInPreferenceManager
1617
import com.google.android.gms.common.api.Scope
1718
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
1819
import kotlinx.coroutines.CancellationException
@@ -149,6 +150,23 @@ internal suspend fun FirebaseAuthUI.signInWithGoogle(
149150
displayName = result.displayName,
150151
photoUrl = result.photoUrl,
151152
)
153+
154+
// Save sign-in preference for "Continue as..." feature
155+
try {
156+
val user = auth.currentUser
157+
val identifier = user?.email
158+
if (identifier != null) {
159+
SignInPreferenceManager.saveLastSignIn(
160+
context = context,
161+
providerId = provider.providerId,
162+
identifier = identifier
163+
)
164+
android.util.Log.d("GoogleAuthProvider", "Sign-in preference saved for: $identifier")
165+
}
166+
} catch (e: Exception) {
167+
// Failed to save preference - log but don't break auth flow
168+
android.util.Log.w("GoogleAuthProvider", "Failed to save sign-in preference", e)
169+
}
152170
} catch (e: AuthException.AccountLinkingRequiredException) {
153171
// Account collision occurred - save Facebook credential for linking after email link sign-in
154172
// This happens when a user tries to sign in with Facebook but an email link account exists

auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/OAuthProvider+FirebaseAuthUI.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.firebase.ui.auth.configuration.auth_provider
22

33
import android.app.Activity
4+
import android.content.Context
45
import androidx.compose.runtime.Composable
56
import androidx.compose.runtime.remember
67
import androidx.compose.runtime.rememberCoroutineScope
@@ -9,6 +10,7 @@ import com.firebase.ui.auth.AuthState
910
import com.firebase.ui.auth.FirebaseAuthUI
1011
import com.firebase.ui.auth.configuration.AuthUIConfiguration
1112
import com.firebase.ui.auth.configuration.auth_provider.AuthProvider.Companion.canUpgradeAnonymous
13+
import com.firebase.ui.auth.util.SignInPreferenceManager
1214
import com.google.firebase.auth.FirebaseAuthUserCollisionException
1315
import com.google.firebase.auth.OAuthCredential
1416
import com.google.firebase.auth.OAuthProvider
@@ -48,6 +50,7 @@ import kotlinx.coroutines.tasks.await
4850
*/
4951
@Composable
5052
internal fun FirebaseAuthUI.rememberOAuthSignInHandler(
53+
context: Context,
5154
activity: Activity?,
5255
config: AuthUIConfiguration,
5356
provider: AuthProvider.OAuth,
@@ -63,6 +66,7 @@ internal fun FirebaseAuthUI.rememberOAuthSignInHandler(
6366
coroutineScope.launch {
6467
try {
6568
signInWithProvider(
69+
context = context,
6670
config = config,
6771
activity = activity,
6872
provider = provider
@@ -119,6 +123,7 @@ internal fun FirebaseAuthUI.rememberOAuthSignInHandler(
119123
* @see signInAndLinkWithCredential
120124
*/
121125
internal suspend fun FirebaseAuthUI.signInWithProvider(
126+
context: Context,
122127
config: AuthUIConfiguration,
123128
activity: Activity,
124129
provider: AuthProvider.OAuth,
@@ -172,6 +177,24 @@ internal suspend fun FirebaseAuthUI.signInWithProvider(
172177
val credential = authResult?.credential as? OAuthCredential
173178
if (credential != null) {
174179
// The user is already signed in via startActivityForSignInWithProvider/startActivityForLinkWithProvider
180+
181+
// Save sign-in preference for "Continue as..." feature
182+
try {
183+
val user = auth.currentUser
184+
val identifier = user?.email
185+
if (identifier != null) {
186+
SignInPreferenceManager.saveLastSignIn(
187+
context = context,
188+
providerId = provider.providerId,
189+
identifier = identifier
190+
)
191+
android.util.Log.d("OAuthProvider", "Sign-in preference saved for: $identifier (${provider.providerId})")
192+
}
193+
} catch (e: Exception) {
194+
// Failed to save preference - log but don't break auth flow
195+
android.util.Log.w("OAuthProvider", "Failed to save sign-in preference", e)
196+
}
197+
175198
// Just update state to Idle
176199
updateAuthState(AuthState.Idle)
177200
} else {

auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.firebase.ui.auth.configuration.auth_provider
22

33
import android.app.Activity
4+
import android.content.Context
45
import com.firebase.ui.auth.AuthException
56
import com.firebase.ui.auth.AuthState
67
import com.firebase.ui.auth.FirebaseAuthUI
78
import com.firebase.ui.auth.configuration.AuthUIConfiguration
9+
import com.firebase.ui.auth.util.SignInPreferenceManager
810
import com.google.firebase.auth.AuthResult
911
import com.google.firebase.auth.MultiFactorSession
1012
import com.google.firebase.auth.PhoneAuthCredential
@@ -197,6 +199,7 @@ internal suspend fun FirebaseAuthUI.verifyPhoneNumber(
197199
* @throws AuthException.NetworkException if a network error occurs
198200
*/
199201
internal suspend fun FirebaseAuthUI.submitVerificationCode(
202+
context: Context,
200203
config: AuthUIConfiguration,
201204
verificationId: String,
202205
code: String,
@@ -206,6 +209,7 @@ internal suspend fun FirebaseAuthUI.submitVerificationCode(
206209
updateAuthState(AuthState.Loading("Submitting verification code..."))
207210
val credential = credentialProvider.getCredential(verificationId, code)
208211
return signInWithPhoneAuthCredential(
212+
context = context,
209213
config = config,
210214
credential = credential
211215
)
@@ -288,15 +292,37 @@ internal suspend fun FirebaseAuthUI.submitVerificationCode(
288292
* @throws AuthException.NetworkException if a network error occurs
289293
*/
290294
internal suspend fun FirebaseAuthUI.signInWithPhoneAuthCredential(
295+
context: Context,
291296
config: AuthUIConfiguration,
292297
credential: PhoneAuthCredential,
293298
): AuthResult? {
294299
try {
295300
updateAuthState(AuthState.Loading("Signing in with phone..."))
296-
return signInAndLinkWithCredential(
301+
val result = signInAndLinkWithCredential(
297302
config = config,
298303
credential = credential,
299304
)
305+
306+
// Save sign-in preference for "Continue as..." feature
307+
if (result != null) {
308+
try {
309+
val user = auth.currentUser
310+
val identifier = user?.phoneNumber
311+
if (identifier != null) {
312+
SignInPreferenceManager.saveLastSignIn(
313+
context = context,
314+
providerId = "phone",
315+
identifier = identifier
316+
)
317+
android.util.Log.d("PhoneAuthProvider", "Sign-in preference saved for: $identifier")
318+
}
319+
} catch (e: Exception) {
320+
// Failed to save preference - log but don't break auth flow
321+
android.util.Log.w("PhoneAuthProvider", "Failed to save sign-in preference", e)
322+
}
323+
}
324+
325+
return result
300326
} catch (e: CancellationException) {
301327
val cancelledException = AuthException.AuthCancelledException(
302328
message = "Sign in with phone was cancelled",

auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,33 @@ interface AuthUIStringProvider {
9797
/** Button text for Yahoo sign-in option */
9898
val signInWithYahoo: String
9999

100+
/** Button text for Google continue option */
101+
val continueWithGoogle: String
102+
103+
/** Button text for Facebook continue option */
104+
val continueWithFacebook: String
105+
106+
/** Button text for Twitter continue option */
107+
val continueWithTwitter: String
108+
109+
/** Button text for Github continue option */
110+
val continueWithGithub: String
111+
112+
/** Button text for Email continue option */
113+
val continueWithEmail: String
114+
115+
/** Button text for Phone continue option */
116+
val continueWithPhone: String
117+
118+
/** Button text for Apple continue option */
119+
val continueWithApple: String
120+
121+
/** Button text for Microsoft continue option */
122+
val continueWithMicrosoft: String
123+
124+
/** Button text for Yahoo continue option */
125+
val continueWithYahoo: String
126+
100127
/** Error message when email address field is empty */
101128
val missingEmailAddress: String
102129

auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,28 @@ class DefaultAuthUIStringProvider(
8080
override val signInWithYahoo: String
8181
get() = localizedContext.getString(R.string.fui_sign_in_with_yahoo)
8282

83+
/**
84+
* Auth Provider "Continue With" Button Strings
85+
*/
86+
override val continueWithGoogle: String
87+
get() = localizedContext.getString(R.string.fui_continue_with_google)
88+
override val continueWithFacebook: String
89+
get() = localizedContext.getString(R.string.fui_continue_with_facebook)
90+
override val continueWithTwitter: String
91+
get() = localizedContext.getString(R.string.fui_continue_with_twitter)
92+
override val continueWithGithub: String
93+
get() = localizedContext.getString(R.string.fui_continue_with_github)
94+
override val continueWithEmail: String
95+
get() = localizedContext.getString(R.string.fui_continue_with_email)
96+
override val continueWithPhone: String
97+
get() = localizedContext.getString(R.string.fui_continue_with_phone)
98+
override val continueWithApple: String
99+
get() = localizedContext.getString(R.string.fui_continue_with_apple)
100+
override val continueWithMicrosoft: String
101+
get() = localizedContext.getString(R.string.fui_continue_with_microsoft)
102+
override val continueWithYahoo: String
103+
get() = localizedContext.getString(R.string.fui_continue_with_yahoo)
104+
83105
/**
84106
* Email Validator Strings
85107
*/

0 commit comments

Comments
 (0)