[Scummvm-git-logs] scummvm master -> c85d146f58618bc81ec5173f6087c992e21dc105
sev-
sev at scummvm.org
Fri Sep 27 00:23:19 CEST 2019
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
bc1c4b3ec1 ANDROID: Initial code for external storage enumerator
4e5f26b44e ANDROID: Turn map into spliced list for easier marshalling
2b72cc0b5c ANDROID: Hook external storage class into ScummVMHelper
580142c9ea ANDROID: Hook getAllStorageLocations() into JNI
23211392c0 ANDROID: Use external storage enumerator for the root directory
f12d7160f8 ANDROID: Added list of external storages to the list of accessible directories
0481669b1f ANDROID: Fix exception
3c92722db6 ANDROID: Request permissions to external storage
27fbde1443 ANDROID: Added more logic for scraping the storage paths
c85d146f58 NEWS: Mention new Android functionality
Commit: bc1c4b3ec1893a25cb5f9e52185a19c9b330366e
https://github.com/scummvm/scummvm/commit/bc1c4b3ec1893a25cb5f9e52185a19c9b330366e
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Initial code for external storage enumerator
Changed paths:
A backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
new file mode 100644
index 0000000..42ec185
--- /dev/null
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -0,0 +1,142 @@
+package org.scummvm.scummvm;
+
+import android.os.Environment;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Contains helper methods to get list of available media
+ */
+public class ExternalStorage {
+ public static final String SD_CARD = "sdCard";
+ public static final String EXTERNAL_SD_CARD = "externalSdCard";
+ public static final String DATA_DIRECTORY = "ScummVM data directory";
+
+ /**
+ * @return True if the external storage is available. False otherwise.
+ */
+ public static boolean isAvailable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static String getSdCardPath() {
+ return Environment.getExternalStorageDirectory().getPath() + "/";
+ }
+
+ /**
+ * @return True if the external storage is writable. False otherwise.
+ */
+ public static boolean isWritable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * @return A map of all storage locations available
+ */
+ public static Map<String, String> getAllStorageLocations() {
+ Map<String, String> map = new HashMap<String, String>(10);
+
+ List<String> mMounts = new ArrayList<String>(10);
+ List<String> mVold = new ArrayList<String>(10);
+ mMounts.add("/mnt/sdcard");
+ mVold.add("/mnt/sdcard");
+
+ try {
+ File mountFile = new File("/proc/mounts");
+ if (mountFile.exists()){
+ Scanner scanner = new Scanner(mountFile);
+ while (scanner.hasNext()) {
+ String line = scanner.nextLine();
+ if (line.startsWith("/dev/block/vold/")) {
+ String[] lineElements = line.split(" ");
+ String element = lineElements[1];
+
+ // don't add the default mount path
+ // it's already in the list.
+ if (!element.equals("/mnt/sdcard"))
+ mMounts.add(element);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ File voldFile = new File("/system/etc/vold.fstab");
+ if (voldFile.exists()){
+ Scanner scanner = new Scanner(voldFile);
+ while (scanner.hasNext()) {
+ String line = scanner.nextLine();
+ if (line.startsWith("dev_mount")) {
+ String[] lineElements = line.split(" ");
+ String element = lineElements[2];
+
+ if (element.contains(":"))
+ element = element.substring(0, element.indexOf(":"));
+ if (!element.equals("/mnt/sdcard"))
+ mVold.add(element);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ for (int i = 0; i < mMounts.size(); i++) {
+ String mount = mMounts.get(i);
+ if (!mVold.contains(mount))
+ mMounts.remove(i--);
+ }
+ mVold.clear();
+
+ List<String> mountHash = new ArrayList<String>(10);
+
+ for (String mount : mMounts){
+ File root = new File(mount);
+ if (root.exists() && root.isDirectory() && root.canRead()) {
+ File[] list = root.listFiles();
+ String hash = "[";
+ if (list != null) {
+ for (File f : list) {
+ hash += f.getName().hashCode() + ":" + f.length() + ", ";
+ }
+ }
+ hash += "]";
+ if (!mountHash.contains(hash)){
+ String key = SD_CARD + "_" + map.size();
+ if (map.size() == 0) {
+ key = SD_CARD;
+ } else if (map.size() == 1) {
+ key = EXTERNAL_SD_CARD;
+ }
+ mountHash.add(hash);
+ map.put(key, root.getAbsolutePath());
+ }
+ }
+ }
+
+ mMounts.clear();
+
+ map.put(SD_CARD, Environment.getDataDirectory().getAbsolutePath());
+
+ if (map.isEmpty()) {
+ map.put(DATA_DIRECTORY, Environment.getExternalStorageDirectory().getAbsolutePath());
+ }
+ return map;
+ }
+}
Commit: 4e5f26b44e9ef369641dd0825f17287b8cce8b08
https://github.com/scummvm/scummvm/commit/4e5f26b44e9ef369641dd0825f17287b8cce8b08
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Turn map into spliced list for easier marshalling
Changed paths:
backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
index 42ec185..234fba9 100644
--- a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -3,9 +3,7 @@ package org.scummvm.scummvm;
import android.os.Environment;
import java.io.File;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Scanner;
/**
@@ -44,10 +42,10 @@ public class ExternalStorage {
}
/**
- * @return A map of all storage locations available
+ * @return list of locations available. Odd elements are names, even are paths
*/
- public static Map<String, String> getAllStorageLocations() {
- Map<String, String> map = new HashMap<String, String>(10);
+ public static List<String> getAllStorageLocations() {
+ List<String> map = new ArrayList<String>(20);
List<String> mMounts = new ArrayList<String>(10);
List<String> mVold = new ArrayList<String>(10);
@@ -118,24 +116,27 @@ public class ExternalStorage {
}
hash += "]";
if (!mountHash.contains(hash)){
- String key = SD_CARD + "_" + map.size();
+ String key = SD_CARD + "_" + (map.size() / 2);
if (map.size() == 0) {
key = SD_CARD;
- } else if (map.size() == 1) {
+ } else if (map.size() == 2) {
key = EXTERNAL_SD_CARD;
}
mountHash.add(hash);
- map.put(key, root.getAbsolutePath());
+ map.add(key);
+ map.add(root.getAbsolutePath());
}
}
}
mMounts.clear();
- map.put(SD_CARD, Environment.getDataDirectory().getAbsolutePath());
+ map.add(DATA_DIRECTORY);
+ map.add(Environment.getDataDirectory().getAbsolutePath());
if (map.isEmpty()) {
- map.put(DATA_DIRECTORY, Environment.getExternalStorageDirectory().getAbsolutePath());
+ map.add(SD_CARD);
+ map.add(Environment.getExternalStorageDirectory().getAbsolutePath());
}
return map;
}
Commit: 2b72cc0b5ce716a8163ef211887df5c9742983a5
https://github.com/scummvm/scummvm/commit/2b72cc0b5ce716a8163ef211887df5c9742983a5
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Hook external storage class into ScummVMHelper
Changed paths:
backends/platform/android/org/scummvm/scummvm/ScummVM.java
backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
index 8dd974b..ea7bf52 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
@@ -16,6 +16,7 @@ import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
import java.util.LinkedHashMap;
+import java.util.List;
public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
final protected static String LOG_TAG = "ScummVM";
@@ -62,6 +63,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
abstract protected void showVirtualKeyboard(boolean enable);
abstract protected void showKeyboardControl(boolean enable);
abstract protected String[] getSysArchives();
+ abstract protected List<String> getAllStorageLocations();
public ScummVM(AssetManager asset_manager, SurfaceHolder holder) {
_asset_manager = asset_manager;
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index f353cea..a955f02 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -24,6 +24,7 @@ import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
+import java.util.List;
public class ScummVMActivity extends Activity {
@@ -155,12 +156,18 @@ public class ScummVMActivity extends Activity {
return new String[0];
}
+ @Override
+ protected List<String> getAllStorageLocations() {
+ return _externalStorage.getAllStorageLocations();
+ }
+
}
private MyScummVM _scummvm;
private ScummVMEvents _events;
private MouseHelper _mouseHelper;
private Thread _scummvm_thread;
+ private ExternalStorage _externalStorage;
@Override
public void onCreate(Bundle savedInstanceState) {
Commit: 580142c9eaf7fafd4f15827545aaa7f4a1d03322
https://github.com/scummvm/scummvm/commit/580142c9eaf7fafd4f15827545aaa7f4a1d03322
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Hook getAllStorageLocations() into JNI
Changed paths:
backends/platform/android/jni.cpp
backends/platform/android/jni.h
backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
backends/platform/android/org/scummvm/scummvm/ScummVM.java
backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp
index 2c27838..8c330c0 100644
--- a/backends/platform/android/jni.cpp
+++ b/backends/platform/android/jni.cpp
@@ -86,6 +86,7 @@ jmethodID JNI::_MID_setWindowCaption = 0;
jmethodID JNI::_MID_showVirtualKeyboard = 0;
jmethodID JNI::_MID_showKeyboardControl = 0;
jmethodID JNI::_MID_getSysArchives = 0;
+jmethodID JNI::_MID_getAllStorageLocations = 0;
jmethodID JNI::_MID_initSurface = 0;
jmethodID JNI::_MID_deinitSurface = 0;
@@ -531,6 +532,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
FIND_METHOD(, showVirtualKeyboard, "(Z)V");
FIND_METHOD(, showKeyboardControl, "(Z)V");
FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;");
+ FIND_METHOD(, getAllStorageLocations, "()[Ljava/lang/String;");
FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;");
FIND_METHOD(, deinitSurface, "()V");
@@ -697,4 +699,38 @@ jstring JNI::getCurrentCharset(JNIEnv *env, jobject self) {
return env->NewStringUTF("ISO-8859-1");
}
+Common::Array<Common::String> JNI::getAllStorageLocations() {
+ Common::Array<Common::String> *res = new Common::Array<Common::String>();
+
+ JNIEnv *env = JNI::getEnv();
+
+ jobjectArray array =
+ (jobjectArray)env->CallObjectMethod(_jobj, _MID_getAllStorageLocations);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error finding system archive path");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ return *res;
+ }
+
+ jsize size = env->GetArrayLength(array);
+ for (jsize i = 0; i < size; ++i) {
+ jstring path_obj = (jstring)env->GetObjectArrayElement(array, i);
+ const char *path = env->GetStringUTFChars(path_obj, 0);
+
+ if (path != 0) {
+ res->push_back(path);
+ env->ReleaseStringUTFChars(path_obj, path);
+ }
+
+ env->DeleteLocalRef(path_obj);
+ }
+
+ return *res;
+}
+
+
#endif
diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h
index b6e5df8..fe4b948 100644
--- a/backends/platform/android/jni.h
+++ b/backends/platform/android/jni.h
@@ -30,6 +30,7 @@
#include "common/fs.h"
#include "common/archive.h"
+#include "common/array.h"
class OSystem_Android;
@@ -79,6 +80,8 @@ public:
static inline int writeAudio(JNIEnv *env, jbyteArray &data, int offset,
int size);
+ static Common::Array<Common::String> getAllStorageLocations();
+
private:
static JavaVM *_vm;
// back pointer to (java) peer instance
@@ -104,6 +107,7 @@ private:
static jmethodID _MID_showVirtualKeyboard;
static jmethodID _MID_showKeyboardControl;
static jmethodID _MID_getSysArchives;
+ static jmethodID _MID_getAllStorageLocations;
static jmethodID _MID_initSurface;
static jmethodID _MID_deinitSurface;
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
index 234fba9..d8bab31 100644
--- a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -104,7 +104,7 @@ public class ExternalStorage {
List<String> mountHash = new ArrayList<String>(10);
- for (String mount : mMounts){
+ for (String mount : mMounts) {
File root = new File(mount);
if (root.exists() && root.isDirectory() && root.canRead()) {
File[] list = root.listFiles();
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
index ea7bf52..34349d4 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
@@ -63,7 +63,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
abstract protected void showVirtualKeyboard(boolean enable);
abstract protected void showKeyboardControl(boolean enable);
abstract protected String[] getSysArchives();
- abstract protected List<String> getAllStorageLocations();
+ abstract protected String[] getAllStorageLocations();
public ScummVM(AssetManager asset_manager, SurfaceHolder holder) {
_asset_manager = asset_manager;
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index a955f02..6978f6e 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -157,8 +157,8 @@ public class ScummVMActivity extends Activity {
}
@Override
- protected List<String> getAllStorageLocations() {
- return _externalStorage.getAllStorageLocations();
+ protected String[] getAllStorageLocations() {
+ return _externalStorage.getAllStorageLocations().toArray(new String[0]);
}
}
Commit: 23211392c0310179bf27612d7a7b58eec106b8ce
https://github.com/scummvm/scummvm/commit/23211392c0310179bf27612d7a7b58eec106b8ce
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Use external storage enumerator for the root directory
Changed paths:
backends/fs/posix/posix-fs.cpp
diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp
index 507f075..fe72cfe 100644
--- a/backends/fs/posix/posix-fs.cpp
+++ b/backends/fs/posix/posix-fs.cpp
@@ -57,6 +57,9 @@
#include <os2.h>
#endif
+#if defined(__ANDROID__) && !defined(ANDROIDSDL)
+#include "backends/platform/android/jni.h"
+#endif
bool POSIXFilesystemNode::exists() const {
return access(_path.c_str(), F_OK) == 0;
@@ -190,6 +193,23 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo
}
#endif
+#if defined(__ANDROID__) && !defined(ANDROIDSDL)
+ if (_path == "/") {
+ Common::Array<Common::String> list = JNI::getAllStorageLocations();
+ for (Common::Array<Common::String>::const_iterator it = list.begin(), end = list.end(); it != end; ++it) {
+ POSIXFilesystemNode *entry = new POSIXFilesystemNode();
+
+ entry->_isDirectory = true;
+ entry->_isValid = true;
+ entry->_displayName = *it;
+ ++it;
+ entry->_path = *it;
+ myList.push_back(entry);
+ }
+ return true;
+ }
+#endif
+
DIR *dirp = opendir(_path.c_str());
struct dirent *dp;
Commit: f12d7160f840eaa2607002cf0be2e3e8c1b17941
https://github.com/scummvm/scummvm/commit/f12d7160f840eaa2607002cf0be2e3e8c1b17941
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Added list of external storages to the list of accessible directories
Changed paths:
backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
index d8bab31..acfd239 100644
--- a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -115,7 +115,7 @@ public class ExternalStorage {
}
}
hash += "]";
- if (!mountHash.contains(hash)){
+ if (!mountHash.contains(hash)) {
String key = SD_CARD + "_" + (map.size() / 2);
if (map.size() == 0) {
key = SD_CARD;
@@ -134,10 +134,38 @@ public class ExternalStorage {
map.add(DATA_DIRECTORY);
map.add(Environment.getDataDirectory().getAbsolutePath());
- if (map.isEmpty()) {
- map.add(SD_CARD);
- map.add(Environment.getExternalStorageDirectory().getAbsolutePath());
+ // Now go through the external storage
+ String state = Environment.getExternalStorageState();
+
+ if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) { // we can read the External Storage...
+ // Retrieve the primary External Storage:
+ File primaryExternalStorage = Environment.getExternalStorageDirectory();
+
+ //Retrieve the External Storages root directory:
+ String externalStorageRootDir;
+ int count = 0;
+ if ((externalStorageRootDir = primaryExternalStorage.getParent()) == null) { // no parent...
+ String key = primaryExternalStorage.getAbsolutePath();
+ if (!map.contains(key)) {
+ map.add(key); // Make name as directory
+ map.add(key);
+ }
+ } else {
+ File externalStorageRoot = new File(externalStorageRootDir);
+ File[] files = externalStorageRoot.listFiles();
+
+ for (final File file : files) {
+ if (file.isDirectory() && file.canRead() && (file.listFiles().length > 0)) { // it is a real directory (not a USB drive)...
+ String key = file.getAbsolutePath();
+ if (!map.contains(key)) {
+ map.add(key); // Make name as directory
+ map.add(key);
+ }
+ }
+ }
+ }
}
+
return map;
}
}
Commit: 0481669b1f89f026786fb689169be9ff1f7b1466
https://github.com/scummvm/scummvm/commit/0481669b1f89f026786fb689169be9ff1f7b1466
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Fix exception
Changed paths:
backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
index acfd239..b9e7bf0 100644
--- a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -54,7 +54,7 @@ public class ExternalStorage {
try {
File mountFile = new File("/proc/mounts");
- if (mountFile.exists()){
+ if (mountFile.exists()) {
Scanner scanner = new Scanner(mountFile);
while (scanner.hasNext()) {
String line = scanner.nextLine();
@@ -154,12 +154,14 @@ public class ExternalStorage {
File externalStorageRoot = new File(externalStorageRootDir);
File[] files = externalStorageRoot.listFiles();
- for (final File file : files) {
- if (file.isDirectory() && file.canRead() && (file.listFiles().length > 0)) { // it is a real directory (not a USB drive)...
- String key = file.getAbsolutePath();
- if (!map.contains(key)) {
- map.add(key); // Make name as directory
- map.add(key);
+ if (files.length > 0) {
+ for (final File file : files) {
+ if (file.isDirectory() && file.canRead() && (file.listFiles().length > 0)) { // it is a real directory (not a USB drive)...
+ String key = file.getAbsolutePath();
+ if (!map.contains(key)) {
+ map.add(key); // Make name as directory
+ map.add(key);
+ }
}
}
}
Commit: 3c92722db64e0e9af47b44e77a27371940f290f2
https://github.com/scummvm/scummvm/commit/3c92722db64e0e9af47b44e77a27371940f290f2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Request permissions to external storage
Changed paths:
backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
dists/android/AndroidManifest.xml
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index 6978f6e..2d48dfa 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -1,5 +1,7 @@
package org.scummvm.scummvm;
+import android.Manifest;
+import android.content.pm.PackageManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -33,6 +35,11 @@ public class ScummVMActivity extends Activity {
private ClipboardManager _clipboard;
+ /**
+ * Id to identify an external storage read request.
+ */
+ private static final int MY_PERMISSIONS_REQUEST_READ_EXT_STORAGE = 100; // is an app-defined int constant. The callback method gets the result of the request.
+
static {
try {
MouseHelper.checkHoverAvailable(); // this throws exception if we're on too old version
@@ -53,6 +60,7 @@ public class ScummVMActivity extends Activity {
}
};
+
private class MyScummVM extends ScummVM {
public MyScummVM(SurfaceHolder holder) {
super(ScummVMActivity.this.getAssets(), holder);
@@ -158,7 +166,14 @@ public class ScummVMActivity extends Activity {
@Override
protected String[] getAllStorageLocations() {
- return _externalStorage.getAllStorageLocations().toArray(new String[0]);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
+ ) {
+ requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXT_STORAGE);
+ } else {
+ return _externalStorage.getAllStorageLocations().toArray(new String[0]);
+ }
+ return new String[0]; // an array of zero length
}
}
@@ -306,6 +321,28 @@ public class ScummVMActivity extends Activity {
}
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ switch (requestCode) {
+ case MY_PERMISSIONS_REQUEST_READ_EXT_STORAGE:
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted
+ Log.i(ScummVM.LOG_TAG, "Read External Storage permission was granted at Runtime");
+ } else {
+ // permission denied! We won't be able to make use of functionality depending on this permission.
+ Toast.makeText(this, "Until permission is granted, some folders might not be listed!", Toast.LENGTH_SHORT)
+ .show();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
@Override
public boolean onTrackballEvent(MotionEvent e) {
if (_events != null)
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index 923da5f..0d32c4b 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -14,6 +14,9 @@
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission
+ android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+ <uses-permission
android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-feature
Commit: 27fbde1443b8a53d39a43c4ff6c93b638c0944ab
https://github.com/scummvm/scummvm/commit/27fbde1443b8a53d39a43c4ff6c93b638c0944ab
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
ANDROID: Added more logic for scraping the storage paths
Changed paths:
backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
diff --git a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
index b9e7bf0..01482a3 100644
--- a/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
+++ b/backends/platform/android/org/scummvm/scummvm/ExternalStorage.java
@@ -6,6 +6,19 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
+import android.text.TextUtils;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Locale;
+import java.util.regex.Pattern;
+import android.util.Log;
+import android.os.Build;
+
+
/**
* Contains helper methods to get list of available media
*/
@@ -14,6 +27,308 @@ public class ExternalStorage {
public static final String EXTERNAL_SD_CARD = "externalSdCard";
public static final String DATA_DIRECTORY = "ScummVM data directory";
+
+ // Find candidate removable sd card paths
+ // Code reference: https://stackoverflow.com/a/54411385
+ private static final String ANDROID_DIR = File.separator + "Android";
+
+ private static String ancestor(File dir) {
+ // getExternalFilesDir() and getExternalStorageDirectory()
+ // may return something app-specific like:
+ // /storage/sdcard1/Android/data/com.mybackuparchives.android/files
+ // so we want the great-great-grandparent folder.
+ if (dir == null) {
+ return null;
+ } else {
+ String path = dir.getAbsolutePath();
+ int i = path.indexOf(ANDROID_DIR);
+ if (i == -1) {
+ return path;
+ } else {
+ return path.substring(0, i);
+ }
+ }
+ }
+
+ private static Pattern
+ /** Pattern that SD card device should match */
+ devicePattern = Pattern.compile("/dev/(block/.*vold.*|fuse)|/mnt/.*"),
+ /** Pattern that SD card mount path should match */
+ pathPattern = Pattern.compile("/(mnt|storage|external_sd|extsd|_ExternalSD|Removable|.*MicroSD).*", Pattern.CASE_INSENSITIVE),
+ /** Pattern that the mount path should not match.
+ * 'emulated' indicates an internal storage location, so skip it.
+ * 'asec' is an encrypted package file, decrypted and mounted as a directory. */
+ pathAntiPattern = Pattern.compile(".*(/secure|/asec|/emulated).*"),
+ /** These are expected fs types, including vfat. tmpfs is not OK.
+ * fuse can be removable SD card (as on Moto E or Asus ZenPad), or can be internal (Huawei G610). */
+ fsTypePattern = Pattern.compile(".*(fat|msdos|ntfs|ext[34]|fuse|sdcard|esdfs).*");
+
+ /** Common paths for microSD card. **/
+ private static String[] commonPaths = {
+ // Some of these taken from
+ // https://stackoverflow.com/questions/13976982/removable-storage-external-sdcard-path-by-manufacturers
+ // These are roughly in order such that the earlier ones, if they exist, are more sure
+ // to be removable storage than the later ones.
+ "/mnt/Removable/MicroSD",
+ "/storage/removable/sdcard1", // !< Sony Xperia Z1
+ "/Removable/MicroSD", // Asus ZenPad C
+ "/removable/microsd",
+ "/external_sd", // Samsung
+ "/_ExternalSD", // some LGs
+ "/storage/extSdCard", // later Samsung
+ "/storage/extsdcard", // Main filesystem is case-sensitive; FAT isn't.
+ "/mnt/extsd", // some Chinese tablets, e.g. Zeki
+ "/storage/sdcard1", // If this exists it's more likely than sdcard0 to be removable.
+ "/mnt/extSdCard",
+ "/mnt/sdcard/external_sd",
+ "/mnt/external_sd",
+ "/storage/external_SD",
+ "/storage/ext_sd", // HTC One Max
+ "/mnt/sdcard/_ExternalSD",
+ "/mnt/sdcard-ext",
+
+ "/sdcard2", // HTC One M8s
+ "/sdcard1", // Sony Xperia Z
+ "/mnt/media_rw/sdcard1", // 4.4.2 on CyanogenMod S3
+ "/mnt/sdcard", // This can be built-in storage (non-removable).
+ "/sdcard",
+ "/storage/sdcard0",
+ "/emmc",
+ "/mnt/emmc",
+ "/sdcard/sd",
+ "/mnt/sdcard/bpemmctest",
+ "/mnt/external1",
+ "/data/sdext4",
+ "/data/sdext3",
+ "/data/sdext2",
+ "/data/sdext",
+ "/storage/microsd" //ASUS ZenFone 2
+
+ // If we ever decide to support USB OTG storage, the following paths could be helpful:
+ // An LG Nexus 5 apparently uses usb://1002/UsbStorage/ as a URI to access an SD
+ // card over OTG cable. Other models, like Galaxy S5, use /storage/UsbDriveA
+ // "/mnt/usb_storage",
+ // "/mnt/UsbDriveA",
+ // "/mnt/UsbDriveB",
+ };
+
+ /** Find path to removable SD card. */
+ public static LinkedHashSet<File> findSdCardPath() {
+ String[] mountFields;
+ BufferedReader bufferedReader = null;
+ String lineRead = null;
+
+ /** Possible SD card paths */
+ LinkedHashSet<File> candidatePaths = new LinkedHashSet<File>();
+
+ /** Build a list of candidate paths, roughly in order of preference. That way if
+ * we can't definitively detect removable storage, we at least can pick a more likely
+ * candidate. */
+
+ // Could do: use getExternalStorageState(File path), with and without an argument, when
+ // available. With an argument is available since API level 21.
+ // This may not be necessary, since we also check whether a directory exists and has contents,
+ // which would fail if the external storage state is neither MOUNTED nor MOUNTED_READ_ONLY.
+
+ // I moved hard-coded paths toward the end, but we need to make sure we put the ones in
+ // backwards order that are returned by the OS. And make sure the iterators respect
+ // the order!
+ // This is because when multiple "external" storage paths are returned, it's always (in
+ // experience, but not guaranteed by documentation) with internal/emulated storage
+ // first, removable storage second.
+
+ // Add value of environment variables as candidates, if set:
+ // EXTERNAL_STORAGE, SECONDARY_STORAGE, EXTERNAL_SDCARD_STORAGE
+ // But note they are *not* necessarily *removable* storage! Especially EXTERNAL_STORAGE.
+ // And they are not documented (API) features. Typically useful only for old versions of Android.
+
+ String val = System.getenv("SECONDARY_STORAGE");
+ if (!TextUtils.isEmpty(val)) {
+ addPath(val, candidatePaths);
+ }
+
+ val = System.getenv("EXTERNAL_SDCARD_STORAGE");
+ if (!TextUtils.isEmpty(val)) {
+ addPath(val, candidatePaths);
+ }
+
+ // Get listing of mounted devices with their properties.
+ ArrayList<File> mountedPaths = new ArrayList<File>();
+ try {
+ // Note: Despite restricting some access to /proc (http://stackoverflow.com/a/38728738/423105),
+ // Android 7.0 does *not* block access to /proc/mounts, according to our test on George's Alcatel A30 GSM.
+ bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
+
+ // Iterate over each line of the mounts listing.
+ while ((lineRead = bufferedReader.readLine()) != null) {
+// Log.d(ScummVM.LOG_TAG, "\nMounts line: " + lineRead);
+ mountFields = lineRead.split(" ");
+
+ // columns: device, mountpoint, fs type, options... Example:
+ // /dev/block/vold/179:97 /storage/sdcard1 vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0002,dmask=0002,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
+ String device = mountFields[0], path = mountFields[1], fsType = mountFields[2];
+
+ // The device, path, and fs type must conform to expected patterns.
+ // mtdblock is internal, I'm told.
+ // Check for disqualifying patterns in the path.
+ // If this mounts line fails our tests, skip it.
+ if (!(devicePattern.matcher(device).matches()
+ && pathPattern.matcher(path).matches()
+ && fsTypePattern.matcher(fsType).matches())
+ || device.contains("mtdblock")
+ || pathAntiPattern.matcher(path).matches()
+ ) {
+ continue;
+ }
+
+ // TODO maybe: check options to make sure it's mounted RW?
+ // The answer at http://stackoverflow.com/a/13648873/423105 does.
+ // But it hasn't seemed to be necessary so far in my testing.
+
+ // This line met the criteria so far, so add it to candidate list.
+ addPath(path, mountedPaths);
+ }
+ } catch (IOException ignored) { }
+ finally {
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (IOException ignored) { }
+ }
+ }
+
+ // Append the paths from mount table to candidate list, in reverse order.
+ if (!mountedPaths.isEmpty()) {
+ // See https://stackoverflow.com/a/5374346/423105 on why the following is necessary.
+ // Basically, .toArray() needs its parameter to know what type of array to return.
+ File[] mountedPathsArray = mountedPaths.toArray(new File[mountedPaths.size()]);
+ addAncestors(mountedPathsArray, candidatePaths);
+ }
+
+ // Add hard-coded known common paths to candidate list:
+ addStrings(commonPaths, candidatePaths);
+
+ // If the above doesn't work we could try the following other options, but in my experience they
+ // haven't added anything helpful yet.
+
+ // getExternalFilesDir() and getExternalStorageDirectory() typically something app-specific like
+ // /storage/sdcard1/Android/data/com.mybackuparchives.android/files
+ // so we want the great-great-grandparent folder.
+
+ // This may be non-removable.
+ Log.d(ScummVM.LOG_TAG, "Environment.getExternalStorageDirectory():");
+ addPath(ancestor(Environment.getExternalStorageDirectory()), candidatePaths);
+
+ // TODO maybe: use getExternalStorageState(File path), with and without an argument, when
+ // available. With an argument is available since API level 21.
+ // This may not be necessary, since we also check whether a directory exists,
+ // which would fail if the external storage state is neither MOUNTED nor MOUNTED_READ_ONLY.
+
+ // A "public" external storage directory. But in my experience it doesn't add anything helpful.
+ // Note that you can't pass null, or you'll get an NPE.
+ final File publicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
+ // Take the parent, because we tend to get a path like /pathTo/sdCard/Music.
+ addPath(publicDirectory.getParentFile().getAbsolutePath(), candidatePaths);
+ // EXTERNAL_STORAGE: may not be removable.
+ val = System.getenv("EXTERNAL_STORAGE");
+ if (!TextUtils.isEmpty(val)) {
+ addPath(val, candidatePaths);
+ }
+
+ if (candidatePaths.isEmpty()) {
+ Log.w(ScummVM.LOG_TAG, "No removable microSD card found.");
+ return candidatePaths;
+ } else {
+ Log.i(ScummVM.LOG_TAG, "\nFound potential removable storage locations: " + candidatePaths);
+ }
+
+ // Accept or eliminate candidate paths if we can determine whether they're removable storage.
+ // In Lollipop and later, we can check isExternalStorageRemovable() status on each candidate.
+ if (Build.VERSION.SDK_INT >= 21) {
+ Iterator<File> itf = candidatePaths.iterator();
+ while (itf.hasNext()) {
+ File dir = itf.next();
+ // handle illegalArgumentException if the path is not a valid storage device.
+ try {
+ if (Environment.isExternalStorageRemovable(dir)) {
+ Log.i(ScummVM.LOG_TAG, dir.getPath() + " is removable external storage");
+ addPath(dir.getAbsolutePath(), candidatePaths);
+ } else if (Environment.isExternalStorageEmulated(dir)) {
+ Log.d(ScummVM.LOG_TAG, "Removing emulated external storage dir " + dir);
+ itf.remove();
+ }
+ } catch (IllegalArgumentException e) {
+ Log.d(ScummVM.LOG_TAG, "isRemovable(" + dir.getPath() + "): not a valid storage device.", e);
+ }
+ }
+ }
+
+ // Continue trying to accept or eliminate candidate paths based on whether they're removable storage.
+ // On pre-Lollipop, we only have singular externalStorage. Check whether it's removable.
+ if (Build.VERSION.SDK_INT >= 9) {
+ File externalStorage = Environment.getExternalStorageDirectory();
+ Log.d(ScummVM.LOG_TAG, String.format(Locale.ROOT, "findSDCardPath: getExternalStorageDirectory = %s", externalStorage.getPath()));
+ if (Environment.isExternalStorageRemovable()) {
+ // Make sure this is a candidate.
+ // TODO: Does this contains() work? Should we be canonicalizing paths before comparing?
+ if (candidatePaths.contains(externalStorage)) {
+ Log.d(ScummVM.LOG_TAG, "Using externalStorage dir " + externalStorage);
+ // return externalStorage;
+ addPath(externalStorage.getAbsolutePath(), candidatePaths);
+ }
+ } else if (Build.VERSION.SDK_INT >= 11 && Environment.isExternalStorageEmulated()) {
+ Log.d(ScummVM.LOG_TAG, "Removing emulated external storage dir " + externalStorage);
+ candidatePaths.remove(externalStorage);
+ }
+ }
+
+ return candidatePaths;
+ }
+
+
+ /** Add each path to the collection. */
+ private static void addStrings(String[] newPaths, LinkedHashSet<File> candidatePaths) {
+ for (String path : newPaths) {
+ addPath(path, candidatePaths);
+ }
+ }
+
+ /** Add ancestor of each File to the collection. */
+ private static void addAncestors(File[] files, LinkedHashSet<File> candidatePaths) {
+ for (int i = files.length - 1; i >= 0; i--) {
+ addPath(ancestor(files[i]), candidatePaths);
+ }
+ }
+
+ /**
+ * Add a new candidate directory path to our list, if it's not obviously wrong.
+ * Supply path as either String or File object.
+ * @param strNew path of directory to add
+ */
+ private static void addPath(String strNew, Collection<File> paths) {
+ // If one of the arguments is null, fill it in from the other.
+ if (strNew != null && !strNew.isEmpty()) {
+ File fileNew = new File(strNew);
+
+ if (!paths.contains(fileNew) &&
+ // Check for paths known not to be removable SD card.
+ // The antipattern check can be redundant, depending on where this is called from.
+ !pathAntiPattern.matcher(strNew).matches()) {
+
+ // Eliminate candidate if not a directory or not fully accessible.
+ if (fileNew.exists() && fileNew.isDirectory() && fileNew.canExecute()) {
+ Log.d(ScummVM.LOG_TAG, " Adding candidate path " + strNew);
+ paths.add(fileNew);
+ } else {
+ Log.d(ScummVM.LOG_TAG, String.format(Locale.ROOT, " Invalid path %s: exists: %b isDir: %b canExec: %b canRead: %b",
+ strNew, fileNew.exists(), fileNew.isDirectory(), fileNew.canExecute(), fileNew.canRead()));
+ }
+ }
+ }
+ }
+
+
+
/**
* @return True if the external storage is available. False otherwise.
*/
@@ -135,9 +450,7 @@ public class ExternalStorage {
map.add(Environment.getDataDirectory().getAbsolutePath());
// Now go through the external storage
- String state = Environment.getExternalStorageState();
-
- if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) { // we can read the External Storage...
+ if (isAvailable()) { // we can read the External Storage...
// Retrieve the primary External Storage:
File primaryExternalStorage = Environment.getExternalStorageDirectory();
@@ -154,7 +467,7 @@ public class ExternalStorage {
File externalStorageRoot = new File(externalStorageRootDir);
File[] files = externalStorageRoot.listFiles();
- if (files.length > 0) {
+ if (files != null) {
for (final File file : files) {
if (file.isDirectory() && file.canRead() && (file.listFiles().length > 0)) { // it is a real directory (not a USB drive)...
String key = file.getAbsolutePath();
@@ -168,6 +481,16 @@ public class ExternalStorage {
}
}
+ // Get candidates for removable external storage
+ LinkedHashSet<File> candidateRemovableSdCardPaths = findSdCardPath();
+ for (final File file : candidateRemovableSdCardPaths) {
+ String key = file.getAbsolutePath();
+ if (!map.contains(key)) {
+ map.add(key); // Make name as directory
+ map.add(key);
+ }
+ }
+
return map;
}
}
Commit: c85d146f58618bc81ec5173f6087c992e21dc105
https://github.com/scummvm/scummvm/commit/c85d146f58618bc81ec5173f6087c992e21dc105
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2019-09-27T00:22:20+02:00
Commit Message:
NEWS: Mention new Android functionality
Changed paths:
NEWS.md
diff --git a/NEWS.md b/NEWS.md
index bf6a571..5a77eb7 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -134,6 +134,7 @@ For a more comprehensive changelog of the latest experimental code, see:
- Added a button to show the virtual keyboard.
- Implemented clipboard support.
- Use the dedicated GUI option for enabling the touchpad mode
+ - Added code for searching accessible external media.
iOS port:
- Added support for Smart Keyboard.
More information about the Scummvm-git-logs
mailing list