ANDROID: Use SAF if a directory is not writeable
This commit is contained in:
parent
e79e58e077
commit
4ac31d5481
5 changed files with 72 additions and 7 deletions
|
@ -68,7 +68,14 @@ bool POSIXFilesystemNode::isReadable() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool POSIXFilesystemNode::isWritable() const {
|
bool POSIXFilesystemNode::isWritable() const {
|
||||||
return access(_path.c_str(), W_OK) == 0;
|
bool retVal = access(_path.c_str(), W_OK) == 0;
|
||||||
|
#if defined(ANDROID_PLAIN_PORT)
|
||||||
|
if (!retVal) {
|
||||||
|
// Update return value if going through Android's SAF grants the permission
|
||||||
|
retVal = JNI::isDirectoryWritableWithSAF(_path);
|
||||||
|
}
|
||||||
|
#endif // ANDROID_PLAIN_PORT
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void POSIXFilesystemNode::setFlags() {
|
void POSIXFilesystemNode::setFlags() {
|
||||||
|
|
|
@ -91,6 +91,7 @@ jmethodID JNI::_MID_deinitSurface = 0;
|
||||||
jmethodID JNI::_MID_createDirectoryWithSAF = 0;
|
jmethodID JNI::_MID_createDirectoryWithSAF = 0;
|
||||||
jmethodID JNI::_MID_createFileWithSAF = 0;
|
jmethodID JNI::_MID_createFileWithSAF = 0;
|
||||||
jmethodID JNI::_MID_closeFileWithSAF = 0;
|
jmethodID JNI::_MID_closeFileWithSAF = 0;
|
||||||
|
jmethodID JNI::_MID_isDirectoryWritableWithSAF = 0;
|
||||||
|
|
||||||
jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0;
|
jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0;
|
||||||
|
|
||||||
|
@ -561,6 +562,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
|
||||||
FIND_METHOD(, createDirectoryWithSAF, "(Ljava/lang/String;)Z");
|
FIND_METHOD(, createDirectoryWithSAF, "(Ljava/lang/String;)Z");
|
||||||
FIND_METHOD(, createFileWithSAF, "(Ljava/lang/String;)Ljava/lang/String;");
|
FIND_METHOD(, createFileWithSAF, "(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
FIND_METHOD(, closeFileWithSAF, "(Ljava/lang/String;)V");
|
FIND_METHOD(, closeFileWithSAF, "(Ljava/lang/String;)V");
|
||||||
|
FIND_METHOD(, isDirectoryWritableWithSAF, "(Ljava/lang/String;)Z");
|
||||||
|
|
||||||
_jobj_egl = env->NewGlobalRef(egl);
|
_jobj_egl = env->NewGlobalRef(egl);
|
||||||
_jobj_egl_display = env->NewGlobalRef(egl_display);
|
_jobj_egl_display = env->NewGlobalRef(egl_display);
|
||||||
|
@ -814,7 +816,6 @@ Common::U32String JNI::createFileWithSAF(const Common::String &filePath) {
|
||||||
|
|
||||||
Common::U32String hackyFilenameStr = convertFromJString(env, hackyFilenameJSTR);
|
Common::U32String hackyFilenameStr = convertFromJString(env, hackyFilenameJSTR);
|
||||||
|
|
||||||
//LOGD("JNI - _MID_createFileWithSAF returned %s", hackyFilenameStr.c_str());
|
|
||||||
env->DeleteLocalRef(hackyFilenameJSTR);
|
env->DeleteLocalRef(hackyFilenameJSTR);
|
||||||
|
|
||||||
return hackyFilenameStr;
|
return hackyFilenameStr;
|
||||||
|
@ -836,4 +837,22 @@ void JNI::closeFileWithSAF(const Common::String &hackyFilename) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JNI::isDirectoryWritableWithSAF(const Common::String &dirPath) {
|
||||||
|
JNIEnv *env = JNI::getEnv();
|
||||||
|
jstring javaDirPath = env->NewStringUTF(dirPath.c_str());
|
||||||
|
|
||||||
|
bool isWritable = env->CallBooleanMethod(_jobj, _MID_isDirectoryWritableWithSAF, javaDirPath);
|
||||||
|
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
LOGE("JNI - Failed to check if directory is writable SAF enhanced method");
|
||||||
|
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
env->ExceptionClear();
|
||||||
|
isWritable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isWritable;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -87,6 +87,7 @@ public:
|
||||||
static bool createDirectoryWithSAF(const Common::String &dirPath);
|
static bool createDirectoryWithSAF(const Common::String &dirPath);
|
||||||
static Common::U32String createFileWithSAF(const Common::String &filePath);
|
static Common::U32String createFileWithSAF(const Common::String &filePath);
|
||||||
static void closeFileWithSAF(const Common::String &hackyFilename);
|
static void closeFileWithSAF(const Common::String &hackyFilename);
|
||||||
|
static bool isDirectoryWritableWithSAF(const Common::String &dirPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static JavaVM *_vm;
|
static JavaVM *_vm;
|
||||||
|
@ -119,6 +120,7 @@ private:
|
||||||
static jmethodID _MID_createDirectoryWithSAF;
|
static jmethodID _MID_createDirectoryWithSAF;
|
||||||
static jmethodID _MID_createFileWithSAF;
|
static jmethodID _MID_createFileWithSAF;
|
||||||
static jmethodID _MID_closeFileWithSAF;
|
static jmethodID _MID_closeFileWithSAF;
|
||||||
|
static jmethodID _MID_isDirectoryWritableWithSAF;
|
||||||
|
|
||||||
static jmethodID _MID_EGL10_eglSwapBuffers;
|
static jmethodID _MID_EGL10_eglSwapBuffers;
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
|
||||||
abstract protected boolean createDirectoryWithSAF(String dirPath);
|
abstract protected boolean createDirectoryWithSAF(String dirPath);
|
||||||
abstract protected String createFileWithSAF(String filePath);
|
abstract protected String createFileWithSAF(String filePath);
|
||||||
abstract protected void closeFileWithSAF(String hackyFilename);
|
abstract protected void closeFileWithSAF(String hackyFilename);
|
||||||
|
abstract protected boolean isDirectoryWritableWithSAF(String dirPath);
|
||||||
|
|
||||||
public ScummVM(AssetManager asset_manager, SurfaceHolder holder, final MyScummVMDestroyedCallback scummVMDestroyedCallback) {
|
public ScummVM(AssetManager asset_manager, SurfaceHolder holder, final MyScummVMDestroyedCallback scummVMDestroyedCallback) {
|
||||||
_asset_manager = asset_manager;
|
_asset_manager = asset_manager;
|
||||||
|
|
|
@ -417,19 +417,19 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
|
||||||
|
|
||||||
// TODO - "Swipe" behavior does not seem to work currently. Should we support it?
|
// TODO - "Swipe" behavior does not seem to work currently. Should we support it?
|
||||||
public void swipeLeft() {
|
public void swipeLeft() {
|
||||||
//Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeLeft");
|
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeLeft");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void swipeRight() {
|
public void swipeRight() {
|
||||||
//Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeRight" );
|
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeRight" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void swipeDown() {
|
public void swipeDown() {
|
||||||
//Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeDown" );
|
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeDown" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void swipeUp() {
|
public void swipeUp() {
|
||||||
//Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeUp ");
|
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeUp ");
|
||||||
}
|
}
|
||||||
public void onKey(int key, int[] keysAround) {
|
public void onKey(int key, int[] keysAround) {
|
||||||
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onKey key: " + key );
|
// Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - onKey key: " + key );
|
||||||
|
@ -583,7 +583,6 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private class MyScummVM extends ScummVM {
|
private class MyScummVM extends ScummVM {
|
||||||
|
|
||||||
public MyScummVM(SurfaceHolder holder, final MyScummVMDestroyedCallback destroyedCallback) {
|
public MyScummVM(SurfaceHolder holder, final MyScummVMDestroyedCallback destroyedCallback) {
|
||||||
|
@ -793,6 +792,36 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
|
||||||
return retRes[0];
|
return retRes[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is a simplified version of createDirectoryWithSAF
|
||||||
|
// TODO Maybe we could merge isDirectoryWritableWithSAF() with createDirectoryWithSAF() using an extra argument parameter
|
||||||
|
@Override
|
||||||
|
protected boolean isDirectoryWritableWithSAF(String dirPath) {
|
||||||
|
final boolean[] retRes = {false};
|
||||||
|
|
||||||
|
Log.d(ScummVM.LOG_TAG, "Check if folder writable: " + dirPath);
|
||||||
|
File folderToCheck = new File (dirPath);
|
||||||
|
if (folderToCheck.canWrite()) {
|
||||||
|
Log.d(ScummVM.LOG_TAG, "This path has write permission!" + dirPath);
|
||||||
|
} else {
|
||||||
|
Log.d(ScummVM.LOG_TAG, "Trying to get write access with SAF");
|
||||||
|
if (getStorageAccessFrameworkTreeUri() == null) {
|
||||||
|
requestStorageAccessFramework(dirPath);
|
||||||
|
} else {
|
||||||
|
Log.d(ScummVM.LOG_TAG, "Already requested Storage Access (Storage Access Framework) in the past (share prefs saved)!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canWriteFile(folderToCheck, true)) {
|
||||||
|
Log.d(ScummVM.LOG_TAG, "(post SAF request) Writing is possible for this directory node");
|
||||||
|
retRes[0] = true;
|
||||||
|
} else {
|
||||||
|
Log.d(ScummVM.LOG_TAG, "(post SAF request) Error - writing is still not possible for this directory node");
|
||||||
|
}
|
||||||
|
|
||||||
|
return retRes[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String createFileWithSAF(String filePath) {
|
protected String createFileWithSAF(String filePath) {
|
||||||
final String[] retResStr = {""};
|
final String[] retResStr = {""};
|
||||||
|
@ -2158,6 +2187,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
|
||||||
_scummvm.displayMessageOnOSD(getString(R.string.saf_request_prompt) + dirPathSample);
|
_scummvm.displayMessageOnOSD(getString(R.string.saf_request_prompt) + dirPathSample);
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// Directory picker
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
@ -2298,14 +2328,20 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
originalDirectory = true;
|
originalDirectory = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri treeUri;
|
Uri treeUri;
|
||||||
if ((treeUri = getStorageAccessFrameworkTreeUri()) == null) {
|
if ((treeUri = getStorageAccessFrameworkTreeUri()) == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentFile dof = DocumentFile.fromTreeUri(getApplicationContext(), treeUri);
|
DocumentFile dof = DocumentFile.fromTreeUri(getApplicationContext(), treeUri);
|
||||||
if (originalDirectory) {
|
if (originalDirectory) {
|
||||||
return dof;
|
return dof;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Important note: We cannot assume that anything sent here is a relative path on top of the *ONLY* SAF "root" path
|
||||||
|
// since the the user could select another SD Card (from multiple inserted or replaces the current one and inserts another)
|
||||||
|
// TODO Can we translate our path string "/storage/XXXX-XXXXX/folder/doc.ext' a content URI? or a document URI?
|
||||||
String[] parts = relPath.split("\\/");
|
String[] parts = relPath.split("\\/");
|
||||||
for (int i = 0; i < parts.length; i++) {
|
for (int i = 0; i < parts.length; i++) {
|
||||||
DocumentFile nextDof = dof.findFile(parts[i]);
|
DocumentFile nextDof = dof.findFile(parts[i]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue