aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/pixart/messenger/services/ExportBackupService.java139
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java1
-rw-r--r--src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java3
-rw-r--r--src/main/java/de/pixart/messenger/utils/MimeUtils.java2
-rw-r--r--src/main/java/de/pixart/messenger/utils/UIHelper.java5
-rw-r--r--src/main/res/drawable-hdpi/ic_backup_black_48dp.pngbin0 -> 943 bytes
-rw-r--r--src/main/res/drawable-hdpi/ic_backup_white_48dp.pngbin0 -> 932 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_backup_black_48dp.pngbin0 -> 813 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_backup_white_48dp.pngbin0 -> 813 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_backup_black_48dp.pngbin0 -> 1554 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_backup_white_48dp.pngbin0 -> 1585 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_backup_black_48dp.pngbin0 -> 2008 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_backup_white_48dp.pngbin0 -> 2040 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_backup_black_48dp.pngbin0 -> 4951 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_backup_white_48dp.pngbin0 -> 5049 bytes
-rw-r--r--src/main/res/values/attrs.xml2
-rw-r--r--src/main/res/values/strings.xml3
-rw-r--r--src/main/res/values/themes.xml2
18 files changed, 96 insertions, 61 deletions
diff --git a/src/main/java/de/pixart/messenger/services/ExportBackupService.java b/src/main/java/de/pixart/messenger/services/ExportBackupService.java
index 4489eca9f..7640c6ea0 100644
--- a/src/main/java/de/pixart/messenger/services/ExportBackupService.java
+++ b/src/main/java/de/pixart/messenger/services/ExportBackupService.java
@@ -30,7 +30,9 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -67,6 +69,8 @@ public class ExportBackupService extends Service {
public static final String CIPHERMODE = "AES/GCM/NoPadding";
public static final String PROVIDER = "BC";
+ public static final String MIME_TYPE = "application/vnd.conversations.backup";
+
boolean ReadableLogsEnabled = false;
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
private static final String DIRECTORY_STRING_FORMAT = FileBackend.getAppLogsDirectory() + "%s";
@@ -247,11 +251,19 @@ public class ExportBackupService extends Service {
if (extras != null && extras.containsKey("NOTIFY_ON_BACKUP_COMPLETE")) {
notify = extras.getBoolean("NOTIFY_ON_BACKUP_COMPLETE");
}
- final boolean success = export();
+ boolean success;
+ List<File> files;
+ try {
+ files = export();
+ success = true;
+ } catch (Exception e) {
+ success = false;
+ files = Collections.emptyList();
+ }
stopForeground(true);
running.set(false);
if (success) {
- notifySuccess(notify);
+ notifySuccess(files, notify);
} else {
notifyError();
}
@@ -299,92 +311,97 @@ public class ExportBackupService extends Service {
}
}
- private boolean export() {
+ private List<File> export() throws Exception {
wakeLock.acquire(15 * 60 * 1000L /*15 minutes*/);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.notification_create_backup_title))
.setSmallIcon(R.drawable.ic_archive_white_24dp)
.setProgress(1, 0, false);
startForeground(NOTIFICATION_ID, mBuilder.build());
- try {
- int count = 0;
- final int max = this.mAccounts.size();
- final SecureRandom secureRandom = new SecureRandom();
- if (mAccounts.size() >= 1) {
- if (ReadableLogsEnabled) {
- List<Conversation> conversations = mDatabaseBackend.getConversations(Conversation.STATUS_AVAILABLE);
- conversations.addAll(mDatabaseBackend.getConversations(Conversation.STATUS_ARCHIVED));
- for (Conversation conversation : conversations) {
- writeToFile(conversation);
- }
- }
+ int count = 0;
+ final int max = this.mAccounts.size();
+ final SecureRandom secureRandom = new SecureRandom();
+ final List<File> files = new ArrayList<>();
+ for (Account account : this.mAccounts) {
+ final byte[] IV = new byte[12];
+ final byte[] salt = new byte[16];
+ secureRandom.nextBytes(IV);
+ secureRandom.nextBytes(salt);
+ final BackupFileHeader backupFileHeader = new BackupFileHeader(getString(R.string.app_name), account.getJid(), System.currentTimeMillis(), IV, salt);
+ final Progress progress = new Progress(mBuilder, max, count);
+ final File file = new File(FileBackend.getBackupDirectory() + account.getJid().asBareJid().toEscapedString() + ".ceb");
+ files.add(file);
+ if (file.getParentFile().mkdirs()) {
+ Log.d(Config.LOGTAG, "created backup directory " + file.getParentFile().getAbsolutePath());
}
- for (Account account : this.mAccounts) {
- final byte[] IV = new byte[12];
- final byte[] salt = new byte[16];
- secureRandom.nextBytes(IV);
- secureRandom.nextBytes(salt);
- final BackupFileHeader backupFileHeader = new BackupFileHeader(getString(R.string.app_name), account.getJid(), System.currentTimeMillis(), IV, salt);
- final Progress progress = new Progress(mBuilder, max, count);
- final File file = new File(FileBackend.getBackupDirectory() + account.getJid().asBareJid().toEscapedString() + ".ceb");
- if (file.getParentFile().mkdirs()) {
- Log.d(Config.LOGTAG, "created backup directory " + file.getParentFile().getAbsolutePath());
- }
- final FileOutputStream fileOutputStream = new FileOutputStream(file);
- final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
- backupFileHeader.write(dataOutputStream);
- dataOutputStream.flush();
-
- final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER);
- byte[] key = getKey(account.getPassword(), salt);
- Log.d(Config.LOGTAG, backupFileHeader.toString());
- SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
- IvParameterSpec ivSpec = new IvParameterSpec(IV);
- cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
- CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher);
-
- GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cipherOutputStream);
- PrintWriter writer = new PrintWriter(gzipOutputStream);
- SQLiteDatabase db = this.mDatabaseBackend.getReadableDatabase();
- final String uuid = account.getUuid();
- accountExport(db, uuid, writer);
- simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, writer);
- messageExport(db, uuid, writer, progress);
- for (String table : Arrays.asList(SQLiteAxolotlStore.PREKEY_TABLENAME, SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, SQLiteAxolotlStore.SESSION_TABLENAME, SQLiteAxolotlStore.IDENTITIES_TABLENAME)) {
- simpleExport(db, table, SQLiteAxolotlStore.ACCOUNT, uuid, writer);
- }
- writer.flush();
- writer.close();
- Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile());
- count++;
+ final FileOutputStream fileOutputStream = new FileOutputStream(file);
+ final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
+ backupFileHeader.write(dataOutputStream);
+ dataOutputStream.flush();
+
+ final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER);
+ byte[] key = getKey(account.getPassword(), salt);
+ Log.d(Config.LOGTAG, backupFileHeader.toString());
+ SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
+ IvParameterSpec ivSpec = new IvParameterSpec(IV);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher);
+
+ GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cipherOutputStream);
+ PrintWriter writer = new PrintWriter(gzipOutputStream);
+ SQLiteDatabase db = this.mDatabaseBackend.getReadableDatabase();
+ final String uuid = account.getUuid();
+ accountExport(db, uuid, writer);
+ simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, writer);
+ messageExport(db, uuid, writer, progress);
+ for (String table : Arrays.asList(SQLiteAxolotlStore.PREKEY_TABLENAME, SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, SQLiteAxolotlStore.SESSION_TABLENAME, SQLiteAxolotlStore.IDENTITIES_TABLENAME)) {
+ simpleExport(db, table, SQLiteAxolotlStore.ACCOUNT, uuid, writer);
}
- return true;
- } catch (Exception e) {
- Log.d(Config.LOGTAG, "unable to create backup ", e);
- return false;
+ writer.flush();
+ writer.close();
+ Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile());
+ count++;
}
+ return files;
}
- private void notifySuccess(final boolean notify) {
+ private void notifySuccess(List<File> files, final boolean notify) {
if (!notify) {
return;
}
final String path = FileBackend.getBackupDirectory();
- PendingIntent pendingIntent = null;
+ PendingIntent openFolderIntent = null;
for (Intent intent : getPossibleFileOpenIntents(this, path)) {
if (intent.resolveActivityInfo(getPackageManager(), 0) != null) {
- pendingIntent = PendingIntent.getActivity(this, 189, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ openFolderIntent = PendingIntent.getActivity(this, 189, intent, PendingIntent.FLAG_UPDATE_CURRENT);
break;
}
}
+ PendingIntent shareFilesIntent = null;
+ if (files.size() > 0) {
+ final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+ ArrayList<Uri> uris = new ArrayList<>();
+ for (File file : files) {
+ uris.add(FileBackend.getUriForFile(this, file));
+ }
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType(MIME_TYPE);
+ final Intent chooser = Intent.createChooser(intent, getString(R.string.share_backup_files));
+ shareFilesIntent = PendingIntent.getActivity(this, 190, chooser, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.notification_backup_created_title))
.setContentText(getString(R.string.notification_backup_created_subtitle, path))
.setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.notification_backup_created_subtitle, FileBackend.getBackupDirectory())))
.setAutoCancel(true)
- .setContentIntent(pendingIntent)
+ .setContentIntent(openFolderIntent)
.setSmallIcon(R.drawable.ic_archive_white_24dp);
+ if (shareFilesIntent != null) {
+ mBuilder.addAction(R.drawable.ic_share_white_24dp, getString(R.string.share_backup_files), shareFilesIntent);
+ }
notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
index 15efb7921..f7be6a365 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/ConversationAdapter.java
@@ -118,6 +118,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte
imageResource = activity.getThemeResource(R.attr.ic_attach_location, R.drawable.ic_attach_location);
showPreviewText = false;
} else {
+ //TODO move this into static MediaPreview method and use same icons as in MediaAdapter
final String mime = message.getMimeType();
switch (mime == null ? "" : mime.split("/")[0]) {
case "image":
diff --git a/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java
index e8968bbac..847ab35cf 100644
--- a/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java
+++ b/src/main/java/de/pixart/messenger/ui/adapter/MediaAdapter.java
@@ -23,6 +23,7 @@ import java.util.concurrent.RejectedExecutionException;
import de.pixart.messenger.R;
import de.pixart.messenger.databinding.MediaBinding;
+import de.pixart.messenger.services.ExportBackupService;
import de.pixart.messenger.ui.XmppActivity;
import de.pixart.messenger.ui.util.Attachment;
import de.pixart.messenger.ui.util.StyledAttributes;
@@ -80,6 +81,8 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
attr = R.attr.media_preview_archive;
} else if (mime.equals("application/epub+zip") || mime.equals("application/vnd.amazon.mobi8-ebook")) {
attr = R.attr.media_preview_ebook;
+ } else if (mime.equals(ExportBackupService.MIME_TYPE)) {
+ attr = R.attr.media_preview_backup;
} else if (DOCUMENT_MIMES.contains(mime)) {
attr = R.attr.media_preview_document;
} else {
diff --git a/src/main/java/de/pixart/messenger/utils/MimeUtils.java b/src/main/java/de/pixart/messenger/utils/MimeUtils.java
index 431cde39a..af170b082 100644
--- a/src/main/java/de/pixart/messenger/utils/MimeUtils.java
+++ b/src/main/java/de/pixart/messenger/utils/MimeUtils.java
@@ -30,6 +30,7 @@ import java.util.Properties;
import de.pixart.messenger.Config;
import de.pixart.messenger.entities.Transferable;
+import de.pixart.messenger.services.ExportBackupService;
/**
* Utilities for dealing with MIME types.
@@ -76,6 +77,7 @@ public final class MimeUtils {
add("application/vnd.amazon.mobi8-ebook","kfx");
add("application/vnd.android.package-archive", "apk");
add("application/vnd.cinderella", "cdy");
+ add(ExportBackupService.MIME_TYPE, "ceb");
add("application/vnd.ms-pki.stl", "stl");
add("application/vnd.oasis.opendocument.database", "odb");
add("application/vnd.oasis.opendocument.formula", "odf");
diff --git a/src/main/java/de/pixart/messenger/utils/UIHelper.java b/src/main/java/de/pixart/messenger/utils/UIHelper.java
index b2e73fb46..097baa3f6 100644
--- a/src/main/java/de/pixart/messenger/utils/UIHelper.java
+++ b/src/main/java/de/pixart/messenger/utils/UIHelper.java
@@ -27,6 +27,7 @@ import de.pixart.messenger.entities.Message;
import de.pixart.messenger.entities.MucOptions;
import de.pixart.messenger.entities.Presence;
import de.pixart.messenger.entities.Transferable;
+import de.pixart.messenger.services.ExportBackupService;
import rocks.xmpp.addr.Jid;
public class UIHelper {
@@ -477,8 +478,12 @@ public class UIHelper {
return context.getString(R.string.pdf_document);
} else if (mime.equals("application/vnd.android.package-archive")) {
return context.getString(R.string.apk);
+ } else if (mime.equals(ExportBackupService.MIME_TYPE)) {
+ return context.getString(R.string.conversations_backup);
} else if (mime.contains("vcard")) {
return context.getString(R.string.vcard);
+ } else if (mime.equals("text/x-vcalendar") || mime.equals("text/calendar")) {
+ return context.getString(R.string.event);
} else if (mime.equals("application/epub+zip") || mime.equals("application/vnd.amazon.mobi8-ebook")) {
return context.getString(R.string.ebook);
} else {
diff --git a/src/main/res/drawable-hdpi/ic_backup_black_48dp.png b/src/main/res/drawable-hdpi/ic_backup_black_48dp.png
new file mode 100644
index 000000000..e5add7f82
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_backup_black_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-hdpi/ic_backup_white_48dp.png b/src/main/res/drawable-hdpi/ic_backup_white_48dp.png
new file mode 100644
index 000000000..57aac8f23
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_backup_white_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_backup_black_48dp.png b/src/main/res/drawable-mdpi/ic_backup_black_48dp.png
new file mode 100644
index 000000000..f83b4a074
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_backup_black_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_backup_white_48dp.png b/src/main/res/drawable-mdpi/ic_backup_white_48dp.png
new file mode 100644
index 000000000..cc199bd78
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_backup_white_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_backup_black_48dp.png b/src/main/res/drawable-xhdpi/ic_backup_black_48dp.png
new file mode 100644
index 000000000..ba468fa18
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_backup_black_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_backup_white_48dp.png b/src/main/res/drawable-xhdpi/ic_backup_white_48dp.png
new file mode 100644
index 000000000..11e4afcae
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_backup_white_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_backup_black_48dp.png b/src/main/res/drawable-xxhdpi/ic_backup_black_48dp.png
new file mode 100644
index 000000000..08e7857b2
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_backup_black_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_backup_white_48dp.png b/src/main/res/drawable-xxhdpi/ic_backup_white_48dp.png
new file mode 100644
index 000000000..08ca7efac
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_backup_white_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_backup_black_48dp.png b/src/main/res/drawable-xxxhdpi/ic_backup_black_48dp.png
new file mode 100644
index 000000000..182f1b2eb
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_backup_black_48dp.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_backup_white_48dp.png b/src/main/res/drawable-xxxhdpi/ic_backup_white_48dp.png
new file mode 100644
index 000000000..c1863568c
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_backup_white_48dp.png
Binary files differ
diff --git a/src/main/res/values/attrs.xml b/src/main/res/values/attrs.xml
index 5a5bbc62a..e7d44519e 100644
--- a/src/main/res/values/attrs.xml
+++ b/src/main/res/values/attrs.xml
@@ -125,6 +125,8 @@
<attr name="ic_settings_expert" format="reference" />
<attr name="ic_settings_about" format="reference" />
+ <attr name="media_preview_backup" format="reference" />
+
<declare-styleable name="UnreadCountCustomView">
<attr name="backgroundColor" format="reference|color" />
</declare-styleable>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 3407f6e9e..287ccd23a 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -922,4 +922,7 @@
<string name="change_password_in_next_step">You can change the generated password in the next step to your needs.</string>
<string name="action_unblock_participant">Unblock participant</string>
<string name="action_block_participant">Block participant</string>
+ <string name="share_backup_files">Share backup files</string>
+ <string name="conversations_backup">Conversations backup</string>
+ <string name="event">Event</string>
</resources>
diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml
index 6f9898a75..b9261a4d5 100644
--- a/src/main/res/values/themes.xml
+++ b/src/main/res/values/themes.xml
@@ -78,6 +78,7 @@
<item name="media_preview_archive" type="reference">@drawable/ic_archive_black_48dp</item>
<item name="media_preview_ebook" type="reference">@drawable/ic_book_black_48dp</item>
<item name="media_preview_unknown" type="reference">@drawable/ic_help_black_48dp</item>
+ <item name="media_preview_backup" type="reference">@drawable/ic_backup_black_48dp</item>
<item name="icon_add_group" type="reference">@drawable/ic_group_add_white_24dp</item>
<item name="icon_add_person" type="reference">@drawable/ic_person_add_white_24dp</item>
@@ -254,6 +255,7 @@
<item name="media_preview_archive" type="reference">@drawable/ic_archive_white_48dp</item>
<item name="media_preview_ebook" type="reference">@drawable/ic_book_white_48dp</item>
<item name="media_preview_unknown" type="reference">@drawable/ic_help_white_48dp</item>
+ <item name="media_preview_backup" type="reference">@drawable/ic_backup_white_48dp</item>
<item name="icon_add_group" type="reference">@drawable/ic_group_add_white_24dp</item>
<item name="icon_add_person" type="reference">@drawable/ic_person_add_white_24dp</item>