Improve backup creation exception messaging to user.
This commit is contained in:
parent
36f1183d6c
commit
019025ab8a
6 changed files with 117 additions and 83 deletions
|
@ -11,7 +11,7 @@ public class BackupEvent {
|
||||||
private final long count;
|
private final long count;
|
||||||
private final long estimatedTotalCount;
|
private final long estimatedTotalCount;
|
||||||
|
|
||||||
BackupEvent(Type type, long count, long estimatedTotalCount) {
|
public BackupEvent(Type type, long count, long estimatedTotalCount) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.estimatedTotalCount = estimatedTotalCount;
|
this.estimatedTotalCount = estimatedTotalCount;
|
||||||
|
|
|
@ -22,6 +22,7 @@ public enum BackupFileIOError {
|
||||||
FILE_TOO_LARGE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_file_is_too_large),
|
FILE_TOO_LARGE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_file_is_too_large),
|
||||||
NOT_ENOUGH_SPACE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_there_is_not_enough_space),
|
NOT_ENOUGH_SPACE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_there_is_not_enough_space),
|
||||||
VERIFICATION_FAILED(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_could_not_be_verified),
|
VERIFICATION_FAILED(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_could_not_be_verified),
|
||||||
|
ATTACHMENT_TOO_LARGE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_contains_a_very_large_file),
|
||||||
UNKNOWN(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_tap_to_manage_backups);
|
UNKNOWN(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_tap_to_manage_backups);
|
||||||
|
|
||||||
private static final short BACKUP_FAILED_ID = 31321;
|
private static final short BACKUP_FAILED_ID = 31321;
|
||||||
|
@ -44,6 +45,7 @@ public enum BackupFileIOError {
|
||||||
.setSmallIcon(R.drawable.ic_signal_backup)
|
.setSmallIcon(R.drawable.ic_signal_backup)
|
||||||
.setContentTitle(context.getString(titleId))
|
.setContentTitle(context.getString(titleId))
|
||||||
.setContentText(context.getString(messageId))
|
.setContentText(context.getString(messageId))
|
||||||
|
.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(messageId)))
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -51,22 +53,27 @@ public enum BackupFileIOError {
|
||||||
.notify(BACKUP_FAILED_ID, backupFailedNotification);
|
.notify(BACKUP_FAILED_ID, backupFailedNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void postNotificationForException(@NonNull Context context, @NonNull IOException e, int runAttempt) {
|
public static void postNotificationForException(@NonNull Context context, @NonNull IOException e) {
|
||||||
BackupFileIOError error = getFromException(e);
|
BackupFileIOError error = getFromException(e);
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
error.postNotification(context);
|
error.postNotification(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == null && runAttempt > 0) {
|
if (error == null) {
|
||||||
UNKNOWN.postNotification(context);
|
UNKNOWN.postNotification(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @Nullable BackupFileIOError getFromException(@NonNull IOException e) {
|
private static @Nullable BackupFileIOError getFromException(@NonNull IOException e) {
|
||||||
if (e.getMessage() != null) {
|
if (e instanceof FullBackupExporter.InvalidBackupStreamException) {
|
||||||
if (e.getMessage().contains("EFBIG")) return FILE_TOO_LARGE;
|
return ATTACHMENT_TOO_LARGE;
|
||||||
else if (e.getMessage().contains("ENOSPC")) return NOT_ENOUGH_SPACE;
|
} else if (e.getMessage() != null) {
|
||||||
|
if (e.getMessage().contains("EFBIG")) {
|
||||||
|
return FILE_TOO_LARGE;
|
||||||
|
} else if (e.getMessage().contains("ENOSPC")) {
|
||||||
|
return NOT_ENOUGH_SPACE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.signal.core.util.CursorUtil;
|
||||||
import org.signal.core.util.SetUtil;
|
import org.signal.core.util.SetUtil;
|
||||||
import org.signal.core.util.Stopwatch;
|
import org.signal.core.util.Stopwatch;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.libsignal.protocol.kdf.HKDFv3;
|
import org.signal.libsignal.protocol.kdf.HKDF;
|
||||||
import org.signal.libsignal.protocol.util.ByteUtil;
|
import org.signal.libsignal.protocol.util.ByteUtil;
|
||||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||||
|
@ -144,7 +144,7 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
{
|
{
|
||||||
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
|
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
long estimatedCountOutside = 0L;
|
long estimatedCountOutside;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
outputStream.writeDatabaseVersion(input.getVersion());
|
outputStream.writeDatabaseVersion(input.getVersion());
|
||||||
|
@ -351,80 +351,86 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count, long estimatedCount) {
|
private static int exportAttachment(@NonNull AttachmentSecret attachmentSecret,
|
||||||
try {
|
@NonNull Cursor cursor,
|
||||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID));
|
@NonNull BackupFrameOutputStream outputStream,
|
||||||
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID));
|
int count,
|
||||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.SIZE));
|
long estimatedCount)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID));
|
||||||
|
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID));
|
||||||
|
long size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.SIZE));
|
||||||
|
|
||||||
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA));
|
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA));
|
||||||
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM));
|
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM));
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(data)) {
|
if (!TextUtils.isEmpty(data)) {
|
||||||
long fileLength = new File(data).length();
|
long fileLength = new File(data).length();
|
||||||
long dbLength = size;
|
long dbLength = size;
|
||||||
|
|
||||||
if (size <= 0 || fileLength != dbLength) {
|
if (size <= 0 || fileLength != dbLength) {
|
||||||
size = calculateVeryOldStreamLength(attachmentSecret, random, data);
|
size = calculateVeryOldStreamLength(attachmentSecret, random, data);
|
||||||
Log.w(TAG, "Needed size calculation! Manual: " + size + " File: " + fileLength + " DB: " + dbLength + " ID: " + new AttachmentId(rowId, uniqueId));
|
Log.w(TAG, "Needed size calculation! Manual: " + size + " File: " + fileLength + " DB: " + dbLength + " ID: " + new AttachmentId(rowId, uniqueId));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(data) && size > 0) {
|
if (!TextUtils.isEmpty(data) && size > 0) {
|
||||||
InputStream inputStream;
|
try (InputStream inputStream = openAttachmentStream(attachmentSecret, random, data)) {
|
||||||
|
|
||||||
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
|
|
||||||
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
|
|
||||||
|
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
|
||||||
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
|
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
|
||||||
inputStream.close();
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int exportSticker(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count, long estimatedCount) {
|
private static int exportSticker(@NonNull AttachmentSecret attachmentSecret,
|
||||||
try {
|
@NonNull Cursor cursor,
|
||||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase._ID));
|
@NonNull BackupFrameOutputStream outputStream,
|
||||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_LENGTH));
|
int count,
|
||||||
|
long estimatedCount)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase._ID));
|
||||||
|
long size = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_LENGTH));
|
||||||
|
|
||||||
String data = cursor.getString(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_PATH));
|
String data = cursor.getString(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_PATH));
|
||||||
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_RANDOM));
|
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_RANDOM));
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(data) && size > 0) {
|
if (!TextUtils.isEmpty(data) && size > 0) {
|
||||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count, estimatedCount));
|
||||||
try (InputStream inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0)) {
|
try (InputStream inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0)) {
|
||||||
outputStream.writeSticker(rowId, inputStream, size);
|
outputStream.writeSticker(rowId, inputStream, size);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
|
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
|
||||||
long result = 0;
|
long result = 0;
|
||||||
InputStream inputStream;
|
|
||||||
|
|
||||||
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
|
try (InputStream inputStream = openAttachmentStream(attachmentSecret, random, data)) {
|
||||||
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
|
int read;
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
|
||||||
int read;
|
while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
|
||||||
byte[] buffer = new byte[8192];
|
result += read;
|
||||||
|
}
|
||||||
while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
|
|
||||||
result += read;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static InputStream openAttachmentStream(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
|
||||||
|
if (random != null && random.length == 32) {
|
||||||
|
return ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
|
||||||
|
} else {
|
||||||
|
return ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static int exportKeyValues(@NonNull BackupFrameOutputStream outputStream,
|
private static int exportKeyValues(@NonNull BackupFrameOutputStream outputStream,
|
||||||
@NonNull List<String> keysToIncludeInBackup,
|
@NonNull List<String> keysToIncludeInBackup,
|
||||||
int count,
|
int count,
|
||||||
|
@ -528,20 +534,18 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
private final Mac mac;
|
private final Mac mac;
|
||||||
|
|
||||||
private final byte[] cipherKey;
|
private final byte[] cipherKey;
|
||||||
private final byte[] macKey;
|
private final byte[] iv;
|
||||||
|
private int counter;
|
||||||
private byte[] iv;
|
|
||||||
private int counter;
|
|
||||||
|
|
||||||
private BackupFrameOutputStream(@NonNull OutputStream output, @NonNull String passphrase) throws IOException {
|
private BackupFrameOutputStream(@NonNull OutputStream output, @NonNull String passphrase) throws IOException {
|
||||||
try {
|
try {
|
||||||
byte[] salt = Util.getSecretBytes(32);
|
byte[] salt = Util.getSecretBytes(32);
|
||||||
byte[] key = getBackupKey(passphrase, salt);
|
byte[] key = getBackupKey(passphrase, salt);
|
||||||
byte[] derived = new HKDFv3().deriveSecrets(key, "Backup Export".getBytes(), 64);
|
byte[] derived = HKDF.deriveSecrets(key, "Backup Export".getBytes(), 64);
|
||||||
byte[][] split = ByteUtil.split(derived, 32, 32);
|
byte[][] split = ByteUtil.split(derived, 32, 32);
|
||||||
|
|
||||||
this.cipherKey = split[0];
|
this.cipherKey = split[0];
|
||||||
this.macKey = split[1];
|
byte[] macKey = split[1];
|
||||||
|
|
||||||
this.cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
this.cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
this.mac = Mac.getInstance("HmacSHA256");
|
this.mac = Mac.getInstance("HmacSHA256");
|
||||||
|
@ -576,12 +580,17 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(@NonNull String avatarName, @NonNull InputStream in, long size) throws IOException {
|
public void write(@NonNull String avatarName, @NonNull InputStream in, long size) throws IOException {
|
||||||
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
try {
|
||||||
.setAvatar(BackupProtos.Avatar.newBuilder()
|
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
||||||
.setRecipientId(avatarName)
|
.setAvatar(BackupProtos.Avatar.newBuilder()
|
||||||
.setLength(Util.toIntExact(size))
|
.setRecipientId(avatarName)
|
||||||
.build())
|
.setLength(Util.toIntExact(size))
|
||||||
.build());
|
.build())
|
||||||
|
.build());
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
Log.w(TAG, "Unable to write avatar to backup", e);
|
||||||
|
throw new InvalidBackupStreamException();
|
||||||
|
}
|
||||||
|
|
||||||
if (writeStream(in) != size) {
|
if (writeStream(in) != size) {
|
||||||
throw new IOException("Size mismatch!");
|
throw new IOException("Size mismatch!");
|
||||||
|
@ -589,13 +598,18 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(@NonNull AttachmentId attachmentId, @NonNull InputStream in, long size) throws IOException {
|
public void write(@NonNull AttachmentId attachmentId, @NonNull InputStream in, long size) throws IOException {
|
||||||
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
try {
|
||||||
.setAttachment(BackupProtos.Attachment.newBuilder()
|
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
||||||
.setRowId(attachmentId.getRowId())
|
.setAttachment(BackupProtos.Attachment.newBuilder()
|
||||||
.setAttachmentId(attachmentId.getUniqueId())
|
.setRowId(attachmentId.getRowId())
|
||||||
.setLength(Util.toIntExact(size))
|
.setAttachmentId(attachmentId.getUniqueId())
|
||||||
.build())
|
.setLength(Util.toIntExact(size))
|
||||||
.build());
|
.build())
|
||||||
|
.build());
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
Log.w(TAG, "Unable to write " + attachmentId + " to backup", e);
|
||||||
|
throw new InvalidBackupStreamException();
|
||||||
|
}
|
||||||
|
|
||||||
if (writeStream(in) != size) {
|
if (writeStream(in) != size) {
|
||||||
throw new IOException("Size mismatch!");
|
throw new IOException("Size mismatch!");
|
||||||
|
@ -603,12 +617,17 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeSticker(long rowId, @NonNull InputStream in, long size) throws IOException {
|
public void writeSticker(long rowId, @NonNull InputStream in, long size) throws IOException {
|
||||||
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
try {
|
||||||
.setSticker(BackupProtos.Sticker.newBuilder()
|
write(outputStream, BackupProtos.BackupFrame.newBuilder()
|
||||||
.setRowId(rowId)
|
.setSticker(BackupProtos.Sticker.newBuilder()
|
||||||
.setLength(Util.toIntExact(size))
|
.setRowId(rowId)
|
||||||
.build())
|
.setLength(Util.toIntExact(size))
|
||||||
.build());
|
.build())
|
||||||
|
.build());
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
Log.w(TAG, "Unable to write sticker to backup", e);
|
||||||
|
throw new InvalidBackupStreamException();
|
||||||
|
}
|
||||||
|
|
||||||
if (writeStream(in) != size) {
|
if (writeStream(in) != size) {
|
||||||
throw new IOException("Size mismatch!");
|
throw new IOException("Size mismatch!");
|
||||||
|
@ -687,13 +706,14 @@ public class FullBackupExporter extends FullBackupBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface PostProcessor {
|
public interface PostProcessor {
|
||||||
int postProcess(@NonNull Cursor cursor, int count);
|
int postProcess(@NonNull Cursor cursor, int count) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface BackupCancellationSignal {
|
public interface BackupCancellationSignal {
|
||||||
boolean isCanceled();
|
boolean isCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class BackupCanceledException extends IOException {
|
public static final class BackupCanceledException extends IOException {}
|
||||||
}
|
|
||||||
|
public static final class InvalidBackupStreamException extends IOException {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,10 +145,13 @@ public final class LocalBackupJob extends BaseJob {
|
||||||
BackupFileIOError.VERIFICATION_FAILED.postNotification(context);
|
BackupFileIOError.VERIFICATION_FAILED.postNotification(context);
|
||||||
}
|
}
|
||||||
} catch (FullBackupExporter.BackupCanceledException e) {
|
} catch (FullBackupExporter.BackupCanceledException e) {
|
||||||
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, 0, 0));
|
||||||
Log.w(TAG, "Backup cancelled");
|
Log.w(TAG, "Backup cancelled");
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
Log.w(TAG, "Error during backup!", e);
|
||||||
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, 0, 0));
|
||||||
|
BackupFileIOError.postNotificationForException(context, e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
if (tempFile.exists()) {
|
if (tempFile.exists()) {
|
||||||
|
|
|
@ -138,11 +138,13 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
||||||
BackupFileIOError.VERIFICATION_FAILED.postNotification(context);
|
BackupFileIOError.VERIFICATION_FAILED.postNotification(context);
|
||||||
}
|
}
|
||||||
} catch (FullBackupExporter.BackupCanceledException e) {
|
} catch (FullBackupExporter.BackupCanceledException e) {
|
||||||
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, 0, 0));
|
||||||
Log.w(TAG, "Backup cancelled");
|
Log.w(TAG, "Backup cancelled");
|
||||||
throw e;
|
throw e;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Error during backup!", e);
|
Log.w(TAG, "Error during backup!", e);
|
||||||
BackupFileIOError.postNotificationForException(context, e, getRunAttempt());
|
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, 0, 0));
|
||||||
|
BackupFileIOError.postNotificationForException(context, e);
|
||||||
throw e;
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
DocumentFile fileToCleanUp = backupDirectory.findFile(temporaryName);
|
DocumentFile fileToCleanUp = backupDirectory.findFile(temporaryName);
|
||||||
|
|
|
@ -3286,6 +3286,8 @@
|
||||||
<string name="LocalBackupJobApi29_there_is_not_enough_space">There is not enough space to store your backup.</string>
|
<string name="LocalBackupJobApi29_there_is_not_enough_space">There is not enough space to store your backup.</string>
|
||||||
<!-- Error message shown if a newly created backup could not be verified as accurate -->
|
<!-- Error message shown if a newly created backup could not be verified as accurate -->
|
||||||
<string name="LocalBackupJobApi29_your_backup_could_not_be_verified">Your recent backup could not be created and verified. Please create a new one.</string>
|
<string name="LocalBackupJobApi29_your_backup_could_not_be_verified">Your recent backup could not be created and verified. Please create a new one.</string>
|
||||||
|
<!-- Error message shown if a very large attachment is encountered during the backup creation and causes the backup to fail -->
|
||||||
|
<string name="LocalBackupJobApi29_your_backup_contains_a_very_large_file">Your backup contains a very large file that cannot be backed up. Please delete it and create a new backup.</string>
|
||||||
<string name="LocalBackupJobApi29_tap_to_manage_backups">Tap to manage backups.</string>
|
<string name="LocalBackupJobApi29_tap_to_manage_backups">Tap to manage backups.</string>
|
||||||
<string name="ProgressPreference_d_messages_so_far">%d messages so far</string>
|
<string name="ProgressPreference_d_messages_so_far">%d messages so far</string>
|
||||||
<string name="RegistrationActivity_wrong_number">Wrong number</string>
|
<string name="RegistrationActivity_wrong_number">Wrong number</string>
|
||||||
|
|
Loading…
Add table
Reference in a new issue