mirror of
https://github.com/element-hq/element-android
synced 2024-10-14 20:19:09 +00:00
Merge pull request #8578 from vector-im/feature/bma/crashFixes
Crash fixes
This commit is contained in:
commit
180a2eec60
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.handler
|
||||||
import androidx.work.BackoffPolicy
|
import androidx.work.BackoffPolicy
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
|
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
|
||||||
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
|
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
|
||||||
import org.matrix.android.sdk.internal.di.SessionId
|
import org.matrix.android.sdk.internal.di.SessionId
|
||||||
|
@ -81,7 +82,9 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasUpdate) {
|
if (hasUpdate) {
|
||||||
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
|
tryOrNull("Unable to update user account data") {
|
||||||
|
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.failure.GlobalError
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
|
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
|
||||||
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
|
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
|
||||||
|
@ -122,7 +123,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
|
||||||
val updateUserAccountParams = UpdateUserAccountDataTask.DirectChatParams(
|
val updateUserAccountParams = UpdateUserAccountDataTask.DirectChatParams(
|
||||||
directMessages = directChats
|
directMessages = directChats
|
||||||
)
|
)
|
||||||
updateUserAccountDataTask.execute(updateUserAccountParams)
|
tryOrNull("Unable to update user account data") { updateUserAccountDataTask.execute(updateUserAccountParams) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
sealed class BootstrapActions : VectorViewModelAction {
|
sealed class BootstrapActions : VectorViewModelAction {
|
||||||
|
object Retry : BootstrapActions()
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,11 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
|
||||||
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
|
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
|
||||||
showFragment(BootstrapMigrateBackupFragment::class)
|
showFragment(BootstrapMigrateBackupFragment::class)
|
||||||
}
|
}
|
||||||
|
is BootstrapStep.Error -> {
|
||||||
|
views.bootstrapIcon.isVisible = true
|
||||||
|
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||||
|
showFragment(BootstrapErrorFragment::class)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.invalidate()
|
super.invalidate()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.features.crypto.recover
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentBootstrapErrorBinding
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class BootstrapErrorFragment :
|
||||||
|
VectorBaseFragment<FragmentBootstrapErrorBinding>() {
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapErrorBinding {
|
||||||
|
return FragmentBootstrapErrorBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
|
when (state.step) {
|
||||||
|
is BootstrapStep.Error -> {
|
||||||
|
views.bootstrapDescriptionText.setTextOrHide(errorFormatter.toHumanReadable(state.step.error))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Should not happen, show a generic error
|
||||||
|
views.bootstrapDescriptionText.setTextOrHide(getString(R.string.unknown_error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
views.bootstrapRetryButton.onClick {
|
||||||
|
sharedViewModel.handle(BootstrapActions.Retry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
|
||||||
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
|
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
|
||||||
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
|
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
|
@ -118,37 +119,48 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetupMode.NORMAL -> {
|
SetupMode.NORMAL -> {
|
||||||
// need to check if user have an existing keybackup
|
checkMigration()
|
||||||
setState {
|
}
|
||||||
copy(step = BootstrapStep.CheckingMigration)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to check if there is an existing backup
|
private fun checkMigration() {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
// need to check if user have an existing keybackup
|
||||||
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
|
setState {
|
||||||
if (version == null) {
|
copy(step = BootstrapStep.CheckingMigration)
|
||||||
// we just resume plain bootstrap
|
}
|
||||||
doesKeyBackupExist = false
|
|
||||||
|
// We need to check if there is an existing backup
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
|
||||||
|
if (version == null) {
|
||||||
|
// we just resume plain bootstrap
|
||||||
|
doesKeyBackupExist = false
|
||||||
|
setState {
|
||||||
|
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we need to get existing backup passphrase/key and convert to SSSS
|
||||||
|
val keyVersion = tryOrNull {
|
||||||
|
session.cryptoService().keysBackupService().getVersion(version.version)
|
||||||
|
}
|
||||||
|
if (keyVersion == null) {
|
||||||
|
// strange case... just finish?
|
||||||
|
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
|
||||||
|
} else {
|
||||||
|
doesKeyBackupExist = true
|
||||||
|
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
|
||||||
setState {
|
setState {
|
||||||
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
|
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// we need to get existing backup passphrase/key and convert to SSSS
|
|
||||||
val keyVersion = tryOrNull {
|
|
||||||
session.cryptoService().keysBackupService().getVersion(version.version)
|
|
||||||
}
|
|
||||||
if (keyVersion == null) {
|
|
||||||
// strange case... just finish?
|
|
||||||
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
|
|
||||||
} else {
|
|
||||||
doesKeyBackupExist = true
|
|
||||||
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
|
|
||||||
setState {
|
|
||||||
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.e(failure, "Error while checking key backup")
|
||||||
|
setState {
|
||||||
|
copy(step = BootstrapStep.Error(failure))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,6 +280,9 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
||||||
copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error)))
|
copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BootstrapActions.Retry -> {
|
||||||
|
checkMigration()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +583,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is BootstrapStep.Error -> {
|
||||||
|
// do we let you cancel from here?
|
||||||
|
if (state.canLeave) {
|
||||||
|
_viewEvents.post(BootstrapViewEvents.SkipBootstrap(state.passphrase != null))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,8 @@ sealed class BootstrapStep {
|
||||||
object Initializing : BootstrapStep()
|
object Initializing : BootstrapStep()
|
||||||
data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep()
|
data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep()
|
||||||
object DoneSuccess : BootstrapStep()
|
object DoneSuccess : BootstrapStep()
|
||||||
|
|
||||||
|
data class Error(val error: Throwable) : BootstrapStep()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean {
|
fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean {
|
||||||
|
|
|
@ -71,6 +71,7 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerC
|
||||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||||
import org.matrix.android.sdk.flow.flow
|
import org.matrix.android.sdk.flow.flow
|
||||||
import org.matrix.android.sdk.flow.unwrap
|
import org.matrix.android.sdk.flow.unwrap
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
@ -265,7 +266,17 @@ class VectorSettingsGeneralFragment :
|
||||||
// Disable it while updating the state, will be re-enabled by the account data listener.
|
// Disable it while updating the state, will be re-enabled by the account data listener.
|
||||||
it.isEnabled = false
|
it.isEnabled = false
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
|
try {
|
||||||
|
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
Timber.e(failure, "Failed to update integration manager state")
|
||||||
|
activity?.let { activity ->
|
||||||
|
Toast.makeText(activity, errorFormatter.toHumanReadable(failure), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
// Restore the previous state
|
||||||
|
it.isChecked = !it.isChecked
|
||||||
|
it.isEnabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
33
vector/src/main/res/layout/fragment_bootstrap_error.xml
Normal file
33
vector/src/main/res/layout/fragment_bootstrap_error.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="200dp"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bootstrapDescriptionText"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/error_check_network"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bootstrapRetryButton"
|
||||||
|
style="@style/Widget.Vector.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||||
|
android:text="@string/global_retry"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText"
|
||||||
|
tools:ignore="MissingConstraints" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue