Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(494)

Unified Diff: base/android/java/src/org/chromium/base/ContentUriUtils.java

Issue 2545343002: Add support for virtual files to Clank. (Closed)
Patch Set: Add support for virtual files to Clank. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/android/java/src/org/chromium/base/ContentUriUtils.java
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
index 5448aa0e9ebf4b30cbf138bbb77aa0705e817ef0..db16d9763f3b07d20b857da71f3ef0b6d614a2c8 100644
--- a/base/android/java/src/org/chromium/base/ContentUriUtils.java
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -6,10 +6,14 @@ package org.chromium.base;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
import android.util.Log;
+import android.webkit.MimeTypeMap;
import org.chromium.base.annotations.CalledByNative;
@@ -67,9 +71,9 @@ public abstract class ContentUriUtils {
*/
@CalledByNative
public static int openContentUriForRead(Context context, String uriString) {
- ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
- if (pfd != null) {
- return pfd.detachFd();
+ AssetFileDescriptor afd = getAssetFileDescriptor(context, uriString);
+ if (afd != null) {
+ return afd.getParcelFileDescriptor().detachFd();
}
return -1;
}
@@ -83,7 +87,13 @@ public abstract class ContentUriUtils {
*/
@CalledByNative
public static boolean contentUriExists(Context context, String uriString) {
- return getParcelFileDescriptor(context, uriString) != null;
+ AssetFileDescriptor asf = null;
+ try {
+ asf = getAssetFileDescriptor(context, uriString);
+ return asf != null;
+ } finally {
+ StreamUtil.closeQuietly(asf);
+ }
}
/**
@@ -96,8 +106,11 @@ public abstract class ContentUriUtils {
@CalledByNative
public static String getMimeType(Context context, String uriString) {
ContentResolver resolver = context.getContentResolver();
- if (resolver == null) return null;
Uri uri = Uri.parse(uriString);
+ if (isVirtualDocument(uri, context)) {
+ String[] streamTypes = resolver.getStreamTypes(uri, "*/*");
+ return (streamTypes != null && streamTypes.length > 0) ? streamTypes[0] : null;
+ }
return resolver.getType(uri);
}
@@ -106,15 +119,30 @@ public abstract class ContentUriUtils {
*
* @param context {@link Context} in interest.
* @param uriString the content URI to open.
- * @return ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
+ * @return AssetFileDescriptor of the content URI, or NULL if the file does not exist.
*/
- private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
+ private static AssetFileDescriptor getAssetFileDescriptor(Context context, String uriString) {
ContentResolver resolver = context.getContentResolver();
Uri uri = Uri.parse(uriString);
- ParcelFileDescriptor pfd = null;
try {
- pfd = resolver.openFileDescriptor(uri, "r");
+ if (isVirtualDocument(uri, context)) {
+ String[] streamTypes = resolver.getStreamTypes(uri, "*/*");
+ if (streamTypes != null && streamTypes.length > 0) {
+ AssetFileDescriptor afd =
+ resolver.openTypedAssetFileDescriptor(uri, streamTypes[0], null);
+ if (afd.getStartOffset() != 0) {
+ StreamUtil.closeQuietly(afd);
+ throw new SecurityException("Cannot open files with non-zero offset type.");
+ }
+ return afd;
+ }
+ } else {
+ ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
+ if (pfd != null) {
+ return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+ }
+ }
} catch (FileNotFoundException e) {
Log.w(TAG, "Cannot find content uri: " + uriString, e);
} catch (SecurityException e) {
@@ -124,37 +152,102 @@ public abstract class ContentUriUtils {
} catch (IllegalStateException e) {
Log.w(TAG, "Unknown content uri: " + uriString, e);
}
- return pfd;
+
+ return null;
}
/**
* Method to resolve the display name of a content URI.
*
* @param uri the content URI to be resolved.
- * @param contentResolver the content resolver to query.
- * @param columnField the column field to query.
+ * @param context {@link Context} in interest.
* @return the display name of the @code uri if present in the database
* or an empty string otherwise.
*/
- public static String getDisplayName(
- Uri uri, ContentResolver contentResolver, String columnField) {
- if (contentResolver == null || uri == null) return "";
+ public static String getDisplayName(Uri uri, Context context, String columnField) {
+ if (uri == null) return "";
+ ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() >= 1) {
cursor.moveToFirst();
- int index = cursor.getColumnIndex(columnField);
- if (index > -1) return cursor.getString(index);
+ int displayNameIndex = cursor.getColumnIndex(columnField);
+ if (displayNameIndex == -1) {
+ return "";
+ }
+ String displayName = cursor.getString(displayNameIndex);
+ // For Virtual documents, try to modify the file extension so it's compatible
+ // with the alternative MIME type.
+ if (hasVirtualFlag(cursor)) {
+ String[] mimeTypes = contentResolver.getStreamTypes(uri, "*/*");
+ if (mimeTypes != null && mimeTypes.length > 0) {
+ String ext =
+ MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeTypes[0]);
+ if (ext != null) {
+ // Just append, it's simpler and more secure than altering an
+ // existing extension.
+ displayName += "." + ext;
+ }
+ }
+ }
+ return displayName;
}
} catch (NullPointerException e) {
// Some android models don't handle the provider call correctly.
// see crbug.com/345393
return "";
} finally {
- if (cursor != null) cursor.close();
+ StreamUtil.closeQuietly(cursor);
}
return "";
}
+
+ /**
+ * Checks whether the passed Uri represents a virtual document.
+ *
+ * @param uri the content URI to be resolved.
+ * @param contentResolver the content resolver to query.
+ * @return True for virtual file, false for any other file.
+ */
+ private static boolean isVirtualDocument(Uri uri, Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return false;
+ if (uri == null) return false;
+ if (!DocumentsContract.isDocumentUri(context, uri)) return false;
+ ContentResolver contentResolver = context.getContentResolver();
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(uri, null, null, null, null);
+
+ if (cursor != null && cursor.getCount() >= 1) {
+ cursor.moveToFirst();
+ return hasVirtualFlag(cursor);
+ }
+ } catch (NullPointerException e) {
+ // Some android models don't handle the provider call correctly.
+ // see crbug.com/345393
+ return false;
+ } finally {
+ StreamUtil.closeQuietly(cursor);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether the passed cursor for a document has a virtual document flag.
+ *
+ * The called must close the passed cursor.
+ *
+ * @param cursor Cursor with COLUMN_FLAGS.
+ * @return True for virtual file, false for any other file.
+ */
+ private static boolean hasVirtualFlag(Cursor cursor) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return false;
+ int index = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS);
+ if (index > -1) {
+ return (cursor.getLong(index) & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
+ }
+ return false;
+ }
}

Powered by Google App Engine
This is Rietveld 408576698