Merge pull request #2382 from k9mail/saf_exporter
Use Storage Access Framework for settings export
This commit is contained in:
commit
6a318bdc6a
3 changed files with 101 additions and 24 deletions
|
@ -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<String> 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) +
|
||||
"</a>"))
|
||||
.append("</p><hr/><p>")
|
||||
.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("</p><hr/><p>")
|
||||
.append(getString(R.string.app_license))
|
||||
.append("</p><hr/><p>");
|
||||
|
@ -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<String> accountUuids = null;
|
||||
ArrayList<String> accountUuids = null;
|
||||
if (account != null) {
|
||||
accountUuids = new HashSet<String>();
|
||||
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<String> 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<String> mAccountUuids;
|
||||
private String mFileName;
|
||||
private Uri mUri;
|
||||
|
||||
|
||||
private ExportAsyncTask(Accounts activity, boolean includeGlobals,
|
||||
Set<String> accountUuids) {
|
||||
List<String> 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,
|
||||
|
|
|
@ -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<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -975,6 +975,7 @@ Please submit bug reports, contribute new features and ask questions at
|
|||
<string name="settings_importing">Importing settings…</string>
|
||||
<string name="settings_import_scanning_file">Scanning file…</string>
|
||||
<string name="settings_export_success">Saved exported settings to <xliff:g id="filename">%s</xliff:g></string>
|
||||
<string name="settings_export_success_generic">Settings successfully exported</string>
|
||||
<string name="settings_import_global_settings_success">Imported global settings from <xliff:g id="filename">%s</xliff:g></string>
|
||||
<string name="settings_import_success">Imported <xliff:g id="accounts">%s</xliff:g> from <xliff:g id="filename">%s</xliff:g></string>
|
||||
<plurals name="settings_import_accounts">
|
||||
|
|
Loading…
Reference in a new issue