1eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddpackage com.bumptech.glide.load.data; 2eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 3eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.content.ContentResolver; 4eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.content.Context; 5eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.database.Cursor; 6eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.net.Uri; 7eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.provider.MediaStore; 8eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport android.text.TextUtils; 9eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport com.bumptech.glide.Priority; 10eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 11eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport java.io.File; 12eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport java.io.FileNotFoundException; 13eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport java.io.IOException; 14eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddimport java.io.InputStream; 15eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 16eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Juddpublic class MediaStoreThumbFetcher implements DataFetcher<InputStream> { 17eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static final int MINI_WIDTH = 512; 18eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static final int MINI_HEIGHT = 384; 19eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static final ThumbnailStreamOpenerFactory DEFAULT_FACTORY = new ThumbnailStreamOpenerFactory(); 20eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 21eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final Context context; 22eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final Uri mediaStoreUri; 23eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final DataFetcher<InputStream> defaultFetcher; 24eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final int width; 25eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final int height; 2678bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd private final long dateModified; 2778bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd private final int orientation; 28eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final ThumbnailStreamOpenerFactory factory; 29eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private InputStream inputStream; 3078bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd private String mimeType; 31eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 32eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher, 3378bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd int width, int height, String mimeType, long dateModified, int orientation) { 3478bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd this(context, mediaStoreUri, defaultFetcher, width, height, mimeType, dateModified, orientation, 3578bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd DEFAULT_FACTORY); 36eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 37eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 38eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher, int width, 3978bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd int height, String mimeType, long dateModified, int orientation, ThumbnailStreamOpenerFactory factory) { 40eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.context = context; 41eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.mediaStoreUri = mediaStoreUri; 42eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.defaultFetcher = defaultFetcher; 43eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.width = width; 44eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.height = height; 4578bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd this.mimeType = mimeType; 4678bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd this.dateModified = dateModified; 4778bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd this.orientation = orientation; 48eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.factory = factory; 49eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 50eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 51eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd @Override 52eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public InputStream loadData(Priority priority) throws Exception { 53eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd ThumbnailStreamOpener fetcher = factory.build(mediaStoreUri, width, height); 54eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 55eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (fetcher != null) { 56eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd inputStream = fetcher.open(context, mediaStoreUri); 57eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 58eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 59eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (inputStream != null) { 60eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return inputStream; 61eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } else { 62eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return defaultFetcher.loadData(priority); 63eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 64eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 65eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 66eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd @Override 67eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public void cleanup() { 68eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (inputStream != null) { 69eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd try { 70eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd inputStream.close(); 71eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } catch (IOException e) { 72eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd // Do nothing. 73eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 74eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 75eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd defaultFetcher.cleanup(); 76eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 77eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 78eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd @Override 7978bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd public String getId() { 8078bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd return mediaStoreUri + mimeType + String.valueOf(dateModified) + String.valueOf(orientation); 8178bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd } 8278bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd 8378bad2aa32f824f9e098b5058dfa3506a7ed3f62Sam Judd @Override 84eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public void cancel() { 85eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd // Do nothing. 86eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 87eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 88eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static boolean isMediaStoreUri(Uri uri) { 89eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return uri != null 90eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) 91eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd && MediaStore.AUTHORITY.equals(uri.getAuthority()); 92eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 93eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 94eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static boolean isMediaStoreVideo(Uri uri) { 95eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return isMediaStoreUri(uri) && uri.getPathSegments().contains("video"); 96eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 97eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 98eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd static class FileService { 99eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public boolean exists(File file) { 100eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return file.exists(); 101eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 102eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 103eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public long length(File file) { 104eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return file.length(); 105eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 106eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 107eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public File get(String path) { 108eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return new File(path); 109eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 110eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 111eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 112eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd interface ThumbnailQuery { 113eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public Cursor query(Context context, Uri uri); 114eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 115eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 116eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd static class ThumbnailStreamOpener { 117eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private static final FileService DEFAULT_SERVICE = new FileService(); 118eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private final FileService service; 119eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd private ThumbnailQuery query; 120eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 121eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public ThumbnailStreamOpener(ThumbnailQuery query) { 122eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this(DEFAULT_SERVICE, query); 123eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 124eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 125eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public ThumbnailStreamOpener(FileService service, ThumbnailQuery query) { 126eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.service = service; 127eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd this.query = query; 128eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 129eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 130eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public InputStream open(Context context, Uri uri) throws FileNotFoundException { 131eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd Uri thumbnailUri = null; 132eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd InputStream inputStream = null; 133eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 134eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd final Cursor cursor = query.query(context, uri); 135eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd try { 136eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (cursor != null && cursor.moveToFirst()) { 137eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd String path = cursor.getString(0); 138eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (!TextUtils.isEmpty(path)) { 139eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd File file = service.get(path); 140eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (service.exists(file) && service.length(file) > 0) { 141eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd thumbnailUri = Uri.fromFile(file); 142eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 143eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 144eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 145eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } finally { 146eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (cursor != null) { 147eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd cursor.close(); 148eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 149eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 150eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (thumbnailUri != null) { 151eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd inputStream = context.getContentResolver().openInputStream(thumbnailUri); 152eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 153eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return inputStream; 154eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 155eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 156eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 157eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd static class ImageThumbnailQuery implements ThumbnailQuery { 158eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 159eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd @Override 160eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public Cursor query(Context context, Uri uri) { 161eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd String id = uri.getLastPathSegment(); 162eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return context.getContentResolver().query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, new String[] { 163eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd MediaStore.Images.Thumbnails.DATA 164eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd }, MediaStore.Images.Thumbnails.IMAGE_ID + " = ? AND " + MediaStore.Images.Thumbnails.KIND + " = ?", 165eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd new String[] { id, String.valueOf(MediaStore.Images.Thumbnails.MINI_KIND) }, null); 166eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 167eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 168eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 169eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd static class VideoThumbnailQuery implements ThumbnailQuery { 170eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 171eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd @Override 172eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public Cursor query(Context context, Uri uri) { 173eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd String id = uri.getLastPathSegment(); 174eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return context.getContentResolver().query(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, new String[] { 175eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd MediaStore.Video.Thumbnails.DATA 176eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd }, MediaStore.Video.Thumbnails.VIDEO_ID + " = ? AND " + MediaStore.Video.Thumbnails.KIND + " = ?", 177eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd new String[] { id, String.valueOf(MediaStore.Video.Thumbnails.MINI_KIND) }, null); 178eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 179eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 180eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 181eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd static class ThumbnailStreamOpenerFactory { 182eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd 183eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd public ThumbnailStreamOpener build(Uri uri, int width, int height) { 184eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd if (!isMediaStoreUri(uri) || width > MINI_WIDTH || height > MINI_HEIGHT) { 185eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return null; 186eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } else if (isMediaStoreVideo(uri)) { 187eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return new ThumbnailStreamOpener(new VideoThumbnailQuery()); 188eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } else { 189eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd return new ThumbnailStreamOpener(new ImageThumbnailQuery()); 190eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 191eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 192eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd } 193eba30dc89f6138cf85e1adf0fd1d23a87849c9e6Sam Judd} 194