From cee6ec593995f8cab4b27e64f326976dff36bde5 Mon Sep 17 00:00:00 2001 From: David Langley Date: Tue, 23 May 2023 16:51:26 +0100 Subject: [PATCH 1/2] Always allow users sign out - Updates the dialog with a more helpful error message for the user, letting them know what happens if they logout without informing the homeserver. --- changelog.d/4855.bugfix | 1 + .../src/main/res/values/strings.xml | 3 +++ .../im/vector/app/features/MainActivity.kt | 23 ++++++++++++------- 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 changelog.d/4855.bugfix diff --git a/changelog.d/4855.bugfix b/changelog.d/4855.bugfix new file mode 100644 index 0000000000..d85feb42e7 --- /dev/null +++ b/changelog.d/4855.bugfix @@ -0,0 +1 @@ +Fix: Allow users to sign out even if the sign out request fails. diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 3d1a36d4c3..ddd333017e 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -328,6 +328,9 @@ Back up You’ll lose access to your encrypted messages unless you back up your keys before signing out. + Cannot reach the homeserver. If you sign out anyway, this device will not be erased from your device list, you may want to remove it using another client. + Sign out anyway + Loading… diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index cffb1577cf..676986d0df 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -252,13 +252,10 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity try { session.signOutService().signOut(!args.isUserLoggedOut) } catch (failure: Throwable) { - displayError(failure) + displaySignOutFailedDialog(onboardingStore) return@launch } - Timber.w("SIGN_OUT: success, start app") - activeSessionHolder.clearActiveSession() - doLocalCleanup(clearPreferences = true, onboardingStore) - startNextActivityAndFinish() + completeSignout(onboardingStore) } } args.clearCache -> { @@ -272,6 +269,15 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } + private fun completeSignout(onboardingStore: VectorSessionStore) { + lifecycleScope.launch { + Timber.w("SIGN_OUT: success, start app") + activeSessionHolder.clearActiveSession() + doLocalCleanup(clearPreferences = true, onboardingStore) + startNextActivityAndFinish() + } + } + override fun handleInvalidToken(globalError: GlobalError.InvalidToken) { // No op here Timber.w("Ignoring invalid token global error") @@ -299,12 +305,13 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } - private fun displayError(failure: Throwable) { + private fun displaySignOutFailedDialog(onboardingStore: VectorSessionStore) { if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { MaterialAlertDialogBuilder(this) .setTitle(R.string.dialog_title_error) - .setMessage(errorFormatter.toHumanReadable(failure)) - .setPositiveButton(R.string.global_retry) { _, _ -> doCleanUp() } + .setMessage(R.string.sign_out_failed_dialog_message) + .setPositiveButton(R.string.sign_out_anyway) { _, _ -> completeSignout(onboardingStore) } + .setNeutralButton(R.string.global_retry) { _, _ -> doCleanUp() } .setNegativeButton(R.string.action_cancel) { _, _ -> startNextActivityAndFinish(ignoreClearCredentials = true) } .setCancelable(false) .show() From 997c9dd9177fd5470ccb92d0b8de6160e44a88f2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 May 2023 10:38:08 +0200 Subject: [PATCH 2/2] Ensure signout service is always use even if users want to ignore sigout error from the server. The SDK is doing more cleanup. --- .../sdk/api/session/signout/SignOutService.kt | 3 +- .../session/signout/DefaultSignOutService.kt | 9 ++++- .../internal/session/signout/SignOutTask.kt | 7 +++- .../im/vector/app/features/MainActivity.kt | 37 ++++++++++++------- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt index d64b2e6e92..fade51600a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/signout/SignOutService.kt @@ -37,6 +37,7 @@ interface SignOutService { /** * Sign out, and release the session, clear all the session data, including crypto data. * @param signOutFromHomeserver true if the sign out request has to be done + * @param ignoreServerRequestError true to ignore server error if any */ - suspend fun signOut(signOutFromHomeserver: Boolean) + suspend fun signOut(signOutFromHomeserver: Boolean, ignoreServerRequestError: Boolean = false) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt index 1bb86ecb4b..2c34f1e2d9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/DefaultSignOutService.kt @@ -35,7 +35,12 @@ internal class DefaultSignOutService @Inject constructor( sessionParamsStore.updateCredentials(credentials) } - override suspend fun signOut(signOutFromHomeserver: Boolean) { - return signOutTask.execute(SignOutTask.Params(signOutFromHomeserver)) + override suspend fun signOut(signOutFromHomeserver: Boolean, ignoreServerRequestError: Boolean) { + return signOutTask.execute( + SignOutTask.Params( + signOutFromHomeserver = signOutFromHomeserver, + ignoreServerRequestError = ignoreServerRequestError + ) + ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt index e5213c4696..f8ec23b24d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/signout/SignOutTask.kt @@ -30,7 +30,8 @@ import javax.inject.Inject internal interface SignOutTask : Task { data class Params( - val signOutFromHomeserver: Boolean + val signOutFromHomeserver: Boolean, + val ignoreServerRequestError: Boolean, ) } @@ -59,7 +60,9 @@ internal class DefaultSignOutTask @Inject constructor( // Ignore Timber.w("Ignore error due to https://github.com/matrix-org/synapse/issues/5755") } else { - throw throwable + if (!params.ignoreServerRequestError) { + throw throwable + } } } } diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 676986d0df..5518d1bba2 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -59,6 +59,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.failure.GlobalError +import org.matrix.android.sdk.api.session.Session import timber.log.Timber import javax.inject.Inject @@ -248,15 +249,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } args.clearCredentials -> { - lifecycleScope.launch { - try { - session.signOutService().signOut(!args.isUserLoggedOut) - } catch (failure: Throwable) { - displaySignOutFailedDialog(onboardingStore) - return@launch - } - completeSignout(onboardingStore) - } + signout(session, onboardingStore, ignoreServerError = false) } args.clearCache -> { lifecycleScope.launch { @@ -269,8 +262,19 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } - private fun completeSignout(onboardingStore: VectorSessionStore) { + private fun signout( + session: Session, + onboardingStore: VectorSessionStore, + ignoreServerError: Boolean, + ) { lifecycleScope.launch { + try { + session.signOutService().signOut(!args.isUserLoggedOut, ignoreServerError) + } catch (failure: Throwable) { + Timber.e(failure, "SIGN_OUT: error, propose to sign out anyway") + displaySignOutFailedDialog(session, onboardingStore) + return@launch + } Timber.w("SIGN_OUT: success, start app") activeSessionHolder.clearActiveSession() doLocalCleanup(clearPreferences = true, onboardingStore) @@ -305,13 +309,20 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity } } - private fun displaySignOutFailedDialog(onboardingStore: VectorSessionStore) { + private fun displaySignOutFailedDialog( + session: Session, + onboardingStore: VectorSessionStore, + ) { if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { MaterialAlertDialogBuilder(this) .setTitle(R.string.dialog_title_error) .setMessage(R.string.sign_out_failed_dialog_message) - .setPositiveButton(R.string.sign_out_anyway) { _, _ -> completeSignout(onboardingStore) } - .setNeutralButton(R.string.global_retry) { _, _ -> doCleanUp() } + .setPositiveButton(R.string.sign_out_anyway) { _, _ -> + signout(session, onboardingStore, ignoreServerError = true) + } + .setNeutralButton(R.string.global_retry) { _, _ -> + signout(session, onboardingStore, ignoreServerError = false) + } .setNegativeButton(R.string.action_cancel) { _, _ -> startNextActivityAndFinish(ignoreClearCredentials = true) } .setCancelable(false) .show()