Skip to content

Commit 180a2ee

Browse files
authored
Merge pull request #8578 from vector-im/feature/bma/crashFixes
Crash fixes
2 parents 1359659 + ae52d4c commit 180a2ee

File tree

9 files changed

+159
-28
lines changed

9 files changed

+159
-28
lines changed

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.handler
1919
import androidx.work.BackoffPolicy
2020
import androidx.work.ExistingWorkPolicy
2121
import org.matrix.android.sdk.api.MatrixPatterns
22+
import org.matrix.android.sdk.api.extensions.tryOrNull
2223
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
2324
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository
2425
import org.matrix.android.sdk.internal.di.SessionId
@@ -81,7 +82,9 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor(
8182
}
8283
}
8384
if (hasUpdate) {
84-
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
85+
tryOrNull("Unable to update user account data") {
86+
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats))
87+
}
8588
}
8689
}
8790

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
2020
import io.realm.Realm
2121
import io.realm.RealmList
2222
import io.realm.kotlin.where
23+
import org.matrix.android.sdk.api.extensions.tryOrNull
2324
import org.matrix.android.sdk.api.failure.GlobalError
2425
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
2526
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
@@ -122,7 +123,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
122123
val updateUserAccountParams = UpdateUserAccountDataTask.DirectChatParams(
123124
directMessages = directChats
124125
)
125-
updateUserAccountDataTask.execute(updateUserAccountParams)
126+
tryOrNull("Unable to update user account data") { updateUserAccountDataTask.execute(updateUserAccountParams) }
126127
}
127128
}
128129

vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapActions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction
2020
import java.io.OutputStream
2121

2222
sealed class BootstrapActions : VectorViewModelAction {
23+
object Retry : BootstrapActions()
2324

2425
// Navigation
2526

vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
212212
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
213213
showFragment(BootstrapMigrateBackupFragment::class)
214214
}
215+
is BootstrapStep.Error -> {
216+
views.bootstrapIcon.isVisible = true
217+
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
218+
showFragment(BootstrapErrorFragment::class)
219+
}
215220
}
216221
super.invalidate()
217222
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.features.crypto.recover
18+
19+
import android.view.LayoutInflater
20+
import android.view.ViewGroup
21+
import com.airbnb.mvrx.parentFragmentViewModel
22+
import com.airbnb.mvrx.withState
23+
import dagger.hilt.android.AndroidEntryPoint
24+
import im.vector.app.R
25+
import im.vector.app.core.epoxy.onClick
26+
import im.vector.app.core.extensions.setTextOrHide
27+
import im.vector.app.core.platform.VectorBaseFragment
28+
import im.vector.app.databinding.FragmentBootstrapErrorBinding
29+
30+
@AndroidEntryPoint
31+
class BootstrapErrorFragment :
32+
VectorBaseFragment<FragmentBootstrapErrorBinding>() {
33+
34+
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapErrorBinding {
35+
return FragmentBootstrapErrorBinding.inflate(inflater, container, false)
36+
}
37+
38+
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
39+
40+
override fun invalidate() = withState(sharedViewModel) { state ->
41+
when (state.step) {
42+
is BootstrapStep.Error -> {
43+
views.bootstrapDescriptionText.setTextOrHide(errorFormatter.toHumanReadable(state.step.error))
44+
}
45+
else -> {
46+
// Should not happen, show a generic error
47+
views.bootstrapDescriptionText.setTextOrHide(getString(R.string.unknown_error))
48+
}
49+
}
50+
views.bootstrapRetryButton.onClick {
51+
sharedViewModel.handle(BootstrapActions.Retry)
52+
}
53+
}
54+
}

vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR
5454
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
5555
import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
5656
import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
57+
import timber.log.Timber
5758
import java.io.OutputStream
5859
import kotlin.coroutines.Continuation
5960
import kotlin.coroutines.resumeWithException
@@ -118,37 +119,48 @@ class BootstrapSharedViewModel @AssistedInject constructor(
118119
}
119120
}
120121
SetupMode.NORMAL -> {
121-
// need to check if user have an existing keybackup
122-
setState {
123-
copy(step = BootstrapStep.CheckingMigration)
124-
}
122+
checkMigration()
123+
}
124+
}
125+
}
126+
127+
private fun checkMigration() {
128+
// need to check if user have an existing keybackup
129+
setState {
130+
copy(step = BootstrapStep.CheckingMigration)
131+
}
125132

126-
// We need to check if there is an existing backup
127-
viewModelScope.launch(Dispatchers.IO) {
128-
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
129-
if (version == null) {
130-
// we just resume plain bootstrap
131-
doesKeyBackupExist = false
133+
// We need to check if there is an existing backup
134+
viewModelScope.launch(Dispatchers.IO) {
135+
try {
136+
val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult()
137+
if (version == null) {
138+
// we just resume plain bootstrap
139+
doesKeyBackupExist = false
140+
setState {
141+
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
142+
}
143+
} else {
144+
// we need to get existing backup passphrase/key and convert to SSSS
145+
val keyVersion = tryOrNull {
146+
session.cryptoService().keysBackupService().getVersion(version.version)
147+
}
148+
if (keyVersion == null) {
149+
// strange case... just finish?
150+
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
151+
} else {
152+
doesKeyBackupExist = true
153+
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
132154
setState {
133155
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
134156
}
135-
} else {
136-
// we need to get existing backup passphrase/key and convert to SSSS
137-
val keyVersion = tryOrNull {
138-
session.cryptoService().keysBackupService().getVersion(version.version)
139-
}
140-
if (keyVersion == null) {
141-
// strange case... just finish?
142-
_viewEvents.post(BootstrapViewEvents.Dismiss(false))
143-
} else {
144-
doesKeyBackupExist = true
145-
isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
146-
setState {
147-
copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod))
148-
}
149-
}
150157
}
151158
}
159+
} catch (failure: Throwable) {
160+
Timber.e(failure, "Error while checking key backup")
161+
setState {
162+
copy(step = BootstrapStep.Error(failure))
163+
}
152164
}
153165
}
154166
}
@@ -268,6 +280,9 @@ class BootstrapSharedViewModel @AssistedInject constructor(
268280
copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error)))
269281
}
270282
}
283+
BootstrapActions.Retry -> {
284+
checkMigration()
285+
}
271286
}
272287
}
273288

@@ -568,6 +583,12 @@ class BootstrapSharedViewModel @AssistedInject constructor(
568583
)
569584
}
570585
}
586+
is BootstrapStep.Error -> {
587+
// do we let you cancel from here?
588+
if (state.canLeave) {
589+
_viewEvents.post(BootstrapViewEvents.SkipBootstrap(state.passphrase != null))
590+
}
591+
}
571592
}
572593
}
573594

vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapStep.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ sealed class BootstrapStep {
105105
object Initializing : BootstrapStep()
106106
data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep()
107107
object DoneSuccess : BootstrapStep()
108+
109+
data class Error(val error: Throwable) : BootstrapStep()
108110
}
109111

110112
fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean {

vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerC
7171
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
7272
import org.matrix.android.sdk.flow.flow
7373
import org.matrix.android.sdk.flow.unwrap
74+
import timber.log.Timber
7475
import java.io.File
7576
import java.net.URL
7677
import java.util.UUID
@@ -265,7 +266,17 @@ class VectorSettingsGeneralFragment :
265266
// Disable it while updating the state, will be re-enabled by the account data listener.
266267
it.isEnabled = false
267268
lifecycleScope.launch {
268-
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
269+
try {
270+
session.integrationManagerService().setIntegrationEnabled(newValue as Boolean)
271+
} catch (failure: Throwable) {
272+
Timber.e(failure, "Failed to update integration manager state")
273+
activity?.let { activity ->
274+
Toast.makeText(activity, errorFormatter.toHumanReadable(failure), Toast.LENGTH_SHORT).show()
275+
}
276+
// Restore the previous state
277+
it.isChecked = !it.isChecked
278+
it.isEnabled = true
279+
}
269280
}
270281
true
271282
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="match_parent"
6+
android:layout_height="wrap_content"
7+
android:minHeight="200dp"
8+
android:padding="16dp">
9+
10+
<TextView
11+
android:id="@+id/bootstrapDescriptionText"
12+
style="@style/Widget.Vector.TextView.Body"
13+
android:layout_width="match_parent"
14+
android:layout_height="wrap_content"
15+
android:layout_marginTop="8dp"
16+
android:text="@string/error_check_network"
17+
android:textColor="?vctr_content_primary"
18+
app:layout_constraintTop_toTopOf="parent" />
19+
20+
<Button
21+
android:id="@+id/bootstrapRetryButton"
22+
style="@style/Widget.Vector.Button"
23+
android:layout_width="wrap_content"
24+
android:layout_height="wrap_content"
25+
android:layout_marginTop="@dimen/layout_vertical_margin"
26+
android:text="@string/global_retry"
27+
app:layout_constraintBottom_toBottomOf="parent"
28+
app:layout_constraintEnd_toEndOf="parent"
29+
app:layout_constraintStart_toStartOf="parent"
30+
app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText"
31+
tools:ignore="MissingConstraints" />
32+
33+
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)