Skip to content

Commit ce8f56b

Browse files
fix(auth): preserve cached auth flow state across activity recreation
1 parent d8c7424 commit ce8f56b

2 files changed

Lines changed: 31 additions & 18 deletions

File tree

auth/src/main/java/com/firebase/ui/auth/FirebaseAuthActivity.kt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,16 @@ class FirebaseAuthActivity : ComponentActivity() {
7272

7373
private lateinit var authUI: FirebaseAuthUI
7474
private lateinit var configuration: AuthUIConfiguration
75+
private var launchKey: String? = null
7576

7677
override fun onCreate(savedInstanceState: Bundle?) {
7778
super.onCreate(savedInstanceState)
7879
enableEdgeToEdge()
7980

8081
// Extract configuration and auth instance from cache using UUID key
81-
val launchKey = intent.getStringExtra(EXTRA_CONFIGURATION_KEY)
82+
launchKey = intent.getStringExtra(EXTRA_CONFIGURATION_KEY)
8283
configuration = if (launchKey != null) {
83-
configurationCache.remove(launchKey)
84+
configurationCache[launchKey]
8485
} else {
8586
null
8687
} ?: run {
@@ -91,7 +92,7 @@ class FirebaseAuthActivity : ComponentActivity() {
9192
}
9293

9394
authUI = if (launchKey != null) {
94-
authUICache.remove(launchKey)
95+
authUICache[launchKey]
9596
} else {
9697
null
9798
} ?: run {
@@ -159,11 +160,17 @@ class FirebaseAuthActivity : ComponentActivity() {
159160
}
160161

161162
override fun onDestroy() {
162-
super.onDestroy()
163-
// Reset auth state when activity is destroyed
164-
if (!isFinishing) {
163+
if (isFinishing) {
164+
launchKey?.let { key ->
165+
configurationCache.remove(key)
166+
authUICache.remove(key)
167+
}
168+
} else {
169+
// Preserve cached launch state so the recreated activity can recover it.
165170
authUI.updateAuthState(AuthState.Idle)
166171
}
172+
173+
super.onDestroy()
167174
}
168175

169176
companion object {

auth/src/test/java/com/firebase/ui/auth/FirebaseAuthActivityTest.kt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -447,22 +447,28 @@ class FirebaseAuthActivityTest {
447447
// =============================================================================================
448448

449449
@Test
450-
fun `configuration is removed from cache after onCreate`() {
451-
val intent1 = FirebaseAuthActivity.createIntent(applicationContext, configuration)
452-
val configKey1 = intent1.getStringExtra("com.firebase.ui.auth.CONFIGURATION_KEY")
450+
fun `launch state survives recreation and is cleared when activity finishes`() {
451+
val intent = FirebaseAuthActivity.createIntent(applicationContext, configuration)
453452

454-
assertThat(configKey1).isNotNull()
453+
val firstController = Robolectric.buildActivity(FirebaseAuthActivity::class.java, intent)
454+
val firstActivity = firstController.create().start().resume().get()
455+
assertThat(firstActivity.isFinishing).isFalse()
455456

456-
// Create activity - this should consume the configuration from cache
457-
val controller1 = Robolectric.buildActivity(FirebaseAuthActivity::class.java, intent1)
458-
controller1.create().get()
457+
// Simulate recreation: the first activity is destroyed without finishing.
458+
firstController.pause().stop().destroy()
459+
460+
val recreatedController = Robolectric.buildActivity(FirebaseAuthActivity::class.java, intent)
461+
val recreatedActivity = recreatedController.create().start().resume().get()
462+
assertThat(recreatedActivity.isFinishing).isFalse()
459463

460-
// Create another intent
461-
val intent2 = FirebaseAuthActivity.createIntent(applicationContext, configuration)
462-
val configKey2 = intent2.getStringExtra("com.firebase.ui.auth.CONFIGURATION_KEY")
464+
// Once the recreated activity actually finishes, the cached launch state should be released.
465+
recreatedActivity.finish()
466+
recreatedController.pause().stop().destroy()
463467

464-
// Should be a different key
465-
assertThat(configKey2).isNotEqualTo(configKey1)
468+
val postFinishController = Robolectric.buildActivity(FirebaseAuthActivity::class.java, intent)
469+
val postFinishActivity = postFinishController.create().get()
470+
assertThat(postFinishActivity.isFinishing).isTrue()
471+
assertThat(shadowOf(postFinishActivity).resultCode).isEqualTo(Activity.RESULT_CANCELED)
466472
}
467473

468474
@Test

0 commit comments

Comments
 (0)