|
|
@@ -9,8 +9,15 @@ import android.os.Build;
|
|
|
import android.os.Environment;
|
|
|
import android.provider.DocumentsContract;
|
|
|
import android.provider.MediaStore;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+
|
|
|
+// The following refs
|
|
|
// https://stackoverflow.com/questions/29713587/how-to-get-the-real-path-with-action-open-document-tree-intent
|
|
|
// https://gist.github.com/asifmujteba/d89ba9074bc941de1eaa#file-asfurihelper
|
|
|
+// with bug fixes and patches.
|
|
|
public class FileUtil {
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
|
public static String getPath(final Context context, final Uri uri) {
|
|
|
@@ -24,24 +31,64 @@ public class FileUtil {
|
|
|
final String docId = DocumentsContract.getDocumentId(uri);
|
|
|
final String[] split = docId.split(":");
|
|
|
final String type = split[0];
|
|
|
+ // NOTE: It's not a good idea to use storage root as Graph root.
|
|
|
+ String remain = "";
|
|
|
+ if (split.length == 2) {
|
|
|
+ remain = split[1];
|
|
|
+ }
|
|
|
|
|
|
if ("primary".equalsIgnoreCase(type)) {
|
|
|
- return Environment.getExternalStorageDirectory() + "/" + split[1];
|
|
|
+ return Environment.getExternalStorageDirectory() + "/" + remain;
|
|
|
+ } else if ("home".equalsIgnoreCase(type)) {
|
|
|
+ return Environment.getExternalStorageDirectory() + "/Documents/" + remain;
|
|
|
+ } else if ("downloads".equalsIgnoreCase(type)) {
|
|
|
+ return Environment.getExternalStorageDirectory() + "/Download/" + remain; // No 's' here
|
|
|
}
|
|
|
|
|
|
- // TODO handle non-primary volumes
|
|
|
- }
|
|
|
- // DownloadsProvider
|
|
|
- else if (isDownloadsDocument(uri)) {
|
|
|
+ File dir = null;
|
|
|
+ File[] mdirs = context.getExternalMediaDirs();
|
|
|
+ for (File mdir : mdirs) {
|
|
|
+ String extPath = mdir.getAbsolutePath();
|
|
|
+
|
|
|
+ if (extPath.contains("/" + type + "/")) {
|
|
|
+ dir = new File(extPath.substring(0, extPath.indexOf("/Android")) + "/" + remain);
|
|
|
+ if (dir.exists()) {
|
|
|
+ return dir.getAbsolutePath();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // FIXME: The following attempt cannot handle same directory name on different devices!
|
|
|
+ // attempt 1
|
|
|
+ dir = new File("/storage/" + type + "/" + remain);
|
|
|
+ if (dir.exists()) {
|
|
|
+ return dir.getAbsolutePath();
|
|
|
+ }
|
|
|
+ // attempt 3
|
|
|
+ dir = new File("/mnt/media_rw/" + type + "/" + remain);
|
|
|
+ if (dir.exists()) {
|
|
|
+ return dir.getAbsolutePath();
|
|
|
+ }
|
|
|
+ // attempt 3
|
|
|
+ dir = new File("/mnt/" + type + "/" + remain);
|
|
|
+ if (dir.exists()) {
|
|
|
+ return dir.getAbsolutePath();
|
|
|
+ }
|
|
|
|
|
|
+ // TODO: other cases
|
|
|
+ } else if (isDownloadsDocument(uri)) {
|
|
|
final String id = DocumentsContract.getDocumentId(uri);
|
|
|
- final Uri contentUri = ContentUris.withAppendedId(
|
|
|
- Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
|
|
-
|
|
|
- return getDataColumn(context, contentUri, null, null);
|
|
|
- }
|
|
|
- // MediaProvider
|
|
|
- else if (isMediaDocument(uri)) {
|
|
|
+ if (!TextUtils.isEmpty(id)) {
|
|
|
+ if (id.startsWith("raw:")) {
|
|
|
+ return id.replaceFirst("raw:", "");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
|
|
+ return getDataColumn(context, contentUri, null, null);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (isMediaDocument(uri)) {
|
|
|
final String docId = DocumentsContract.getDocumentId(uri);
|
|
|
final String[] split = docId.split(":");
|
|
|
final String type = split[0];
|
|
|
@@ -56,24 +103,49 @@ public class FileUtil {
|
|
|
}
|
|
|
|
|
|
final String selection = "_id=?";
|
|
|
- final String[] selectionArgs = new String[] {
|
|
|
+ final String[] selectionArgs = new String[]{
|
|
|
split[1]
|
|
|
};
|
|
|
|
|
|
return getDataColumn(context, contentUri, selection, selectionArgs);
|
|
|
+ } else if (isTermuxDocument(uri)) {
|
|
|
+ String docId = DocumentsContract.getDocumentId(uri);
|
|
|
+
|
|
|
+ // Ref: https://github.com/termux/termux-app/blob/master/app/src/main/java/com/termux/app/TermuxInstaller.java
|
|
|
+ if (docId.startsWith("/")) {
|
|
|
+ if (docId.contains("/com.termux/files/home/storage/")) {
|
|
|
+ String remain = docId.replaceFirst("^.*?com\\.termux/files/home/storage/[^/]+/", "");
|
|
|
+ if (docId.contains("/storage/external-1")) { // TODO: Support external-2 or more
|
|
|
+ File[] dirs = context.getExternalFilesDirs(remain);
|
|
|
+ if (dirs != null && dirs.length >= 2) {
|
|
|
+ docId = dirs[1].getAbsolutePath();
|
|
|
+ }
|
|
|
+ } else if (docId.contains("/storage/media-1")) {
|
|
|
+ File[] dirs = context.getExternalMediaDirs();
|
|
|
+ if (dirs != null && dirs.length >= 2) {
|
|
|
+ docId = dirs[1].getAbsolutePath() + "/" + remain;
|
|
|
+ }
|
|
|
+ } else if (docId.contains("/storage/downloads")) {
|
|
|
+ docId = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + remain;
|
|
|
+ } else if (docId.contains("/storage/shared")) {
|
|
|
+ docId = Environment.getExternalStorageDirectory() + "/" + remain;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ File dir = new File(docId);
|
|
|
+ if (dir.exists()) {
|
|
|
+ return dir.getAbsolutePath();
|
|
|
+ }
|
|
|
+ Log.e("Logseq/FileUtil", "Handle termux content url failed: " + docId);
|
|
|
+ }
|
|
|
+ // FIXME: Are there any other cases?
|
|
|
}
|
|
|
- }
|
|
|
- // MediaStore (and general)
|
|
|
- else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
|
|
-
|
|
|
+ } else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
|
|
// Return the remote address
|
|
|
if (isGooglePhotosUri(uri))
|
|
|
return uri.getLastPathSegment();
|
|
|
|
|
|
return getDataColumn(context, uri, null, null);
|
|
|
- }
|
|
|
- // File
|
|
|
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
|
|
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
|
|
return uri.getPath();
|
|
|
}
|
|
|
|
|
|
@@ -135,4 +207,8 @@ public class FileUtil {
|
|
|
public static boolean isGooglePhotosUri(Uri uri) {
|
|
|
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
|
|
|
}
|
|
|
+
|
|
|
+ public static boolean isTermuxDocument(Uri uri) {
|
|
|
+ return "com.termux.documents".equals(uri.getAuthority());
|
|
|
+ }
|
|
|
}
|