package com.bumptech.glide.load.model; import android.os.ParcelFileDescriptor; import android.util.Log; import com.bumptech.glide.Priority; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.signature.ObjectKey; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * A simple model loader for loading data from {@link File}s. * * @param <Data> The type of data loaded from the given {@link java.io.File} ({@link * java.io.InputStream} or {@link java.io.FileDescriptor} etc). */ public class FileLoader<Data> implements ModelLoader<File, Data> { private static final String TAG = "FileLoader"; private final FileOpener<Data> fileOpener; public FileLoader(FileOpener<Data> fileOpener) { this.fileOpener = fileOpener; } @Override public LoadData<Data> buildLoadData(File model, int width, int height, Options options) { return new LoadData<>(new ObjectKey(model), new FileFetcher<>(model, fileOpener)); } @Override public boolean handles(File model) { return true; } /** * Allows opening a specific type of data from a {@link java.io.File}. * @param <Data> The type of data that can be opened. */ public interface FileOpener<Data> { Data open(File file) throws FileNotFoundException; void close(Data data) throws IOException; Class<Data> getDataClass(); } private static class FileFetcher<Data> implements DataFetcher<Data> { private final File file; private final FileOpener<Data> opener; private Data data; public FileFetcher(File file, FileOpener<Data> opener) { this.file = file; this.opener = opener; } @Override public void loadData(Priority priority, DataCallback<? super Data> callback) { try { data = opener.open(file); } catch (FileNotFoundException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to open file", e); } callback.onLoadFailed(e); return; } callback.onDataReady(data); } @Override public void cleanup() { if (data != null) { try { opener.close(data); } catch (IOException e) { // Ignored. } } } @Override public void cancel() { // Do nothing. } @Override public Class<Data> getDataClass() { return opener.getDataClass(); } @Override public DataSource getDataSource() { return DataSource.LOCAL; } } /** * Base factory for loading data from {@link java.io.File files}. * @param <Data> The type of data that will be loaded for a given {@link java.io.File}. */ public static class Factory<Data> implements ModelLoaderFactory<File, Data> { private final FileOpener<Data> opener; public Factory(FileOpener<Data> opener) { this.opener = opener; } @Override public final ModelLoader<File, Data> build(MultiModelLoaderFactory multiFactory) { return new FileLoader<>(opener); } @Override public final void teardown() { // Do nothing. } } /** * Factory for loading {@link InputStream}s from {@link File}s. */ public static class StreamFactory extends Factory<InputStream> { public StreamFactory() { super(new FileOpener<InputStream>() { @Override public InputStream open(File file) throws FileNotFoundException { return new FileInputStream(file); } @Override public void close(InputStream inputStream) throws IOException { inputStream.close(); } @Override public Class<InputStream> getDataClass() { return InputStream.class; } }); } } /** * Factory for loading {@link ParcelFileDescriptor}s from {@link File}s. */ public static class FileDescriptorFactory extends Factory<ParcelFileDescriptor> { public FileDescriptorFactory() { super(new FileOpener<ParcelFileDescriptor>() { @Override public ParcelFileDescriptor open(File file) throws FileNotFoundException { return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } @Override public void close(ParcelFileDescriptor parcelFileDescriptor) throws IOException { parcelFileDescriptor.close(); } @Override public Class<ParcelFileDescriptor> getDataClass() { return ParcelFileDescriptor.class; } }); } } }