Suspend: continue cleaning

This commit is contained in:
ganfra 2022-04-14 15:36:03 +02:00
parent ed84e38a9b
commit 91daa1ab90
18 changed files with 132 additions and 91 deletions

View File

@ -100,7 +100,7 @@ interface CryptoService {
fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>) fun getDeviceInfo(deviceId: String, callback: MatrixCallback<DeviceInfo>)
fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int suspend fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int
fun isRoomEncrypted(roomId: String): Boolean fun isRoomEncrypted(roomId: String): Boolean

View File

@ -26,6 +26,7 @@ import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
interface KeysBackupService { interface KeysBackupService {
/** /**
* Retrieve the current version of the backup from the homeserver * Retrieve the current version of the backup from the homeserver
* *
@ -45,12 +46,12 @@ interface KeysBackupService {
/** /**
* Facility method to get the total number of locally stored keys * Facility method to get the total number of locally stored keys
*/ */
fun getTotalNumbersOfKeys(): Int suspend fun getTotalNumbersOfKeys(): Int
/** /**
* Facility method to get the number of backed up keys * Facility method to get the number of backed up keys
*/ */
fun getTotalNumbersOfBackedUpKeys(): Int suspend fun getTotalNumbersOfBackedUpKeys(): Int
// /** // /**
// * Start to back up keys immediately. // * Start to back up keys immediately.
@ -71,7 +72,7 @@ interface KeysBackupService {
/** /**
* Return the current progress of the backup * Return the current progress of the backup
*/ */
fun getBackupProgress(progressListener: ProgressListener) suspend fun getBackupProgress(progressListener: ProgressListener)
/** /**
* Get information about a backup version defined on the homeserver. * Get information about a backup version defined on the homeserver.
@ -128,7 +129,7 @@ interface KeysBackupService {
* Ask if the backup on the server contains keys that we may do not have locally. * Ask if the backup on the server contains keys that we may do not have locally.
* This should be called when entering in the state READY_TO_BACKUP * This should be called when entering in the state READY_TO_BACKUP
*/ */
fun canRestoreKeys(): Boolean suspend fun canRestoreKeys(): Boolean
/** /**
* Set trust on a keys backup version. * Set trust on a keys backup version.
@ -199,7 +200,7 @@ interface KeysBackupService {
// For gossiping // For gossiping
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? suspend fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo?
suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String): Boolean suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String): Boolean
} }

View File

@ -132,7 +132,7 @@ internal class DefaultCryptoService @Inject constructor(
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val taskExecutor: TaskExecutor, private val taskExecutor: TaskExecutor,
private val cryptoCoroutineScope: CoroutineScope, private val cryptoCoroutineScope: CoroutineScope,
private val sender: RequestSender, private val requestSender: RequestSender,
private val crossSigningService: CrossSigningService, private val crossSigningService: CrossSigningService,
private val verificationService: RustVerificationService, private val verificationService: RustVerificationService,
private val keysBackupService: RustKeyBackupService, private val keysBackupService: RustKeyBackupService,
@ -248,7 +248,7 @@ internal class DefaultCryptoService @Inject constructor(
.executeBy(taskExecutor) .executeBy(taskExecutor)
} }
override fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int { override suspend fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int {
return if (onlyBackedUp) { return if (onlyBackedUp) {
keysBackupService.getTotalNumbersOfBackedUpKeys() keysBackupService.getTotalNumbersOfBackedUpKeys()
} else { } else {
@ -594,7 +594,6 @@ internal class DefaultCryptoService @Inject constructor(
// Timber.e(throwable, "## CRYPTO | onRoomEncryptionEvent ERROR FAILED TO SETUP CRYPTO ") // Timber.e(throwable, "## CRYPTO | onRoomEncryptionEvent ERROR FAILED TO SETUP CRYPTO ")
// } finally { // } finally {
val userIds = getRoomUserIds(roomId) val userIds = getRoomUserIds(roomId)
olmMachine.updateTrackedUsers(userIds)
setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), userIds) setEncryptionInRoom(roomId, event.content?.get("algorithm")?.toString(), userIds)
// } // }
} }
@ -758,14 +757,18 @@ internal class DefaultCryptoService @Inject constructor(
} }
private suspend fun uploadKeys(request: Request.KeysUpload) { private suspend fun uploadKeys(request: Request.KeysUpload) {
val response = this.sender.uploadKeys(request) try {
this.olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response) val response = requestSender.uploadKeys(request)
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response)
} catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "## CRYPTO uploadKeys(): error")
}
} }
private suspend fun queryKeys(request: Request.KeysQuery) { private suspend fun queryKeys(request: Request.KeysQuery) {
try { try {
val response = this.sender.queryKeys(request) val response = requestSender.queryKeys(request)
this.olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response) olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response)
// Update the shields! // Update the shields!
cryptoCoroutineScope.launch { cryptoCoroutineScope.launch {
@ -781,18 +784,38 @@ internal class DefaultCryptoService @Inject constructor(
} }
private suspend fun sendToDevice(request: Request.ToDevice) { private suspend fun sendToDevice(request: Request.ToDevice) {
this.sender.sendToDevice(request) try {
olmMachine.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}") requestSender.sendToDevice(request)
olmMachine.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}")
} catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "## CRYPTO sendToDevice(): error")
}
} }
private suspend fun claimKeys(request: Request.KeysClaim) { private suspend fun claimKeys(request: Request.KeysClaim) {
val response = this.sender.claimKeys(request) try {
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response) val response = requestSender.claimKeys(request)
olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response)
} catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "## CRYPTO claimKeys(): error")
}
} }
private suspend fun signatureUpload(request: Request.SignatureUpload) { private suspend fun signatureUpload(request: Request.SignatureUpload) {
this.sender.sendSignatureUpload(request) try {
olmMachine.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, "{}") requestSender.sendSignatureUpload(request)
olmMachine.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, "{}")
} catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "## CRYPTO signatureUpload(): error")
}
}
private suspend fun sendRoomMessage(request: Request.RoomMessage){
try {
requestSender.sendRoomMessage(request)
} catch (throwable: Throwable) {
Timber.tag(loggerTag.value).e(throwable, "## CRYPTO sendRoomMessage(): error")
}
} }
private suspend fun sendOutgoingRequests() { private suspend fun sendOutgoingRequests() {
@ -822,7 +845,7 @@ internal class DefaultCryptoService @Inject constructor(
} }
is Request.RoomMessage -> { is Request.RoomMessage -> {
async { async {
sender.sendRoomMessage(it) sendRoomMessage(it)
} }
} }
is Request.SignatureUpload -> { is Request.SignatureUpload -> {

View File

@ -833,21 +833,24 @@ internal class OlmMachine(
} }
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
fun roomKeyCounts(): RoomKeyCounts { suspend fun roomKeyCounts(): RoomKeyCounts {
// TODO convert this to a suspendable method return withContext(Dispatchers.Default) {
return inner.roomKeyCounts() inner.roomKeyCounts()
}
} }
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
fun getBackupKeys(): BackupKeys? { suspend fun getBackupKeys(): BackupKeys? {
// TODO this needs to be suspendable return withContext(Dispatchers.Default) {
return inner.getBackupKeys() inner.getBackupKeys()
}
} }
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)
fun saveRecoveryKey(key: String?, version: String?) { suspend fun saveRecoveryKey(key: String?, version: String?) {
// TODO convert this to a suspendable method withContext(Dispatchers.Default) {
inner.saveRecoveryKey(key, version) inner.saveRecoveryKey(key, version)
}
} }
@Throws(CryptoStoreException::class) @Throws(CryptoStoreException::class)

View File

@ -16,6 +16,7 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types import com.squareup.moshi.Types
import dagger.Lazy import dagger.Lazy
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
@ -80,6 +81,7 @@ internal class RequestSender @Inject constructor(
private val getSessionsDataTask: GetSessionsDataTask, private val getSessionsDataTask: GetSessionsDataTask,
private val getRoomSessionsDataTask: GetRoomSessionsDataTask, private val getRoomSessionsDataTask: GetRoomSessionsDataTask,
private val getRoomSessionDataTask: GetRoomSessionDataTask, private val getRoomSessionDataTask: GetRoomSessionDataTask,
private val moshi: Moshi
) { ) {
companion object { companion object {
const val REQUEST_RETRY_COUNT = 3 const val REQUEST_RETRY_COUNT = 3
@ -97,16 +99,16 @@ internal class RequestSender @Inject constructor(
suspend fun queryKeys(request: Request.KeysQuery): String { suspend fun queryKeys(request: Request.KeysQuery): String {
val params = DownloadKeysForUsersTask.Params(request.users, null) val params = DownloadKeysForUsersTask.Params(request.users, null)
val response = downloadKeysForUsersTask.executeRetry(params, REQUEST_RETRY_COUNT) val response = downloadKeysForUsersTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysQueryResponse::class.java) val adapter = moshi.adapter(KeysQueryResponse::class.java)
return adapter.toJson(response)!! return adapter.toJson(response)!!
} }
suspend fun uploadKeys(request: Request.KeysUpload): String { suspend fun uploadKeys(request: Request.KeysUpload): String {
val body = MoshiProvider.providesMoshi().adapter<JsonDict>(Map::class.java).fromJson(request.body)!! val body = moshi.adapter<JsonDict>(Map::class.java).fromJson(request.body)!!
val params = UploadKeysTask.Params(body) val params = UploadKeysTask.Params(body)
val response = uploadKeysTask.executeRetry(params, REQUEST_RETRY_COUNT) val response = uploadKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val adapter = MoshiProvider.providesMoshi().adapter(KeysUploadResponse::class.java) val adapter = moshi.adapter(KeysUploadResponse::class.java)
return adapter.toJson(response)!! return adapter.toJson(response)!!
} }
@ -127,7 +129,7 @@ internal class RequestSender @Inject constructor(
} }
suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String): String { suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String): String {
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java) val adapter = moshi.adapter<Content>(Map::class.java)
val jsonContent = adapter.fromJson(content) val jsonContent = adapter.fromJson(content)
val event = Event(eventType, transactionId, jsonContent, roomId = roomId) val event = Event(eventType, transactionId, jsonContent, roomId = roomId)
val params = SendVerificationMessageTask.Params(event) val params = SendVerificationMessageTask.Params(event)
@ -143,7 +145,7 @@ internal class RequestSender @Inject constructor(
} }
private suspend fun sendSignatureUpload(body: String) { private suspend fun sendSignatureUpload(body: String) {
val adapter = MoshiProvider.providesMoshi().adapter<Map<String, Map<String, Any>>>(Map::class.java) val adapter = moshi.adapter<Map<String, Map<String, Any>>>(Map::class.java)
val signatures = adapter.fromJson(body)!! val signatures = adapter.fromJson(body)!!
val params = UploadSignaturesTask.Params(signatures) val params = UploadSignaturesTask.Params(signatures)
this.signaturesUploadTask.executeRetry(params, REQUEST_RETRY_COUNT) this.signaturesUploadTask.executeRetry(params, REQUEST_RETRY_COUNT)
@ -153,7 +155,7 @@ internal class RequestSender @Inject constructor(
request: UploadSigningKeysRequest, request: UploadSigningKeysRequest,
interactiveAuthInterceptor: UserInteractiveAuthInterceptor? interactiveAuthInterceptor: UserInteractiveAuthInterceptor?
) { ) {
val adapter = MoshiProvider.providesMoshi().adapter(RestKeyInfo::class.java) val adapter = moshi.adapter(RestKeyInfo::class.java)
val masterKey = adapter.fromJson(request.masterKey)!!.toCryptoModel() val masterKey = adapter.fromJson(request.masterKey)!!.toCryptoModel()
val selfSigningKey = adapter.fromJson(request.selfSigningKey)!!.toCryptoModel() val selfSigningKey = adapter.fromJson(request.selfSigningKey)!!.toCryptoModel()
val userSigningKey = adapter.fromJson(request.userSigningKey)!!.toCryptoModel() val userSigningKey = adapter.fromJson(request.userSigningKey)!!.toCryptoModel()
@ -195,8 +197,7 @@ internal class RequestSender @Inject constructor(
} }
suspend fun sendToDevice(eventType: String, body: String, transactionId: String) { suspend fun sendToDevice(eventType: String, body: String, transactionId: String) {
val adapter = MoshiProvider val adapter = moshi
.providesMoshi()
.newBuilder() .newBuilder()
.add(CheckNumberType.JSON_ADAPTER_FACTORY) .add(CheckNumberType.JSON_ADAPTER_FACTORY)
.build() .build()
@ -252,7 +253,7 @@ internal class RequestSender @Inject constructor(
val keys = adapter.fromJson(request.rooms)!! val keys = adapter.fromJson(request.rooms)!!
val params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys)) val params = StoreSessionsDataTask.Params(request.version, KeysBackupData(keys))
val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT) val response = backupRoomKeysTask.executeRetry(params, REQUEST_RETRY_COUNT)
val responseAdapter = MoshiProvider.providesMoshi().adapter(BackupKeysResult::class.java) val responseAdapter = moshi.adapter(BackupKeysResult::class.java)
return responseAdapter.toJson(response)!! return responseAdapter.toJson(response)!!
} }

View File

@ -237,7 +237,7 @@ internal class RustKeyBackupService @Inject constructor(
} }
} }
override fun canRestoreKeys(): Boolean { override suspend fun canRestoreKeys(): Boolean {
val keyCountOnServer = keysBackupVersion?.count ?: return false val keyCountOnServer = keysBackupVersion?.count ?: return false
val keyCountLocally = getTotalNumbersOfKeys() val keyCountLocally = getTotalNumbersOfKeys()
@ -246,11 +246,11 @@ internal class RustKeyBackupService @Inject constructor(
return keyCountLocally < keyCountOnServer return keyCountLocally < keyCountOnServer
} }
override fun getTotalNumbersOfKeys(): Int { override suspend fun getTotalNumbersOfKeys(): Int {
return olmMachine.roomKeyCounts().total.toInt() return olmMachine.roomKeyCounts().total.toInt()
} }
override fun getTotalNumbersOfBackedUpKeys(): Int { override suspend fun getTotalNumbersOfBackedUpKeys(): Int {
return olmMachine.roomKeyCounts().backedUp.toInt() return olmMachine.roomKeyCounts().backedUp.toInt()
} }
@ -405,7 +405,7 @@ internal class RustKeyBackupService @Inject constructor(
} }
} }
override fun getBackupProgress(progressListener: ProgressListener) { override suspend fun getBackupProgress(progressListener: ProgressListener) {
val backedUpKeys = getTotalNumbersOfBackedUpKeys() val backedUpKeys = getTotalNumbersOfBackedUpKeys()
val total = getTotalNumbersOfKeys() val total = getTotalNumbersOfKeys()
@ -725,7 +725,7 @@ internal class RustKeyBackupService @Inject constructor(
} }
} }
override fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? { override suspend fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? {
val info = olmMachine.getBackupKeys() ?: return null val info = olmMachine.getBackupKeys() ?: return null
return SavedKeyBackupKeyInfo(info.recoveryKey, info.backupVersion) return SavedKeyBackupKeyInfo(info.recoveryKey, info.backupVersion)
} }

View File

@ -64,12 +64,12 @@ fun Session.startSyncing(context: Context) {
/** /**
* Tell is the session has unsaved e2e keys in the backup * Tell is the session has unsaved e2e keys in the backup
*/ */
fun Session.hasUnsavedKeys(): Boolean { suspend fun Session.hasUnsavedKeys(): Boolean {
return cryptoService().inboundGroupSessionsCount(false) > 0 && return cryptoService().inboundGroupSessionsCount(false) > 0 &&
cryptoService().keysBackupService().state != KeysBackupState.ReadyToBackUp cryptoService().keysBackupService().state != KeysBackupState.ReadyToBackUp
} }
fun Session.cannotLogoutSafely(): Boolean { suspend fun Session.cannotLogoutSafely(): Boolean {
// has some encrypted chat // has some encrypted chat
return hasUnsavedKeys() || return hasUnsavedKeys() ||
// has local cross signing keys // has local cross signing keys

View File

@ -26,5 +26,8 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionR
data class KeysBackupSettingViewState(val keysBackupVersionTrust: Async<KeysBackupVersionTrust> = Uninitialized, data class KeysBackupSettingViewState(val keysBackupVersionTrust: Async<KeysBackupVersionTrust> = Uninitialized,
val keysBackupState: KeysBackupState? = null, val keysBackupState: KeysBackupState? = null,
val keysBackupVersion: KeysVersionResult? = null, val keysBackupVersion: KeysVersionResult? = null,
val remainingKeysToBackup: Int = 0,
val deleteBackupRequest: Async<Unit> = Uninitialized) : val deleteBackupRequest: Async<Unit> = Uninitialized) :
MavericksState MavericksState

View File

@ -124,10 +124,7 @@ class KeysBackupSettingsRecyclerViewController @Inject constructor(
style(ItemStyle.BIG_TEXT) style(ItemStyle.BIG_TEXT)
hasIndeterminateProcess(true) hasIndeterminateProcess(true)
val totalKeys = host.session.cryptoService().inboundGroupSessionsCount(false) val remainingKeysToBackup = data.remainingKeysToBackup
val backedUpKeys = host.session.cryptoService().inboundGroupSessionsCount(true)
val remainingKeysToBackup = totalKeys - backedUpKeys
if (data.keysBackupVersionTrust()?.usable == false) { if (data.keysBackupVersionTrust()?.usable == false) {
description(host.stringProvider.getString(R.string.keys_backup_settings_untrusted_backup).toEpoxyCharSequence()) description(host.stringProvider.getString(R.string.keys_backup_settings_untrusted_backup).toEpoxyCharSequence())

View File

@ -18,7 +18,6 @@ package im.vector.app.features.crypto.keysbackup.settings
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -32,7 +31,6 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
import timber.log.Timber
class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialState: KeysBackupSettingViewState, class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialState: KeysBackupSettingViewState,
session: Session session: Session
@ -46,6 +44,7 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
companion object : MavericksViewModelFactory<KeysBackupSettingsViewModel, KeysBackupSettingViewState> by hiltMavericksViewModelFactory() companion object : MavericksViewModelFactory<KeysBackupSettingsViewModel, KeysBackupSettingViewState> by hiltMavericksViewModelFactory()
private val cryptoService = session.cryptoService()
private val keysBackupService: KeysBackupService = session.cryptoService().keysBackupService() private val keysBackupService: KeysBackupService = session.cryptoService().keysBackupService()
init { init {
@ -75,34 +74,12 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
private fun getKeysBackupTrust() = withState { state -> private fun getKeysBackupTrust() = withState { state ->
val versionResult = keysBackupService.keysBackupVersion val versionResult = keysBackupService.keysBackupVersion
Timber.d("BACKUP: HEEEEEEE $versionResult ${state.keysBackupVersionTrust}")
if (state.keysBackupVersionTrust is Uninitialized && versionResult != null) { if (state.keysBackupVersionTrust is Uninitialized && versionResult != null) {
setState { setState { copy(deleteBackupRequest = Uninitialized) }
copy( suspend {
keysBackupVersionTrust = Loading(), keysBackupService.getKeysBackupTrust(versionResult)
deleteBackupRequest = Uninitialized }.execute {
) copy(keysBackupVersionTrust = it)
}
Timber.d("BACKUP: HEEEEEEE TWO")
viewModelScope.launch {
try {
val data = keysBackupService.getKeysBackupTrust(versionResult)
Timber.d("BACKUP: HEEEE suceeeded $data")
setState {
copy(
keysBackupVersionTrust = Success(data)
)
}
} catch (failure: Throwable) {
Timber.d("BACKUP: HEEEE FAILED $failure")
setState {
copy(
keysBackupVersionTrust = Fail(failure)
)
}
}
} }
} }
} }
@ -119,10 +96,24 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
keysBackupVersion = keysBackupService.keysBackupVersion keysBackupVersion = keysBackupService.keysBackupVersion
) )
} }
when (newState) {
KeysBackupState.BackingUp, KeysBackupState.WillBackUp -> updateKeysCount()
else -> Unit
}
getKeysBackupTrust() getKeysBackupTrust()
} }
private fun updateKeysCount() {
viewModelScope.launch {
val totalKeys = cryptoService.inboundGroupSessionsCount(false)
val backedUpKeys = cryptoService.inboundGroupSessionsCount(true)
val remainingKeysToBackup = totalKeys - backedUpKeys
setState {
copy(remainingKeysToBackup = remainingKeysToBackup)
}
}
}
private fun deleteCurrentBackup() { private fun deleteCurrentBackup() {
val keysBackupService = keysBackupService val keysBackupService = keysBackupService

View File

@ -80,6 +80,7 @@ class HomeDrawerFragment @Inject constructor(
} }
// Sign out // Sign out
views.homeDrawerHeaderSignoutView.debouncedClicks { views.homeDrawerHeaderSignoutView.debouncedClicks {
signout()
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
SignOutUiWorker(requireActivity()).perform() SignOutUiWorker(requireActivity()).perform()
} }
@ -118,4 +119,8 @@ class HomeDrawerFragment @Inject constructor(
navigator.openDebug(requireActivity()) navigator.openDebug(requireActivity())
} }
} }
private fun signout() {
}
} }

