@@ -130,21 +130,9 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
130130 override fun onCreate (savedInstanceState : Bundle ? ) {
131131 super .onCreate(savedInstanceState)
132132
133- // Log OAuth redirect details for debugging (especially Firefox issues)
134133 Timber .d(" onCreate called with intent data: ${intent.data} , isTaskRoot: $isTaskRoot " )
135134
136- if (intent.data != null && (intent.data?.getQueryParameter(" code" ) != null || intent.data?.getQueryParameter(" error" ) != null )) {
137- Timber .d(" OAuth redirect detected with code or error parameter" )
138- if (! isTaskRoot) {
139- Timber .d(" Not task root, forwarding OAuth redirect to existing LoginActivity instance" )
140- val newIntent = Intent (this , LoginActivity ::class .java)
141- newIntent.data = intent.data
142- newIntent.addFlags(Intent .FLAG_ACTIVITY_CLEAR_TOP or Intent .FLAG_ACTIVITY_SINGLE_TOP )
143- startActivity(newIntent)
144- finish()
145- return
146- }
147- }
135+ if (handleOAuthRedirectOnCreate()) return
148136
149137 checkPasscodeEnforced(this )
150138
@@ -173,8 +161,7 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
173161
174162 // UI initialization
175163 binding = AccountSetupBinding .inflate(layoutInflater)
176- val view = binding.root
177- setContentView(view)
164+ setContentView(binding.root)
178165
179166 if (loginAction != ACTION_CREATE ) {
180167 binding.accountUsername.isEnabled = false
@@ -258,8 +245,35 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
258245
259246 // Note: pendingAuthorizationIntent is processed in checkServerType() after
260247 // getServerInfo() completes (process death recovery flow).
248+ }
261249
250+ /* *
251+ * If this onCreate is an OAuth redirect, either forward it to the existing instance
252+ * (when not task root) or let it proceed. Otherwise, track this instance so the
253+ * redirect instance can finish it later (see [launchFileDisplayActivity]).
254+ * @return true if onCreate should return early (redirect was forwarded).
255+ */
256+ private fun handleOAuthRedirectOnCreate (): Boolean {
257+ val hasOAuthData = intent.data != null &&
258+ (intent.data?.getQueryParameter(" code" ) != null || intent.data?.getQueryParameter(" error" ) != null )
262259
260+ if (hasOAuthData) {
261+ Timber .d(" OAuth redirect detected with code or error parameter" )
262+ if (! isTaskRoot) {
263+ Timber .d(" Not task root, forwarding OAuth redirect to existing LoginActivity instance" )
264+ val newIntent = Intent (this , LoginActivity ::class .java)
265+ newIntent.data = intent.data
266+ newIntent.addFlags(Intent .FLAG_ACTIVITY_CLEAR_TOP or Intent .FLAG_ACTIVITY_SINGLE_TOP )
267+ startActivity(newIntent)
268+ finish()
269+ return true
270+ }
271+ } else {
272+ // Not an OAuth redirect — track this instance so the redirect instance
273+ // can finish it later (see companion object and launchFileDisplayActivity).
274+ orphanedInstance = java.lang.ref.WeakReference (this )
275+ }
276+ return false
263277 }
264278
265279 private fun handleDeepLink () {
@@ -274,6 +288,29 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
274288 }
275289
276290 private fun launchFileDisplayActivity () {
291+ // Finish the orphaned LoginActivity in the main task (if any).
292+ // During re-auth, startActivityForResult forces the first instance into the main
293+ // task. This second instance (OAuth redirect) runs in its own task and can't reach
294+ // the first via task flags, so we finish it directly via the static reference.
295+ var mainTaskId = - 1
296+ orphanedInstance?.get()?.let { other ->
297+ if (other != = this ) {
298+ Timber .d(" Finishing orphaned LoginActivity in main task" )
299+ mainTaskId = other.taskId
300+ other.finish()
301+ }
302+ }
303+ orphanedInstance = null
304+
305+ if (mainTaskId != - 1 ) {
306+ // The main task already has FileDisplayActivity. Bring it to the foreground
307+ // and finish this instance. Just calling finish() would leave the browser on top.
308+ val am = getSystemService(android.content.Context .ACTIVITY_SERVICE ) as android.app.ActivityManager
309+ am.moveTaskToFront(mainTaskId, 0 )
310+ finish()
311+ return
312+ }
313+
277314 val newIntent = Intent (this , FileDisplayActivity ::class .java)
278315 if (authenticationViewModel.launchedFromDeepLink) {
279316 newIntent.data = intent.data
@@ -1127,4 +1164,14 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
11271164 null
11281165 }
11291166 }
1167+
1168+ companion object {
1169+ /* *
1170+ * During re-auth, startActivityForResult forces the first LoginActivity into the
1171+ * main task (ignoring singleTask). The OAuth redirect then creates a second instance
1172+ * in its own task. We track the first (orphaned) instance here so the second one
1173+ * can explicitly finish() it after auth completes.
1174+ */
1175+ private var orphanedInstance: java.lang.ref.WeakReference <LoginActivity >? = null
1176+ }
11301177}
0 commit comments