diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupFileIOError.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupFileIOError.java
index 6edb15daea..812d771f00 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupFileIOError.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupFileIOError.java
@@ -64,7 +64,7 @@ public enum BackupFileIOError {
}
}
- private static @Nullable BackupFileIOError getFromException(@NonNull IOException e) {
+ public static @Nullable BackupFileIOError getFromException(@NonNull IOException e) {
if (e instanceof FullBackupExporter.InvalidBackupStreamException) {
return ATTACHMENT_TOO_LARGE;
} else if (e.getMessage() != null) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt
index 12dc9155ba..a0f0aa4a33 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt
@@ -314,27 +314,38 @@ fun DeviceListScreen(
)
}
is DialogState.SyncingFailed -> {
- if (state.dialogState.canRetry) {
- Dialogs.SimpleAlertDialog(
- title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
- body = stringResource(R.string.LinkDeviceFragment__sync_failure_body),
- confirm = stringResource(R.string.LinkDeviceFragment__sync_failure_retry_button),
- onConfirm = onSyncFailureRetryRequested,
- dismiss = stringResource(R.string.LinkDeviceFragment__sync_failure_dismiss_button),
- onDismissRequest = onSyncFailureIgnored,
- onDeny = onSyncFailureIgnored
- )
- } else {
- Dialogs.AdvancedAlertDialog(
- title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
- body = stringResource(R.string.LinkDeviceFragment__sync_failure_body_unretryable),
- positive = stringResource(R.string.LinkDeviceFragment__contact_support),
- onPositive = onSyncFailureContactSupport,
- neutral = stringResource(R.string.LinkDeviceFragment__learn_more),
- onNeutral = onSyncFailureLearnMore,
- negative = stringResource(R.string.LinkDeviceFragment__continue),
- onNegative = onSyncFailureIgnored
- )
+ when (state.dialogState.syncFailType) {
+ LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE -> {
+ Dialogs.AdvancedAlertDialog(
+ title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
+ body = stringResource(R.string.LinkDeviceFragment__sync_failure_body_unretryable),
+ positive = stringResource(R.string.LinkDeviceFragment__contact_support),
+ onPositive = onSyncFailureContactSupport,
+ neutral = stringResource(R.string.LinkDeviceFragment__learn_more),
+ onNeutral = onSyncFailureLearnMore,
+ negative = stringResource(R.string.LinkDeviceFragment__continue),
+ onNegative = onSyncFailureIgnored
+ )
+ }
+ LinkDeviceSettingsState.SyncFailType.RETRYABLE -> {
+ Dialogs.SimpleAlertDialog(
+ title = stringResource(R.string.LinkDeviceFragment__sync_failure_title),
+ body = stringResource(R.string.LinkDeviceFragment__sync_failure_body),
+ confirm = stringResource(R.string.LinkDeviceFragment__sync_failure_retry_button),
+ onConfirm = onSyncFailureRetryRequested,
+ dismiss = stringResource(R.string.LinkDeviceFragment__sync_failure_dismiss_button),
+ onDismissRequest = onSyncFailureIgnored,
+ onDeny = onSyncFailureIgnored
+ )
+ }
+ LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE -> {
+ Dialogs.SimpleMessageDialog(
+ message = stringResource(R.string.LinkDeviceFragment__you_dont_have_enough),
+ dismiss = stringResource(id = R.string.LinkDeviceFragment__ok),
+ onDismiss = onSyncFailureRetryRequested,
+ title = stringResource(R.string.LinkDeviceFragment__not_enough_storage_space)
+ )
+ }
}
}
DialogState.SyncingTimedOut -> {
@@ -681,7 +692,11 @@ private fun DeviceListScreenSyncingFailedPreview() {
Previews.Preview {
DeviceListScreen(
state = LinkDeviceSettingsState(
- dialogState = DialogState.SyncingFailed(1, 1, false),
+ dialogState = DialogState.SyncingFailed(
+ deviceId = 1,
+ deviceCreatedAt = 1,
+ syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE
+ ),
seenQrEducationSheet = true,
seenBioAuthEducationSheet = true
)
@@ -716,3 +731,21 @@ private fun DeviceListScreenDeviceUnlinkedPreview() {
)
}
}
+
+@SignalPreview
+@Composable
+private fun DeviceListScreenNotEnoughStoragePreview() {
+ Previews.Preview {
+ DeviceListScreen(
+ state = LinkDeviceSettingsState(
+ dialogState = DialogState.SyncingFailed(
+ deviceId = 1,
+ deviceCreatedAt = 1,
+ syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE
+ ),
+ seenQrEducationSheet = true,
+ seenBioAuthEducationSheet = true
+ )
+ )
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt
index 38ce770d7a..71617baf7c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt
@@ -10,6 +10,7 @@ import org.signal.core.util.logging.logI
import org.signal.core.util.logging.logW
import org.signal.libsignal.protocol.InvalidKeyException
import org.signal.libsignal.protocol.ecc.Curve
+import org.thoughtcrime.securesms.backup.BackupFileIOError
import org.thoughtcrime.securesms.backup.v2.ArchiveValidator
import org.thoughtcrime.securesms.backup.v2.BackupRepository
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
@@ -263,7 +264,12 @@ object LinkDeviceRepository {
)
} catch (e: Exception) {
Log.w(TAG, "[createAndUploadArchive] Failed to export a backup!", e)
- return LinkUploadArchiveResult.BackupCreationFailure(e)
+ val cause = e.cause
+ return if (cause is IOException && BackupFileIOError.getFromException(cause) == BackupFileIOError.NOT_ENOUGH_SPACE) {
+ LinkUploadArchiveResult.NotEnoughSpace
+ } else {
+ LinkUploadArchiveResult.BackupCreationFailure(e)
+ }
}
Log.d(TAG, "[createAndUploadArchive] Successfully created backup.")
stopwatch.split("create-backup")
@@ -440,6 +446,7 @@ object LinkDeviceRepository {
data object Success : LinkUploadArchiveResult
data object BackupCreationCancelled : LinkUploadArchiveResult
data class BackupCreationFailure(val exception: Exception) : LinkUploadArchiveResult
+ data object NotEnoughSpace : LinkUploadArchiveResult
data class BadRequest(val exception: IOException) : LinkUploadArchiveResult
data class NetworkError(val exception: IOException) : LinkUploadArchiveResult
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt
index 82056b38fe..6d416cf7a2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt
@@ -32,7 +32,7 @@ data class LinkDeviceSettingsState(
data object Unlinking : DialogState
data class SyncingMessages(val deviceId: Int, val deviceCreatedAt: Long) : DialogState
data object SyncingTimedOut : DialogState
- data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long, val canRetry: Boolean) : DialogState
+ data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long, val syncFailType: SyncFailType) : DialogState
data class DeviceUnlinked(val deviceCreatedAt: Long) : DialogState
data object LoadingDebugLog : DialogState
data object ContactSupport : DialogState
@@ -55,4 +55,10 @@ data class LinkDeviceSettingsState(
enum class QrCodeState {
NONE, VALID_WITH_SYNC, VALID_WITHOUT_SYNC, INVALID
}
+
+ enum class SyncFailType {
+ NOT_RETRYABLE,
+ RETRYABLE,
+ NOT_ENOUGH_SPACE
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt
index 6cf02e3b67..de71be0c90 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt
@@ -339,17 +339,39 @@ class LinkDeviceViewModel : ViewModel() {
}
loadDevices()
}
- is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure,
- is LinkDeviceRepository.LinkUploadArchiveResult.BadRequest,
- is LinkDeviceRepository.LinkUploadArchiveResult.NetworkError -> {
- Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive! Result: $uploadResult")
- val canRetry = uploadResult !is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure
+ is LinkDeviceRepository.LinkUploadArchiveResult.NotEnoughSpace -> {
+ Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive because there is not enough space")
_state.update {
it.copy(
dialogState = DialogState.SyncingFailed(
deviceId = waitResult.id,
deviceCreatedAt = waitResult.created,
- canRetry = canRetry
+ syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE
+ )
+ )
+ }
+ }
+ is LinkDeviceRepository.LinkUploadArchiveResult.BackupCreationFailure -> {
+ Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive because of backup creation failure")
+ _state.update {
+ it.copy(
+ dialogState = DialogState.SyncingFailed(
+ deviceId = waitResult.id,
+ deviceCreatedAt = waitResult.created,
+ syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE
+ )
+ )
+ }
+ }
+ is LinkDeviceRepository.LinkUploadArchiveResult.BadRequest,
+ is LinkDeviceRepository.LinkUploadArchiveResult.NetworkError -> {
+ Log.w(TAG, "[addDeviceWithSync] Failed to upload the archive! Result: $uploadResult")
+ _state.update {
+ it.copy(
+ dialogState = DialogState.SyncingFailed(
+ deviceId = waitResult.id,
+ deviceCreatedAt = waitResult.created,
+ syncFailType = LinkDeviceSettingsState.SyncFailType.RETRYABLE
)
)
}
@@ -457,11 +479,13 @@ class LinkDeviceViewModel : ViewModel() {
}
}
+ val shouldLaunchQrScanner = !(dialogState is DialogState.SyncingFailed && dialogState.syncFailType != LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE)
+
_state.update {
it.copy(
linkDeviceResult = LinkDeviceResult.None,
dialogState = DialogState.None,
- oneTimeEvent = OneTimeEvent.LaunchQrCodeScanner
+ oneTimeEvent = if (shouldLaunchQrScanner) OneTimeEvent.LaunchQrCodeScanner else OneTimeEvent.None
)
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 75c5339165..bd0a4f2f79 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1091,6 +1091,10 @@
The device that was linked %1$s is no longer linked.
OK
+
+ Not enough storage space
+
+ You don\'t have enough free storage space on your device to transfer your messages. Free up some space and try again, or link your device without transferring your messages.