-
-
Notifications
You must be signed in to change notification settings - Fork 25
/
UriToFilePath.java
186 lines (169 loc) · 7.29 KB
/
UriToFilePath.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package org.commcare.utils;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import java.util.List;
/**
* Util for turning URIs into a normal file path strings Needed because new
* versions of Android have a content resolution abstraction layer that doesn't
* use vanilla file system paths.
*
* Taken from aFileChooser by Paul Burke (paulburke.co)
* https://github.com/iPaulPro/aFileChooser
* Under the Apache 2.0 license
*/
public class UriToFilePath {
/**
* Get a file path from a Uri. This will get the the path for Storage
* Access Framework Documents, as well as the _data field for the
* MediaStore and other file-based ContentProviders. Doesn't handle
* document Uri's on secondary storage.
*
* @param context The context.
* @param uri The Uri to query.
* @return Filepath string extracted from the Uri argument. Returns the original uri if
* filepath couldn't be succesfully extracted.
*/
@SuppressLint("NewApi")
public static String getPathFromUri(final Context context, final Uri uri) throws NoDataColumnForUriException {
String filePath = null;
if (DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
Uri contentUri;
try {
contentUri = ContentUris.withAppendedId(
Uri.parse(Environment.DIRECTORY_DOWNLOADS), Long.valueOf(id));
} catch (NumberFormatException e) {
// id is an actual Path instead of a row id, hence use the original uri as it is.
contentUri = uri;
}
filePath = getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
filePath = getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
filePath = getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
filePath = uri.getPath();
}
if(filePath == null){
filePath = uri.toString();
}
return filePath;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) throws NoDataColumnForUriException {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
try {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
} catch (IllegalArgumentException e) {
throw new NoDataColumnForUriException();
}
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri Check this Uri's authority.
* @return Is this Uri's authority ExternalStorageProvider?
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri Check this Uri's authority.
* @return Is this Uri's authority DownloadsProvider?
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri Check this Uri's authority.
* @return Is this Uri's authority MediaProvider?
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
* Gives the activities that can handle given intent permissions for given uri. Not doing so will result in a SecurityException from Android N upwards
*
* @param context context of the activity requesting resolution for given intent
* @param intent intent that needs to get resolved
* @param uri uri for which permissions are to be given
* @param flags what permissions are to be given
*/
public static void grantPermissionForUri(Context context, Intent intent, Uri uri, int flags) {
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, flags);
}
}
public static class NoDataColumnForUriException extends Exception {
}
}