Fix clear cache issue: sometimes, after a clear cache, there is still a token, so the init sync service is not started.

Migratiing to supend methods fixes the problem, I'm not sure why...
This commit is contained in:
Benoit Marty 2021-01-20 15:19:21 +01:00
parent 68f422e498
commit 4709002429
11 changed files with 172 additions and 143 deletions

View file

@ -8,7 +8,7 @@ Improvements 🙌:
-
Bugfix 🐛:
-
- Fix clear cache issue: sometimes, after a clear cache, there is still a token, so the init sync service is not started.
Translations 🗣:
-

View file

@ -16,8 +16,6 @@
package org.matrix.android.sdk.api.session.cache
import org.matrix.android.sdk.api.MatrixCallback
/**
* This interface defines a method to clear the cache. It's implemented at the session level.
*/
@ -26,5 +24,5 @@ interface CacheService {
/**
* Clear the whole cached data, except credentials. Once done, the sync has to be restarted by the sdk user.
*/
fun clearCache(callback: MatrixCallback<Unit>)
suspend fun clearCache()
}

View file

@ -16,9 +16,7 @@
package org.matrix.android.sdk.api.session.signout
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.util.Cancelable
/**
* This interface defines a method to sign out, or to renew the token. It's implemented at the session level.
@ -29,19 +27,16 @@ interface SignOutService {
* Ask the homeserver for a new access token.
* The same deviceId will be used
*/
fun signInAgain(password: String,
callback: MatrixCallback<Unit>): Cancelable
suspend fun signInAgain(password: String)
/**
* Update the session with credentials received after SSO
*/
fun updateCredentials(credentials: Credentials,
callback: MatrixCallback<Unit>): Cancelable
suspend fun updateCredentials(credentials: Credentials)
/**
* 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
*/
fun signOut(signOutFromHomeserver: Boolean,
callback: MatrixCallback<Unit>): Cancelable
suspend fun signOut(signOutFromHomeserver: Boolean)
}

View file

