blob: b9b622a11b8af09e8c87bbafb4510ed5fe94e2d4 [file] [log] [blame]
package com.bumptech.glide.load.data;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import com.bumptech.glide.Priority;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* A DataFetcher that retrieves an {@link java.io.InputStream} for a local Uri that may or may not be for a resource
* in the media store. If the local Uri is for a resource in the media store and the size requested is less than or
* equal to the media store thumbnail size, preferentially attempts to fetch data for the pre-generated media store
* thumbs using {@link android.provider.MediaStore.Images.Thumbnails} and
* {@link android.provider.MediaStore.Video.Thumbnails}.
*/
public class MediaStoreThumbFetcher implements DataFetcher<InputStream> {
private static final int MINI_WIDTH = 512;
private static final int MINI_HEIGHT = 384;
private static final ThumbnailStreamOpenerFactory DEFAULT_FACTORY = new ThumbnailStreamOpenerFactory();
private final Context context;
private final Uri mediaStoreUri;
private final DataFetcher<InputStream> defaultFetcher;
private final int width;
private final int height;
private final ThumbnailStreamOpenerFactory factory;
private InputStream inputStream;
public MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher,
int width, int height) {
this(context, mediaStoreUri, defaultFetcher, width, height, DEFAULT_FACTORY);
}
MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher, int width,
int height, ThumbnailStreamOpenerFactory factory) {
this.context = context;
this.mediaStoreUri = mediaStoreUri;
this.defaultFetcher = defaultFetcher;
this.width = width;
this.height = height;
this.factory = factory;
}
@Override
public InputStream loadData(Priority priority) throws Exception {
ThumbnailStreamOpener fetcher = factory.build(mediaStoreUri, width, height);
if (fetcher != null) {
inputStream = fetcher.open(context, mediaStoreUri);
}
if (inputStream != null) {
return inputStream;
} else {
return defaultFetcher.loadData(priority);
}
}
@Override
public void cleanup() {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Do nothing.
}
}
defaultFetcher.cleanup();
}
@Override
public String getId() {
return mediaStoreUri.toString();
}
@Override
public void cancel() {
// Do nothing.
}
private static boolean isMediaStoreUri(Uri uri) {
return uri != null
&& ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
&& MediaStore.AUTHORITY.equals(uri.getAuthority());
}
private static boolean isMediaStoreVideo(Uri uri) {
return isMediaStoreUri(uri) && uri.getPathSegments().contains("video");
}
static class FileService {
public boolean exists(File file) {
return file.exists();
}
public long length(File file) {
return file.length();
}
public File get(String path) {
return new File(path);
}
}
interface ThumbnailQuery {
Cursor query(Context context, Uri uri);
}
static class ThumbnailStreamOpener {
private static final FileService DEFAULT_SERVICE = new FileService();
private final FileService service;
private ThumbnailQuery query;
public ThumbnailStreamOpener(ThumbnailQuery query) {
this(DEFAULT_SERVICE, query);
}
public ThumbnailStreamOpener(FileService service, ThumbnailQuery query) {
this.service = service;
this.query = query;
}
public InputStream open(Context context, Uri uri) throws FileNotFoundException {
Uri thumbnailUri = null;
InputStream inputStream = null;
final Cursor cursor = query.query(context, uri);
try {
if (cursor != null && cursor.moveToFirst()) {
String path = cursor.getString(0);
if (!TextUtils.isEmpty(path)) {
File file = service.get(path);
if (service.exists(file) && service.length(file) > 0) {
thumbnailUri = Uri.fromFile(file);
}
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
if (thumbnailUri != null) {
inputStream = context.getContentResolver().openInputStream(thumbnailUri);
}
return inputStream;
}
}
static class ImageThumbnailQuery implements ThumbnailQuery {
@Override
public Cursor query(Context context, Uri uri) {
String id = uri.getLastPathSegment();
return context.getContentResolver().query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, new String[] {
MediaStore.Images.Thumbnails.DATA
}, MediaStore.Images.Thumbnails.IMAGE_ID + " = ? AND " + MediaStore.Images.Thumbnails.KIND + " = ?",
new String[] { id, String.valueOf(MediaStore.Images.Thumbnails.MINI_KIND) }, null);
}
}
static class VideoThumbnailQuery implements ThumbnailQuery {
@Override
public Cursor query(Context context, Uri uri) {
String id = uri.getLastPathSegment();
return context.getContentResolver().query(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, new String[] {
MediaStore.Video.Thumbnails.DATA
}, MediaStore.Video.Thumbnails.VIDEO_ID + " = ? AND " + MediaStore.Video.Thumbnails.KIND + " = ?",
new String[] { id, String.valueOf(MediaStore.Video.Thumbnails.MINI_KIND) }, null);
}
}
static class ThumbnailStreamOpenerFactory {
public ThumbnailStreamOpener build(Uri uri, int width, int height) {
if (!isMediaStoreUri(uri) || width > MINI_WIDTH || height > MINI_HEIGHT) {
return null;
} else if (isMediaStoreVideo(uri)) {
return new ThumbnailStreamOpener(new VideoThumbnailQuery());
} else {
return new ThumbnailStreamOpener(new ImageThumbnailQuery());
}
}
}
}