OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.base; | 5 package org.chromium.base; |
6 | 6 |
7 import android.content.ContentResolver; | 7 import android.content.ContentResolver; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.res.AssetFileDescriptor; | 9 import android.content.res.AssetFileDescriptor; |
10 import android.database.Cursor; | 10 import android.database.Cursor; |
(...skipping 20 matching lines...) Expand all Loading... |
31 // Guards access to sFileProviderUtil. | 31 // Guards access to sFileProviderUtil. |
32 private static final Object sLock = new Object(); | 32 private static final Object sLock = new Object(); |
33 | 33 |
34 /** | 34 /** |
35 * Provides functionality to translate a file into a content URI for use | 35 * Provides functionality to translate a file into a content URI for use |
36 * with a content provider. | 36 * with a content provider. |
37 */ | 37 */ |
38 public interface FileProviderUtil { | 38 public interface FileProviderUtil { |
39 /** | 39 /** |
40 * Generate a content URI from the given file. | 40 * Generate a content URI from the given file. |
41 * @param context Application context. | 41 * |
42 * @param file The file to be translated. | 42 * @param file The file to be translated. |
43 */ | 43 */ |
44 Uri getContentUriFromFile(Context context, File file); | 44 Uri getContentUriFromFile(File file); |
45 } | 45 } |
46 | 46 |
47 // Prevent instantiation. | 47 // Prevent instantiation. |
48 private ContentUriUtils() {} | 48 private ContentUriUtils() {} |
49 | 49 |
50 public static void setFileProviderUtil(FileProviderUtil util) { | 50 public static void setFileProviderUtil(FileProviderUtil util) { |
51 synchronized (sLock) { | 51 synchronized (sLock) { |
52 sFileProviderUtil = util; | 52 sFileProviderUtil = util; |
53 } | 53 } |
54 } | 54 } |
55 | 55 |
56 public static Uri getContentUriFromFile(Context context, File file) { | 56 public static Uri getContentUriFromFile(File file) { |
57 synchronized (sLock) { | 57 synchronized (sLock) { |
58 if (sFileProviderUtil != null) { | 58 if (sFileProviderUtil != null) { |
59 return sFileProviderUtil.getContentUriFromFile(context, file); | 59 return sFileProviderUtil.getContentUriFromFile(file); |
60 } | 60 } |
61 } | 61 } |
62 return null; | 62 return null; |
63 } | 63 } |
64 | 64 |
65 /** | 65 /** |
66 * Opens the content URI for reading, and returns the file descriptor to | 66 * Opens the content URI for reading, and returns the file descriptor to |
67 * the caller. The caller is responsible for closing the file desciptor. | 67 * the caller. The caller is responsible for closing the file descriptor. |
68 * | 68 * |
69 * @param context {@link Context} in interest | |
70 * @param uriString the content URI to open | 69 * @param uriString the content URI to open |
71 * @return file desciptor upon success, or -1 otherwise. | 70 * @return file descriptor upon success, or -1 otherwise. |
72 */ | 71 */ |
73 @CalledByNative | 72 @CalledByNative |
74 public static int openContentUriForRead(Context context, String uriString) { | 73 public static int openContentUriForRead(String uriString) { |
75 AssetFileDescriptor afd = getAssetFileDescriptor(context, uriString); | 74 AssetFileDescriptor afd = getAssetFileDescriptor(uriString); |
76 if (afd != null) { | 75 if (afd != null) { |
77 return afd.getParcelFileDescriptor().detachFd(); | 76 return afd.getParcelFileDescriptor().detachFd(); |
78 } | 77 } |
79 return -1; | 78 return -1; |
80 } | 79 } |
81 | 80 |
82 /** | 81 /** |
83 * Check whether a content URI exists. | 82 * Check whether a content URI exists. |
84 * | 83 * |
85 * @param context {@link Context} in interest. | |
86 * @param uriString the content URI to query. | 84 * @param uriString the content URI to query. |
87 * @return true if the URI exists, or false otherwise. | 85 * @return true if the URI exists, or false otherwise. |
88 */ | 86 */ |
89 @CalledByNative | 87 @CalledByNative |
90 public static boolean contentUriExists(Context context, String uriString) { | 88 public static boolean contentUriExists(String uriString) { |
91 AssetFileDescriptor asf = null; | 89 AssetFileDescriptor asf = null; |
92 try { | 90 try { |
93 asf = getAssetFileDescriptor(context, uriString); | 91 asf = getAssetFileDescriptor(uriString); |
94 return asf != null; | 92 return asf != null; |
95 } finally { | 93 } finally { |
96 // Do not use StreamUtil.closeQuietly here, as AssetFileDescriptor | 94 // Do not use StreamUtil.closeQuietly here, as AssetFileDescriptor |
97 // does not implement Closeable until KitKat. | 95 // does not implement Closeable until KitKat. |
98 if (asf != null) { | 96 if (asf != null) { |
99 try { | 97 try { |
100 asf.close(); | 98 asf.close(); |
101 } catch (IOException e) { | 99 } catch (IOException e) { |
102 // Closing quietly. | 100 // Closing quietly. |
103 } | 101 } |
104 } | 102 } |
105 } | 103 } |
106 } | 104 } |
107 | 105 |
108 /** | 106 /** |
109 * Retrieve the MIME type for the content URI. | 107 * Retrieve the MIME type for the content URI. |
110 * | 108 * |
111 * @param context {@link Context} in interest. | |
112 * @param uriString the content URI to look up. | 109 * @param uriString the content URI to look up. |
113 * @return MIME type or null if the input params are empty or invalid. | 110 * @return MIME type or null if the input params are empty or invalid. |
114 */ | 111 */ |
115 @CalledByNative | 112 @CalledByNative |
116 public static String getMimeType(Context context, String uriString) { | 113 public static String getMimeType(String uriString) { |
117 ContentResolver resolver = context.getContentResolver(); | 114 ContentResolver resolver = ContextUtils.getApplicationContext().getConte
ntResolver(); |
118 Uri uri = Uri.parse(uriString); | 115 Uri uri = Uri.parse(uriString); |
119 if (isVirtualDocument(uri, context)) { | 116 if (isVirtualDocument(uri)) { |
120 String[] streamTypes = resolver.getStreamTypes(uri, "*/*"); | 117 String[] streamTypes = resolver.getStreamTypes(uri, "*/*"); |
121 return (streamTypes != null && streamTypes.length > 0) ? streamTypes
[0] : null; | 118 return (streamTypes != null && streamTypes.length > 0) ? streamTypes
[0] : null; |
122 } | 119 } |
123 return resolver.getType(uri); | 120 return resolver.getType(uri); |
124 } | 121 } |
125 | 122 |
126 /** | 123 /** |
127 * Helper method to open a content URI and returns the ParcelFileDescriptor. | 124 * Helper method to open a content URI and returns the ParcelFileDescriptor. |
128 * | 125 * |
129 * @param context {@link Context} in interest. | |
130 * @param uriString the content URI to open. | 126 * @param uriString the content URI to open. |
131 * @return AssetFileDescriptor of the content URI, or NULL if the file does
not exist. | 127 * @return AssetFileDescriptor of the content URI, or NULL if the file does
not exist. |
132 */ | 128 */ |
133 private static AssetFileDescriptor getAssetFileDescriptor(Context context, S
tring uriString) { | 129 private static AssetFileDescriptor getAssetFileDescriptor(String uriString)
{ |
134 ContentResolver resolver = context.getContentResolver(); | 130 ContentResolver resolver = ContextUtils.getApplicationContext().getConte
ntResolver(); |
135 Uri uri = Uri.parse(uriString); | 131 Uri uri = Uri.parse(uriString); |
136 | 132 |
137 try { | 133 try { |
138 if (isVirtualDocument(uri, context)) { | 134 if (isVirtualDocument(uri)) { |
139 String[] streamTypes = resolver.getStreamTypes(uri, "*/*"); | 135 String[] streamTypes = resolver.getStreamTypes(uri, "*/*"); |
140 if (streamTypes != null && streamTypes.length > 0) { | 136 if (streamTypes != null && streamTypes.length > 0) { |
141 AssetFileDescriptor afd = | 137 AssetFileDescriptor afd = |
142 resolver.openTypedAssetFileDescriptor(uri, streamTyp
es[0], null); | 138 resolver.openTypedAssetFileDescriptor(uri, streamTyp
es[0], null); |
143 if (afd.getStartOffset() != 0) { | 139 if (afd != null && afd.getStartOffset() != 0) { |
144 // Do not use StreamUtil.closeQuietly here, as AssetFile
Descriptor | 140 // Do not use StreamUtil.closeQuietly here, as AssetFile
Descriptor |
145 // does not implement Closeable until KitKat. | 141 // does not implement Closeable until KitKat. |
146 try { | 142 try { |
147 afd.close(); | 143 afd.close(); |
148 } catch (IOException e) { | 144 } catch (IOException e) { |
149 // Closing quietly. | 145 // Closing quietly. |
150 } | 146 } |
151 throw new SecurityException("Cannot open files with non-
zero offset type."); | 147 throw new SecurityException("Cannot open files with non-
zero offset type."); |
152 } | 148 } |
153 return afd; | 149 return afd; |
154 } | 150 } |
155 } else { | 151 } else { |
156 ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")
; | 152 ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")
; |
157 if (pfd != null) { | 153 if (pfd != null) { |
158 return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.U
NKNOWN_LENGTH); | 154 return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.U
NKNOWN_LENGTH); |
159 } | 155 } |
160 } | 156 } |
161 } catch (FileNotFoundException e) { | 157 } catch (FileNotFoundException e) { |
162 Log.w(TAG, "Cannot find content uri: " + uriString, e); | 158 Log.w(TAG, "Cannot find content uri: " + uriString, e); |
163 } catch (SecurityException e) { | 159 } catch (SecurityException e) { |
164 Log.w(TAG, "Cannot open content uri: " + uriString, e); | 160 Log.w(TAG, "Cannot open content uri: " + uriString, e); |
165 } catch (IllegalArgumentException e) { | 161 } catch (IllegalArgumentException | IllegalStateException e) { |
166 Log.w(TAG, "Unknown content uri: " + uriString, e); | |
167 } catch (IllegalStateException e) { | |
168 Log.w(TAG, "Unknown content uri: " + uriString, e); | 162 Log.w(TAG, "Unknown content uri: " + uriString, e); |
169 } | 163 } |
170 | 164 |
171 return null; | 165 return null; |
172 } | 166 } |
173 | 167 |
174 /** | 168 /** |
175 * Method to resolve the display name of a content URI. | 169 * Method to resolve the display name of a content URI. |
176 * | 170 * |
177 * @param uri the content URI to be resolved. | 171 * @param uri the content URI to be resolved. |
178 * @param context {@link Context} in interest. | 172 * @param context {@link Context} in interest. |
179 * @param columnField the column field to query. | 173 * @param columnField the column field to query. |
180 * @return the display name of the @code uri if present in the database | 174 * @return the display name of the @code uri if present in the database |
181 * or an empty string otherwise. | 175 * or an empty string otherwise. |
182 */ | 176 */ |
183 public static String getDisplayName(Uri uri, Context context, String columnF
ield) { | 177 public static String getDisplayName(Uri uri, Context context, String columnF
ield) { |
184 if (uri == null) return ""; | 178 if (uri == null) return ""; |
185 ContentResolver contentResolver = context.getContentResolver(); | 179 ContentResolver contentResolver = context.getContentResolver(); |
186 Cursor cursor = null; | 180 Cursor cursor = null; |
187 try { | 181 try { |
188 cursor = contentResolver.query(uri, null, null, null, null); | 182 cursor = contentResolver.query(uri, null, null, null, null); |
189 | 183 |
190 if (cursor != null && cursor.getCount() >= 1) { | 184 if (cursor != null && cursor.getCount() >= 1) { |
191 cursor.moveToFirst(); | 185 cursor.moveToFirst(); |
(...skipping 25 matching lines...) Expand all Loading... |
217 } finally { | 211 } finally { |
218 StreamUtil.closeQuietly(cursor); | 212 StreamUtil.closeQuietly(cursor); |
219 } | 213 } |
220 return ""; | 214 return ""; |
221 } | 215 } |
222 | 216 |
223 /** | 217 /** |
224 * Checks whether the passed Uri represents a virtual document. | 218 * Checks whether the passed Uri represents a virtual document. |
225 * | 219 * |
226 * @param uri the content URI to be resolved. | 220 * @param uri the content URI to be resolved. |
227 * @param contentResolver the content resolver to query. | |
228 * @return True for virtual file, false for any other file. | 221 * @return True for virtual file, false for any other file. |
229 */ | 222 */ |
230 private static boolean isVirtualDocument(Uri uri, Context context) { | 223 private static boolean isVirtualDocument(Uri uri) { |
231 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return false; | 224 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return false; |
232 if (uri == null) return false; | 225 if (uri == null) return false; |
233 if (!DocumentsContract.isDocumentUri(context, uri)) return false; | 226 if (!DocumentsContract.isDocumentUri(ContextUtils.getApplicationContext(
), uri)) { |
234 ContentResolver contentResolver = context.getContentResolver(); | 227 return false; |
| 228 } |
| 229 ContentResolver contentResolver = ContextUtils.getApplicationContext().g
etContentResolver(); |
235 Cursor cursor = null; | 230 Cursor cursor = null; |
236 try { | 231 try { |
237 cursor = contentResolver.query(uri, null, null, null, null); | 232 cursor = contentResolver.query(uri, null, null, null, null); |
238 | 233 |
239 if (cursor != null && cursor.getCount() >= 1) { | 234 if (cursor != null && cursor.getCount() >= 1) { |
240 cursor.moveToFirst(); | 235 cursor.moveToFirst(); |
241 return hasVirtualFlag(cursor); | 236 return hasVirtualFlag(cursor); |
242 } | 237 } |
243 } catch (NullPointerException e) { | 238 } catch (NullPointerException e) { |
244 // Some android models don't handle the provider call correctly. | 239 // Some android models don't handle the provider call correctly. |
245 // see crbug.com/345393 | 240 // see crbug.com/345393 |
246 return false; | 241 return false; |
247 } finally { | 242 } finally { |
248 StreamUtil.closeQuietly(cursor); | 243 StreamUtil.closeQuietly(cursor); |
249 } | 244 } |
250 return false; | 245 return false; |
251 } | 246 } |
252 | 247 |
253 /** | 248 /** |
254 * Checks whether the passed cursor for a document has a virtual document fl
ag. | 249 * Checks whether the passed cursor for a document has a virtual document fl
ag. |
255 * | 250 * |
256 * The called must close the passed cursor. | 251 * The called must close the passed cursor. |
257 * | 252 * |
258 * @param cursor Cursor with COLUMN_FLAGS. | 253 * @param cursor Cursor with COLUMN_FLAGS. |
259 * @return True for virtual file, false for any other file. | 254 * @return True for virtual file, false for any other file. |
260 */ | 255 */ |
261 private static boolean hasVirtualFlag(Cursor cursor) { | 256 private static boolean hasVirtualFlag(Cursor cursor) { |
262 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return false; | 257 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return false; |
263 int index = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAG
S); | 258 int index = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAG
S); |
264 if (index > -1) { | 259 return index > -1 |
265 return (cursor.getLong(index) & DocumentsContract.Document.FLAG_VIRT
UAL_DOCUMENT) != 0; | 260 && (cursor.getLong(index) & DocumentsContract.Document.FLAG_VIRT
UAL_DOCUMENT) != 0; |
266 } | |
267 return false; | |
268 } | 261 } |
269 } | 262 } |
OLD | NEW |