-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android: Support of SAF #2699
Android: Support of SAF #2699
Conversation
I can already see the async loading: Searching for games please come back in 2 hours. Send hate to Google kthxbye |
It is now possible to use a custom soundfont by putting the .sf2 in the games folder (only on the android side). As discussed with Ghabry, the idea is to also provide a default sounfont in the apk and drop Timidity. |
The browser now scans games asynchronously. I will later add a visual feedback explaining that it's processing. |
The games list is now cached and only refreshed when the player click the "refresh" button, or change the games folder in settings. |
The speed of game scanning has been dramatically improved, it's not a problem anymore. |
The user doesn't need anymore to choose the games folder at each startup, even on API 30. |
The favorite ("like") feature is now instant. It previously used to rescan the games folder. The app has never been so snappy. |
I researced the query stuff a bit more (good job btw) If yes it is a folder. Should make recursive scanning possible again :) |
Here is a patch to make the native part faster and to fix some API warnings diff --git a/builds/android/app/src/main/java/org/easyrpg/player/player/SafFile.java b/builds/android/app/src/main/java/org/easyrpg/player/player/SafFile.java
index f26e09f5..050d7ea6 100644
--- a/builds/android/app/src/main/java/org/easyrpg/player/player/SafFile.java
+++ b/builds/android/app/src/main/java/org/easyrpg/player/player/SafFile.java
@@ -1,14 +1,18 @@
package org.easyrpg.player.player;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
import android.util.Log;
import androidx.documentfile.provider.DocumentFile;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
/**
* A wrapper around SAF for use from JNI
@@ -82,7 +86,7 @@ public class SafFile {
}
// No difference between read mode and binary read mode
- try (ParcelFileDescriptor fd = context.getContentResolver().openFile(root.getUri(), "r", null)) {
+ try (ParcelFileDescriptor fd = context.getContentResolver().openFileDescriptor(root.getUri(), "r")) {
return fd.detachFd();
} catch (IOException e) {
return -1;
@@ -119,7 +123,7 @@ public class SafFile {
actualFile = df.getUri();
}
- try (ParcelFileDescriptor fd = context.getContentResolver().openFile(actualFile, mode, null)) {
+ try (ParcelFileDescriptor fd = context.getContentResolver().openFileDescriptor(actualFile, mode)) {
return fd.detachFd();
} catch (IOException e) {
return -1;
@@ -131,13 +135,33 @@ public class SafFile {
return null;
}
+ Uri root_uri = root.getUri();
+
ArrayList<String> files = new ArrayList<>();
ArrayList<Boolean> is_dir = new ArrayList<>();
- for (DocumentFile file: root.listFiles()) {
- files.add(file.getName());
- is_dir.add(file.isDirectory());
+ final ContentResolver resolver = context.getContentResolver();
+ final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(root_uri, DocumentsContract.getDocumentId(root_uri));
+
+ Cursor c = resolver.query(childrenUri,new String[] {
+ DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+ DocumentsContract.Document.COLUMN_MIME_TYPE },
+ null, null, null);
+ while (c.moveToNext()) {
+ // The name can be something like ``primary:path/of/the/folder/the_file.txt
+ // Get rid of all that junk
+ String file_path = c.getString(0);
+ int slash_pos = file_path.lastIndexOf('/');
+ if (slash_pos != -1) {
+ file_path = file_path.substring(slash_pos + 1);
+ }
+
+ String mime_type = c.getString(1);
+
+ files.add(file_path);
+ is_dir.add(mime_type.equals(DocumentsContract.Document.MIME_TYPE_DIR));
}
+ c.close();
return new DirectoryTree(files, is_dir);
} |
//String str = SettingsManager.getEasyRPGFolder() + "/rtp"; | ||
// Log.v("SDL", "getRtpPath " + str); | ||
//return str; | ||
return SettingsManager.getRtpFolder().toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this return a valid SAF Uri? (content:// and stuff)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tested it.
You must use return SettingsManager.getRtpFolder().getUri().toString();
, then it will work.Yours gives back the class name + pointer (Standard toString impl)
The recursive games search is back and is fast. The game browser is officially better than before. :) I've also moved all the file's related operation to the Helper class in order to centralized them, in case Google decides to change all the rules again. |
@BlisterB added my two commits as requested |
@BlisterB You can now grab the APK from the PR builder in case you want to do some native code testing. Finally fixed the build ^^ |
The app can now retrieve the encoding of the game, it can also save another encoding settings. Thank you @Ghabry ;) |
That is due to missing Midi support. It still uses "get_timidity_path" JNI stuff on Android. Have to patch this out and hook it in with fluidsynth. |
The Gamebrowser activity now recovers from the crash of a child activity (a game crashed for example). |
The input layouts feature has been reworked. You can continue to create multiple input layouts and choose an active layout. |
The Audio Settings activity now display a checkbox to enable/disable custom SoundFounts. There is also some text explaining the feature and the .sf2 currently used (the first .sf2 fount in the games folder). |
@BlisterB |
Hello @Ghabry |
I guess "Report a bug" is also kinda broken? Because attaching the files does not really work. On the good news: We are down to ca. 5 bug reports per month so looks a bit as if we do not really need it anymore (and can just link e.g. Github) |
Dropped now Timidity support completely. When no soundfont is provided Player uses now FmMidi. Also the |
About the "TODO: Convert to SAF" functions: They can be all removed. I expect that SAF makes the folder the user selects writable solving this permission mess. |
@BlisterB Soundfont stuff works now properly. When a game ran before then after changing the setting the app must be restarted due to some global state in C++ Player but this is no big deal imo. Is not like this is changed alot ^^. Btw is the "games" folder still created in easyrpg? I mean it is not really needed anymore but maybe some users want to stay organized, so just create it by default ^^ Some nits about the terms: I suggest changing the following terms: Settings -> Game Directories: Change to "EasyRPG Folder" Then the wording in "EasyRPG folder":
Audio:
Also the path displayed for Soundfont should be trimmed so they do not contain garbage like |
The soundfont feature works great! 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just few nits.
We probably should document somewhere, that the android files have a different license.
builds/android/app/src/main/java/org/easyrpg/player/button_mapping/ButtonMappingActivity.java
Show resolved
Hide resolved
The basic app functionality appears to work 👍 Can you quickly reformat the files IniFileManager.java and Game.java with your IDE? They look very messy indentationn wise. |
- Bump dependencies - Fix warnings and formating issues in AndroidManifest.xml - Revert SDL changes
This PR add the support of Android SAF in order to be compatible with API 30 and the new rules about scoped storage permissions.
What has been done :
Important notes :
- SAF is really slow and using tricks to avoid this system would probably lead to future incompatibilities.What remains to do :
.ini
file--soundfont
argument in the command line)Fix #1041
Fix #1330
Fix #2434