diff --git a/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java b/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java
index f1bb39f2..60781efa 100644
--- a/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java
+++ b/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java
@@ -16,11 +16,9 @@
*/
package org.transdroid.core.app.settings;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Environment;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean;
@@ -30,9 +28,13 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.transdroid.daemon.util.HttpHelper;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.os.Environment;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/**
* Singleton class that can persist user settings (servers, RSS feeds, etc.) to and from a plain text JSON file.
@@ -48,8 +50,8 @@ public class SettingsPersistence {
protected SystemSettings systemSettings;
public static final String DEFAULT_SETTINGS_DIR = Environment.getExternalStorageDirectory().toString()
- + "/Transdroid";
- public static final String DEFAULT_SETTINGS_FILENAME = "/settings.json";
+ + "/Transdroid/";
+ public static final String DEFAULT_SETTINGS_FILENAME = "settings.json";
public static final File DEFAULT_SETTINGS_FILE = new File(DEFAULT_SETTINGS_DIR + DEFAULT_SETTINGS_FILENAME);
/**
@@ -59,9 +61,7 @@ public class SettingsPersistence {
* @throws JSONException Thrown when the file did not contain valid JSON content
*/
public void importSettingsAsString(SharedPreferences prefs, String contents) throws JSONException {
-
importSettings(prefs, new JSONObject(contents));
-
}
/**
@@ -72,14 +72,22 @@ public class SettingsPersistence {
* @throws FileNotFoundException Thrown when the settings file doesn't exist or couldn't be read
* @throws JSONException Thrown when the file did not contain valid JSON content
*/
- public void importSettingsFromFile(SharedPreferences prefs, File settingsFile) throws FileNotFoundException,
- JSONException {
-
- String raw = HttpHelper.convertStreamToString(new FileInputStream(settingsFile));
- importSettings(prefs, new JSONObject(raw));
-
+ public void importSettingsFromFile(SharedPreferences prefs, File settingsFile) throws FileNotFoundException, JSONException {
+ importSettingsFromStream(prefs, new FileInputStream(settingsFile));
}
+ /**
+ * Synchronously reads the server, web searches, RSS feed, background service and system settings from a stream (file) in
+ * JSON format.
+ * @param prefs The application-global preferences object to write settings to
+ * @param settingsStream The stream to read the settings from
+ * @throws JSONException Thrown when the file did not contain valid JSON content
+ */
+ public void importSettingsFromStream(SharedPreferences prefs, InputStream settingsStream) throws JSONException {
+ String raw = HttpHelper.convertStreamToString(settingsStream);
+ importSettings(prefs, new JSONObject(raw));
+ }
+
public void importSettings(SharedPreferences prefs, JSONObject json) throws JSONException {
Editor editor = prefs.edit();
@@ -227,7 +235,7 @@ public class SettingsPersistence {
public String exportSettingsAsString(SharedPreferences prefs) throws JSONException {
return exportSettings(prefs).toString();
}
-
+
/**
* Synchronously writes the server, web searches, RSS feed, background service and system settings to a file in JSON
* format.
@@ -237,20 +245,30 @@ public class SettingsPersistence {
* @throws IOException Thrown when the settings file could not be created or written to
*/
public void exportSettingsToFile(SharedPreferences prefs, File settingsFile) throws JSONException, IOException {
-
- JSONObject json = exportSettings(prefs);
-
- // Serialise the JSON object to a file
if (settingsFile.exists()) {
settingsFile.delete();
}
settingsFile.getParentFile().mkdirs();
settingsFile.createNewFile();
- FileWriter writer = new FileWriter(settingsFile);
- writer.write(json.toString(2));
- writer.flush();
- writer.close();
+ exportSettingsToStream(prefs, new FileOutputStream(settingsFile));
+ }
+ /**
+ * Synchronously writes the server, web searches, RSS feed, background service and system settings to a stream (file) in JSON format. The stream
+ * will be closed regardless of success.
+ *
+ * @param prefs The application-global preferences object to read settings from
+ * @param settingsStream The stream to read the settings to
+ * @throws JSONException Thrown when the JSON content could not be constructed properly
+ * @throws IOException Thrown when the settings file could not be created or written to
+ */
+ public void exportSettingsToStream(SharedPreferences prefs, OutputStream settingsStream) throws JSONException, IOException {
+ try {
+ JSONObject json = exportSettings(prefs);
+ settingsStream.write(json.toString(2).getBytes());
+ } finally {
+ settingsStream.close();
+ }
}
private JSONObject exportSettings(SharedPreferences prefs) throws JSONException {
diff --git a/app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java b/app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java
index 5c96b72c..ebc1e066 100644
--- a/app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java
+++ b/app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java
@@ -1,16 +1,16 @@
-/*
+/*
* Copyright 2010-2018 Eric Kok et al.
- *
+ *
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see .
*/
@@ -50,6 +50,8 @@ import org.transdroid.core.service.AppUpdateJob;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
@EActivity
public class SystemSettingsActivity extends PreferenceCompatActivity {
@@ -72,6 +74,9 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
return true;
}
};
+ protected static final int ACTIVITY_IMPORT_SETTINGS = 1;
+ protected static final int ACTIVITY_EXPORT_SETTINGS = 2;
+
@Bean
protected NavigationHelper navigationHelper;
@Bean
@@ -99,7 +104,8 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
private OnClickListener importSettingsFromFile = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (!navigationHelper.checkSettingsReadPermission(SystemSettingsActivity.this))
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
+ && !navigationHelper.checkSettingsReadPermission(SystemSettingsActivity.this))
return; // We are requesting permission to access file storage
importSettingsFromFile();
}
@@ -114,7 +120,8 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
private OnClickListener exportSettingsToFile = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (!navigationHelper.checkSettingsWritePermission(SystemSettingsActivity.this))
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
+ && !navigationHelper.checkSettingsWritePermission(SystemSettingsActivity.this))
return; // We are requesting permission to access file storage
exportSettingsToFile();
}
@@ -171,10 +178,17 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
}
private void importSettingsFromFile() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
try {
- settingsPersistence.importSettingsFromFile(prefs, SettingsPersistence.DEFAULT_SETTINGS_FILE);
- SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_import_success));
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
+ settingsPersistence.importSettingsFromFile(prefs, SettingsPersistence.DEFAULT_SETTINGS_FILE);
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_import_success));
+ } else {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("application/json");
+ startActivityForResult(intent, ACTIVITY_IMPORT_SETTINGS);
+ }
} catch (FileNotFoundException e) {
SnackbarManager
.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.error_file_not_found).colorResource(R.color.red));
@@ -184,17 +198,59 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
}
}
+ @OnActivityResult(ACTIVITY_IMPORT_SETTINGS)
+ public void importSettingsFilePicked(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK && data != null && data.getData() != null) {
+ try {
+ InputStream fis = getContentResolver().openInputStream(data.getData());
+ if (fis != null) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
+ settingsPersistence.importSettingsFromStream(prefs, fis);
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_import_success));
+ }
+ } catch (IOException | JSONException e) {
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.error_file_not_found)
+ .colorResource(R.color.red));
+ }
+ }
+ }
+
private void exportSettingsToFile() {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
try {
- settingsPersistence.exportSettingsToFile(prefs, SettingsPersistence.DEFAULT_SETTINGS_FILE);
- SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_export_success));
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
+ settingsPersistence.exportSettingsToFile(prefs, SettingsPersistence.DEFAULT_SETTINGS_FILE);
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_export_success));
+ } else {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("application/json");
+ intent.putExtra(Intent.EXTRA_TITLE, SettingsPersistence.DEFAULT_SETTINGS_FILENAME);
+ startActivityForResult(intent, ACTIVITY_EXPORT_SETTINGS);
+ }
} catch (JSONException | IOException e) {
SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.error_cant_write_settings_file)
.colorResource(R.color.red));
}
}
+ @OnActivityResult(ACTIVITY_EXPORT_SETTINGS)
+ public void exportSettingsFilePicked(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK && data != null && data.getData() != null) {
+ try {
+ OutputStream fos = getContentResolver().openOutputStream(data.getData());
+ if (fos != null) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SystemSettingsActivity.this);
+ settingsPersistence.exportSettingsToStream(prefs, fos);
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.pref_export_success));
+ }
+ } catch (IOException | JSONException e) {
+ SnackbarManager.show(Snackbar.with(SystemSettingsActivity.this).text(R.string.error_cant_write_settings_file)
+ .colorResource(R.color.red));
+ }
+ }
+ }
+
@OnActivityResult(BarcodeHelper.ACTIVITY_BARCODE_QRSETTINGS)
public void onQrCodeScanned(@SuppressWarnings("UnusedParameters") int resultCode, Intent data) {
// We should have received Intent extras with the QR-decoded data representing Transdroid settings
@@ -219,22 +275,24 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
switch (id) {
case DIALOG_IMPORTSETTINGS:
// @formatter:off
- return new AlertDialog.Builder(this)
- .setMessage(
- getString(
- R.string.pref_import_dialog,
- getString(R.string.app_name),
- SettingsPersistence.DEFAULT_SETTINGS_FILE.toString()))
- .setPositiveButton(R.string.pref_import_fromfile, importSettingsFromFile)
- .setNeutralButton(R.string.pref_import_fromqr, importSettingsFromQr)
- .setNegativeButton(android.R.string.cancel, null).create();
- // @formatter:on
+ return new AlertDialog.Builder(this)
+ .setMessage(
+ getString(
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
+ ? R.string.pref_import_dialog : R.string.pref_import_dialog_android10,
+ getString(R.string.app_name),
+ SettingsPersistence.DEFAULT_SETTINGS_FILE.toString()))
+ .setPositiveButton(R.string.pref_import_fromfile, importSettingsFromFile)
+ .setNeutralButton(R.string.pref_import_fromqr, importSettingsFromQr)
+ .setNegativeButton(android.R.string.cancel, null).create();
+ // @formatter:on
case DIALOG_EXPORTSETTINGS:
// @formatter:off
return new AlertDialog.Builder(this)
.setMessage(
getString(
- R.string.pref_export_dialog,
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
+ ? R.string.pref_export_dialog : R.string.pref_export_dialog_android10,
getString(R.string.app_name),
SettingsPersistence.DEFAULT_SETTINGS_FILE.toString()))
.setPositiveButton(R.string.pref_export_tofile, exportSettingsToFile)
diff --git a/app/src/main/res/values/changelog.xml b/app/src/main/res/values/changelog.xml
index 7c2ea118..2e8dfc0f 100644
--- a/app/src/main/res/values/changelog.xml
+++ b/app/src/main/res/values/changelog.xml
@@ -19,6 +19,7 @@
Transdroid 2.5.18\n
- BitComet details fixes\n
+- Settings import/export on Android 10+\n
\n
Transdroid 2.5.17\n
- qBittorrent 4.2+ support\n
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 642bf0ed..7da99ef8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -356,11 +356,13 @@
Search history is cleared
Import settings
%1$s will try to import server, web search, RSS and system settings from: %2$s
+ %1$s will try to import server, web search, RSS and system settings
Use file
Use QR code
Settings successfully imported
Export settings
%1$s will export server (including passwords), web search, RSS and system settings to the following plain text JSON file: %2$s
+ %1$s will export server (including passwords), web search, RSS and system settings
To file
To QR code
Settings successfully exported