@@ -99,6 +99,10 @@ private const val KEY_OIDC_SUPPORTED = "KEY_OIDC_SUPPORTED"
9999private const val KEY_CODE_VERIFIER = " KEY_CODE_VERIFIER"
100100private const val KEY_CODE_CHALLENGE = " KEY_CODE_CHALLENGE"
101101private const val KEY_OIDC_STATE = " KEY_OIDC_STATE"
102+ private const val KEY_AUTH_SERVER_BASE_URL = " KEY_AUTH_SERVER_BASE_URL"
103+ private const val KEY_AUTH_OIDC_SUPPORTED = " KEY_AUTH_OIDC_SUPPORTED"
104+ private const val KEY_AUTH_LOGIN_ACTION = " KEY_AUTH_LOGIN_ACTION"
105+ private const val KEY_AUTH_USER_ACCOUNT = " KEY_AUTH_USER_ACCOUNT"
102106
103107class LoginActivity : AppCompatActivity (), SslUntrustedCertDialog.OnSslUntrustedCertListener, SecurityEnforced {
104108
@@ -237,14 +241,19 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
237241 if (savedInstanceState == null ) {
238242 restoreAuthState()
239243 }
240- handleGetAuthorizationCodeResponse(intent)
244+ if (authenticationViewModel.serverInfo.value?.peekContent()?.getStoredData() == null
245+ && ::serverBaseUrl.isInitialized && serverBaseUrl.isNotEmpty()) {
246+ // Process death: serverInfo is gone. Re-fetch it before processing the OAuth response.
247+ // Store the intent as pending — getServerInfoIsSuccess will process it via checkServerType bypass.
248+ pendingAuthorizationIntent = intent
249+ authenticationViewModel.getServerInfo(serverBaseUrl)
250+ } else {
251+ handleGetAuthorizationCodeResponse(intent)
252+ }
241253 }
242254
243- // Process any pending intent that arrived before binding was ready
244- pendingAuthorizationIntent?.let {
245- handleGetAuthorizationCodeResponse(it)
246- pendingAuthorizationIntent = null
247- }
255+ // Note: pendingAuthorizationIntent is processed in checkServerType() after
256+ // getServerInfo() completes (process death recovery flow).
248257
249258
250259 }
@@ -262,7 +271,10 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
262271
263272 private fun launchFileDisplayActivity () {
264273 val newIntent = Intent (this , FileDisplayActivity ::class .java)
265- newIntent.data = intent.data
274+ if (authenticationViewModel.launchedFromDeepLink) {
275+ newIntent.data = intent.data
276+ }
277+ newIntent.addFlags(Intent .FLAG_ACTIVITY_CLEAR_TOP )
266278 startActivity(newIntent)
267279 finish()
268280 }
@@ -296,11 +308,7 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
296308 authenticationViewModel.accountDiscovery.observe(this ) {
297309 if (it.peekContent() is UIResult .Success ) {
298310 notifyDocumentsProviderRoots(applicationContext)
299- if (authenticationViewModel.launchedFromDeepLink) {
300- launchFileDisplayActivity()
301- } else {
302- finish()
303- }
311+ launchFileDisplayActivity()
304312 } else {
305313 binding.authStatusText.run {
306314 text = context.getString(R .string.login_account_preparing)
@@ -425,6 +433,18 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
425433 }
426434
427435 private fun checkServerType (serverInfo : ServerInfo ) {
436+ // If we have a pending OAuth response (process death recovery), process it now
437+ // that serverInfo has been re-fetched, instead of starting a new auth flow.
438+ pendingAuthorizationIntent?.let { pendingIntent ->
439+ pendingAuthorizationIntent = null
440+ authTokenType = OAUTH_TOKEN_TYPE
441+ if (serverInfo is ServerInfo .OIDCServer ) {
442+ oidcSupported = true
443+ }
444+ handleGetAuthorizationCodeResponse(pendingIntent)
445+ return
446+ }
447+
428448 when (serverInfo) {
429449 is ServerInfo .BasicServer -> {
430450 authTokenType = BASIC_TOKEN_TYPE
@@ -1016,6 +1036,15 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
10161036 putString(KEY_CODE_VERIFIER , authenticationViewModel.codeVerifier)
10171037 putString(KEY_CODE_CHALLENGE , authenticationViewModel.codeChallenge)
10181038 putString(KEY_OIDC_STATE , authenticationViewModel.oidcState)
1039+ if (::serverBaseUrl.isInitialized) {
1040+ putString(KEY_AUTH_SERVER_BASE_URL , serverBaseUrl)
1041+ }
1042+ putBoolean(KEY_AUTH_OIDC_SUPPORTED , oidcSupported)
1043+ // The browser is also opened for re-login (ACTION_UPDATE_TOKEN / ACTION_UPDATE_EXPIRED_TOKEN),
1044+ // not just for new account creation. Persist these so the redirect back knows
1045+ // whether to update an existing account or create a new one.
1046+ putInt(KEY_AUTH_LOGIN_ACTION , loginAction.toInt())
1047+ userAccount?.name?.let { putString(KEY_AUTH_USER_ACCOUNT , it) }
10191048 apply ()
10201049 }
10211050 }
@@ -1025,6 +1054,17 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
10251054 prefs.getString(KEY_CODE_VERIFIER , null )?.let { authenticationViewModel.codeVerifier = it }
10261055 prefs.getString(KEY_CODE_CHALLENGE , null )?.let { authenticationViewModel.codeChallenge = it }
10271056 prefs.getString(KEY_OIDC_STATE , null )?.let { authenticationViewModel.oidcState = it }
1057+ prefs.getString(KEY_AUTH_SERVER_BASE_URL , null )?.let { serverBaseUrl = it }
1058+ oidcSupported = prefs.getBoolean(KEY_AUTH_OIDC_SUPPORTED , false )
1059+ val savedLoginAction = prefs.getInt(KEY_AUTH_LOGIN_ACTION , - 1 )
1060+ if (savedLoginAction != - 1 ) {
1061+ loginAction = savedLoginAction.toByte()
1062+ }
1063+ if (userAccount == null ) {
1064+ prefs.getString(KEY_AUTH_USER_ACCOUNT , null )?.let { accountName ->
1065+ userAccount = Account (accountName, getString(R .string.account_type))
1066+ }
1067+ }
10281068 }
10291069
10301070 private fun clearAuthState () {
0 commit comments