diff --git a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java index 74765fd86..86022cfb0 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java @@ -29,6 +29,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.Editable; @@ -137,6 +138,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { private TextView mActionBarSubTitle; private TextView mActionBarUnread; + private boolean exportGlobalSettings; + private ArrayList exportAccountUuids; + /** * Contains information about objects that need to be retained on configuration changes. * @@ -146,6 +150,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { private static final int ACTIVITY_REQUEST_PICK_SETTINGS_FILE = 1; + private static final int ACTIVITY_REQUEST_SAVE_SETTINGS_FILE = 2; class AccountsHandler extends Handler { private void setViewTitle() { @@ -328,6 +333,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { private static String ACCOUNT_STATS = "accountStats"; private static String STATE_UNREAD_COUNT = "unreadCount"; private static String SELECTED_CONTEXT_ACCOUNT = "selectedContextAccount"; + private static final String STATE_EXPORT_GLOBAL_SETTINGS = "exportGlobalSettings"; + private static final String STATE_EXPORT_ACCOUNTS = "exportAccountUuids"; + public static final String EXTRA_STARTUP = "startup"; @@ -476,6 +484,17 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { } outState.putSerializable(STATE_UNREAD_COUNT, mUnreadMessageCount); outState.putSerializable(ACCOUNT_STATS, accountStats); + + outState.putBoolean(STATE_EXPORT_GLOBAL_SETTINGS, exportGlobalSettings); + outState.putStringArrayList(STATE_EXPORT_ACCOUNTS, exportAccountUuids); + } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + + exportGlobalSettings = state.getBoolean(STATE_EXPORT_GLOBAL_SETTINGS, false); + exportAccountUuids = state.getStringArrayList(STATE_EXPORT_ACCOUNTS); } private StorageManager.StorageListener storageListener = new StorageManager.StorageListener() { @@ -1290,7 +1309,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { getString(R.string.app_revision_url) + "")) .append("


") - .append(String.format(getString(R.string.app_copyright_fmt), year, year)) + .append(String.format(getString(R.string.app_copyright_fmt), Integer.toString(year), Integer.toString(year))) .append("


") .append(getString(R.string.app_license)) .append("


"); @@ -1418,9 +1437,12 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { return; } switch (requestCode) { - case ACTIVITY_REQUEST_PICK_SETTINGS_FILE: - onImport(data.getData()); - break; + case ACTIVITY_REQUEST_PICK_SETTINGS_FILE: + onImport(data.getData()); + break; + case ACTIVITY_REQUEST_SAVE_SETTINGS_FILE: + onExport(data); + break; } } @@ -1884,15 +1906,35 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { } public void onExport(final boolean includeGlobals, final Account account) { - // TODO, prompt to allow a user to choose which accounts to export - Set accountUuids = null; + ArrayList accountUuids = null; if (account != null) { - accountUuids = new HashSet(); + accountUuids = new ArrayList<>(); accountUuids.add(account.getUuid()); } - ExportAsyncTask asyncTask = new ExportAsyncTask(this, includeGlobals, accountUuids); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + exportGlobalSettings = includeGlobals; + exportAccountUuids = accountUuids; + + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.setType("application/octet-stream"); + intent.putExtra(Intent.EXTRA_TITLE, SettingsExporter.EXPORT_FILENAME); + intent.addCategory(Intent.CATEGORY_OPENABLE); + + startActivityForResult(intent, ACTIVITY_REQUEST_SAVE_SETTINGS_FILE); + } else { + startExport(includeGlobals, accountUuids, null); + } + } + + public void onExport(Intent intent) { + Uri documentsUri = intent.getData(); + startExport(exportGlobalSettings, exportAccountUuids, documentsUri); + } + + private void startExport(boolean exportGlobalSettings, ArrayList exportAccountUuids, Uri documentsUri) { + ExportAsyncTask asyncTask = new ExportAsyncTask(this, exportGlobalSettings, exportAccountUuids, documentsUri); setNonConfigurationInstance(asyncTask); asyncTask.execute(); } @@ -1904,13 +1946,17 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { private boolean mIncludeGlobals; private Set mAccountUuids; private String mFileName; + private Uri mUri; private ExportAsyncTask(Accounts activity, boolean includeGlobals, - Set accountUuids) { + List accountUuids, Uri uri) { super(activity); mIncludeGlobals = includeGlobals; - mAccountUuids = accountUuids; + mUri = uri; + if (accountUuids != null) { + mAccountUuids = new HashSet<>(accountUuids); + } } @Override @@ -1923,8 +1969,13 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { @Override protected Boolean doInBackground(Void... params) { try { - mFileName = SettingsExporter.exportToFile(mContext, mIncludeGlobals, + if (mUri == null) { + mFileName = SettingsExporter.exportToFile(mContext, mIncludeGlobals, mAccountUuids); + } else { + SettingsExporter.exportToUri(mContext, mIncludeGlobals, mAccountUuids, mUri); + } + } catch (SettingsImportExportException e) { Timber.w(e, "Exception during export"); return false; @@ -1942,8 +1993,13 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { removeProgressDialog(); if (success) { - activity.showSimpleDialog(R.string.settings_export_success_header, - R.string.settings_export_success, mFileName); + if (mFileName != null) { + activity.showSimpleDialog(R.string.settings_export_success_header, + R.string.settings_export_success, mFileName); + } else { + activity.showSimpleDialog(R.string.settings_export_success_header, + R.string.settings_export_success_generic); + } } else { //TODO: better error messages activity.showSimpleDialog(R.string.settings_export_failed_header, diff --git a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java index 913173cde..37130cfa7 100644 --- a/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java +++ b/k9mail/src/main/java/com/fsck/k9/preferences/SettingsExporter.java @@ -15,12 +15,13 @@ import java.util.Set; import java.util.TreeMap; import android.content.Context; +import android.net.Uri; import android.os.Environment; + import timber.log.Timber; import android.util.Xml; import com.fsck.k9.Account; -import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.helper.FileHelper; import com.fsck.k9.mail.ServerSettings; @@ -32,7 +33,7 @@ import org.xmlpull.v1.XmlSerializer; public class SettingsExporter { - private static final String EXPORT_FILENAME = "settings.k9s"; + public static final String EXPORT_FILENAME = "settings.k9s"; /** * File format version number. @@ -80,7 +81,6 @@ public class SettingsExporter { throws SettingsImportExportException { OutputStream os = null; - String filename = null; try { File dir = new File(Environment.getExternalStorageDirectory() + File.separator + context.getPackageName()); if (!dir.mkdirs()) { @@ -88,7 +88,7 @@ public class SettingsExporter { } File file = FileHelper.createUniqueFile(dir, EXPORT_FILENAME); - filename = file.getAbsolutePath(); + String filename = file.getAbsolutePath(); os = new FileOutputStream(filename); exportPreferences(context, os, includeGlobals, accountUuids); @@ -98,13 +98,33 @@ public class SettingsExporter { } catch (Exception e) { throw new SettingsImportExportException(e); } finally { - if (os != null) { - try { - os.close(); - } catch (IOException ioe) { - Timber.w("Couldn't close exported settings file: %s", filename); - } - } + closeOrThrow(os); + } + } + + public static void exportToUri(Context context, boolean includeGlobals, Set accountUuids, Uri uri) + throws SettingsImportExportException { + + OutputStream os = null; + try { + os = context.getContentResolver().openOutputStream(uri); + exportPreferences(context, os, includeGlobals, accountUuids); + } catch (Exception e) { + throw new SettingsImportExportException(e); + } finally { + closeOrThrow(os); + } + } + + private static void closeOrThrow(OutputStream outputStream) throws SettingsImportExportException { + if (outputStream == null) { + return; + } + + try { + outputStream.close(); + } catch (IOException e) { + throw new SettingsImportExportException(e); } } diff --git a/k9mail/src/main/res/values/strings.xml b/k9mail/src/main/res/values/strings.xml index 052485cd6..6fac436c3 100644 --- a/k9mail/src/main/res/values/strings.xml +++ b/k9mail/src/main/res/values/strings.xml @@ -975,6 +975,7 @@ Please submit bug reports, contribute new features and ask questions at Importing settings… Scanning file… Saved exported settings to %s + Settings successfully exported Imported global settings from %s Imported %s from %s