View File

@ -95,7 +95,7 @@ class SoftLogoutActivity : LoginActivity() {
MainActivity.restartApp(this, MainActivityArgs()) MainActivity.restartApp(this, MainActivityArgs())
} }
views.loginLoading.isVisible = softLogoutViewState.isLoading() views.loginLoading.isVisible = softLogoutViewState.isLoading
} }
companion object { companion object {

View File

@ -34,6 +34,7 @@ import im.vector.app.features.signout.soft.epoxy.loginRedButtonItem
import im.vector.app.features.signout.soft.epoxy.loginTextItem import im.vector.app.features.signout.soft.epoxy.loginTextItem
import im.vector.app.features.signout.soft.epoxy.loginTitleItem import im.vector.app.features.signout.soft.epoxy.loginTitleItem
import im.vector.app.features.signout.soft.epoxy.loginTitleSmallItem import im.vector.app.features.signout.soft.epoxy.loginTitleSmallItem
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject import javax.inject.Inject
class SoftLogoutController @Inject constructor( class SoftLogoutController @Inject constructor(
@ -52,6 +53,7 @@ class SoftLogoutController @Inject constructor(
override fun buildModels() { override fun buildModels() {
val safeViewState = viewState ?: return val safeViewState = viewState ?: return
if (safeViewState.hasUnsavedKeys is Incomplete) return
buildHeader(safeViewState) buildHeader(safeViewState)
buildForm(safeViewState) buildForm(safeViewState)
@ -78,7 +80,7 @@ class SoftLogoutController @Inject constructor(
state.userDisplayName, state.userDisplayName,
state.userId)) state.userId))
} }
if (state.hasUnsavedKeys) { if (state.hasUnsavedKeys().orFalse()) {
loginTextItem { loginTextItem {
id("signText2") id("signText2")
text(host.stringProvider.getString(R.string.soft_logout_signin_e2e_warning_notice)) text(host.stringProvider.getString(R.string.soft_logout_signin_e2e_warning_notice))

View File

@ -32,6 +32,7 @@ import im.vector.app.features.login.AbstractLoginFragment
import im.vector.app.features.login.LoginAction import im.vector.app.features.login.LoginAction
import im.vector.app.features.login.LoginMode import im.vector.app.features.login.LoginMode
import im.vector.app.features.login.LoginViewEvents import im.vector.app.features.login.LoginViewEvents
import org.matrix.android.sdk.api.extensions.orFalse
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -118,7 +119,7 @@ class SoftLogoutFragment @Inject constructor(
withState(softLogoutViewModel) { state -> withState(softLogoutViewModel) { state ->
cleanupUi() cleanupUi()
val messageResId = if (state.hasUnsavedKeys) { val messageResId = if (state.hasUnsavedKeys().orFalse()) {
R.string.soft_logout_clear_data_dialog_e2e_warning_content R.string.soft_logout_clear_data_dialog_e2e_warning_content
} else { } else {
R.string.soft_logout_clear_data_dialog_content R.string.soft_logout_clear_data_dialog_content

View File

@ -69,7 +69,6 @@ class SoftLogoutViewModel @AssistedInject constructor(
userId = userId, userId = userId,
deviceId = session.sessionParams.deviceId.orEmpty(), deviceId = session.sessionParams.deviceId.orEmpty(),
userDisplayName = session.getUser(userId)?.displayName ?: userId, userDisplayName = session.getUser(userId)?.displayName ?: userId,
hasUnsavedKeys = session.hasUnsavedKeys()
) )
} else { } else {
SoftLogoutViewState( SoftLogoutViewState(
@ -77,17 +76,25 @@ class SoftLogoutViewModel @AssistedInject constructor(
userId = "", userId = "",
deviceId = "", deviceId = "",
userDisplayName = "", userDisplayName = "",
hasUnsavedKeys = false
) )
} }
} }
} }
init { init {
checkHasUnsavedKeys()
// Get the supported login flow // Get the supported login flow
getSupportedLoginFlow() getSupportedLoginFlow()
} }
private fun checkHasUnsavedKeys() {
suspend {
session.hasUnsavedKeys()
}.execute {
copy(hasUnsavedKeys = it)
}
}
private fun getSupportedLoginFlow() { private fun getSupportedLoginFlow() {
viewModelScope.launch { viewModelScope.launch {
authenticationService.cancelPendingLoginOrRegistration() authenticationService.cancelPendingLoginOrRegistration()

View File

@ -30,13 +30,12 @@ data class SoftLogoutViewState(
val userId: String, val userId: String,
val deviceId: String, val deviceId: String,
val userDisplayName: String, val userDisplayName: String,
val hasUnsavedKeys: Boolean, val hasUnsavedKeys: Async<Boolean> = Uninitialized,
val enteredPassword: String = "" val enteredPassword: String = ""
) : MavericksState { ) : MavericksState {
fun isLoading(): Boolean { val isLoading: Boolean =
return asyncLoginAction is Loading || asyncLoginAction is Loading ||
// Keep loading when it is success because of the delay to switch to the next Activity // Keep loading when it is success because of the delay to switch to the next Activity
asyncLoginAction is Success asyncLoginAction is Success
}
} }

View File

@ -130,14 +130,14 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
/** /**
* Safe way to get the number of keys to backup * Safe way to get the number of keys to backup
*/ */
fun getNumberOfKeysToBackup(): Int { private suspend fun getNumberOfKeysToBackup(): Int {
return session.cryptoService().inboundGroupSessionsCount(false) return session.cryptoService().inboundGroupSessionsCount(false)
} }
/** /**
* Safe way to tell if there are more keys on the server * Safe way to tell if there are more keys on the server
*/ */
fun canRestoreKeys(): Boolean { private suspend fun canRestoreKeys(): Boolean {
return session.cryptoService().keysBackupService().canRestoreKeys() return session.cryptoService().keysBackupService().canRestoreKeys()
} }
@ -161,5 +161,5 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS
} }
} }
override fun handle(action: EmptyAction) {} override fun handle(action: EmptyAction) = Unit
} }

View File

@ -17,17 +17,25 @@
package im.vector.app.features.workers.signout package im.vector.app.features.workers.signout
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.cannotLogoutSafely import im.vector.app.core.extensions.cannotLogoutSafely
import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.features.MainActivity import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs import im.vector.app.features.MainActivityArgs
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
class SignOutUiWorker(private val activity: FragmentActivity) { class SignOutUiWorker(private val activity: FragmentActivity) {
fun perform() { fun perform() {
val session = activity.singletonEntryPoint().activeSessionHolder().getSafeActiveSession() ?: return val session = activity.singletonEntryPoint().activeSessionHolder().getSafeActiveSession() ?: return
activity.lifecycleScope.perform(session)
}
private fun CoroutineScope.perform(session: Session) = launch {
if (session.cannotLogoutSafely()) { if (session.cannotLogoutSafely()) {
// The backup check on logout flow has to be displayed if there are keys in the store, and the keys backup state is not Ready // The backup check on logout flow has to be displayed if there are keys in the store, and the keys backup state is not Ready
val signOutDialog = SignOutBottomSheetDialogFragment.newInstance() val signOutDialog = SignOutBottomSheetDialogFragment.newInstance()