1package eu.siacs.conversations.utils;
2
3import android.annotation.SuppressLint;
4import android.content.ContentUris;
5import android.content.Context;
6import android.database.Cursor;
7import android.net.Uri;
8import android.os.Build;
9import android.os.Environment;
10import android.provider.DocumentsContract;
11import android.provider.MediaStore;
12
13import java.io.File;
14import java.util.List;
15
16import eu.siacs.conversations.persistance.FileBackend;
17
18public class FileUtils {
19
20 private static final Uri PUBLIC_DOWNLOADS = Uri.parse("content://downloads/public_downloads");
21
22 /**
23 * Get a file path from a Uri. This will get the the path for Storage Access
24 * Framework Documents, as well as the _data field for the MediaStore and
25 * other file-based ContentProviders.
26 *
27 * @param context The context.
28 * @param uri The Uri to query.
29 * @author paulburke
30 */
31 @SuppressLint("NewApi")
32 public static String getPath(final Context context, final Uri uri) {
33 if (uri == null) {
34 return null;
35 }
36
37 // DocumentProvider
38 if (DocumentsContract.isDocumentUri(context, uri)) {
39 // ExternalStorageProvider
40 if (isExternalStorageDocument(uri)) {
41 final String docId = DocumentsContract.getDocumentId(uri);
42 final String[] split = docId.split(":");
43 final String type = split[0];
44
45 if ("primary".equalsIgnoreCase(type)) {
46 return Environment.getExternalStorageDirectory() + "/" + split[1];
47 }
48
49 // TODO handle non-primary volumes
50 }
51 // DownloadsProvider
52 else if (isDownloadsDocument(uri)) {
53
54 final String id = DocumentsContract.getDocumentId(uri);
55 try {
56 final Uri contentUri = ContentUris.withAppendedId(PUBLIC_DOWNLOADS, Long.valueOf(id));
57 return getDataColumn(context, contentUri, null, null);
58 } catch (NumberFormatException e) {
59 return null;
60 }
61 }
62 // MediaProvider
63 else if (isMediaDocument(uri)) {
64 final String docId = DocumentsContract.getDocumentId(uri);
65 final String[] split = docId.split(":");
66 final String type = split[0];
67
68 Uri contentUri = null;
69 if ("image".equals(type)) {
70 contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
71 } else if ("video".equals(type)) {
72 contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
73 } else if ("audio".equals(type)) {
74 contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
75 }
76
77 final String selection = "_id=?";
78 final String[] selectionArgs = new String[]{
79 split[1]
80 };
81
82 return getDataColumn(context, contentUri, selection, selectionArgs);
83 }
84 }
85 // MediaStore (and general)
86 else if ("content".equalsIgnoreCase(uri.getScheme())) {
87 List<String> segments = uri.getPathSegments();
88 String path;
89 if (FileBackend.getAuthority(context).equals(uri.getAuthority()) && segments.size() > 1 && segments.get(0).equals("external")) {
90 path = Environment.getExternalStorageDirectory().getAbsolutePath() + uri.getPath().substring(segments.get(0).length() + 1);
91 } else {
92 path = getDataColumn(context, uri, null, null);
93 }
94 if (path != null) {
95 File file = new File(path);
96 if (!file.canRead()) {
97 return null;
98 }
99 }
100 return path;
101 }
102 // File
103 else if ("file".equalsIgnoreCase(uri.getScheme())) {
104 return uri.getPath();
105 }
106
107 return null;
108 }
109
110 /**
111 * Get the value of the data column for this Uri. This is useful for
112 * MediaStore Uris, and other file-based ContentProviders.
113 *
114 * @param context The context.
115 * @param uri The Uri to query.
116 * @param selection (Optional) Filter used in the query.
117 * @param selectionArgs (Optional) Selection arguments used in the query.
118 * @return The value of the _data column, which is typically a file path.
119 */
120 public static String getDataColumn(Context context, Uri uri, String selection,
121 String[] selectionArgs) {
122
123 Cursor cursor = null;
124 final String column = "_data";
125 final String[] projection = {
126 column
127 };
128
129 try {
130 cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
131 if (cursor != null && cursor.moveToFirst()) {
132 final int column_index = cursor.getColumnIndexOrThrow(column);
133 return cursor.getString(column_index);
134 }
135 } catch (Exception e) {
136 return null;
137 } finally {
138 if (cursor != null) {
139 cursor.close();
140 }
141 }
142 return null;
143 }
144
145
146 /**
147 * @param uri The Uri to check.
148 * @return Whether the Uri authority is ExternalStorageProvider.
149 */
150 public static boolean isExternalStorageDocument(Uri uri) {
151 return "com.android.externalstorage.documents".equals(uri.getAuthority());
152 }
153
154 /**
155 * @param uri The Uri to check.
156 * @return Whether the Uri authority is DownloadsProvider.
157 */
158 public static boolean isDownloadsDocument(Uri uri) {
159 return "com.android.providers.downloads.documents".equals(uri.getAuthority());
160 }
161
162 /**
163 * @param uri The Uri to check.
164 * @return Whether the Uri authority is MediaProvider.
165 */
166 public static boolean isMediaDocument(Uri uri) {
167 return "com.android.providers.media.documents".equals(uri.getAuthority());
168 }
169}