package com.bumptech.glide.load.data.mediastore; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import android.util.Log; import com.bumptech.glide.Glide; import com.bumptech.glide.Priority; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.data.ExifOrientationStream; import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * A {@link DataFetcher} implementation for {@link InputStream}s that loads data from thumbnail * files obtained from the {@link MediaStore}. */ @SuppressWarnings("PMD.FieldDeclarationsShouldBeAtStartOfClass") public class ThumbFetcher implements DataFetcher<InputStream> { private static final String TAG = "MediaStoreThumbFetcher"; private final Uri mediaStoreImageUri; private final ThumbnailStreamOpener opener; private InputStream inputStream; // TODO(nnaze): These build methods do not need the full Glide or Context objects. public static ThumbFetcher buildImageFetcher(Context context, Uri uri) { return build(context, uri, new ImageThumbnailQuery(context.getContentResolver())); } public static ThumbFetcher buildVideoFetcher(Context context, Uri uri) { return build(context, uri, new VideoThumbnailQuery(context.getContentResolver())); } private static ThumbFetcher build(Context context, Uri uri, ThumbnailQuery query) { ArrayPool byteArrayPool = Glide.get(context).getArrayPool(); ThumbnailStreamOpener opener = new ThumbnailStreamOpener( Glide.get(context).getRegistry().getImageHeaderParsers(), query, byteArrayPool, context.getContentResolver()); return new ThumbFetcher(uri, opener); } // Visible for testing. ThumbFetcher(Uri mediaStoreImageUri, ThumbnailStreamOpener opener) { this.mediaStoreImageUri = mediaStoreImageUri; this.opener = opener; } @Override public void loadData(Priority priority, DataCallback<? super InputStream> callback) { try { inputStream = openThumbInputStream(); } catch (FileNotFoundException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to find thumbnail file", e); } callback.onLoadFailed(e); return; } callback.onDataReady(inputStream); } private InputStream openThumbInputStream() throws FileNotFoundException { InputStream result = opener.open(mediaStoreImageUri); int orientation = -1; if (result != null) { orientation = opener.getOrientation(mediaStoreImageUri); } if (orientation != -1) { result = new ExifOrientationStream(result, orientation); } return result; } @Override public void cleanup() { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // Ignored. } } } @Override public void cancel() { // Do nothing. } @Override public Class<InputStream> getDataClass() { return InputStream.class; } @Override public DataSource getDataSource() { return DataSource.LOCAL; } static class VideoThumbnailQuery implements ThumbnailQuery { private final ContentResolver contentResolver; VideoThumbnailQuery(ContentResolver contentResolver) { this.contentResolver = contentResolver; } private static final String[] PATH_PROJECTION = { MediaStore.Video.Thumbnails.DATA }; private static final String PATH_SELECTION = MediaStore.Video.Thumbnails.KIND + " = " + MediaStore.Video.Thumbnails.MINI_KIND + " AND " + MediaStore.Video.Thumbnails.VIDEO_ID + " = ?"; @Override public Cursor query(Uri uri) { String videoId = uri.getLastPathSegment(); return contentResolver.query( MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, PATH_PROJECTION, PATH_SELECTION, new String[] {videoId}, null /*sortOrder*/); } } static class ImageThumbnailQuery implements ThumbnailQuery { private final ContentResolver contentResolver; ImageThumbnailQuery(ContentResolver contentResolver) { this.contentResolver = contentResolver; } private static final String[] PATH_PROJECTION = { MediaStore.Images.Thumbnails.DATA, }; private static final String PATH_SELECTION = MediaStore.Images.Thumbnails.KIND + " = " + MediaStore.Images.Thumbnails.MINI_KIND + " AND " + MediaStore.Images.Thumbnails.IMAGE_ID + " = ?"; @Override public Cursor query(Uri uri) { String imageId = uri.getLastPathSegment(); return contentResolver.query( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, PATH_PROJECTION, PATH_SELECTION, new String[] {imageId}, null /*sortOrder*/); } } }