summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java218
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java31
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java (renamed from app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java)76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java111
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java118
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java139
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java33
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java283
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java227
12 files changed, 549 insertions, 735 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
deleted file mode 100644
index f85a1cd77..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java
+++ /dev/null
@@ -1,218 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.ParcelFileDescriptor;
-import com.google.android.material.snackbar.Snackbar;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import android.util.Log;
-import android.view.MenuItem;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.channels.FileChannel;
-import java.util.Arrays;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-
-/**
- * Displays the 'import/export' screen
- */
-public class ImportExportActivity extends AppCompatActivity {
- private static final int REQUEST_CODE_RESTORE = 43;
- private static final int REQUEST_CODE_BACKUP_DOCUMENT = 44;
- private static final String EXPORT_FILENAME = "AntennaPodBackup.db";
- private static final String TAG = ImportExportActivity.class.getSimpleName();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayShowHomeEnabled(true);
- }
- setContentView(R.layout.import_export_activity);
-
- findViewById(R.id.button_export).setOnClickListener(view -> backup());
- findViewById(R.id.button_import).setOnClickListener(view -> restore());
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void backup() {
- if (Build.VERSION.SDK_INT >= 19) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
- .addCategory(Intent.CATEGORY_OPENABLE)
- .setType("application/x-sqlite3")
- .putExtra(Intent.EXTRA_TITLE, EXPORT_FILENAME);
-
- startActivityForResult(intent, REQUEST_CODE_BACKUP_DOCUMENT);
- } else {
- try {
- File sd = Environment.getExternalStorageDirectory();
- File backupDB = new File(sd, EXPORT_FILENAME);
- writeBackupTo(new FileOutputStream(backupDB));
- } catch (IOException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
- }
- }
- }
-
- private void restore() {
- if (Build.VERSION.SDK_INT >= 19) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.setType("*/*");
- startActivityForResult(intent, REQUEST_CODE_RESTORE);
- } else {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType("*/*");
- startActivityForResult(Intent.createChooser(intent,
- getString(R.string.import_select_file)), REQUEST_CODE_RESTORE);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
- if (resultCode != RESULT_OK || resultData == null) {
- return;
- }
- Uri uri = resultData.getData();
-
- if (requestCode == REQUEST_CODE_RESTORE) {
- restoreFrom(uri);
- } else if (requestCode == REQUEST_CODE_BACKUP_DOCUMENT) {
- backupToDocument(uri);
- }
- }
-
- private void restoreFrom(Uri inputUri) {
- InputStream inputStream = null;
- try {
- if (!validateDB(inputUri)) {
- displayBadFileDialog();
- return;
- }
-
- File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
- inputStream = getContentResolver().openInputStream(inputUri);
- FileUtils.copyInputStreamToFile(inputStream, currentDB);
- displayImportSuccessDialog();
- } catch (IOException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
- } finally {
- IOUtils.closeQuietly(inputStream);
- }
- }
-
- private static final byte[] SQLITE3_MAGIC = "SQLite format 3\0".getBytes();
- private boolean validateDB(Uri inputUri) throws IOException {
- try (InputStream inputStream = getContentResolver().openInputStream(inputUri)) {
- byte[] magicBuf = new byte[SQLITE3_MAGIC.length];
- if (inputStream.read(magicBuf) == magicBuf.length) {
- return Arrays.equals(SQLITE3_MAGIC, magicBuf);
- }
- }
-
- return false;
- }
-
- private void displayBadFileDialog() {
- AlertDialog.Builder d = new AlertDialog.Builder(ImportExportActivity.this);
- d.setMessage(R.string.import_bad_file)
- .setCancelable(false)
- .setPositiveButton(android.R.string.ok, ((dialogInterface, i) -> {
- // do nothing
- }))
- .show();
- }
-
- private void displayImportSuccessDialog() {
- AlertDialog.Builder d = new AlertDialog.Builder(ImportExportActivity.this);
- d.setMessage(R.string.import_ok);
- d.setCancelable(false);
- d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
- Intent intent = new Intent(getApplicationContext(), SplashActivity.class);
- ComponentName cn = intent.getComponent();
- Intent mainIntent = Intent.makeRestartActivityTask(cn);
- startActivity(mainIntent);
- });
- d.show();
- }
-
- private void backupToDocument(Uri uri) {
- ParcelFileDescriptor pfd = null;
- FileOutputStream fileOutputStream = null;
- try {
- pfd = getContentResolver().openFileDescriptor(uri, "w");
- fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
- writeBackupTo(fileOutputStream);
-
- Snackbar.make(findViewById(R.id.import_export_layout),
- R.string.export_ok, Snackbar.LENGTH_SHORT).show();
- } catch (IOException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
- } finally {
- IOUtils.closeQuietly(fileOutputStream);
-
- if (pfd != null) {
- try {
- pfd.close();
- } catch (IOException e) {
- Log.d(TAG, "Unable to close ParcelFileDescriptor");
- }
- }
- }
- }
-
- private void writeBackupTo(FileOutputStream outFileStream) {
- FileChannel src = null;
- FileChannel dst = null;
- try {
- File currentDB = getDatabasePath(PodDBAdapter.DATABASE_NAME);
-
- if (currentDB.exists()) {
- src = new FileInputStream(currentDB).getChannel();
- dst = outFileStream.getChannel();
- dst.transferFrom(src, 0, src.size());
-
- Snackbar.make(findViewById(R.id.import_export_layout),
- R.string.export_ok, Snackbar.LENGTH_SHORT).show();
- } else {
- Snackbar.make(findViewById(R.id.import_export_layout),
- "Can not access current database", Snackbar.LENGTH_SHORT).show();
- }
- } catch (IOException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- Snackbar.make(findViewById(R.id.import_export_layout), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
- } finally {
- IOUtils.closeQuietly(src);
- IOUtils.closeQuietly(dst);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 538ed1231..021ff774d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -358,10 +358,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
}
- boolean sleepTimerSet = controller.sleepTimerActive();
- boolean sleepTimerNotSet = controller.sleepTimerNotActive();
- menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet);
- menu.findItem(R.id.disable_sleeptimer_item).setVisible(sleepTimerSet);
+ menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive());
+ menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive());
if (this instanceof AudioplayerActivity) {
int[] attrs = {R.attr.action_bar_icon_color};
@@ -422,30 +420,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
.show();
}
break;
- case R.id.disable_sleeptimer_item:
- if (controller.serviceAvailable()) {
-
- new AlertDialog.Builder(this)
- .setTitle(R.string.sleep_timer_label)
- .setMessage(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) controller
- .getSleepTimerTimeLeft()))
- .setPositiveButton(R.string.disable_sleeptimer_label, (dialog, which)
- -> controller.disableSleepTimer())
- .setNegativeButton(R.string.cancel_label, null)
- .show();
- }
- break;
+ case R.id.disable_sleeptimer_item: // Fall-through
case R.id.set_sleeptimer_item:
- if (controller.serviceAvailable()) {
- SleepTimerDialog td = new SleepTimerDialog(this) {
- @Override
- public void onTimerSet(long millis, boolean shakeToReset, boolean vibrate) {
- controller.setSleepTimer(millis, shakeToReset, vibrate);
- }
- };
- td.createNewDialog().show();
- }
+ new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog");
break;
case R.id.audio_controls:
boolean isPlayingVideo = controller.getMedia().getMediaType() == MediaType.VIDEO;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index d7a4b9517..03e6b89db 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -4,35 +4,53 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
import android.os.Environment;
+import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
-import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;
-import android.util.Log;
-
-import org.apache.commons.lang3.ArrayUtils;
-
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-
+import androidx.core.app.ActivityCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.OpmlFeedQueuer;
import de.danoeh.antennapod.asynctask.OpmlImportWorker;
import de.danoeh.antennapod.core.export.opml.OpmlElement;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.LangUtils;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
/**
- * Base activity for Opml Import - e.g. with code what to do afterwards
+ * Activity for Opml Import.
* */
-public class OpmlImportBaseActivity extends AppCompatActivity {
-
+public class OpmlImportActivity extends AppCompatActivity {
private static final String TAG = "OpmlImportBaseActivity";
private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5;
- private OpmlImportWorker importWorker;
@Nullable private Uri uri;
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setTheme(UserPreferences.getTheme());
+ super.onCreate(savedInstanceState);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+
+ Uri uri = getIntent().getData();
+ if (uri != null && uri.toString().startsWith("/")) {
+ uri = Uri.parse("file://" + uri.toString());
+ } else {
+ String extraText = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+ if (extraText != null) {
+ uri = Uri.parse(extraText);
+ }
+ }
+ importUri(uri);
+ }
+
/**
* Handles the choices made by the user in the OpmlFeedChooserActivity and
* starts the OpmlFeedQueuer if necessary.
@@ -42,9 +60,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
Log.d(TAG, "Received result");
if (resultCode == RESULT_CANCELED) {
Log.d(TAG, "Activity was cancelled");
- if (finishWhenCanceled()) {
- finish();
- }
+ finish();
} else {
int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS);
if (selected != null && selected.length > 0) {
@@ -53,7 +69,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
- Intent intent = new Intent(OpmlImportBaseActivity.this, MainActivity.class);
+ Intent intent = new Intent(OpmlImportActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
@@ -68,7 +84,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
}
void importUri(@Nullable Uri uri) {
- if(uri == null) {
+ if (uri == null) {
new AlertDialog.Builder(this)
.setMessage(R.string.opml_import_error_no_file)
.setPositiveButton(android.R.string.ok, null)
@@ -76,9 +92,10 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
return;
}
this.uri = uri;
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
- uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
- int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && uri.toString().contains(Environment.getExternalStorageDirectory().toString())) {
+ int permission = ActivityCompat.checkSelfPermission(this,
+ android.Manifest.permission.READ_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
requestPermission();
return;
@@ -93,9 +110,8 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
}
@Override
- public void onRequestPermissionsResult(int requestCode,
- String[] permissions,
- int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
if (requestCode != PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
return;
}
@@ -113,8 +129,8 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
/** Starts the import process. */
private void startImport() {
try {
- Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
- importWorker = new OpmlImportWorker(this, mReader) {
+ Reader reader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
+ OpmlImportWorker importWorker = new OpmlImportWorker(this, reader) {
@Override
protected void onPostExecute(ArrayList<OpmlElement> result) {
@@ -123,7 +139,7 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
Log.d(TAG, "Parsing was successful");
OpmlImportHolder.setReadElements(result);
startActivityForResult(new Intent(
- OpmlImportBaseActivity.this,
+ OpmlImportActivity.this,
OpmlFeedChooserActivity.class), 0);
} else {
Log.d(TAG, "Parser error occurred");
@@ -140,10 +156,4 @@ public class OpmlImportBaseActivity extends AppCompatActivity {
.show();
}
}
-
- boolean finishWhenCanceled() {
- return false;
- }
-
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
deleted file mode 100644
index 557510808..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-
-/**
- * Lets the user start the OPML-import process.
- */
-public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity {
-
- private static final String TAG = "OpmlImportFromIntentAct";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- Uri uri = getIntent().getData();
- if (uri != null && uri.toString().startsWith("/")) {
- uri = Uri.parse("file://" + uri.toString());
- } else {
- String extraText = getIntent().getStringExtra(Intent.EXTRA_TEXT);
- if(extraText != null) {
- uri = Uri.parse(extraText);
- }
- }
- importUri(uri);
- }
-
- @Override
- protected boolean finishWhenCanceled() {
- return true;
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
deleted file mode 100644
index 158e3b7a4..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package de.danoeh.antennapod.activity;
-
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.StorageUtils;
-
-/**
- * Lets the user start the OPML-import process from a path
- */
-public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
-
- private static final String TAG = "OpmlImportFromPathAct";
-
- private static final int CHOOSE_OPML_FILE = 1;
-
- private Intent intentGetContentAction;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- setContentView(R.layout.opml_import);
-
- final TextView txtvHeaderExplanation = findViewById(R.id.txtvHeadingExplanation);
- final TextView txtvExplanation = findViewById(R.id.txtvExplanation);
- final TextView txtvHeaderExplanationOpenWith = findViewById(R.id.txtvHeadingExplanationOpenWith);
-
- Button butChooseFilesystem = findViewById(R.id.butChooseFileFromFilesystem);
- butChooseFilesystem.setOnClickListener(v -> chooseFileFromExternal());
-
- int nextOption = 1;
- String optionLabel = getString(R.string.opml_import_option);
- intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
- intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
- intentGetContentAction.setType("*/*");
-
- if (IntentUtils.isCallable(getApplicationContext(), intentGetContentAction)) {
- txtvHeaderExplanation.setText(String.format(optionLabel, nextOption));
- nextOption++;
- } else {
- txtvHeaderExplanation.setVisibility(View.GONE);
- txtvExplanation.setVisibility(View.GONE);
- findViewById(R.id.divider).setVisibility(View.GONE);
- butChooseFilesystem.setVisibility(View.GONE);
- }
-
- txtvHeaderExplanationOpenWith.setText(String.format(optionLabel, nextOption));
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- StorageUtils.checkStorageAvailability(this);
- }
-
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- default:
- return false;
- }
- }
-
- private void chooseFileFromExternal() {
- try {
- startActivityForResult(intentGetContentAction, CHOOSE_OPML_FILE);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "No activity found. Should never happen...");
- }
- }
-
- /**
- * Gets the path of the file chosen with chooseFileToImport()
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) {
- Uri uri = data.getData();
- if(uri != null && uri.toString().startsWith("/")) {
- uri = Uri.parse("file://" + uri.toString());
- }
- importUri(uri);
- }
- }
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index a0f9bf6d8..dd91b7e2a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -16,6 +16,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.preferences.AutoDownloadPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.GpodderPreferencesFragment;
+import de.danoeh.antennapod.fragment.preferences.ImportExportPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.IntegrationsPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment;
import de.danoeh.antennapod.fragment.preferences.NetworkPreferencesFragment;
@@ -59,6 +60,8 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
prefFragment = new NetworkPreferencesFragment();
} else if (screen == R.xml.preferences_storage) {
prefFragment = new StoragePreferencesFragment();
+ } else if (screen == R.xml.preferences_import_export) {
+ prefFragment = new ImportExportPreferencesFragment();
} else if (screen == R.xml.preferences_autodownload) {
prefFragment = new AutoDownloadPreferencesFragment();
} else if (screen == R.xml.preferences_gpodder) {
@@ -79,6 +82,8 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
return R.string.playback_pref;
case R.xml.preferences_storage:
return R.string.storage_pref;
+ case R.xml.preferences_import_export:
+ return R.string.import_export_pref;
case R.xml.preferences_user_interface:
return R.string.user_interface_label;
case R.xml.preferences_integrations:
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index b88b58537..e037eb392 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -16,84 +16,78 @@ import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.export.opml.OpmlElement;
import de.danoeh.antennapod.core.export.opml.OpmlReader;
-public class OpmlImportWorker extends
- AsyncTask<Void, Void, ArrayList<OpmlElement>> {
- private static final String TAG = "OpmlImportWorker";
+public class OpmlImportWorker extends AsyncTask<Void, Void, ArrayList<OpmlElement>> {
+ private static final String TAG = "OpmlImportWorker";
- private final Context context;
- private Exception exception;
+ private final Context context;
+ private Exception exception;
+ private ProgressDialog progDialog;
- private ProgressDialog progDialog;
-
- private final Reader mReader;
+ private final Reader reader;
public OpmlImportWorker(Context context, Reader reader) {
super();
this.context = context;
- this.mReader=reader;
+ this.reader = reader;
}
- @Override
- protected ArrayList<OpmlElement> doInBackground(Void... params) {
- Log.d(TAG, "Starting background work");
+ @Override
+ protected ArrayList<OpmlElement> doInBackground(Void... params) {
+ Log.d(TAG, "Starting background work");
- if (mReader==null) {
+ if (reader == null) {
return null;
}
- OpmlReader opmlReader = new OpmlReader();
- try {
- ArrayList<OpmlElement> result = opmlReader.readDocument(mReader);
- mReader.close();
- return result;
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- exception = e;
- return null;
- } catch (IOException e) {
- e.printStackTrace();
- exception = e;
- return null;
- }
-
- }
-
- @Override
- protected void onPostExecute(ArrayList<OpmlElement> result) {
- if (mReader != null) {
+ OpmlReader opmlReader = new OpmlReader();
+ try {
+ ArrayList<OpmlElement> result = opmlReader.readDocument(reader);
+ reader.close();
+ return result;
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ exception = e;
+ return null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ exception = e;
+ return null;
+ }
+
+ }
+
+ @Override
+ protected void onPostExecute(ArrayList<OpmlElement> result) {
+ if (reader != null) {
try {
- mReader.close();
+ reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- progDialog.dismiss();
- if (exception != null) {
- Log.d(TAG, "An error occurred while trying to parse the opml document");
- AlertDialog.Builder alert = new AlertDialog.Builder(context);
- alert.setTitle(R.string.error_label);
- alert.setMessage(context.getString(R.string.opml_reader_error)
- + exception.getMessage());
- alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- alert.create().show();
- }
- }
-
- @Override
- protected void onPreExecute() {
- progDialog = new ProgressDialog(context);
- progDialog.setMessage(context.getString(R.string.reading_opml_label));
- progDialog.setIndeterminate(true);
- progDialog.setCancelable(false);
- progDialog.show();
- }
-
- public boolean wasSuccessful() {
- return exception != null;
- }
-
- public void executeAsync() {
- executeOnExecutor(THREAD_POOL_EXECUTOR);
- }
+ progDialog.dismiss();
+ if (exception != null) {
+ Log.d(TAG, "An error occurred while trying to parse the opml document");
+ AlertDialog.Builder alert = new AlertDialog.Builder(context);
+ alert.setTitle(R.string.error_label);
+ alert.setMessage(context.getString(R.string.opml_reader_error)
+ + exception.getMessage());
+ alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.create().show();
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ progDialog = new ProgressDialog(context);
+ progDialog.setMessage(context.getString(R.string.please_wait));
+ progDialog.setIndeterminate(true);
+ progDialog.setCancelable(false);
+ progDialog.show();
+ }
+
+ public void executeAsync() {
+ executeOnExecutor(THREAD_POOL_EXECUTOR);
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index 8d176c708..d36f97c7a 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -1,67 +1,101 @@
package de.danoeh.antennapod.dialog;
+import android.app.Dialog;
import android.content.Context;
+import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
+import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
+import android.widget.LinearLayout;
import android.widget.Spinner;
+import android.widget.TextView;
import android.widget.Toast;
-
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
-import org.greenrobot.eventbus.EventBus;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
-public abstract class SleepTimerDialog {
-
- private static final String TAG = SleepTimerDialog.class.getSimpleName();
+import java.util.concurrent.TimeUnit;
- private final Context context;
+public class SleepTimerDialog extends DialogFragment {
+ private PlaybackController controller;
+ private Disposable timeUpdater;
- private AlertDialog dialog;
private EditText etxtTime;
private Spinner spTimeUnit;
private CheckBox cbShakeToReset;
private CheckBox cbVibrate;
private CheckBox chAutoEnable;
+ private LinearLayout timeSetup;
+ private LinearLayout timeDisplay;
+ private TextView time;
+ public SleepTimerDialog() {
- protected SleepTimerDialog(Context context) {
- this.context = context;
}
- public AlertDialog createNewDialog() {
- View content = View.inflate(context, R.layout.time_dialog, null);
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.set_sleeptimer_label);
- builder.setView(content);
- builder.setNegativeButton(R.string.cancel_label, (dialog, which) -> dialog.dismiss());
- builder.setPositiveButton(R.string.set_sleeptimer_label, (dialog, which) -> {
- try {
- savePreferences();
- long input = SleepTimerPreferences.timerMillis();
- onTimerSet(input, cbShakeToReset.isChecked(), cbVibrate.isChecked());
- dialog.dismiss();
- } catch (NumberFormatException e) {
- e.printStackTrace();
- Toast toast = Toast.makeText(context, R.string.time_dialog_invalid_input,
- Toast.LENGTH_LONG);
- toast.show();
+ @Override
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity(), false) {
+ @Override
+ public void setupGUI() {
+ updateTime();
}
- });
- dialog = builder.create();
+
+ @Override
+ public void onSleepTimerUpdate() {
+ updateTime();
+ }
+ };
+ controller.init();
+ timeUpdater = Observable.interval(1, TimeUnit.SECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(tick -> updateTime());
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (controller != null) {
+ controller.release();
+ }
+ if (timeUpdater != null) {
+ timeUpdater.dispose();
+ }
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ View content = View.inflate(getContext(), R.layout.time_dialog, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(R.string.sleep_timer_label);
+ builder.setView(content);
+ builder.setPositiveButton(android.R.string.ok, null);
etxtTime = content.findViewById(R.id.etxtTime);
spTimeUnit = content.findViewById(R.id.spTimeUnit);
cbShakeToReset = content.findViewById(R.id.cbShakeToReset);
cbVibrate = content.findViewById(R.id.cbVibrate);
chAutoEnable = content.findViewById(R.id.chAutoEnable);
+ timeSetup = content.findViewById(R.id.timeSetup);
+ timeDisplay = content.findViewById(R.id.timeDisplay);
+ time = content.findViewById(R.id.time);
+ AlertDialog dialog = builder.create();
etxtTime.setText(SleepTimerPreferences.lastTimerValue());
etxtTime.addTextChangedListener(new TextWatcher() {
@Override
@@ -78,15 +112,15 @@ public abstract class SleepTimerDialog {
}
});
etxtTime.postDelayed(() -> {
- InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(etxtTime, InputMethodManager.SHOW_IMPLICIT);
}, 100);
String[] spinnerContent = new String[] {
- context.getString(R.string.time_seconds),
- context.getString(R.string.time_minutes),
- context.getString(R.string.time_hours) };
- ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(context,
+ getString(R.string.time_seconds),
+ getString(R.string.time_minutes),
+ getString(R.string.time_hours) };
+ ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(getContext(),
android.R.layout.simple_spinner_item, spinnerContent);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spTimeUnit.setAdapter(spinnerAdapter);
@@ -96,16 +130,33 @@ public abstract class SleepTimerDialog {
cbVibrate.setChecked(SleepTimerPreferences.vibrate());
chAutoEnable.setChecked(SleepTimerPreferences.autoEnable());
- chAutoEnable.setOnCheckedChangeListener((compoundButton, isChecked) -> {
- SleepTimerPreferences.setAutoEnable(isChecked);
- int messageString = isChecked ? R.string.sleep_timer_enabled_label : R.string.sleep_timer_disabled_label;
- EventBus.getDefault().post(new MessageEvent(context.getString(messageString)));
+ chAutoEnable.setOnCheckedChangeListener((compoundButton, isChecked)
+ -> SleepTimerPreferences.setAutoEnable(isChecked));
+ Button disableButton = content.findViewById(R.id.disableSleeptimerButton);
+ disableButton.setOnClickListener(v -> {
+ if (controller != null) {
+ controller.disableSleepTimer();
+ }
+ });
+ Button setButton = content.findViewById(R.id.setSleeptimerButton);
+ setButton.setOnClickListener(v -> {
+ if (!PlaybackService.isRunning) {
+ Toast.makeText(getContext(), R.string.no_media_playing_label, Toast.LENGTH_LONG).show();
+ }
+ try {
+ savePreferences();
+ long time = SleepTimerPreferences.timerMillis();
+ if (controller != null) {
+ controller.setSleepTimer(time, cbShakeToReset.isChecked(), cbVibrate.isChecked());
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ Toast.makeText(getContext(), R.string.time_dialog_invalid_input, Toast.LENGTH_LONG).show();
+ }
});
return dialog;
}
- public abstract void onTimerSet(long millis, boolean shakeToReset, boolean vibrate);
-
private void savePreferences() {
SleepTimerPreferences.setLastTimer(etxtTime.getText().toString(),
spTimeUnit.getSelectedItemPosition());
@@ -114,4 +165,12 @@ public abstract class SleepTimerDialog {
SleepTimerPreferences.setAutoEnable(chAutoEnable.isChecked());
}
+ private void updateTime() {
+ if (controller == null) {
+ return;
+ }
+ timeSetup.setVisibility(controller.sleepTimerActive() ? View.GONE : View.VISIBLE);
+ timeDisplay.setVisibility(controller.sleepTimerActive() ? View.VISIBLE : View.GONE);
+ time.setText(Converter.getDurationStringLong((int) controller.getSleepTimerTimeLeft()));
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 2cfe7c1e8..343cf76ab 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -1,7 +1,11 @@
package de.danoeh.antennapod.fragment;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
+import android.util.Log;
import androidx.fragment.app.Fragment;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -14,7 +18,7 @@ import android.widget.EditText;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
-import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.activity.OpmlImportActivity;
import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment;
/**
@@ -28,6 +32,7 @@ public class AddFeedFragment extends Fragment {
* Preset value for url text field.
*/
private static final String ARG_FEED_URL = "feedurl";
+ private static final int REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH = 1;
private EditText combinedFeedSearchBox;
private MainActivity activity;
@@ -44,8 +49,16 @@ public class AddFeedFragment extends Fragment {
setupSeachBox(root);
View butOpmlImport = root.findViewById(R.id.btn_opml_import);
- butOpmlImport.setOnClickListener(v -> startActivity(new Intent(getActivity(),
- OpmlImportFromPathActivity.class)));
+ butOpmlImport.setOnClickListener(v -> {
+ try {
+ Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
+ intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
+ intentGetContentAction.setType("*/*");
+ startActivityForResult(intentGetContentAction, REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ });
root.findViewById(R.id.search_icon).setOnClickListener(view -> performSearch());
return root;
}
@@ -130,4 +143,18 @@ public class AddFeedFragment extends Fragment {
// persist. mfietz thinks this causes the ActionBar to be invalidated
setHasOptionsMenu(true);
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != Activity.RESULT_OK || data == null) {
+ return;
+ }
+ Uri uri = data.getData();
+
+ if (requestCode == REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH) {
+ Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
new file mode 100644
index 000000000..9a09d55b0
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -0,0 +1,283 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+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.Environment;
+import android.util.Log;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.content.FileProvider;
+import androidx.preference.PreferenceFragmentCompat;
+import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.OpmlImportActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.activity.SplashActivity;
+import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
+import de.danoeh.antennapod.asynctask.ExportWorker;
+import de.danoeh.antennapod.core.export.ExportWriter;
+import de.danoeh.antennapod.core.export.html.HtmlWriter;
+import de.danoeh.antennapod.core.export.opml.OpmlWriter;
+import de.danoeh.antennapod.core.storage.DatabaseExporter;
+import io.reactivex.Completable;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+
+public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
+ private static final String TAG = "ImportExPrefFragment";
+ private static final String PREF_OPML_EXPORT = "prefOpmlExport";
+ private static final String PREF_OPML_IMPORT = "prefOpmlImport";
+ private static final String PREF_HTML_EXPORT = "prefHtmlExport";
+ private static final String PREF_DATABASE_IMPORT = "prefDatabaseImport";
+ private static final String PREF_DATABASE_EXPORT = "prefDatabaseExport";
+ private static final String DEFAULT_OPML_OUTPUT_NAME = "antennapod-feeds.opml";
+ private static final String CONTENT_TYPE_OPML = "text/x-opml";
+ private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds.html";
+ private static final String CONTENT_TYPE_HTML = "text/html";
+ private static final int REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH = 1;
+ private static final int REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH = 2;
+ private static final int REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH = 3;
+ private static final int REQUEST_CODE_RESTORE_DATABASE = 4;
+ private static final int REQUEST_CODE_BACKUP_DATABASE = 5;
+ private static final String DATABASE_EXPORT_FILENAME = "AntennaPodBackup.db";
+ private Disposable disposable;
+ private ProgressDialog progressDialog;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.preferences_import_export);
+ setupStorageScreen();
+ progressDialog = new ProgressDialog(getContext());
+ progressDialog.setIndeterminate(true);
+ progressDialog.setMessage(getContext().getString(R.string.please_wait));
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.import_export_pref);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ private void setupStorageScreen() {
+ findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ openExportPathPicker(CONTENT_TYPE_OPML, DEFAULT_OPML_OUTPUT_NAME,
+ REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH, new OpmlWriter());
+ return true;
+ }
+ );
+ findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ openExportPathPicker(CONTENT_TYPE_HTML, DEFAULT_HTML_OUTPUT_NAME,
+ REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH, new HtmlWriter());
+ return true;
+ });
+ findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
+ preference -> {
+ try {
+ Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
+ intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
+ intentGetContentAction.setType("*/*");
+ startActivityForResult(intentGetContentAction, REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ return true;
+ });
+ findPreference(PREF_DATABASE_IMPORT).setOnPreferenceClickListener(
+ preference -> {
+ importDatabase();
+ return true;
+ });
+ findPreference(PREF_DATABASE_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ exportDatabase();
+ return true;
+ });
+ }
+
+ private void exportWithWriter(ExportWriter exportWriter, final Uri uri) {
+ Context context = getActivity();
+ progressDialog.show();
+ if (uri == null) {
+ Observable<File> observable = new ExportWorker(exportWriter, getContext()).exportObservable();
+ disposable = observable.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output -> {
+ Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
+ context.getString(R.string.provider_authority), output);
+ showExportSuccessDialog(output.toString(), fileUri);
+ }, this::showExportErrorDialog, progressDialog::dismiss);
+ } else {
+ DocumentFileExportWorker worker = new DocumentFileExportWorker(exportWriter, context, uri);
+ disposable = worker.exportObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(output ->
+ showExportSuccessDialog(output.getUri().toString(), output.getUri()),
+ this::showExportErrorDialog, progressDialog::dismiss);
+ }
+ }
+
+ private void exportDatabase() {
+ if (Build.VERSION.SDK_INT >= 19) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType("application/x-sqlite3")
+ .putExtra(Intent.EXTRA_TITLE, DATABASE_EXPORT_FILENAME);
+
+ startActivityForResult(intent, REQUEST_CODE_BACKUP_DATABASE);
+ } else {
+ File sd = Environment.getExternalStorageDirectory();
+ File backupDB = new File(sd, DATABASE_EXPORT_FILENAME);
+ progressDialog.show();
+ disposable = Completable.fromAction(() ->
+ DatabaseExporter.exportToStream(new FileOutputStream(backupDB), getContext()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ Snackbar.make(getView(), R.string.export_success_title, Snackbar.LENGTH_LONG).show();
+ progressDialog.dismiss();
+ }, this::showExportErrorDialog);
+ }
+ }
+
+ private void importDatabase() {
+ if (Build.VERSION.SDK_INT >= 19) {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.setType("*/*");
+ startActivityForResult(intent, REQUEST_CODE_RESTORE_DATABASE);
+ } else {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("*/*");
+ startActivityForResult(Intent.createChooser(intent,
+ getString(R.string.import_select_file)), REQUEST_CODE_RESTORE_DATABASE);
+ }
+ }
+
+ private void showDatabaseImportSuccessDialog() {
+ AlertDialog.Builder d = new AlertDialog.Builder(getContext());
+ d.setMessage(R.string.import_ok);
+ d.setCancelable(false);
+ d.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ Intent intent = new Intent(getContext(), SplashActivity.class);
+ ComponentName cn = intent.getComponent();
+ Intent mainIntent = Intent.makeRestartActivityTask(cn);
+ startActivity(mainIntent);
+ });
+ d.show();
+ }
+
+ private void showExportSuccessDialog(final String path, final Uri streamUri) {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
+ alert.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_success_title);
+ alert.setMessage(getContext().getString(R.string.export_success_sum, path));
+ alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.opml_export_label));
+ sendIntent.putExtra(Intent.EXTRA_STREAM, streamUri);
+ sendIntent.setType("text/plain");
+ sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
+ List<ResolveInfo> resInfoList = getContext().getPackageManager()
+ .queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ getContext().grantUriPermission(packageName, streamUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ }
+ getContext().startActivity(Intent.createChooser(sendIntent, getString(R.string.send_label)));
+ });
+ alert.create().show();
+ }
+
+ private void showExportErrorDialog(final Throwable error) {
+ progressDialog.dismiss();
+ final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
+ .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
+ alert.setTitle(R.string.export_error_label);
+ alert.setMessage(error.getMessage());
+ alert.show();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != Activity.RESULT_OK || data == null) {
+ return;
+ }
+ Uri uri = data.getData();
+
+ if (requestCode == REQUEST_CODE_CHOOSE_OPML_EXPORT_PATH) {
+ exportWithWriter(new OpmlWriter(), uri);
+ } else if (requestCode == REQUEST_CODE_CHOOSE_HTML_EXPORT_PATH) {
+ exportWithWriter(new HtmlWriter(), uri);
+ } else if (requestCode == REQUEST_CODE_RESTORE_DATABASE) {
+ progressDialog.show();
+ disposable = Completable.fromAction(() -> DatabaseExporter.importBackup(uri, getContext()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ showDatabaseImportSuccessDialog();
+ progressDialog.dismiss();
+ }, this::showExportErrorDialog);
+ } else if (requestCode == REQUEST_CODE_BACKUP_DATABASE) {
+ progressDialog.show();
+ disposable = Completable.fromAction(() -> DatabaseExporter.exportToDocument(uri, getContext()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ Snackbar.make(getView(), R.string.export_success_title, Snackbar.LENGTH_LONG).show();
+ progressDialog.dismiss();
+ }, this::showExportErrorDialog);
+ } else if (requestCode == REQUEST_CODE_CHOOSE_OPML_IMPORT_PATH) {
+ Intent intent = new Intent(getContext(), OpmlImportActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ }
+ }
+
+ private void openExportPathPicker(String contentType, String title, int requestCode, ExportWriter writer) {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .setType(contentType)
+ .putExtra(Intent.EXTRA_TITLE, title);
+
+ // Creates an implicit intent to launch a file manager which lets
+ // the user choose a specific directory to export to.
+ try {
+ startActivityForResult(intentPickAction, requestCode);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
+
+ // If we are using a SDK lower than API 21 or the implicit intent failed
+ // fallback to the legacy export process
+ exportWithWriter(writer, null);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
index 5fd38d663..da82d4f8c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -103,6 +103,9 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_network));
config.index(R.xml.preferences_storage)
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_storage));
+ config.index(R.xml.preferences_import_export)
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_storage))
+ .addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_import_export));
config.index(R.xml.preferences_autodownload)
.addBreadcrumb(PreferenceActivity.getTitleOfPage(R.xml.preferences_network))
.addBreadcrumb(R.string.automation)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
index 5ce852ed2..8a0742b7f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -1,62 +1,32 @@
package de.danoeh.antennapod.fragment.preferences;
import android.Manifest;
-import android.annotation.SuppressLint;
import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.FileProvider;
-import androidx.documentfile.provider.DocumentFile;
+import android.util.Log;
import androidx.appcompat.app.AlertDialog;
+import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceFragmentCompat;
-import android.util.Log;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
-import de.danoeh.antennapod.activity.ImportExportActivity;
-import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.asynctask.DocumentFileExportWorker;
-import de.danoeh.antennapod.asynctask.ExportWorker;
-import de.danoeh.antennapod.core.export.ExportWriter;
-import de.danoeh.antennapod.core.export.html.HtmlWriter;
-import de.danoeh.antennapod.core.export.opml.OpmlWriter;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
import java.io.File;
-import java.util.List;
public class StoragePreferencesFragment extends PreferenceFragmentCompat {
private static final String TAG = "StoragePrefFragment";
- private static final String PREF_OPML_EXPORT = "prefOpmlExport";
- private static final String PREF_OPML_IMPORT = "prefOpmlImport";
- private static final String PREF_HTML_EXPORT = "prefHtmlExport";
- private static final String IMPORT_EXPORT = "importExport";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
+ private static final String PREF_IMPORT_EXPORT = "prefImportExport";
private static final String[] EXTERNAL_STORAGE_PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE };
private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41;
- private static final int CHOOSE_OPML_EXPORT_PATH = 1;
- private static final String DEFAULT_OPML_OUTPUT_NAME = "antennapod-feeds.opml";
- private static final String CONTENT_TYPE_OPML = "text/x-opml";
- private static final int CHOOSE_HTML_EXPORT_PATH = 2;
- private static final String DEFAULT_HTML_OUTPUT_NAME = "antennapod-feeds.html";
- private static final String CONTENT_TYPE_HTML = "text/html";
- private Disposable disposable;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -76,51 +46,20 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
setDataFolderText();
}
- @Override
- public void onStop() {
- super.onStop();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
private void setupStorageScreen() {
final Activity activity = getActivity();
-
- findPreference(IMPORT_EXPORT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, ImportExportActivity.class));
- return true;
- }
- );
- findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
- preference -> {
- openOpmlExportPathPicker();
- return true;
- }
- );
- findPreference(PREF_HTML_EXPORT).setOnPreferenceClickListener(
- preference -> {
- openHtmlExportPathPicker();
- return true;
- });
- findPreference(PREF_OPML_IMPORT).setOnPreferenceClickListener(
- preference -> {
- activity.startActivity(new Intent(activity, OpmlImportFromPathActivity.class));
- return true;
- });
findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
preference -> {
- if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
- Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
showChooseDataFolderDialog();
} else {
int readPermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ActivityCompat.checkSelfPermission(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
- if (readPermission == PackageManager.PERMISSION_GRANTED &&
- writePermission == PackageManager.PERMISSION_GRANTED) {
+ if (readPermission == PackageManager.PERMISSION_GRANTED
+ && writePermission == PackageManager.PERMISSION_GRANTED) {
openDirectoryChooser();
} else {
requestPermission();
@@ -129,19 +68,18 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
return true;
}
);
- findPreference(PREF_CHOOSE_DATA_DIR)
- .setOnPreferenceClickListener(
- preference -> {
- if (Build.VERSION.SDK_INT >= 19) {
- showChooseDataFolderDialog();
- } else {
- Intent intent = new Intent(activity, DirectoryChooserActivity.class);
- activity.startActivityForResult(intent,
- DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
- }
- return true;
- }
- );
+ findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
+ preference -> {
+ if (Build.VERSION.SDK_INT >= 19) {
+ showChooseDataFolderDialog();
+ } else {
+ Intent intent = new Intent(activity, DirectoryChooserActivity.class);
+ activity.startActivityForResult(intent,
+ DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ }
+ return true;
+ }
+ );
findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener(
(preference, o) -> {
if (o instanceof String) {
@@ -158,74 +96,16 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
return false;
}
);
- }
-
- private boolean export(ExportWriter exportWriter) {
- return export(exportWriter, null);
- }
-
- private boolean export(ExportWriter exportWriter, final Uri uri) {
- Context context = getActivity();
- final ProgressDialog progressDialog = new ProgressDialog(context);
- progressDialog.setMessage(context.getString(R.string.exporting_label));
- progressDialog.setIndeterminate(true);
- progressDialog.show();
- if (uri == null) {
- Observable<File> observable = new ExportWorker(exportWriter, getContext()).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- Uri fileUri = FileProvider.getUriForFile(context.getApplicationContext(),
- context.getString(R.string.provider_authority), output);
- showExportSuccessDialog(context.getString(R.string.export_success_sum, output.toString()), fileUri);
- }, this::showExportErrorDialog, progressDialog::dismiss);
- } else {
- Observable<DocumentFile> observable = new DocumentFileExportWorker(exportWriter, context, uri).exportObservable();
- disposable = observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(output -> {
- showExportSuccessDialog(context.getString(R.string.export_success_sum, output.getUri()), output.getUri());
- }, this::showExportErrorDialog, progressDialog::dismiss);
- }
- return true;
- }
-
- private void showExportSuccessDialog(final String message, final Uri streamUri) {
- final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
- .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- alert.setTitle(R.string.export_success_title);
- alert.setMessage(message);
- alert.setPositiveButton(R.string.send_label, (dialog, which) -> {
- Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.opml_export_label));
- sendIntent.putExtra(Intent.EXTRA_STREAM, streamUri);
- sendIntent.setType("text/plain");
- sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
- List<ResolveInfo> resInfoList = getContext().getPackageManager()
- .queryIntentActivities(sendIntent, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- getContext().grantUriPermission(packageName, streamUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ findPreference(PREF_IMPORT_EXPORT).setOnPreferenceClickListener(
+ preference -> {
+ ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_import_export);
+ return true;
}
- }
- getContext().startActivity(Intent.createChooser(sendIntent, getString(R.string.send_label)));
- });
- alert.create().show();
- }
-
- private void showExportErrorDialog(final Throwable error) {
- final AlertDialog.Builder alert = new AlertDialog.Builder(getContext())
- .setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
- alert.setTitle(R.string.export_error_label);
- alert.setMessage(error.getMessage());
- alert.show();
+ );
}
- @SuppressLint("NewApi")
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK &&
- requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
+ if (resultCode == Activity.RESULT_OK && requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
File path;
@@ -255,23 +135,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
ab.show();
}
}
-
- if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_OPML_EXPORT_PATH) {
- Uri uri = data.getData();
- export(new OpmlWriter(), uri);
- }
-
- if (resultCode == Activity.RESULT_OK && requestCode == CHOOSE_HTML_EXPORT_PATH) {
- Uri uri = data.getData();
- export(new HtmlWriter(), uri);
- }
}
private void setDataFolderText() {
File f = UserPreferences.getDataFolder(null);
if (f != null) {
- findPreference(PREF_CHOOSE_DATA_DIR)
- .setSummary(f.getAbsolutePath());
+ findPreference(PREF_CHOOSE_DATA_DIR).setSummary(f.getAbsolutePath());
}
}
@@ -286,50 +155,6 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
}
- private void openOpmlExportPathPicker() {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
- Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
- .addCategory(Intent.CATEGORY_OPENABLE)
- .setType(CONTENT_TYPE_OPML)
- .putExtra(Intent.EXTRA_TITLE, DEFAULT_OPML_OUTPUT_NAME);
-
- // Creates an implicit intent to launch a file manager which lets
- // the user choose a specific directory to export to.
- try {
- startActivityForResult(intentPickAction, CHOOSE_OPML_EXPORT_PATH);
- return;
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "No activity found. Should never happen...");
- }
- }
-
- // If we are using a SDK lower than API 21 or the implicit intent failed
- // fallback to the legacy export process
- export(new OpmlWriter());
- }
-
- private void openHtmlExportPathPicker() {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
- Intent intentPickAction = new Intent(Intent.ACTION_CREATE_DOCUMENT)
- .addCategory(Intent.CATEGORY_OPENABLE)
- .setType(CONTENT_TYPE_HTML)
- .putExtra(Intent.EXTRA_TITLE, DEFAULT_HTML_OUTPUT_NAME);
-
- // Creates an implicit intent to launch a file manager which lets
- // the user choose a specific directory to export to.
- try {
- startActivityForResult(intentPickAction, CHOOSE_HTML_EXPORT_PATH);
- return;
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "No activity found. Should never happen...");
- }
- }
-
- // If we are using a SDK lower than API 21 or the implicit intent failed
- // fallback to the legacy export process
- export(new HtmlWriter());
- }
-
private void showChooseDataFolderDialog() {
ChooseDataFolderDialog.showDialog(
getActivity(), new ChooseDataFolderDialog.RunnableWithString() {