@ -217,13 +217,13 @@ internal class DefaultSession @Inject constructor(
}
}
override fun clearCache(callback: MatrixCallback<Unit>) {
override suspend fun clearCache() {
stopSync()
stopAnyBackgroundSync()
uiHandler.post {
lifecycleObservers.forEach { it.onClearCache() }
}
cacheService.get().clearCache(callback)
cacheService.get().clearCache()
workManagerProvider.cancelAllWorks()
}

View file

@ -16,23 +16,18 @@
package org.matrix.android.sdk.internal.session.cache
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.cache.CacheService
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import javax.inject.Inject
internal class DefaultCacheService @Inject constructor(@SessionDatabase
private val clearCacheTask: ClearCacheTask,
private val taskExecutor: TaskExecutor) : CacheService {
private val taskExecutor: TaskExecutor
) : CacheService {
override fun clearCache(callback: MatrixCallback<Unit>) {
override suspend fun clearCache() {
taskExecutor.cancelAll()
clearCacheTask
.configureWith {
this.callback = callback
}
.executeBy(taskExecutor)
clearCacheTask.execute(Unit)
}
}

View file

@ -16,45 +16,25 @@
package org.matrix.android.sdk.internal.session.signout
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.auth.SessionParamsStore
import org.matrix.android.sdk.internal.task.TaskExecutor
import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.task.launchToCallback
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import javax.inject.Inject
internal class DefaultSignOutService @Inject constructor(private val signOutTask: SignOutTask,
private val signInAgainTask: SignInAgainTask,
private val sessionParamsStore: SessionParamsStore,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val taskExecutor: TaskExecutor) : SignOutService {
private val sessionParamsStore: SessionParamsStore
) : SignOutService {
override fun signInAgain(password: String,
callback: MatrixCallback<Unit>): Cancelable {
return signInAgainTask
.configureWith(SignInAgainTask.Params(password)) {
this.callback = callback
}
.executeBy(taskExecutor)
override suspend fun signInAgain(password: String) {
signInAgainTask.execute(SignInAgainTask.Params(password))
}
override fun updateCredentials(credentials: Credentials,
callback: MatrixCallback<Unit>): Cancelable {
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
sessionParamsStore.updateCredentials(credentials)
}
override suspend fun updateCredentials(credentials: Credentials) {
sessionParamsStore.updateCredentials(credentials)
}
override fun signOut(signOutFromHomeserver: Boolean,
callback: MatrixCallback<Unit>): Cancelable {
return signOutTask
.configureWith(SignOutTask.Params(signOutFromHomeserver)) {
this.callback = callback
}
.executeBy(taskExecutor)
override suspend fun signOut(signOutFromHomeserver: Boolean) {
return signOutTask.execute(SignOutTask.Params(signOutFromHomeserver))
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.platform
import com.airbnb.mvrx.MvRxState
data class EmptyState(
val dummy: Int = 0
) : MvRxState

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.platform
/**
* Mainly used to get a viewModelScope
*/
class EmptyViewModel(initialState: EmptyState) : VectorViewModel<EmptyState, EmptyAction, EmptyViewEvents>(initialState) {
override fun handle(action: EmptyAction) {
// N/A
}
}

View file

@ -22,12 +22,15 @@ import android.os.Bundle
import android.os.Parcelable
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.viewModel
import com.bumptech.glide.Glide
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.platform.EmptyViewModel
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.deleteAllFiles
import im.vector.app.databinding.FragmentLoadingBinding
@ -45,10 +48,8 @@ import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.ui.UiStateRepository
import kotlinx.parcelize.Parcelize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.failure.GlobalError
import timber.log.Timber
import javax.inject.Inject
@ -82,6 +83,8 @@ class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActiv
}
}
private val emptyViewModel: EmptyViewModel by viewModel()
override fun getBinding() = FragmentLoadingBinding.inflate(layoutInflater)
private lateinit var args: MainActivityArgs
@ -147,38 +150,41 @@ class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActiv
}
when {
args.isAccountDeactivated -> {
// Just do the local cleanup
Timber.w("Account deactivated, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
startNextActivityAndFinish()
emptyViewModel.viewModelScope.launch {
// Just do the local cleanup
Timber.w("Account deactivated, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
startNextActivityAndFinish()
}
}
args.clearCredentials -> {
emptyViewModel.viewModelScope.launch {
try {
session.signOut(!args.isUserLoggedOut)
Timber.w("SIGN_OUT: success, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
startNextActivityAndFinish()
} catch (failure: Throwable) {
displayError(failure)
}
}
}
args.clearCache -> {
emptyViewModel.viewModelScope.launch {
try {
session.clearCache()
Timber.e("CACHE success")
doLocalCleanup(clearPreferences = false)
session.startSyncing(applicationContext)
startNextActivityAndFinish()
} catch (failure: Throwable) {
Timber.e("CACHE failure")
displayError(failure)
}
}
}
args.clearCredentials -> session.signOut(
!args.isUserLoggedOut,
object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
Timber.w("SIGN_OUT: success, start app")
sessionHolder.clearActiveSession()
doLocalCleanup(clearPreferences = true)
startNextActivityAndFinish()
}
override fun onFailure(failure: Throwable) {
displayError(failure)
}
})
args.clearCache -> session.clearCache(
object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
doLocalCleanup(clearPreferences = false)
session.startSyncing(applicationContext)
startNextActivityAndFinish()
}
override fun onFailure(failure: Throwable) {
displayError(failure)
}
})
}
}
@ -187,24 +193,22 @@ class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActiv
Timber.w("Ignoring invalid token global error")
}
private fun doLocalCleanup(clearPreferences: Boolean) {
GlobalScope.launch(Dispatchers.Main) {
// On UI Thread
Glide.get(this@MainActivity).clearMemory()
private suspend fun doLocalCleanup(clearPreferences: Boolean) {
// On UI Thread
Glide.get(this@MainActivity).clearMemory()
if (clearPreferences) {
vectorPreferences.clearPreferences()
uiStateRepository.reset()
pinLocker.unlock()
pinCodeStore.deleteEncodedPin()
}
withContext(Dispatchers.IO) {
// On BG thread
Glide.get(this@MainActivity).clearDiskCache()
if (clearPreferences) {
vectorPreferences.clearPreferences()
uiStateRepository.reset()
pinLocker.unlock()
pinCodeStore.deleteEncodedPin()
}
withContext(Dispatchers.IO) {
// On BG thread
Glide.get(this@MainActivity).clearDiskCache()
// Also clear cache (Logs, etc...)
deleteAllFiles(this@MainActivity.cacheDir)
}
// Also clear cache (Logs, etc...)
deleteAllFiles(this@MainActivity.cacheDir)
}
}

View file

@ -19,10 +19,13 @@ package im.vector.app.features.link
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.viewModel
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.platform.EmptyViewModel
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityProgressBinding
@ -30,7 +33,7 @@ import im.vector.app.features.login.LoginActivity
import im.vector.app.features.login.LoginConfig
import im.vector.app.features.permalink.PermalinkHandler
import io.reactivex.android.schedulers.AndroidSchedulers
import org.matrix.android.sdk.api.MatrixCallback
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import timber.log.Timber
import java.util.concurrent.TimeUnit
@ -45,6 +48,8 @@ class LinkHandlerActivity : VectorBaseActivity<ActivityProgressBinding>() {
@Inject lateinit var errorFormatter: ErrorFormatter
@Inject lateinit var permalinkHandler: PermalinkHandler
private val emptyViewModel: EmptyViewModel by viewModel()
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
@ -139,23 +144,30 @@ class LinkHandlerActivity : VectorBaseActivity<ActivityProgressBinding>() {
.setTitle(R.string.dialog_title_warning)
.setMessage(R.string.error_user_already_logged_in)
.setCancelable(false)
.setPositiveButton(R.string.logout) { _, _ ->
sessionHolder.getSafeActiveSession()?.signOut(true, object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
displayError(failure)
}
override fun onSuccess(data: Unit) {
Timber.d("## displayAlreadyLoginPopup(): logout succeeded")
sessionHolder.clearActiveSession()
startLoginActivity(uri)
}
}) ?: finish()
}
.setPositiveButton(R.string.logout) { _, _ -> safeSignout(uri) }
.setNegativeButton(R.string.cancel) { _, _ -> finish() }
.show()
}
private fun safeSignout(uri: Uri) {
val session = sessionHolder.getSafeActiveSession()
if(session == null) {
// Should not happen
startLoginActivity(uri)
} else {
emptyViewModel.viewModelScope.launch {
try {
session.signOut(true)
Timber.d("## displayAlreadyLoginPopup(): logout succeeded")
sessionHolder.clearActiveSession()
startLoginActivity(uri)
} catch (failure: Throwable) {
displayError(failure)
}
}
}
}
private fun displayError(failure: Throwable) {
AlertDialog.Builder(this)
.setTitle(R.string.dialog_title_error)

View file

@ -16,6 +16,7 @@
package im.vector.app.features.signout.soft
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
@ -30,6 +31,7 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.hasUnsavedKeys
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.login.LoginMode
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.data.LoginFlowResult
@ -174,22 +176,19 @@ class SoftLogoutViewModel @AssistedInject constructor(
asyncLoginAction = Loading()
)
}
currentTask = session.updateCredentials(action.credentials,
object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(SoftLogoutViewEvents.Failure(failure))
setState {
copy(
asyncLoginAction = Uninitialized
)
}
}
override fun onSuccess(data: Unit) {
onSessionRestored()
}
viewModelScope.launch {
try {
session.updateCredentials(action.credentials)
onSessionRestored()
} catch (failure: Throwable) {
_viewEvents.post(SoftLogoutViewEvents.Failure(failure))
setState {
copy(
asyncLoginAction = Uninitialized
)
}
)
}
}
}
}
}
@ -202,21 +201,18 @@ class SoftLogoutViewModel @AssistedInject constructor(
passwordShown = false
)
}
currentTask = session.signInAgain(action.password,
object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
setState {
copy(
asyncLoginAction = Fail(failure)
)
}
}
override fun onSuccess(data: Unit) {
onSessionRestored()
}
viewModelScope.launch {
try {
session.signInAgain(action.password)
onSessionRestored()
} catch (failure: Throwable) {
setState {
copy(
asyncLoginAction = Fail(failure)
)
}
)
}
}
}
private fun onSessionRestored() {