Merge branch 'master' into develop
This commit is contained in:
commit
663c715e3f
|
@ -14,8 +14,8 @@ android {
|
|||
// "1.2.3-SNAPSHOT" -> 1020300
|
||||
// "1.2.3-RC4" -> 1020304
|
||||
// "1.2.3" -> 1020395
|
||||
versionCode 2000005
|
||||
versionName "2.0.0-RC5"
|
||||
versionCode 2000006
|
||||
versionName "2.0.0-RC6"
|
||||
|
||||
multiDexEnabled false
|
||||
vectorDrawables.useSupportLibrary true
|
||||
|
|
|
@ -192,13 +192,6 @@
|
|||
<data android:mimeType="video/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.DirectoryChooserActivity"
|
||||
android:label="@string/choose_data_directory">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="de.danoeh.antennapod.activity.PreferenceActivity"/>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activity.OnlineFeedViewActivity"
|
||||
|
|
|
@ -1,333 +0,0 @@
|
|||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.FileObserver;
|
||||
import androidx.core.app.NavUtils;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import de.danoeh.antennapod.BuildConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
||||
/**
|
||||
* Let's the user choose a directory on the storage device. The selected folder
|
||||
* will be sent back to the starting activity as an activity result.
|
||||
*/
|
||||
public class DirectoryChooserActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "DirectoryChooserActivit";
|
||||
|
||||
private static final String CREATE_DIRECTORY_NAME = "AntennaPod";
|
||||
|
||||
public static final String RESULT_SELECTED_DIR = "selected_dir";
|
||||
public static final int RESULT_CODE_DIR_SELECTED = 1;
|
||||
|
||||
private Button butConfirm;
|
||||
private Button butCancel;
|
||||
private ImageButton butNavUp;
|
||||
private TextView txtvSelectedFolder;
|
||||
private ListView listDirectories;
|
||||
|
||||
private ArrayAdapter<String> listDirectoriesAdapter;
|
||||
private ArrayList<String> filenames;
|
||||
/** The directory that is currently being shown. */
|
||||
private File selectedDir;
|
||||
private File[] filesInDir;
|
||||
|
||||
private FileObserver fileObserver;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
setContentView(R.layout.directory_chooser);
|
||||
butConfirm = findViewById(R.id.butConfirm);
|
||||
butCancel = findViewById(R.id.butCancel);
|
||||
butNavUp = findViewById(R.id.butNavUp);
|
||||
txtvSelectedFolder = findViewById(R.id.txtvSelectedFolder);
|
||||
listDirectories = findViewById(R.id.directory_list);
|
||||
|
||||
butConfirm.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (isValidFile(selectedDir)) {
|
||||
if (selectedDir.list().length == 0) {
|
||||
returnSelectedFolder();
|
||||
} else {
|
||||
showNonEmptyDirectoryWarning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showNonEmptyDirectoryWarning() {
|
||||
AlertDialog.Builder adb = new AlertDialog.Builder(
|
||||
DirectoryChooserActivity.this);
|
||||
adb.setTitle(R.string.folder_not_empty_dialog_title);
|
||||
adb.setMessage(R.string.folder_not_empty_dialog_msg);
|
||||
adb.setNegativeButton(R.string.cancel_label,
|
||||
(dialog, which) -> dialog.dismiss());
|
||||
adb.setPositiveButton(R.string.confirm_label,
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
returnSelectedFolder();
|
||||
});
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
|
||||
butCancel.setOnClickListener(v -> {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
});
|
||||
|
||||
listDirectories.setOnItemClickListener((adapter, view, position, id) -> {
|
||||
Log.d(TAG, "Selected index: " + position);
|
||||
if (filesInDir != null && position >= 0
|
||||
&& position < filesInDir.length) {
|
||||
changeDirectory(filesInDir[position]);
|
||||
}
|
||||
});
|
||||
|
||||
butNavUp.setOnClickListener(v -> {
|
||||
File parent;
|
||||
if (selectedDir != null
|
||||
&& (parent = selectedDir.getParentFile()) != null) {
|
||||
changeDirectory(parent);
|
||||
}
|
||||
});
|
||||
|
||||
filenames = new ArrayList<>();
|
||||
listDirectoriesAdapter = new ArrayAdapter<>(this,
|
||||
android.R.layout.simple_list_item_1, filenames);
|
||||
listDirectories.setAdapter(listDirectoriesAdapter);
|
||||
changeDirectory(Environment.getExternalStorageDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the activity and returns the selected folder as a result. The
|
||||
* selected folder can also be null.
|
||||
*/
|
||||
private void returnSelectedFolder() {
|
||||
if (selectedDir != null && BuildConfig.DEBUG)
|
||||
Log.d(TAG, "Returning " + selectedDir.getAbsolutePath()
|
||||
+ " as result");
|
||||
Intent resultData = new Intent();
|
||||
if (selectedDir != null) {
|
||||
resultData.putExtra(RESULT_SELECTED_DIR,
|
||||
selectedDir.getAbsolutePath());
|
||||
}
|
||||
setResult(Activity.RESULT_OK, resultData);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (fileObserver != null) {
|
||||
fileObserver.stopWatching();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (fileObserver != null) {
|
||||
fileObserver.startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
listDirectoriesAdapter = null;
|
||||
fileObserver = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the directory that is currently being displayed.
|
||||
*
|
||||
* @param dir
|
||||
* The file the activity should switch to. This File must be
|
||||
* non-null and a directory, otherwise the displayed directory
|
||||
* will not be changed
|
||||
*/
|
||||
private void changeDirectory(File dir) {
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
File[] contents = dir.listFiles();
|
||||
if (contents != null) {
|
||||
int numDirectories = 0;
|
||||
for (File f : contents) {
|
||||
if (f.isDirectory()) {
|
||||
numDirectories++;
|
||||
}
|
||||
}
|
||||
filesInDir = new File[numDirectories];
|
||||
filenames.clear();
|
||||
for (int i = 0, counter = 0; i < numDirectories; counter++) {
|
||||
if (contents[counter].isDirectory()) {
|
||||
filesInDir[i] = contents[counter];
|
||||
filenames.add(contents[counter].getName());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
Arrays.sort(filesInDir);
|
||||
Collections.sort(filenames);
|
||||
selectedDir = dir;
|
||||
txtvSelectedFolder.setText(dir.getAbsolutePath());
|
||||
listDirectoriesAdapter.notifyDataSetChanged();
|
||||
fileObserver = createFileObserver(dir.getAbsolutePath());
|
||||
fileObserver.startWatching();
|
||||
Log.d(TAG, "Changed directory to " + dir.getAbsolutePath());
|
||||
} else {
|
||||
Log.d(TAG, "Could not change folder: contents of dir were null");
|
||||
}
|
||||
} else {
|
||||
if (dir == null) {
|
||||
Log.d(TAG, "Could not change folder: dir was null");
|
||||
} else {
|
||||
Log.d(TAG, "Could not change folder: dir is no directory");
|
||||
}
|
||||
}
|
||||
refreshButtonState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the state of the buttons depending on the currently selected file
|
||||
* or folder.
|
||||
*/
|
||||
private void refreshButtonState() {
|
||||
if (selectedDir != null) {
|
||||
butConfirm.setEnabled(isValidFile(selectedDir));
|
||||
supportInvalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/** Refresh the contents of the directory that is currently shown. */
|
||||
private void refreshDirectory() {
|
||||
if (selectedDir != null) {
|
||||
changeDirectory(selectedDir);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets up a FileObserver to watch the current directory. */
|
||||
private FileObserver createFileObserver(String path) {
|
||||
return new FileObserver(path, FileObserver.CREATE | FileObserver.DELETE
|
||||
| FileObserver.MOVED_FROM | FileObserver.MOVED_TO) {
|
||||
|
||||
@Override
|
||||
public void onEvent(int event, String path) {
|
||||
Log.d(TAG, "FileObserver received event " + event);
|
||||
runOnUiThread(DirectoryChooserActivity.this::refreshDirectory);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
menu.findItem(R.id.new_folder_item).setVisible(isValidFile(selectedDir));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.directory_chooser, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
case R.id.new_folder_item:
|
||||
openNewFolderDialog();
|
||||
return true;
|
||||
case R.id.set_to_default_folder_item:
|
||||
selectedDir = null;
|
||||
returnSelectedFolder();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a confirmation dialog that asks the user if he wants to create a
|
||||
* new folder.
|
||||
*/
|
||||
private void openNewFolderDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.create_folder_label);
|
||||
builder.setMessage(String.format(getString(R.string.create_folder_msg),
|
||||
CREATE_DIRECTORY_NAME));
|
||||
builder.setNegativeButton(R.string.cancel_label,
|
||||
(dialog, which) -> dialog.dismiss());
|
||||
builder.setPositiveButton(R.string.confirm_label,
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
int msg = createFolder();
|
||||
Toast t = Toast.makeText(DirectoryChooserActivity.this,
|
||||
msg, Toast.LENGTH_SHORT);
|
||||
t.show();
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new folder in the current directory with the name
|
||||
* CREATE_DIRECTORY_NAME.
|
||||
*/
|
||||
private int createFolder() {
|
||||
if (selectedDir == null) {
|
||||
return R.string.create_folder_error;
|
||||
} else if (selectedDir.canWrite()) {
|
||||
File newDir = new File(selectedDir, CREATE_DIRECTORY_NAME);
|
||||
if (!newDir.exists()) {
|
||||
boolean result = newDir.mkdir();
|
||||
if (result) {
|
||||
return R.string.create_folder_success;
|
||||
} else {
|
||||
return R.string.create_folder_error;
|
||||
}
|
||||
} else {
|
||||
return R.string.create_folder_error_already_exists;
|
||||
}
|
||||
} else {
|
||||
return R.string.create_folder_error_no_write_access;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the selected file or directory would be valid selection. */
|
||||
private boolean isValidFile(File file) {
|
||||
return file != null && file.isDirectory() && file.canRead() && file.canWrite();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +1,25 @@
|
|||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
|
||||
|
||||
/** Is show if there is now external storage available. */
|
||||
/**
|
||||
* Is show if there is now external storage available.
|
||||
*/
|
||||
public class StorageErrorActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "StorageErrorActivity";
|
||||
|
||||
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 = 42;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
|
@ -41,51 +28,11 @@ public class StorageErrorActivity extends AppCompatActivity {
|
|||
setContentView(R.layout.storage_error);
|
||||
|
||||
Button btnChooseDataFolder = findViewById(R.id.btnChooseDataFolder);
|
||||
btnChooseDataFolder.setOnClickListener(v -> {
|
||||
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT &&
|
||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
showChooseDataFolderDialog();
|
||||
} else {
|
||||
openDirectoryChooser();
|
||||
}
|
||||
});
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
int readPermission = ActivityCompat.checkSelfPermission(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
int writePermission = ActivityCompat.checkSelfPermission(this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (readPermission != PackageManager.PERMISSION_GRANTED ||
|
||||
writePermission != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermission();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void requestPermission() {
|
||||
ActivityCompat.requestPermissions(this, EXTERNAL_STORAGE_PERMISSIONS,
|
||||
PERMISSION_REQUEST_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
private void openDirectoryChooser() {
|
||||
Intent intent = new Intent(this, DirectoryChooserActivity.class);
|
||||
startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
String[] permissions,
|
||||
int[] grantResults) {
|
||||
if (requestCode != PERMISSION_REQUEST_EXTERNAL_STORAGE || grantResults.length != 2) {
|
||||
return;
|
||||
}
|
||||
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
|
||||
grantResults[1] != PackageManager.PERMISSION_GRANTED) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.choose_data_directory_permission_rationale)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> requestPermission())
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
|
||||
.show();
|
||||
}
|
||||
btnChooseDataFolder.setOnClickListener(v ->
|
||||
ChooseDataFolderDialog.showDialog(this, path -> {
|
||||
UserPreferences.setDataFolder(path);
|
||||
leaveErrorState();
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,55 +55,6 @@ public class StorageErrorActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
// see PreferenceController.showChooseDataFolderDialog()
|
||||
private void showChooseDataFolderDialog() {
|
||||
ChooseDataFolderDialog.showDialog(
|
||||
this, new ChooseDataFolderDialog.RunnableWithString() {
|
||||
@Override
|
||||
public void run(final String folder) {
|
||||
UserPreferences.setDataFolder(folder);
|
||||
leaveErrorState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == Activity.RESULT_OK
|
||||
&& requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
||||
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
|
||||
|
||||
File path;
|
||||
if (dir != null) {
|
||||
path = new File(dir);
|
||||
} else {
|
||||
path = getExternalFilesDir(null);
|
||||
}
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
String message = null;
|
||||
if (!path.exists()) {
|
||||
message = String.format(getString(R.string.folder_does_not_exist_error), dir);
|
||||
} else if (!path.canRead()) {
|
||||
message = String.format(getString(R.string.folder_not_readable_error), dir);
|
||||
} else if (!path.canWrite()) {
|
||||
message = String.format(getString(R.string.folder_not_writable_error), dir);
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
Log.d(TAG, "Setting data folder: " + dir);
|
||||
UserPreferences.setDataFolder(dir);
|
||||
leaveErrorState();
|
||||
} else {
|
||||
AlertDialog.Builder ab = new AlertDialog.Builder(this);
|
||||
ab.setMessage(message);
|
||||
ab.setPositiveButton(android.R.string.ok, null);
|
||||
ab.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void leaveErrorState() {
|
||||
finish();
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -9,29 +8,25 @@ import android.view.ViewGroup;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
|
||||
|
||||
|
||||
public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.ViewHolder> {
|
||||
private final ChooseDataFolderDialog.RunnableWithString selectionHandler;
|
||||
private final Consumer<String> selectionHandler;
|
||||
private final String currentPath;
|
||||
private final List<StoragePath> entries;
|
||||
private final String freeSpaceString;
|
||||
private Dialog dialog;
|
||||
|
||||
public DataFolderAdapter(Context context, ChooseDataFolderDialog.RunnableWithString selectionHandler) {
|
||||
public DataFolderAdapter(Context context, @NonNull Consumer<String> selectionHandler) {
|
||||
this.entries = getStorageEntries(context);
|
||||
this.currentPath = getCurrentPath();
|
||||
this.selectionHandler = selectionHandler;
|
||||
|
@ -56,8 +51,10 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
|
|||
holder.path.setText(storagePath.getShortPath());
|
||||
holder.size.setText(String.format(freeSpaceString, freeSpace, totalSpace));
|
||||
holder.progressBar.setProgress(storagePath.getUsagePercentage());
|
||||
holder.root.setOnClickListener((View v) -> selectAndDismiss(storagePath));
|
||||
holder.radioButton.setOnClickListener((View v) -> selectAndDismiss(storagePath));
|
||||
View.OnClickListener selectListener = v -> selectionHandler.accept(storagePath.getFullPath());
|
||||
holder.root.setOnClickListener(selectListener);
|
||||
holder.radioButton.setOnClickListener(selectListener);
|
||||
|
||||
if (storagePath.getFullPath().equals(currentPath)) {
|
||||
holder.radioButton.toggle();
|
||||
}
|
||||
|
@ -65,20 +62,14 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
|
|||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (currentPath == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return entries.size();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
private String getCurrentPath() {
|
||||
File dataFolder = UserPreferences.getDataFolder(null);
|
||||
if (dataFolder != null) return dataFolder.getAbsolutePath();
|
||||
if (dataFolder != null) {
|
||||
return dataFolder.getAbsolutePath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -86,28 +77,27 @@ public class DataFolderAdapter extends RecyclerView.Adapter<DataFolderAdapter.Vi
|
|||
File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
|
||||
final List<StoragePath> entries = new ArrayList<>(mediaDirs.length);
|
||||
for (File dir : mediaDirs) {
|
||||
if (isNotWritable(dir)) continue;
|
||||
|
||||
if (!isWritable(dir)) {
|
||||
continue;
|
||||
}
|
||||
entries.add(new StoragePath(dir.getAbsolutePath()));
|
||||
}
|
||||
if (entries.isEmpty() && isWritable(context.getFilesDir())) {
|
||||
entries.add(new StoragePath(context.getFilesDir().getAbsolutePath()));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private boolean isNotWritable(File dir) {
|
||||
return dir == null || !dir.exists() || !dir.canRead() || !dir.canWrite();
|
||||
}
|
||||
|
||||
private void selectAndDismiss(StoragePath storagePath) {
|
||||
selectionHandler.run(storagePath.getFullPath());
|
||||
dialog.dismiss();
|
||||
private boolean isWritable(File dir) {
|
||||
return dir != null && dir.exists() && dir.canRead() && dir.canWrite();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private View root;
|
||||
private TextView path;
|
||||
private TextView size;
|
||||
private RadioButton radioButton;
|
||||
private ProgressBar progressBar;
|
||||
private final View root;
|
||||
private final TextView path;
|
||||
private final TextView size;
|
||||
private final RadioButton radioButton;
|
||||
private final ProgressBar progressBar;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
|
||||
import android.view.View;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.danoeh.antennapod.R;
|
||||
|
@ -11,29 +12,7 @@ import de.danoeh.antennapod.adapter.DataFolderAdapter;
|
|||
|
||||
public class ChooseDataFolderDialog {
|
||||
|
||||
public abstract static class RunnableWithString implements Runnable {
|
||||
public RunnableWithString() {
|
||||
super();
|
||||
}
|
||||
public abstract void run(final String arg);
|
||||
@Override public void run() {
|
||||
throw new IllegalArgumentException("Expect one String parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
private ChooseDataFolderDialog() {}
|
||||
|
||||
public static void showDialog(final Context context, RunnableWithString handlerFunc) {
|
||||
DataFolderAdapter adapter = new DataFolderAdapter(context, handlerFunc);
|
||||
|
||||
if (adapter.getItemCount() == 0) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.error_label)
|
||||
.setMessage(R.string.external_storage_error_msg)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
public static void showDialog(final Context context, Consumer<String> handlerFunc) {
|
||||
|
||||
View content = View.inflate(context, R.layout.choose_data_folder_dialog, null);
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
|
@ -43,9 +22,22 @@ public class ChooseDataFolderDialog {
|
|||
.setNegativeButton(R.string.cancel_label, null)
|
||||
.create();
|
||||
((RecyclerView) content.findViewById(R.id.recyclerView)).setLayoutManager(new LinearLayoutManager(context));
|
||||
|
||||
DataFolderAdapter adapter = new DataFolderAdapter(context, path -> {
|
||||
dialog.dismiss();
|
||||
handlerFunc.accept(path);
|
||||
});
|
||||
((RecyclerView) content.findViewById(R.id.recyclerView)).setAdapter(adapter);
|
||||
adapter.setDialog(dialog);
|
||||
dialog.show();
|
||||
|
||||
if (adapter.getItemCount() > 0) {
|
||||
dialog.show();
|
||||
} else {
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.error_label)
|
||||
.setMessage(R.string.external_storage_error_msg)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +1,9 @@
|
|||
package de.danoeh.antennapod.fragment.preferences;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
|
||||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
|
||||
|
@ -23,10 +14,6 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
|
|||
private static final String TAG = "StoragePrefFragment";
|
||||
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;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
|
@ -47,36 +34,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
|
||||
private void setupStorageScreen() {
|
||||
final Activity activity = getActivity();
|
||||
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) {
|
||||
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) {
|
||||
openDirectoryChooser();
|
||||
} else {
|
||||
requestPermission();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
ChooseDataFolderDialog.showDialog(getContext(), path -> {
|
||||
UserPreferences.setDataFolder(path);
|
||||
setDataFolderText();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -104,65 +67,10 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat {
|
|||
);
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
||||
String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
|
||||
|
||||
File path;
|
||||
if (dir != null) {
|
||||
path = new File(dir);
|
||||
} else {
|
||||
path = getActivity().getExternalFilesDir(null);
|
||||
}
|
||||
String message = null;
|
||||
final Context context = getActivity().getApplicationContext();
|
||||
if (!path.exists()) {
|
||||
message = String.format(context.getString(R.string.folder_does_not_exist_error), dir);
|
||||
} else if (!path.canRead()) {
|
||||
message = String.format(context.getString(R.string.folder_not_readable_error), dir);
|
||||
} else if (!path.canWrite()) {
|
||||
message = String.format(context.getString(R.string.folder_not_writable_error), dir);
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
Log.d(TAG, "Setting data folder: " + dir);
|
||||
UserPreferences.setDataFolder(dir);
|
||||
setDataFolderText();
|
||||
} else {
|
||||
AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
|
||||
ab.setMessage(message);
|
||||
ab.setPositiveButton(android.R.string.ok, null);
|
||||
ab.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setDataFolderText() {
|
||||
File f = UserPreferences.getDataFolder(null);
|
||||
if (f != null) {
|
||||
findPreference(PREF_CHOOSE_DATA_DIR).setSummary(f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private void requestPermission() {
|
||||
ActivityCompat.requestPermissions(getActivity(), EXTERNAL_STORAGE_PERMISSIONS,
|
||||
PERMISSION_REQUEST_EXTERNAL_STORAGE);
|
||||
}
|
||||
|
||||
private void openDirectoryChooser() {
|
||||
Activity activity = getActivity();
|
||||
Intent intent = new Intent(activity, DirectoryChooserActivity.class);
|
||||
activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
|
||||
}
|
||||
|
||||
private void showChooseDataFolderDialog() {
|
||||
ChooseDataFolderDialog.showDialog(
|
||||
getActivity(), new ChooseDataFolderDialog.RunnableWithString() {
|
||||
@Override
|
||||
public void run(final String folder) {
|
||||
UserPreferences.setDataFolder(folder);
|
||||
setDataFolderText();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class ShownotesWebView extends WebView implements View.OnLongClickListene
|
|||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (Timeline.isTimecodeLink(url) && timecodeSelectedListener != null) {
|
||||
timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(selectedUrl));
|
||||
timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(url));
|
||||
} else {
|
||||
IntentUtils.openInBrowser(getContext(), url);
|
||||
}
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:background="@android:color/darker_gray">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/footer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentBottom="true" >
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dip"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?android:attr/dividerVertical" />
|
||||
|
||||
<View
|
||||
android:id="@+id/horizontal_divider"
|
||||
android:layout_width="1dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?android:attr/dividerVertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/butCancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toLeftOf="@id/horizontal_divider"
|
||||
android:layout_toStartOf="@id/horizontal_divider"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/cancel_label" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/butConfirm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/horizontal_divider"
|
||||
android:layout_toEndOf="@id/horizontal_divider"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:text="@string/confirm_label" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/directory_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true" >
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/butNavUp"
|
||||
android:contentDescription="@string/navigate_upwards_label"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="?attr/navigation_up"
|
||||
tools:src="@drawable/navigation_up"
|
||||
tools:background="@android:color/holo_green_dark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvSelectedFolderLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_toRightOf="@id/butNavUp"
|
||||
android:layout_toEndOf="@id/butNavUp"
|
||||
android:text="@string/selected_folder_label"
|
||||
android:textStyle="bold"
|
||||
tools:background="@android:color/holo_green_dark">
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvSelectedFolder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_below="@id/txtvSelectedFolderLabel"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_toRightOf="@id/butNavUp"
|
||||
android:layout_toEndOf="@id/butNavUp"
|
||||
android:ellipsize="start"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="true"
|
||||
tools:text="/path/to/selected/folder"
|
||||
tools:background="@android:color/holo_green_dark"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_below="@id/butNavUp"
|
||||
android:background="?android:attr/dividerHorizontal" />
|
||||
</RelativeLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/directory_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_above="@id/footer"
|
||||
android:layout_below="@id/directory_info" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/new_folder_item"
|
||||
android:title="@string/create_folder_label"
|
||||
app:icon="?attr/content_new"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
<item
|
||||
android:id="@+id/set_to_default_folder_item"
|
||||
android:title="@string/set_to_default_folder"
|
||||
app:showAsAction="collapseActionView" />
|
||||
|
||||
</menu>
|
|
@ -65,7 +65,7 @@ project.ext {
|
|||
rxAndroidVersion = "2.1.1"
|
||||
rxJavaVersion = "2.2.2"
|
||||
iconifyVersion = "2.2.2"
|
||||
audioPlayerVersion = "v1.0.17"
|
||||
audioPlayerVersion = "v2.0.0"
|
||||
|
||||
// Google Play build
|
||||
wearableSupportVersion = "2.6.0"
|
||||
|
|
|
@ -65,11 +65,12 @@ public class HttpDownloader extends Downloader {
|
|||
final URI uri = URIUtil.getURIFromRequestUrl(request.getSource());
|
||||
Request.Builder httpReq = new Request.Builder().url(uri.toURL());
|
||||
httpReq.tag(request);
|
||||
httpReq.cacheControl(new CacheControl.Builder().noStore().build());
|
||||
|
||||
if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
|
||||
// set header explicitly so that okhttp doesn't do transparent gzip
|
||||
Log.d(TAG, "addHeader(\"Accept-Encoding\", \"identity\")");
|
||||
httpReq.addHeader("Accept-Encoding", "identity");
|
||||
httpReq.cacheControl(new CacheControl.Builder().noStore().build());
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(request.getLastModified())) {
|
||||
|
|
|
@ -274,7 +274,7 @@ public class DownloadRequester implements DownloadStateProvider {
|
|||
}
|
||||
|
||||
File dest;
|
||||
if (feedmedia.getFile_url() != null) {
|
||||
if (feedmedia.getFile_url() != null && new File(feedmedia.getFile_url()).exists()) {
|
||||
dest = new File(feedmedia.getFile_url());
|
||||
} else {
|
||||
dest = new File(getMediafilePath(feedmedia), getMediafilename(feedmedia));
|
||||
|
|
|
@ -4,7 +4,10 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.URLConnection;
|
||||
import java.util.zip.CheckedOutputStream;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
|
@ -80,7 +83,9 @@ public class ChapterUtils {
|
|||
CountingInputStream in = null;
|
||||
try {
|
||||
URL url = new URL(p.getStreamUrl());
|
||||
in = new CountingInputStream(url.openStream());
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT);
|
||||
in = new CountingInputStream(urlConnection.getInputStream());
|
||||
List<Chapter> chapters = readChaptersFrom(in);
|
||||
if (!chapters.isEmpty()) {
|
||||
p.setChapters(chapters);
|
||||
|
@ -149,7 +154,9 @@ public class ChapterUtils {
|
|||
InputStream input = null;
|
||||
try {
|
||||
URL url = new URL(media.getStreamUrl());
|
||||
input = url.openStream();
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT);
|
||||
input = urlConnection.getInputStream();
|
||||
if (input != null) {
|
||||
readOggChaptersFromInputStream(media, input);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.preference.PreferenceManager;
|
|||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import org.antennapod.audio.MediaPlayer;
|
||||
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
@ -17,7 +18,7 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
|
|||
private static final String TAG = "AudioPlayer";
|
||||
|
||||
public AudioPlayer(Context context) {
|
||||
super(context);
|
||||
super(context, true, ClientConfig.USER_AGENT);
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> {
|
||||
if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) {
|
||||
|
|
Loading…
Reference in New Issue