diff --git a/res/values/strings.xml b/res/values/strings.xml
index c0a1d4cec..7a0f410bd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1368,7 +1368,6 @@
TAP TO UNLOCK
Reminder:
About
-
Delta Chat
The messenger with the broadest audience in the world. Free and independent.
@@ -1406,11 +1405,16 @@
Delta Chat needs access to your contacts and media in order to connect with friends and send files
Please enter a valid email address and a password
+ Import backup
+ Backup found at \"%1$s\".\n\nDo you want to import and use all data and settings from it?
+ No backups found.\n\nCopy the backup to \"%1$s\" and try again. Alternatively, press \"Start messaging\" to go with the normal setup process.
+
Email address
Password
Advanced
icon
Loading …
+ One moment …
diff --git a/src/org/thoughtcrime/securesms/RegistrationActivity.java b/src/org/thoughtcrime/securesms/RegistrationActivity.java
index ddb744233..277c475d7 100644
--- a/src/org/thoughtcrime/securesms/RegistrationActivity.java
+++ b/src/org/thoughtcrime/securesms/RegistrationActivity.java
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
+import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
@@ -22,6 +23,7 @@ import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.dd.CircularProgressButton;
+import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Dialogs;
@@ -222,6 +224,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
// calling configure() results in
// receiving multiple DC_EVENT_CONFIGURE_PROGRESS events
+ DcHelper.getContext(this).captureNextError();
DcHelper.getContext(this).configure();
}
@@ -240,14 +243,24 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
@Override
public void handleEvent(int eventId, Object data1, Object data2) {
if (eventId==DcContext.DC_EVENT_CONFIGURE_PROGRESS) {
+ ApplicationDcContext dcContext = DcHelper.getContext(this);
long progress = (Long)data1;
if (progress==0/*error/aborted*/) {
+ dcContext.endCaptureNextError();
progressDialog.dismiss();
+ if (dcContext.hasCapturedError()) {
+ new AlertDialog.Builder(this)
+ .setMessage(dcContext.getCapturedError())
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
}
else if (progress<1000/*progress in permille*/) {
- progressDialog.setMessage("Loading ... " + progress);
+ int percent = (int)progress / 10;
+ progressDialog.setMessage(getResources().getString(R.string.one_moment)+String.format(" %d%%", percent));
}
else if (progress==1000/*done*/) {
+ dcContext.endCaptureNextError();
progressDialog.dismiss();
Intent conversationList = new Intent(getApplicationContext(), ConversationListActivity.class);
startActivity(conversationList);
diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java
index 825d46c0c..ac36d1031 100644
--- a/src/org/thoughtcrime/securesms/WelcomeActivity.java
+++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java
@@ -2,7 +2,10 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -19,9 +22,12 @@ import android.widget.TextView;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
+import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
+import java.io.File;
+
/**
* The welcome activity. Provides the user with useful information about the app.
* It also allows the triggering of the backup import process.
@@ -85,7 +91,10 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
setContentView(R.layout.welcome_activity);
initializeResources();
- DcHelper.getContext(this).eventCenter.addObserver(this, DcContext.DC_EVENT_CONFIGURE_PROGRESS);
+
+ ApplicationDcContext dcContext = DcHelper.getContext(this);
+ dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_CONFIGURE_PROGRESS);
+ dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_IMEX_PROGRESS);
}
@Override
@@ -108,8 +117,8 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
View backupText = findViewById(R.id.backup_text);
View backupImage = findViewById(R.id.backup_icon);
skipButton.setOnClickListener((view) -> startRegistrationActivity());
- backupText.setOnClickListener((view) -> initializePermissions());
- backupImage.setOnClickListener((view) -> initializePermissions());
+ backupText.setOnClickListener((view) -> startImportBackup());
+ backupImage.setOnClickListener((view) -> startImportBackup());
}
private void startRegistrationActivity() {
@@ -119,20 +128,87 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
}
@SuppressLint("InlinedApi")
- private void initializePermissions() {
+ private void startImportBackup() {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.ifNecessary()
.withRationaleDialog("Delta Chat needs access to your files in order start the backup import",
R.drawable.ic_folder_white_48dp)
.onAllGranted(() -> {
- //JavaBindings.loadBackup(); TODO load backup value via bindings
+ ApplicationDcContext dcContext = DcHelper.getContext(this);
+ File imexDir = dcContext.getImexDir();
+ final String backupFile = dcContext.imexHasBackup(imexDir.getAbsolutePath());
+ if (backupFile != null) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.import_backup_title)
+ .setMessage(String.format(getResources().getString(R.string.import_backup_ask), backupFile))
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ startImport(backupFile);
+ })
+ .show();
+ }
+ else {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.import_backup_title)
+ .setMessage(String.format(getResources().getString(R.string.import_backup_no_backup_found), imexDir.getAbsolutePath()))
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
})
.execute();
}
+ private ProgressDialog progressDialog = null;
+ private void startImport(final String backupFile)
+ {
+ ApplicationDcContext dcContext = DcHelper.getContext(this);
+
+ if( progressDialog!=null ) {
+ progressDialog.dismiss();
+ progressDialog = null;
+ }
+
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setMessage(getResources().getString(R.string.one_moment));
+ progressDialog.setCanceledOnTouchOutside(false);
+ progressDialog.setCancelable(false);
+ progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(android.R.string.cancel), (dialog, which) -> {
+ dcContext.stopOngoingProcess();
+ });
+ progressDialog.show();
+
+ dcContext.captureNextError();
+ dcContext.imex(DcContext.DC_IMEX_IMPORT_BACKUP, backupFile);
+ }
+
public void handleEvent(int eventId, Object data1, Object data2) {
- if (eventId== DcContext.DC_EVENT_CONFIGURE_PROGRESS) {
+ if (eventId== DcContext.DC_EVENT_IMEX_PROGRESS) {
+ ApplicationDcContext dcContext = DcHelper.getContext(this);
+ long progress = (Long)data1;
+ if (progress==0/*error/aborted*/) {
+ dcContext.endCaptureNextError();
+ progressDialog.dismiss();
+ if (dcContext.hasCapturedError()) {
+ new AlertDialog.Builder(this)
+ .setMessage(dcContext.getCapturedError())
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+ }
+ else if (progress<1000/*progress in permille*/) {
+ int percent = (int)progress / 10;
+ progressDialog.setMessage(getResources().getString(R.string.one_moment)+String.format(" %d%%", percent));
+ }
+ else if (progress==1000/*done*/) {
+ dcContext.endCaptureNextError();
+ progressDialog.dismiss();
+ Intent conversationList = new Intent(getApplicationContext(), ConversationListActivity.class);
+ startActivity(conversationList);
+ finish();
+ }
+ }
+ else if (eventId== DcContext.DC_EVENT_CONFIGURE_PROGRESS) {
long progress = (Long)data1;
if (progress==1000/*done*/) {
finish(); // remove ourself from the activity stack (finishAffinity is available in API 16, we're targeting API 14)
diff --git a/src/org/thoughtcrime/securesms/connect/ApplicationDcContext.java b/src/org/thoughtcrime/securesms/connect/ApplicationDcContext.java
index afae790b3..60f951a06 100644
--- a/src/org/thoughtcrime/securesms/connect/ApplicationDcContext.java
+++ b/src/org/thoughtcrime/securesms/connect/ApplicationDcContext.java
@@ -17,6 +17,7 @@
package org.thoughtcrime.securesms.connect;
import android.content.Context;
+import android.os.Environment;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;
@@ -67,6 +68,15 @@ public class ApplicationDcContext extends DcContext {
startThreads();
}
+ public File getImexDir()
+ {
+ // DIRECTORY_DOCUMENTS is only available since KitKat;
+ // as we also support Ice Cream Sandwich and Jellybean (2017: 11% in total), this is no option.
+ // Moreover, DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
+ // eg. "Download Managers" are nearly always installed.
+ // CAVE: do not use DownloadManager to add the file as it is deleted on uninstall then ...
+ return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ }
/***********************************************************************************************
* Working Threads
@@ -182,10 +192,34 @@ public class ApplicationDcContext extends DcContext {
public DcEventCenter eventCenter = new DcEventCenter();
- public final Object lastErrorLock = new Object();
- public int lastErrorCode = 0;
- public String lastErrorString = "";
- public boolean showNextErrorAsToast = true;
+ private final Object lastErrorLock = new Object();
+ private String lastErrorString = "";
+ private boolean showNextErrorAsToast = true;
+
+ public void captureNextError() {
+ synchronized (lastErrorLock) {
+ showNextErrorAsToast = false;
+ lastErrorString = "";
+ }
+ }
+
+ public boolean hasCapturedError() {
+ synchronized (lastErrorLock) {
+ return !lastErrorString.isEmpty();
+ }
+ }
+
+ public String getCapturedError() {
+ synchronized (lastErrorLock) {
+ return lastErrorString;
+ }
+ }
+
+ public void endCaptureNextError() {
+ synchronized (lastErrorLock) {
+ showNextErrorAsToast = true;
+ }
+ }
@Override public long handleEvent(final int event, long data1, long data2) {
switch(event) {
@@ -200,7 +234,6 @@ public class ApplicationDcContext extends DcContext {
case DC_EVENT_ERROR:
Log.e("DeltaChat", dataToString(data2));
synchronized (lastErrorLock) {
- lastErrorCode = (int)data1;
lastErrorString = dataToString(data2);
}
Util.runOnMain(new Runnable() {