diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 67e8d56..0684340 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -8,19 +8,23 @@ android {
applicationId = "com.prangesoftwaresolutions.audioanchor"
minSdk = 21
targetSdk = 35
- versionCode = 31
- versionName = "2.4.0"
+ versionCode = 32
+ versionName = "2.5.0"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
+ resValue("string", "app_package_uri",
+ "package:" + android.defaultConfig.applicationId)
}
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-DEBUG"
isDebuggable = true
+ resValue("string", "app_package_uri",
+ "package:" + android.defaultConfig.applicationId + applicationIdSuffix)
}
}
compileOptions {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d141796..8484820 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
android:maxSdkVersion="32" />
+
diff --git a/app/src/main/java/com/prangesoftwaresolutions/audioanchor/activities/DirectoryActivity.java b/app/src/main/java/com/prangesoftwaresolutions/audioanchor/activities/DirectoryActivity.java
index da2f57c..6b5ba81 100644
--- a/app/src/main/java/com/prangesoftwaresolutions/audioanchor/activities/DirectoryActivity.java
+++ b/app/src/main/java/com/prangesoftwaresolutions/audioanchor/activities/DirectoryActivity.java
@@ -4,6 +4,7 @@
import android.content.ContentUris;
import android.content.CursorLoader;
import android.content.Loader;
+import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
@@ -19,6 +20,7 @@
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.preference.PreferenceManager;
import com.nambimobile.widgets.efab.FabOption;
import com.prangesoftwaresolutions.audioanchor.R;
@@ -135,7 +137,12 @@ public void onDestroyActionMode(ActionMode actionMode) {
}
private void addDirectory(boolean isParentDirectory) {
- File baseDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
+ String baseDirectoryPref = PreferenceManager.getDefaultSharedPreferences(this).getString(
+ getString(R.string.settings_directory_picker_initial_path_key), getString(R.string.settings_directory_picker_initial_path_default));
+ File baseDirectory = baseDirectoryPref.isBlank()
+ ? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
+ : new File(baseDirectoryPref);
+
FileDialog fileDialog = new FileDialog(this, baseDirectory, true, null, this);
fileDialog.addDirectoryListener(directory -> {
Directory.Type directoryType = isParentDirectory ? Directory.Type.PARENT_DIR : Directory.Type.SUB_DIR;
@@ -144,6 +151,12 @@ private void addDirectory(boolean isParentDirectory) {
mSynchronizer.addDirectory(newDirectory);
}
});
+ fileDialog.addDefaultDirectoryListener(directory -> {
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
+ editor.putString(getString(R.string.settings_directory_picker_initial_path_key), directory.getAbsolutePath());
+ editor.apply();
+ fileDialog.showDialog();
+ });
fileDialog.showDialog();
}
diff --git a/app/src/main/java/com/prangesoftwaresolutions/audioanchor/dialogs/FileDialog.java b/app/src/main/java/com/prangesoftwaresolutions/audioanchor/dialogs/FileDialog.java
index a1ba1ca..8b92384 100644
--- a/app/src/main/java/com/prangesoftwaresolutions/audioanchor/dialogs/FileDialog.java
+++ b/app/src/main/java/com/prangesoftwaresolutions/audioanchor/dialogs/FileDialog.java
@@ -4,7 +4,10 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
+import android.os.Build;
import android.os.Environment;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import androidx.annotation.NonNull;
import android.util.Log;
import android.view.View;
@@ -47,6 +50,7 @@ public interface DirectorySelectedListener {
private final ListenerList fileListenerList = new ListenerList<>();
private final ListenerList dirListenerList = new ListenerList<>();
+ private final ListenerList defaultDirListenerList = new ListenerList<>();
private final Activity activity;
private final boolean mSelectDirectory;
private String fileEndsWith;
@@ -56,9 +60,22 @@ public FileDialog(Activity activity, File initialPath, boolean selectDirectory,
this.activity = activity;
setFileEndsWith(fileEndsWith);
mSelectDirectory = selectDirectory;
+ mContext = context;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ StorageManager storageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
+ for (StorageVolume v: storageManager.getStorageVolumes()) {
+ File volumePath = v.getDirectory();
+ if (volumePath != null && volumePath.canRead()) {
+ ensureReachabilityOfPath(volumePath);
+ }
+ }
+ } else {
+ ensureReachabilityOfPath(Environment.getExternalStorageDirectory());
+ }
+
if (!initialPath.exists()) initialPath = Environment.getExternalStorageDirectory();
loadFileList(initialPath);
- mContext = context;
}
/**
@@ -86,6 +103,10 @@ public View getView(int position, View convertView, @NonNull ViewGroup parent) {
Log.d(TAG, currentPath.getPath());
fireDirectorySelectedEvent(currentPath);
});
+ builder.setNeutralButton(R.string.dialog_msg_set_default_dir, (dialog1, which) -> {
+ Log.d(TAG, currentPath.getPath());
+ fireDefaultDirectorySelectedEvent(currentPath);
+ });
}
builder.setNegativeButton(R.string.dialog_msg_cancel, (dialog1, which) -> {
if (dialog1 != null) {
@@ -131,6 +152,14 @@ public void removeDirectoryListener(DirectorySelectedListener listener) {
dirListenerList.remove(listener);
}
+ public void addDefaultDirectoryListener(DirectorySelectedListener listener) {
+ defaultDirListenerList.add(listener);
+ }
+
+ public void removeDefaultDirectoryListener(DirectorySelectedListener listener) {
+ defaultDirListenerList.remove(listener);
+ }
+
/**
* Show file dialog
*/
@@ -146,6 +175,10 @@ private void fireDirectorySelectedEvent(final File directory) {
dirListenerList.fireEvent(listener -> listener.directorySelected(directory));
}
+ private void fireDefaultDirectorySelectedEvent(final File directory) {
+ defaultDirListenerList.fireEvent(listener -> listener.directorySelected(directory));
+ }
+
private void loadFileList(File path) {
this.currentPath = path;
List fileList = new ArrayList<>();
@@ -200,6 +233,20 @@ private File getChosenFile(String fileChosen) {
private void setFileEndsWith(String fileEndsWith) {
this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase() : null;
}
+
+ private void ensureReachabilityOfPath(File path) {
+ Log.i("FileDialog.java", "Ensure reachability of " + path);
+ String filename = path.getName();
+ File parent = path.getParentFile();
+ while (parent != null) {
+ HashSet childDirs = childDirectories.get(parent.getAbsolutePath());
+ if (childDirs == null) childDirs = new HashSet<>();
+ childDirs.add(filename);
+ childDirectories.put(parent.getAbsolutePath(), childDirs);
+ filename = parent.getName();
+ parent = parent.getParentFile();
+ }
+ }
}
class ListenerList {
diff --git a/app/src/main/res/values/donttranslate.xml b/app/src/main/res/values/donttranslate.xml
index 26a380c..82e25b0 100644
--- a/app/src/main/res/values/donttranslate.xml
+++ b/app/src/main/res/values/donttranslate.xml
@@ -73,6 +73,9 @@
notification_backward_button
notification_forward_button
%d s
+ manage_external_storage
+ directory_picker_initial_path
+
album_id
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6c2923a..265f8ba 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,6 +100,9 @@
Notification backward button
Notification forward button
Skip interval for %s
+ Request \"All files access\"
+ Initial directory picker path
+
Title
@@ -141,7 +144,8 @@
You can select a single directory that contains audio files or a parent directory that contains several directories containing audio files.
- Select directory
+ Select
+ Set default
Enter the number of minutes for which the player should keep playing
OK
Cancel
diff --git a/app/src/main/res/xml-v26/settings.xml b/app/src/main/res/xml-v26/settings.xml
index d53f027..561add7 100644
--- a/app/src/main/res/xml-v26/settings.xml
+++ b/app/src/main/res/xml-v26/settings.xml
@@ -178,6 +178,13 @@
android:key="@string/settings_keep_deleted_key"
android:title="@string/settings_keep_deleted_label"
android:singleLineTitle="false" />
+
+
diff --git a/app/src/main/res/xml-v30/settings.xml b/app/src/main/res/xml-v30/settings.xml
new file mode 100644
index 0000000..e386898
--- /dev/null
+++ b/app/src/main/res/xml-v30/settings.xml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
index aa6d92c..d285ddd 100644
--- a/app/src/main/res/xml/settings.xml
+++ b/app/src/main/res/xml/settings.xml
@@ -154,6 +154,12 @@
android:defaultValue="@string/settings_keep_deleted_default"
android:key="@string/settings_keep_deleted_key"
android:title="@string/settings_keep_deleted_label" />
+
+