diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1058f0fa4..44e8df630 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1128,6 +1128,8 @@
Read receipts
If read receipts are disabled, you won\'t be able to see read receipts from others.
Request keyboard to disable personalized learning
+ Backup
+ Manage keys
Blocked contacts
When using mobile data
When using Wi-Fi
@@ -1152,6 +1154,19 @@
Message font size
Contact joined Delta Chat
Priority
+ A backup helps you to set up a new installation on this or on another device.\n\nThe backup will contain all messages, contacts and chats and your end-to-end Autocrypt setup. Keep the backup file in a safe place or delete it as soon as possible.
+ Start backup
+ Backup written successfully to %1$s
+ Delta Chat needs access to your files in order to create backups.
+ Manage keys
+ Delta Chat needs access to your files to import/export keys.
+ Export secret keys
+ Export secret keys to \"%1$s\"?
+ Import secret keys
+ Import secret keys from \"%1$s\"?\n\n• Existing secret keys will not be deleted\n\n• The last imported key will be used as the new default key unless it has the word \"legacy\" in its filename
+ Secret keys written successfully to \"%1$s\".
+ Secret keys imported from \"%1$s\".
+
diff --git a/res/xml/preferences_advanced.xml b/res/xml/preferences_advanced.xml
index ddd5bb446..449ad2993 100644
--- a/res/xml/preferences_advanced.xml
+++ b/res/xml/preferences_advanced.xml
@@ -1,15 +1,11 @@
-
+
-
+
diff --git a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 812e38b22..0371508ff 100644
--- a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -1,58 +1,66 @@
package org.thoughtcrime.securesms.preferences;
-import android.app.Activity;
+import android.Manifest;
+import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
-import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
-import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
-import android.widget.Toast;
-import com.google.android.gms.gcm.GoogleCloudMessaging;
+import com.b44t.messenger.DcContext;
+import com.b44t.messenger.DcEventCenter;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.LogSubmitActivity;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.RegistrationActivity;
-import org.thoughtcrime.securesms.contacts.ContactAccessor;
-import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
-import org.thoughtcrime.securesms.push.AccountManagerFactory;
-import org.thoughtcrime.securesms.util.TextSecurePreferences;
-import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
-import org.whispersystems.libsignal.util.guava.Optional;
-import org.whispersystems.signalservice.api.SignalServiceAccountManager;
-import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
+import org.thoughtcrime.securesms.connect.ApplicationDcContext;
+import org.thoughtcrime.securesms.connect.DcHelper;
+import org.thoughtcrime.securesms.permissions.Permissions;
-import java.io.IOException;
+import java.io.File;
-public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
+
+public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment
+ implements DcEventCenter.DcEventDelegate
+{
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
- private static final String PUSH_MESSAGING_PREF = "pref_toggle_push_messaging";
+ private static final String BACKUP_PREF = "pref_backup";
+ private static final String MANAGE_KEYS_PREF = "pref_manage_keys";
private static final String SUBMIT_DEBUG_LOG_PREF = "pref_submit_debug_logs";
- private static final int PICK_IDENTITY_CONTACT = 1;
+ private ApplicationDcContext dcContext;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
- initializeIdentitySelection();
+ dcContext = DcHelper.getContext(getContext());
+ dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_IMEX_PROGRESS);
+
+ Preference backup = this.findPreference(BACKUP_PREF);
+ backup.setOnPreferenceClickListener(new BackupListener());
+
+ Preference manageKeys = this.findPreference(MANAGE_KEYS_PREF);
+ manageKeys.setOnPreferenceClickListener(new ManageKeysListener());
Preference submitDebugLog = this.findPreference(SUBMIT_DEBUG_LOG_PREF);
submitDebugLog.setOnPreferenceClickListener(new SubmitDebugLogListener());
submitDebugLog.setSummary(getVersion(getActivity()));
}
+ @Override
+ public void onDestroy() {
+ dcContext.eventCenter.removeObservers(this);
+ super.onDestroy();
+ }
+
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_advanced);
@@ -63,51 +71,6 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__advanced);
- initializePushMessagingToggle();
- }
-
- @Override
- public void onActivityResult(int reqCode, int resultCode, Intent data) {
- super.onActivityResult(reqCode, resultCode, data);
-
- Log.w(TAG, "Got result: " + resultCode + " for req: " + reqCode);
- if (resultCode == Activity.RESULT_OK && reqCode == PICK_IDENTITY_CONTACT) {
- handleIdentitySelection(data);
- }
- }
-
- private void initializePushMessagingToggle() {
- CheckBoxPreference preference = (CheckBoxPreference)this.findPreference(PUSH_MESSAGING_PREF);
-
- if (TextSecurePreferences.isPushRegistered(getActivity())) {
- preference.setChecked(true);
- preference.setSummary(TextSecurePreferences.getLocalNumber(getActivity()));
- } else {
- preference.setChecked(false);
- preference.setSummary(R.string.preferences__free_private_messages_and_calls);
- }
-
- preference.setOnPreferenceChangeListener(new PushMessagingClickListener());
- }
-
- private void initializeIdentitySelection() {
- ContactIdentityManager identity = ContactIdentityManager.getInstance(getActivity());
-
- Preference preference = this.findPreference(TextSecurePreferences.IDENTITY_PREF);
-
- if (identity.isSelfIdentityAutoDetected()) {
- this.getPreferenceScreen().removePreference(preference);
- } else {
- Uri contactUri = identity.getSelfIdentityUri();
-
- if (contactUri != null) {
- String contactName = ContactAccessor.getInstance().getNameFromContact(getActivity(), contactUri);
- preference.setSummary(String.format(getString(R.string.ApplicationPreferencesActivity_currently_s),
- contactName));
- }
-
- preference.setOnPreferenceClickListener(new IdentityPreferenceClickListener());
- }
}
private @NonNull String getVersion(@Nullable Context context) {
@@ -124,25 +87,6 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
}
}
- private class IdentityPreferenceClickListener implements Preference.OnPreferenceClickListener {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
- startActivityForResult(intent, PICK_IDENTITY_CONTACT);
- return true;
- }
- }
-
- private void handleIdentitySelection(Intent data) {
- Uri contactUri = data.getData();
-
- if (contactUri != null) {
- TextSecurePreferences.setIdentityContactUri(getActivity(), contactUri.toString());
- initializeIdentitySelection();
- }
- }
-
private class SubmitDebugLogListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
@@ -152,83 +96,132 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
}
}
- private class PushMessagingClickListener implements Preference.OnPreferenceChangeListener {
- private static final int SUCCESS = 0;
- private static final int NETWORK_ERROR = 1;
- private class DisablePushMessagesTask extends ProgressDialogAsyncTask {
- private final CheckBoxPreference checkBoxPreference;
-
- public DisablePushMessagesTask(final CheckBoxPreference checkBoxPreference) {
- super(getActivity(), R.string.ApplicationPreferencesActivity_unregistering, R.string.ApplicationPreferencesActivity_unregistering_from_signal_messages_and_calls);
- this.checkBoxPreference = checkBoxPreference;
- }
-
- @Override
- protected void onPostExecute(Integer result) {
- super.onPostExecute(result);
- switch (result) {
- case NETWORK_ERROR:
- Toast.makeText(getActivity(),
- R.string.ApplicationPreferencesActivity_error_connecting_to_server,
- Toast.LENGTH_LONG).show();
- break;
- case SUCCESS:
- TextSecurePreferences.setPushRegistered(getActivity(), false);
- initializePushMessagingToggle();
- break;
- }
- }
-
- @Override
- protected Integer doInBackground(Void... params) {
- try {
- Context context = getActivity();
- SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
-
- try {
- accountManager.setGcmId(Optional.absent());
- } catch (AuthorizationFailedException e) {
- Log.w(TAG, e);
- }
-
- if (!TextSecurePreferences.isGcmDisabled(context)) {
- GoogleCloudMessaging.getInstance(context).unregister();
- }
-
- return SUCCESS;
- } catch (IOException ioe) {
- Log.w(TAG, ioe);
- return NETWORK_ERROR;
- }
- }
- }
+ /***********************************************************************************************
+ * Import/Export
+ **********************************************************************************************/
+ private class BackupListener implements Preference.OnPreferenceClickListener {
@Override
- public boolean onPreferenceChange(final Preference preference, Object newValue) {
- if (((CheckBoxPreference)preference).isChecked()) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setIconAttribute(R.attr.dialog_info_icon);
- builder.setTitle(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls);
- builder.setMessage(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls_by_unregistering);
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new DisablePushMessagesTask((CheckBoxPreference)preference).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- });
- builder.show();
- } else {
- Intent nextIntent = new Intent(getActivity(), ApplicationPreferencesActivity.class);
+ public boolean onPreferenceClick(Preference preference) {
+ Permissions.with(getActivity())
+ .request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .ifNecessary()
+ .withRationaleDialog(getActivity().getString(R.string.preferences_backup__ask_for_storage_permission), R.drawable.ic_folder_white_48dp)
+ .onAllGranted(() -> {
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.preferences__backup)
+ .setMessage(R.string.preferences_backup__export_explain)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.preferences_backup__export_start_button, (dialogInterface, i) -> startImex(DcContext.DC_IMEX_EXPORT_BACKUP))
+ .show();
+ })
+ .execute();
- Intent intent = new Intent(getActivity(), RegistrationActivity.class);
- intent.putExtra(RegistrationActivity.RE_REGISTRATION_EXTRA, true);
- intent.putExtra("next_intent", nextIntent);
- startActivity(intent);
+ return true;
+ }
+ }
+
+ private class ManageKeysListener implements Preference.OnPreferenceClickListener {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Permissions.with(getActivity())
+ .request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .ifNecessary()
+ .withRationaleDialog(getActivity().getString(R.string.preferences_managekeys__ask_for_storage_permission), R.drawable.ic_folder_white_48dp)
+ .onAllGranted(() -> {
+ new android.app.AlertDialog.Builder(getActivity())
+ .setTitle(R.string.preferences_managekeys__menu_title)
+ .setItems(new CharSequence[]{
+ getActivity().getString(R.string.preferences_managekeys__export_secret_keys),
+ getActivity().getString(R.string.preferences_managekeys__import_secret_keys)
+ },
+ (dialogInterface, i) -> {
+ if (i==0) {
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.preferences_managekeys__export_secret_keys)
+ .setMessage(getActivity().getString(R.string.preferences_managekeys__export_explain, dcContext.getImexDir().getAbsolutePath()))
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, (dialogInterface2, i2) -> startImex(DcContext.DC_IMEX_EXPORT_SELF_KEYS))
+ .show();
+ }
+ else {
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.preferences_managekeys__import_secret_keys)
+ .setMessage(getActivity().getString(R.string.preferences_managekeys__import_explain, dcContext.getImexDir().getAbsolutePath()))
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, (dialogInterface2, i2) -> startImex(DcContext.DC_IMEX_IMPORT_SELF_KEYS))
+ .show();
+ }
+ }
+ )
+ .show();
+ })
+ .execute();
+ return true;
+ }
+ }
+
+ private ProgressDialog progressDialog = null;
+ private int progressWhat = 0;
+ private String imexDir = "";
+ private void startImex(int what)
+ {
+ if( progressDialog!=null ) {
+ progressDialog.dismiss();
+ progressDialog = null;
+ }
+ progressWhat = what;
+ progressDialog = new ProgressDialog(getActivity());
+ progressDialog.setMessage(getActivity().getString(R.string.one_moment));
+ progressDialog.setCanceledOnTouchOutside(false);
+ progressDialog.setCancelable(false);
+ progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getActivity().getString(android.R.string.cancel), (dialog, which) -> dcContext.stopOngoingProcess());
+ progressDialog.show();
+
+ imexDir = dcContext.getImexDir().getAbsolutePath();
+ dcContext.captureNextError();
+ dcContext.imex(progressWhat, imexDir);
+ }
+
+ @Override
+ public void handleEvent(int eventId, Object data1, Object data2) {
+ if (eventId== DcContext.DC_EVENT_IMEX_PROGRESS) {
+ long progress = (Long)data1;
+ if (progress==0/*error/aborted*/) {
+ dcContext.endCaptureNextError();
+ progressDialog.dismiss();
+ progressDialog = null;
+ if (dcContext.hasCapturedError()) {
+ new android.app.AlertDialog.Builder(getActivity())
+ .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();
+ progressDialog = null;
+ String msg = "";
+ if (progressWhat==DcContext.DC_IMEX_EXPORT_BACKUP) {
+ msg = getActivity().getString(R.string.preferences_backup__backup_written_to_x, imexDir);
+ }
+ else if (progressWhat==DcContext.DC_IMEX_EXPORT_SELF_KEYS) {
+ msg = getActivity().getString(R.string.preferences_managekeys__secret_keys_exported_to_x, imexDir);
+ }
+ else if (progressWhat==DcContext.DC_IMEX_IMPORT_SELF_KEYS) {
+ msg = getActivity().getString(R.string.preferences_managekeys__secret_keys_imported_from_x, imexDir);
+ }
+ new android.app.AlertDialog.Builder(getActivity())
+ .setMessage(msg)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
}
-
- return false;
}
}
}