Move setting bitmapFactory options from interface to implementation
Moves setting bitmapFactory options from BitmapLoader to DatasourceBitmapLoader
BitmapLoader is a general interface for bitmap loading that could use loading implementations other that BitmapFactory, with the rise of Glide being a loader of choice. It's best to correct this interface so that it remains generic
We can't deprecate easily because the other loadBitmap method in that case has a default implementation that relies on the first one, so the change is still breaking. BitmapLoader is public api in common, but it's @UnstableAPI and hasn't been around for very long (be38670391
added it), so it seems this is the best way forward.
PiperOrigin-RevId: 597897098
This commit is contained in:
parent
09a547953b
commit
6879698d7e
@ -16,7 +16,6 @@
|
||||
package androidx.media3.common.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
@ -29,12 +28,7 @@ public interface BitmapLoader {
|
||||
ListenableFuture<Bitmap> decodeBitmap(byte[] data);
|
||||
|
||||
/** Loads an image from {@code uri}. */
|
||||
default ListenableFuture<Bitmap> loadBitmap(Uri uri) {
|
||||
return loadBitmap(uri, /* options= */ null);
|
||||
}
|
||||
|
||||
/** Loads an image from {@code uri} with the given {@link BitmapFactory.Options}. */
|
||||
ListenableFuture<Bitmap> loadBitmap(Uri uri, @Nullable BitmapFactory.Options options);
|
||||
ListenableFuture<Bitmap> loadBitmap(Uri uri);
|
||||
|
||||
/**
|
||||
* Loads an image from {@link MediaMetadata}. Returns null if {@code metadata} doesn't contain
|
||||
|
@ -205,13 +205,13 @@ public class DataSourceBitmapLoaderTest {
|
||||
File file = tempFolder.newFile();
|
||||
Files.write(Paths.get(file.getAbsolutePath()), imageData);
|
||||
Uri uri = Uri.fromFile(file);
|
||||
DataSourceBitmapLoader bitmapLoader =
|
||||
new DataSourceBitmapLoader(MoreExecutors.newDirectExecutorService(), dataSourceFactory);
|
||||
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inMutable = true;
|
||||
DataSourceBitmapLoader bitmapLoader =
|
||||
new DataSourceBitmapLoader(
|
||||
MoreExecutors.newDirectExecutorService(), dataSourceFactory, options);
|
||||
|
||||
Bitmap bitmap = bitmapLoader.loadBitmap(uri, options).get();
|
||||
Bitmap bitmap = bitmapLoader.loadBitmap(uri).get();
|
||||
|
||||
assertThat(bitmap.isMutable()).isTrue();
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* A {@link BitmapLoader} implementation that uses a {@link DataSource} to support fetching images
|
||||
* from URIs.
|
||||
* from URIs and {@link BitmapFactory} to load them into {@link Bitmap}.
|
||||
*
|
||||
* <p>Loading tasks are delegated to a {@link ListeningExecutorService} defined during construction.
|
||||
* If no executor service is passed, all tasks are delegated to a single-thread executor service
|
||||
@ -54,6 +54,7 @@ public final class DataSourceBitmapLoader implements BitmapLoader {
|
||||
|
||||
private final ListeningExecutorService listeningExecutorService;
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
@Nullable private final BitmapFactory.Options options;
|
||||
|
||||
/**
|
||||
* Creates an instance that uses a {@link DefaultHttpDataSource} for image loading and delegates
|
||||
@ -72,17 +73,33 @@ public final class DataSourceBitmapLoader implements BitmapLoader {
|
||||
*/
|
||||
public DataSourceBitmapLoader(
|
||||
ListeningExecutorService listeningExecutorService, DataSource.Factory dataSourceFactory) {
|
||||
this(listeningExecutorService, dataSourceFactory, /* options= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance that delegates loading tasks to the {@link ListeningExecutorService}.
|
||||
*
|
||||
* @param listeningExecutorService The {@link ListeningExecutorService}.
|
||||
* @param dataSourceFactory The {@link DataSource.Factory} that creates the {@link DataSource}
|
||||
* used to load the image.
|
||||
* @param options The {@link BitmapFactory.Options} the image should be loaded with.
|
||||
*/
|
||||
public DataSourceBitmapLoader(
|
||||
ListeningExecutorService listeningExecutorService,
|
||||
DataSource.Factory dataSourceFactory,
|
||||
@Nullable BitmapFactory.Options options) {
|
||||
this.listeningExecutorService = listeningExecutorService;
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Bitmap> decodeBitmap(byte[] data) {
|
||||
return listeningExecutorService.submit(() -> decode(data, /* options= */ null));
|
||||
return listeningExecutorService.submit(() -> decode(data, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri, @Nullable BitmapFactory.Options options) {
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri) {
|
||||
return listeningExecutorService.submit(
|
||||
() -> load(dataSourceFactory.createDataSource(), uri, options));
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ package androidx.media3.session;
|
||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.util.BitmapLoader;
|
||||
@ -60,11 +59,11 @@ public final class CacheBitmapLoader implements BitmapLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri, @Nullable BitmapFactory.Options options) {
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri) {
|
||||
if (lastBitmapLoadRequest != null && lastBitmapLoadRequest.matches(uri)) {
|
||||
return lastBitmapLoadRequest.getFuture();
|
||||
}
|
||||
ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(uri, options);
|
||||
ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(uri);
|
||||
lastBitmapLoadRequest = new BitmapLoadRequest(uri, future);
|
||||
return future;
|
||||
}
|
||||
|
@ -68,24 +68,21 @@ public final class SimpleBitmapLoader implements BitmapLoader {
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Bitmap> decodeBitmap(byte[] data) {
|
||||
return executorService.submit(() -> decode(data, /* options= */ null));
|
||||
return executorService.submit(() -> decode(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri, @Nullable BitmapFactory.Options options) {
|
||||
return executorService.submit(() -> load(uri, options));
|
||||
public ListenableFuture<Bitmap> loadBitmap(Uri uri) {
|
||||
return executorService.submit(() -> load(uri));
|
||||
}
|
||||
|
||||
// BitmapFactory's options parameter is null-ok.
|
||||
@SuppressWarnings("nullness:argument.type.incompatible")
|
||||
private static Bitmap decode(byte[] data, @Nullable BitmapFactory.Options options) {
|
||||
@Nullable
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(data, /* offset= */ 0, data.length, options);
|
||||
private static Bitmap decode(byte[] data) {
|
||||
@Nullable Bitmap bitmap = BitmapFactory.decodeByteArray(data, /* offset= */ 0, data.length);
|
||||
checkArgument(bitmap != null, "Could not decode image data");
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static Bitmap load(Uri uri, @Nullable BitmapFactory.Options options) throws IOException {
|
||||
private static Bitmap load(Uri uri) throws IOException {
|
||||
if ("file".equals(uri.getScheme())) {
|
||||
@Nullable String path = uri.getPath();
|
||||
if (path == null) {
|
||||
@ -108,7 +105,7 @@ public final class SimpleBitmapLoader implements BitmapLoader {
|
||||
throw new IOException("Invalid response status code: " + responseCode);
|
||||
}
|
||||
try (InputStream inputStream = httpConnection.getInputStream()) {
|
||||
return decode(ByteStreams.toByteArray(inputStream), options);
|
||||
return decode(ByteStreams.toByteArray(inputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,17 +112,18 @@ public final class ImageAssetLoader implements AssetLoader {
|
||||
progressState = PROGRESS_STATE_AVAILABLE;
|
||||
listener.onDurationUs(editedMediaItem.durationUs);
|
||||
listener.onTrackCount(1);
|
||||
BitmapLoader bitmapLoader =
|
||||
new DataSourceBitmapLoader(
|
||||
MoreExecutors.listeningDecorator(scheduledExecutorService), dataSourceFactory);
|
||||
MediaItem.LocalConfiguration localConfiguration =
|
||||
checkNotNull(editedMediaItem.mediaItem.localConfiguration);
|
||||
@Nullable BitmapFactory.Options options = null;
|
||||
if (Util.SDK_INT >= 26) {
|
||||
options = new BitmapFactory.Options();
|
||||
options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
|
||||
}
|
||||
ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(localConfiguration.uri, options);
|
||||
BitmapLoader bitmapLoader =
|
||||
new DataSourceBitmapLoader(
|
||||
MoreExecutors.listeningDecorator(scheduledExecutorService), dataSourceFactory, options);
|
||||
MediaItem.LocalConfiguration localConfiguration =
|
||||
checkNotNull(editedMediaItem.mediaItem.localConfiguration);
|
||||
|
||||
ListenableFuture<Bitmap> future = bitmapLoader.loadBitmap(localConfiguration.uri);
|
||||
Futures.addCallback(
|
||||
future,
|
||||
new FutureCallback<Bitmap>() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user