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 final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
38
39 // DocumentProvider
40 if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
41 // ExternalStorageProvider
42 if (isExternalStorageDocument(uri)) {
43 final String docId = DocumentsContract.getDocumentId(uri);
44 final String[] split = docId.split(":");
45 final String type = split[0];
46
47 if ("primary".equalsIgnoreCase(type)) {
48 return Environment.getExternalStorageDirectory() + "/" + split[1];
49 }
50
51 // TODO handle non-primary volumes
52 }
53 // DownloadsProvider
54 else if (isDownloadsDocument(uri)) {
55
56 final String id = DocumentsContract.getDocumentId(uri);
57 try {
58 final Uri contentUri = ContentUris.withAppendedId(PUBLIC_DOWNLOADS, Long.valueOf(id));
59 return getDataColumn(context, contentUri, null, null);
60 } catch (NumberFormatException e) {
61 return null;
62 }
63 }
64 // MediaProvider
65 else if (isMediaDocument(uri)) {
66 final String docId = DocumentsContract.getDocumentId(uri);
67 final String[] split = docId.split(":");
68 final String type = split[0];
69
70 Uri contentUri = null;
71 if ("image".equals(type)) {
72 contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
73 } else if ("video".equals(type)) {
74 contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
75 } else if ("audio".equals(type)) {
76 contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
77 }
78
79 final String selection = "_id=?";
80 final String[] selectionArgs = new String[]{
81 split[1]
82 };
83
84 return getDataColumn(context, contentUri, selection, selectionArgs);
85 }
86 }
87 // MediaStore (and general)
88 else if ("content".equalsIgnoreCase(uri.getScheme())) {
89 List<String> segments = uri.getPathSegments();
90 String path;
91 if (FileBackend.getAuthority(context).equals(uri.getAuthority()) && segments.size() > 1 && segments.get(0).equals("external")) {
92 path = Environment.getExternalStorageDirectory().getAbsolutePath() + uri.getPath().substring(segments.get(0).length() + 1);
93 } else {
94 path = getDataColumn(context, uri, null, null);
95 }
96 if (path != null) {
97 File file = new File(path);
98 if (!file.canRead()) {
99 return null;
100 }
101 }
102 return path;
103 }
104 // File
105 else if ("file".equalsIgnoreCase(uri.getScheme())) {
106 return uri.getPath();
107 }
108
109 return null;
110 }
111
112 /**
113 * Get the value of the data column for this Uri. This is useful for
114 * MediaStore Uris, and other file-based ContentProviders.
115 *
116 * @param context The context.
117 * @param uri The Uri to query.
118 * @param selection (Optional) Filter used in the query.
119 * @param selectionArgs (Optional) Selection arguments used in the query.
120 * @return The value of the _data column, which is typically a file path.
121 */
122 public static String getDataColumn(Context context, Uri uri, String selection,
123 String[] selectionArgs) {
124
125 Cursor cursor = null;
126 final String column = "_data";
127 final String[] projection = {
128 column
129 };
130
131 try {
132 cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
133 if (cursor != null && cursor.moveToFirst()) {
134 final int column_index = cursor.getColumnIndexOrThrow(column);
135 return cursor.getString(column_index);
136 }
137 } catch (Exception e) {
138 return null;
139 } finally {
140 if (cursor != null) {
141 cursor.close();
142 }
143 }
144 return null;
145 }
146
147
148 /**
149 * @param uri The Uri to check.
150 * @return Whether the Uri authority is ExternalStorageProvider.
151 */
152 public static boolean isExternalStorageDocument(Uri uri) {
153 return "com.android.externalstorage.documents".equals(uri.getAuthority());
154 }
155
156 /**
157 * @param uri The Uri to check.
158 * @return Whether the Uri authority is DownloadsProvider.
159 */
160 public static boolean isDownloadsDocument(Uri uri) {
161 return "com.android.providers.downloads.documents".equals(uri.getAuthority());
162 }
163
164 /**
165 * @param uri The Uri to check.
166 * @return Whether the Uri authority is MediaProvider.
167 */
168 public static boolean isMediaDocument(Uri uri) {
169 return "com.android.providers.media.documents".equals(uri.getAuthority());
170 }
171}