Loading core/java/android/provider/DocumentsProvider.java +0 −26 Original line number Diff line number Diff line Loading @@ -66,8 +66,6 @@ import android.util.Log; import libcore.io.IoUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.Objects; Loading Loading @@ -634,30 +632,6 @@ public abstract class DocumentsProvider extends ContentProvider { throw new UnsupportedOperationException("Metadata not supported"); } /** * Returns metadata for arbitrary file given its stream and mimetype. * * <p><b>Note: Providers should only call this with streams for locally cached resources. * Use of network backed streams is inadvisable for performance reasons. * * @param stream The input stream. Should be backed by locally cached content. * Client retains ownership of the stream. * @param mimeType The mime type of the file. * @param tags The list of tags to load, if known. Pass null to get a default set. * @return Bundle containing any metadata found. * @throws IOException in the event of an error reading metadata. * * @hide */ protected Bundle getDocumentMetadataFromStream(InputStream stream, String mimeType) throws IOException { Bundle metadata = new Bundle(); // TODO: Remove the last null arg from MetadataReader. It was the "tags" value, // the has been removed from the getDocumentMetadata method. MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } /** * Return concrete MIME type of the requested document. Must match the value * of {@link Document#COLUMN_MIME_TYPE} for this document. The default Loading core/java/android/provider/MetadataReader.java +26 −16 Original line number Diff line number Diff line Loading @@ -36,29 +36,31 @@ import java.util.Map; */ public final class MetadataReader { private MetadataReader() { } private MetadataReader() {} private static final String[] DEFAULT_EXIF_TAGS = { ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.TAG_APERTURE, ExifInterface.TAG_COPYRIGHT, ExifInterface.TAG_DATETIME, ExifInterface.TAG_EXPOSURE_TIME, ExifInterface.TAG_F_NUMBER, ExifInterface.TAG_GPS_LATITUDE, ExifInterface.TAG_GPS_LATITUDE_REF, ExifInterface.TAG_GPS_LONGITUDE, ExifInterface.TAG_GPS_LONGITUDE_REF, ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.TAG_MAKE, ExifInterface.TAG_MODEL, ExifInterface.TAG_APERTURE, ExifInterface.TAG_SHUTTER_SPEED_VALUE ExifInterface.TAG_ORIENTATION, ExifInterface.TAG_SHUTTER_SPEED_VALUE, }; private static final Map<String, Integer> TYPE_MAPPING = new HashMap<>(); private static final String[] ALL_KNOWN_EXIF_KEYS; private static final int TYPE_INT = 0; private static final int TYPE_DOUBLE = 1; private static final int TYPE_STRING = 2; private static final Map<String, Integer> TYPE_MAPPING = new HashMap<>(); static { // TODO: Move this over to ExifInterface.java // Since each ExifInterface item has a type, and there's currently no way to get the type Loading Loading @@ -198,11 +200,19 @@ public final class MetadataReader { TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER, TYPE_INT); TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_TOP_BORDER, TYPE_INT); TYPE_MAPPING.put(ExifInterface.TAG_RW2_ISO, TYPE_INT); ALL_KNOWN_EXIF_KEYS = TYPE_MAPPING.keySet().toArray(new String[TYPE_MAPPING.size()]); } private static final String JPG_MIME_TYPE = "image/jpg"; private static final String JPEG_MIME_TYPE = "image/jpeg"; /** * Returns true if caller can generally expect to get metadata results * for the supplied mimetype. */ public static boolean isSupportedMimeType(String mimeType) { return JPG_MIME_TYPE.equals(mimeType) || JPEG_MIME_TYPE.equals(mimeType); } /** * Generic metadata retrieval method that can retrieve any available metadata from a given doc * Currently only functions for exifdata Loading @@ -228,10 +238,9 @@ public final class MetadataReader { */ public static void getMetadata(Bundle metadata, InputStream stream, String mimeType, @Nullable String[] tags) throws IOException { List<String> metadataTypes = new ArrayList(); if (mimeType.equals(JPG_MIME_TYPE) || mimeType.equals(JPEG_MIME_TYPE)) { ExifInterface exifInterface = new ExifInterface(stream); Bundle exifData = getExifData(exifInterface, tags); List<String> metadataTypes = new ArrayList<>(); if (isSupportedMimeType(mimeType)) { Bundle exifData = getExifData(stream, tags); if (exifData.size() > 0) { metadata.putBundle(DocumentsContract.METADATA_EXIF, exifData); metadataTypes.add(DocumentsContract.METADATA_EXIF); Loading @@ -246,8 +255,7 @@ public final class MetadataReader { /** * Helper method that is called if getMetadata is called for an image mimeType. * * @param exif the bundle to which we add exif data. * @param exifInterface an ExifInterface for an image * @param stream the input stream from which to extra data. * @param tags a list of ExifInterface tags that are used to retrieve data. * if null, returns a default set of data from the following keys: * ExifInterface.TAG_IMAGE_WIDTH, Loading @@ -262,11 +270,13 @@ public final class MetadataReader { * ExifInterface.TAG_APERTURE, * ExifInterface.TAG_SHUTTER_SPEED_VALUE */ private static Bundle getExifData(ExifInterface exifInterface, @Nullable String[] tags) private static Bundle getExifData(InputStream stream, @Nullable String[] tags) throws IOException { if (tags == null) { tags = DEFAULT_EXIF_TAGS; } ExifInterface exifInterface = new ExifInterface(stream); Bundle exif = new Bundle(); for (String tag : tags) { if (TYPE_MAPPING.get(tag).equals(TYPE_INT)) { Loading core/java/com/android/internal/content/FileSystemProvider.java +15 −8 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsProvider; import android.provider.MediaStore; import android.provider.MetadataReader; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; Loading @@ -51,6 +52,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; import java.util.Set; Loading Loading @@ -118,26 +120,31 @@ public abstract class FileSystemProvider extends DocumentsProvider { if (!file.isFile()) { Log.w(TAG, "Can't stream non-regular file. Returning empty metadata."); return Bundle.EMPTY; return null; } if (!file.canRead()) { Log.w(TAG, "Can't stream non-readable file. Returning empty metadata."); return Bundle.EMPTY; return null; } String filePath = file.getAbsolutePath(); FileInputStream stream = new FileInputStream(filePath); String mimeType = getTypeForFile(file); if (!MetadataReader.isSupportedMimeType(mimeType)) { return null; } InputStream stream = null; try { return getDocumentMetadataFromStream(stream, getTypeForFile(file)); Bundle metadata = new Bundle(); stream = new FileInputStream(file.getAbsolutePath()); MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } catch (IOException e) { Log.e(TAG, "An error occurred retrieving the metadata", e); return null; } finally { IoUtils.closeQuietly(stream); } return null; } protected final List<String> findDocumentPath(File parent, File doc) Loading Loading @@ -491,7 +498,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } protected boolean typeSupportsMetadata(String mimeType) { return MIMETYPE_JPG.equals(mimeType) || MIMETYPE_JPEG.equals(mimeType); return MetadataReader.isSupportedMimeType(mimeType); } private static String getTypeForName(String name) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +4 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.MetadataReader; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; Loading Loading @@ -900,6 +901,9 @@ class MtpDatabase { protectionState == MtpConstants.PROTECTION_STATUS_NONE) { flag |= Document.FLAG_DIR_SUPPORTS_CREATE; } if (MetadataReader.isSupportedMimeType(mimeType)) { flag |= Document.FLAG_SUPPORTS_METADATA; } if (thumbnailSize > 0) { flag |= Document.FLAG_SUPPORTS_THUMBNAIL; } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +31 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.mtp; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; Loading @@ -37,11 +38,12 @@ import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.ProxyFileDescriptorCallback; import android.os.storage.StorageManager; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Path; import android.provider.DocumentsContract.Root; import android.provider.DocumentsContract; import android.provider.DocumentsProvider; import android.provider.MetadataReader; import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; Loading @@ -50,14 +52,16 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; import libcore.io.IoUtils; /** * DocumentsProvider for MTP devices. Loading Loading @@ -107,7 +111,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { mResources = getContext().getResources(); mMtpManager = new MtpManager(getContext()); mResolver = getContext().getContentResolver(); mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDeviceToolkits = new HashMap<>(); mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE); mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mIntentSender = new ServiceIntentSender(getContext()); Loading Loading @@ -151,7 +155,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { mResources = resources; mMtpManager = mtpManager; mResolver = resolver; mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDeviceToolkits = new HashMap<>(); mDatabase = database; mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mIntentSender = intentSender; Loading Loading @@ -548,6 +552,29 @@ public class MtpDocumentsProvider extends DocumentsProvider { } } @Override public @Nullable Bundle getDocumentMetadata(String docId) throws FileNotFoundException { String mimeType = getDocumentType(docId); if (!MetadataReader.isSupportedMimeType(mimeType)) { return null; } InputStream stream = null; try { stream = new ParcelFileDescriptor.AutoCloseInputStream( openDocument(docId, "r", null)); Bundle metadata = new Bundle(); MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } catch (IOException e) { Log.e(TAG, "An error occurred retrieving the metadata", e); return null; } finally { IoUtils.closeQuietly(stream); } } void openDevice(int deviceId) throws IOException { synchronized (mDeviceListLock) { if (mDeviceToolkits.containsKey(deviceId)) { Loading Loading
core/java/android/provider/DocumentsProvider.java +0 −26 Original line number Diff line number Diff line Loading @@ -66,8 +66,6 @@ import android.util.Log; import libcore.io.IoUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.Objects; Loading Loading @@ -634,30 +632,6 @@ public abstract class DocumentsProvider extends ContentProvider { throw new UnsupportedOperationException("Metadata not supported"); } /** * Returns metadata for arbitrary file given its stream and mimetype. * * <p><b>Note: Providers should only call this with streams for locally cached resources. * Use of network backed streams is inadvisable for performance reasons. * * @param stream The input stream. Should be backed by locally cached content. * Client retains ownership of the stream. * @param mimeType The mime type of the file. * @param tags The list of tags to load, if known. Pass null to get a default set. * @return Bundle containing any metadata found. * @throws IOException in the event of an error reading metadata. * * @hide */ protected Bundle getDocumentMetadataFromStream(InputStream stream, String mimeType) throws IOException { Bundle metadata = new Bundle(); // TODO: Remove the last null arg from MetadataReader. It was the "tags" value, // the has been removed from the getDocumentMetadata method. MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } /** * Return concrete MIME type of the requested document. Must match the value * of {@link Document#COLUMN_MIME_TYPE} for this document. The default Loading
core/java/android/provider/MetadataReader.java +26 −16 Original line number Diff line number Diff line Loading @@ -36,29 +36,31 @@ import java.util.Map; */ public final class MetadataReader { private MetadataReader() { } private MetadataReader() {} private static final String[] DEFAULT_EXIF_TAGS = { ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.TAG_APERTURE, ExifInterface.TAG_COPYRIGHT, ExifInterface.TAG_DATETIME, ExifInterface.TAG_EXPOSURE_TIME, ExifInterface.TAG_F_NUMBER, ExifInterface.TAG_GPS_LATITUDE, ExifInterface.TAG_GPS_LATITUDE_REF, ExifInterface.TAG_GPS_LONGITUDE, ExifInterface.TAG_GPS_LONGITUDE_REF, ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.TAG_MAKE, ExifInterface.TAG_MODEL, ExifInterface.TAG_APERTURE, ExifInterface.TAG_SHUTTER_SPEED_VALUE ExifInterface.TAG_ORIENTATION, ExifInterface.TAG_SHUTTER_SPEED_VALUE, }; private static final Map<String, Integer> TYPE_MAPPING = new HashMap<>(); private static final String[] ALL_KNOWN_EXIF_KEYS; private static final int TYPE_INT = 0; private static final int TYPE_DOUBLE = 1; private static final int TYPE_STRING = 2; private static final Map<String, Integer> TYPE_MAPPING = new HashMap<>(); static { // TODO: Move this over to ExifInterface.java // Since each ExifInterface item has a type, and there's currently no way to get the type Loading Loading @@ -198,11 +200,19 @@ public final class MetadataReader { TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER, TYPE_INT); TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_TOP_BORDER, TYPE_INT); TYPE_MAPPING.put(ExifInterface.TAG_RW2_ISO, TYPE_INT); ALL_KNOWN_EXIF_KEYS = TYPE_MAPPING.keySet().toArray(new String[TYPE_MAPPING.size()]); } private static final String JPG_MIME_TYPE = "image/jpg"; private static final String JPEG_MIME_TYPE = "image/jpeg"; /** * Returns true if caller can generally expect to get metadata results * for the supplied mimetype. */ public static boolean isSupportedMimeType(String mimeType) { return JPG_MIME_TYPE.equals(mimeType) || JPEG_MIME_TYPE.equals(mimeType); } /** * Generic metadata retrieval method that can retrieve any available metadata from a given doc * Currently only functions for exifdata Loading @@ -228,10 +238,9 @@ public final class MetadataReader { */ public static void getMetadata(Bundle metadata, InputStream stream, String mimeType, @Nullable String[] tags) throws IOException { List<String> metadataTypes = new ArrayList(); if (mimeType.equals(JPG_MIME_TYPE) || mimeType.equals(JPEG_MIME_TYPE)) { ExifInterface exifInterface = new ExifInterface(stream); Bundle exifData = getExifData(exifInterface, tags); List<String> metadataTypes = new ArrayList<>(); if (isSupportedMimeType(mimeType)) { Bundle exifData = getExifData(stream, tags); if (exifData.size() > 0) { metadata.putBundle(DocumentsContract.METADATA_EXIF, exifData); metadataTypes.add(DocumentsContract.METADATA_EXIF); Loading @@ -246,8 +255,7 @@ public final class MetadataReader { /** * Helper method that is called if getMetadata is called for an image mimeType. * * @param exif the bundle to which we add exif data. * @param exifInterface an ExifInterface for an image * @param stream the input stream from which to extra data. * @param tags a list of ExifInterface tags that are used to retrieve data. * if null, returns a default set of data from the following keys: * ExifInterface.TAG_IMAGE_WIDTH, Loading @@ -262,11 +270,13 @@ public final class MetadataReader { * ExifInterface.TAG_APERTURE, * ExifInterface.TAG_SHUTTER_SPEED_VALUE */ private static Bundle getExifData(ExifInterface exifInterface, @Nullable String[] tags) private static Bundle getExifData(InputStream stream, @Nullable String[] tags) throws IOException { if (tags == null) { tags = DEFAULT_EXIF_TAGS; } ExifInterface exifInterface = new ExifInterface(stream); Bundle exif = new Bundle(); for (String tag : tags) { if (TYPE_MAPPING.get(tag).equals(TYPE_INT)) { Loading
core/java/com/android/internal/content/FileSystemProvider.java +15 −8 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsProvider; import android.provider.MediaStore; import android.provider.MetadataReader; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; Loading @@ -51,6 +52,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; import java.util.Set; Loading Loading @@ -118,26 +120,31 @@ public abstract class FileSystemProvider extends DocumentsProvider { if (!file.isFile()) { Log.w(TAG, "Can't stream non-regular file. Returning empty metadata."); return Bundle.EMPTY; return null; } if (!file.canRead()) { Log.w(TAG, "Can't stream non-readable file. Returning empty metadata."); return Bundle.EMPTY; return null; } String filePath = file.getAbsolutePath(); FileInputStream stream = new FileInputStream(filePath); String mimeType = getTypeForFile(file); if (!MetadataReader.isSupportedMimeType(mimeType)) { return null; } InputStream stream = null; try { return getDocumentMetadataFromStream(stream, getTypeForFile(file)); Bundle metadata = new Bundle(); stream = new FileInputStream(file.getAbsolutePath()); MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } catch (IOException e) { Log.e(TAG, "An error occurred retrieving the metadata", e); return null; } finally { IoUtils.closeQuietly(stream); } return null; } protected final List<String> findDocumentPath(File parent, File doc) Loading Loading @@ -491,7 +498,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } protected boolean typeSupportsMetadata(String mimeType) { return MIMETYPE_JPG.equals(mimeType) || MIMETYPE_JPEG.equals(mimeType); return MetadataReader.isSupportedMimeType(mimeType); } private static String getTypeForName(String name) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +4 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; import android.net.Uri; import android.provider.DocumentsContract; import android.provider.MetadataReader; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; Loading Loading @@ -900,6 +901,9 @@ class MtpDatabase { protectionState == MtpConstants.PROTECTION_STATUS_NONE) { flag |= Document.FLAG_DIR_SUPPORTS_CREATE; } if (MetadataReader.isSupportedMimeType(mimeType)) { flag |= Document.FLAG_SUPPORTS_METADATA; } if (thumbnailSize > 0) { flag |= Document.FLAG_SUPPORTS_THUMBNAIL; } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +31 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.mtp; import android.annotation.Nullable; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; Loading @@ -37,11 +38,12 @@ import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.ProxyFileDescriptorCallback; import android.os.storage.StorageManager; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Path; import android.provider.DocumentsContract.Root; import android.provider.DocumentsContract; import android.provider.DocumentsProvider; import android.provider.MetadataReader; import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; Loading @@ -50,14 +52,16 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; import libcore.io.IoUtils; /** * DocumentsProvider for MTP devices. Loading Loading @@ -107,7 +111,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { mResources = getContext().getResources(); mMtpManager = new MtpManager(getContext()); mResolver = getContext().getContentResolver(); mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDeviceToolkits = new HashMap<>(); mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE); mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mIntentSender = new ServiceIntentSender(getContext()); Loading Loading @@ -151,7 +155,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { mResources = resources; mMtpManager = mtpManager; mResolver = resolver; mDeviceToolkits = new HashMap<Integer, DeviceToolkit>(); mDeviceToolkits = new HashMap<>(); mDatabase = database; mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase); mIntentSender = intentSender; Loading Loading @@ -548,6 +552,29 @@ public class MtpDocumentsProvider extends DocumentsProvider { } } @Override public @Nullable Bundle getDocumentMetadata(String docId) throws FileNotFoundException { String mimeType = getDocumentType(docId); if (!MetadataReader.isSupportedMimeType(mimeType)) { return null; } InputStream stream = null; try { stream = new ParcelFileDescriptor.AutoCloseInputStream( openDocument(docId, "r", null)); Bundle metadata = new Bundle(); MetadataReader.getMetadata(metadata, stream, mimeType, null); return metadata; } catch (IOException e) { Log.e(TAG, "An error occurred retrieving the metadata", e); return null; } finally { IoUtils.closeQuietly(stream); } } void openDevice(int deviceId) throws IOException { synchronized (mDeviceListLock) { if (mDeviceToolkits.containsKey(deviceId)) { Loading