Commit 88a413b2 by tianyifeng Committed by microkatz

Add injection of `BitmapLoader` from `MediaSession`.

* Add `BitmapLoader` in `MediaSession.Builder` and `MediaLibrarySession.Builder`.
* Pass `BitmapLoader` into the constructor of `MediaSession`, `MediaSessionImpl`, `MediaLibrarySession` and `MediaLibrarySessionImpl`.
* Add an interface method `loadBitmapFromMetadata(MediaMetadata)` in `BitmapLoader`.
* Remove the reference of `BitmapLoader` in `DefaultMediaNotificationProvider`.

PiperOrigin-RevId: 483654596
(cherry picked from commit 3f69df72)
parent 373c23c1
...@@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows; ...@@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.net.Uri; import android.net.Uri;
import androidx.media3.common.MediaMetadata;
import androidx.media3.test.utils.TestUtil; import androidx.media3.test.utils.TestUtil;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
...@@ -166,6 +167,64 @@ public class SimpleBitmapLoaderTest { ...@@ -166,6 +167,64 @@ public class SimpleBitmapLoaderTest {
/* messagePart= */ "unknown protocol"); /* messagePart= */ "unknown protocol");
} }
@Test
public void loadBitmapFromMetadata_decodeFromArtworkData() throws Exception {
byte[] imageData =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TEST_IMAGE_PATH);
MockWebServer mockWebServer = new MockWebServer();
Uri uri = Uri.parse(mockWebServer.url("test_path").toString());
// Set both artworkData and artworkUri
MediaMetadata metadata =
new MediaMetadata.Builder()
.setArtworkData(imageData, MediaMetadata.PICTURE_TYPE_FRONT_COVER)
.setArtworkUri(uri)
.build();
SimpleBitmapLoader bitmapLoader =
new SimpleBitmapLoader(MoreExecutors.newDirectExecutorService());
Bitmap bitmap = bitmapLoader.loadBitmapFromMetadata(metadata).get();
assertThat(
bitmap.sameAs(
BitmapFactory.decodeByteArray(imageData, /* offset= */ 0, imageData.length)))
.isTrue();
assertThat(mockWebServer.getRequestCount()).isEqualTo(0);
}
@Test
public void loadBitmapFromMetadata_loadFromArtworkUri() throws Exception {
byte[] imageData =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TEST_IMAGE_PATH);
MockWebServer mockWebServer = new MockWebServer();
Buffer responseBody = new Buffer().write(imageData);
mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseBody));
Uri uri = Uri.parse(mockWebServer.url("test_path").toString());
// Just set artworkUri
MediaMetadata metadata = new MediaMetadata.Builder().setArtworkUri(uri).build();
SimpleBitmapLoader bitmapLoader =
new SimpleBitmapLoader(MoreExecutors.newDirectExecutorService());
Bitmap bitmap = bitmapLoader.loadBitmapFromMetadata(metadata).get();
assertThat(
bitmap.sameAs(
BitmapFactory.decodeByteArray(imageData, /* offset= */ 0, imageData.length)))
.isTrue();
assertThat(mockWebServer.getRequestCount()).isEqualTo(1);
}
@Test
public void loadBitmapFromMetadata_returnNull() throws Exception {
// Neither artworkData nor artworkUri is set
MediaMetadata metadata = new MediaMetadata.Builder().build();
SimpleBitmapLoader bitmapLoader =
new SimpleBitmapLoader(MoreExecutors.newDirectExecutorService());
ListenableFuture<Bitmap> bitmapFuture = bitmapLoader.loadBitmapFromMetadata(metadata);
assertThat(bitmapFuture).isNull();
}
private static void assertException( private static void assertException(
ThrowingRunnable runnable, Class<? extends Exception> clazz, String messagePart) { ThrowingRunnable runnable, Class<? extends Exception> clazz, String messagePart) {
ExecutionException executionException = assertThrows(ExecutionException.class, runnable); ExecutionException executionException = assertThrows(ExecutionException.class, runnable);
......
...@@ -17,6 +17,8 @@ package androidx.media3.session; ...@@ -17,6 +17,8 @@ package androidx.media3.session;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
...@@ -25,6 +27,29 @@ import com.google.common.util.concurrent.ListenableFuture; ...@@ -25,6 +27,29 @@ import com.google.common.util.concurrent.ListenableFuture;
public interface BitmapLoader { public interface BitmapLoader {
/** Decodes an image from compressed binary data. */ /** Decodes an image from compressed binary data. */
ListenableFuture<Bitmap> decodeBitmap(byte[] data); ListenableFuture<Bitmap> decodeBitmap(byte[] data);
/** Loads an image from {@code uri}. */ /** Loads an image from {@code uri}. */
ListenableFuture<Bitmap> loadBitmap(Uri uri); ListenableFuture<Bitmap> loadBitmap(Uri uri);
/**
* Loads an image from {@link MediaMetadata}. Returns null if {@code metadata} doesn't contain
* bitmap information.
*
* <p>By default, the method will try to decode an image from {@link MediaMetadata#artworkData} if
* it is present. Otherwise, the method will try to load an image from {@link
* MediaMetadata#artworkUri} if it is present. The method will return null if neither {@link
* MediaMetadata#artworkData} nor {@link MediaMetadata#artworkUri} is present.
*/
@Nullable
default ListenableFuture<Bitmap> loadBitmapFromMetadata(MediaMetadata metadata) {
@Nullable ListenableFuture<Bitmap> future;
if (metadata.artworkData != null) {
future = decodeBitmap(metadata.artworkData);
} else if (metadata.artworkUri != null) {
future = loadBitmap(metadata.artworkUri);
} else {
future = null;
}
return future;
}
} }
...@@ -123,7 +123,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -123,7 +123,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
private NotificationIdProvider notificationIdProvider; private NotificationIdProvider notificationIdProvider;
private String channelId; private String channelId;
@StringRes private int channelNameResourceId; @StringRes private int channelNameResourceId;
private BitmapLoader bitmapLoader;
private boolean built; private boolean built;
/** /**
...@@ -136,7 +135,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -136,7 +135,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
notificationIdProvider = session -> DEFAULT_NOTIFICATION_ID; notificationIdProvider = session -> DEFAULT_NOTIFICATION_ID;
channelId = DEFAULT_CHANNEL_ID; channelId = DEFAULT_CHANNEL_ID;
channelNameResourceId = DEFAULT_CHANNEL_NAME_RESOURCE_ID; channelNameResourceId = DEFAULT_CHANNEL_NAME_RESOURCE_ID;
bitmapLoader = new SimpleBitmapLoader();
} }
/** /**
...@@ -197,19 +195,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -197,19 +195,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
} }
/** /**
* Sets the {@link BitmapLoader} used load artwork. By default, a {@link CacheBitmapLoader} with
* a {@link SimpleBitmapLoader} inside will be used.
*
* @param bitmapLoader The bitmap loader.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setBitmapLoader(BitmapLoader bitmapLoader) {
this.bitmapLoader = new CacheBitmapLoader(bitmapLoader);
return this;
}
/**
* Builds the {@link DefaultMediaNotificationProvider}. The method can be called at most once. * Builds the {@link DefaultMediaNotificationProvider}. The method can be called at most once.
*/ */
public DefaultMediaNotificationProvider build() { public DefaultMediaNotificationProvider build() {
...@@ -259,7 +244,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -259,7 +244,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
private final String channelId; private final String channelId;
@StringRes private final int channelNameResourceId; @StringRes private final int channelNameResourceId;
private final NotificationManager notificationManager; private final NotificationManager notificationManager;
private final BitmapLoader bitmapLoader;
// Cache the last bitmap load request to avoid reloading the bitmap again, particularly useful // Cache the last bitmap load request to avoid reloading the bitmap again, particularly useful
// when showing a notification for the same item (e.g. when switching from playing to paused). // when showing a notification for the same item (e.g. when switching from playing to paused).
private final Handler mainHandler; private final Handler mainHandler;
...@@ -272,7 +256,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -272,7 +256,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
this.notificationIdProvider = builder.notificationIdProvider; this.notificationIdProvider = builder.notificationIdProvider;
this.channelId = builder.channelId; this.channelId = builder.channelId;
this.channelNameResourceId = builder.channelNameResourceId; this.channelNameResourceId = builder.channelNameResourceId;
this.bitmapLoader = new CacheBitmapLoader(builder.bitmapLoader);
notificationManager = notificationManager =
checkStateNotNull( checkStateNotNull(
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)); (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
...@@ -312,7 +295,9 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -312,7 +295,9 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
builder builder
.setContentTitle(getNotificationContentTitle(metadata)) .setContentTitle(getNotificationContentTitle(metadata))
.setContentText(getNotificationContentText(metadata)); .setContentText(getNotificationContentText(metadata));
@Nullable ListenableFuture<Bitmap> bitmapFuture = loadArtworkBitmap(metadata); @Nullable
ListenableFuture<Bitmap> bitmapFuture =
mediaSession.getBitmapLoader().loadBitmapFromMetadata(metadata);
if (bitmapFuture != null) { if (bitmapFuture != null) {
if (pendingOnBitmapLoadedFutureCallback != null) { if (pendingOnBitmapLoadedFutureCallback != null) {
pendingOnBitmapLoadedFutureCallback.discardIfPending(); pendingOnBitmapLoadedFutureCallback.discardIfPending();
...@@ -578,23 +563,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi ...@@ -578,23 +563,6 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi
notificationManager, channelId, context.getString(channelNameResourceId)); notificationManager, channelId, context.getString(channelNameResourceId));
} }
/**
* Requests from the bitmapLoader to load artwork or returns null if the metadata don't include
* artwork.
*/
@Nullable
private ListenableFuture<Bitmap> loadArtworkBitmap(MediaMetadata metadata) {
@Nullable ListenableFuture<Bitmap> future;
if (metadata.artworkData != null) {
future = bitmapLoader.decodeBitmap(metadata.artworkData);
} else if (metadata.artworkUri != null) {
future = bitmapLoader.loadBitmap(metadata.artworkUri);
} else {
future = null;
}
return future;
}
private static long getPlaybackStartTimeEpochMs(Player player) { private static long getPlaybackStartTimeEpochMs(Player player) {
// Changing "showWhen" causes notification flicker if SDK_INT < 21. // Changing "showWhen" causes notification flicker if SDK_INT < 21.
if (Util.SDK_INT >= 21 if (Util.SDK_INT >= 21
......
...@@ -24,6 +24,7 @@ import static java.lang.annotation.ElementType.TYPE_USE; ...@@ -24,6 +24,7 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
...@@ -421,6 +422,28 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -421,6 +422,28 @@ public abstract class MediaLibraryService extends MediaSessionService {
} }
/** /**
* Sets a {@link BitmapLoader} for the {@link MediaLibrarySession} to decode bitmaps from
* compressed binary data or load bitmaps from {@link Uri}. If not set, a {@link
* CacheBitmapLoader} with a {@link SimpleBitmapLoader} inside will be used.
*
* <p>The provided instance will likely be called repeatedly with the same request, so it
* would be best if any provided instance does some caching. Simple caching can be added to
* any {@link BitmapLoader} implementation by wrapping it in {@link CacheBitmapLoader} before
* passing it to this method.
*
* <p>If no instance is set, a {@link CacheBitmapLoader} with a {@link SimpleBitmapLoader}
* inside will be used.
*
* @param bitmapLoader The bitmap loader {@link BitmapLoader}.
* @return The builder to allow chaining.
*/
@UnstableApi
@Override
public Builder setBitmapLoader(BitmapLoader bitmapLoader) {
return super.setBitmapLoader(bitmapLoader);
}
/**
* Builds a {@link MediaLibrarySession}. * Builds a {@link MediaLibrarySession}.
* *
* @return A new session. * @return A new session.
...@@ -429,7 +452,11 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -429,7 +452,11 @@ public abstract class MediaLibraryService extends MediaSessionService {
*/ */
@Override @Override
public MediaLibrarySession build() { public MediaLibrarySession build() {
return new MediaLibrarySession(context, id, player, sessionActivity, callback, extras); if (bitmapLoader == null) {
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
}
return new MediaLibrarySession(
context, id, player, sessionActivity, callback, extras, checkNotNull(bitmapLoader));
} }
} }
...@@ -439,8 +466,9 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -439,8 +466,9 @@ public abstract class MediaLibraryService extends MediaSessionService {
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
MediaSession.Callback callback, MediaSession.Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
super(context, id, player, sessionActivity, callback, tokenExtras); BitmapLoader bitmapLoader) {
super(context, id, player, sessionActivity, callback, tokenExtras, bitmapLoader);
} }
@Override @Override
...@@ -450,9 +478,17 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -450,9 +478,17 @@ public abstract class MediaLibraryService extends MediaSessionService {
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
MediaSession.Callback callback, MediaSession.Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
BitmapLoader bitmapLoader) {
return new MediaLibrarySessionImpl( return new MediaLibrarySessionImpl(
this, context, id, player, sessionActivity, (Callback) callback, tokenExtras); this,
context,
id,
player,
sessionActivity,
(Callback) callback,
tokenExtras,
bitmapLoader);
} }
@Override @Override
......
...@@ -64,8 +64,9 @@ import java.util.concurrent.Future; ...@@ -64,8 +64,9 @@ import java.util.concurrent.Future;
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
MediaLibrarySession.Callback callback, MediaLibrarySession.Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
super(instance, context, id, player, sessionActivity, callback, tokenExtras); BitmapLoader bitmapLoader) {
super(instance, context, id, player, sessionActivity, callback, tokenExtras, bitmapLoader);
this.instance = instance; this.instance = instance;
this.callback = callback; this.callback = callback;
subscriptions = new ArrayMap<>(); subscriptions = new ArrayMap<>();
......
...@@ -61,6 +61,7 @@ import com.google.common.util.concurrent.Futures; ...@@ -61,6 +61,7 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* A session that allows a media app to expose its transport controls and playback information in a * A session that allows a media app to expose its transport controls and playback information in a
...@@ -308,6 +309,28 @@ public class MediaSession { ...@@ -308,6 +309,28 @@ public class MediaSession {
} }
/** /**
* Sets a {@link BitmapLoader} for the {@link MediaSession} to decode bitmaps from compressed
* binary data or load bitmaps from {@link Uri}. If not set, a {@link CacheBitmapLoader} with a
* {@link SimpleBitmapLoader} inside will be used.
*
* <p>The provided instance will likely be called repeatedly with the same request, so it would
* be best if any provided instance does some caching. Simple caching can be added to any {@link
* BitmapLoader} implementation by wrapping it in {@link CacheBitmapLoader} before passing it to
* this method.
*
* <p>If no instance is set, a {@link CacheBitmapLoader} with a {@link SimpleBitmapLoader}
* inside will be used.
*
* @param bitmapLoader The bitmap loader {@link BitmapLoader}.
* @return The builder to allow chaining.
*/
@UnstableApi
@Override
public Builder setBitmapLoader(BitmapLoader bitmapLoader) {
return super.setBitmapLoader(bitmapLoader);
}
/**
* Builds a {@link MediaSession}. * Builds a {@link MediaSession}.
* *
* @return A new session. * @return A new session.
...@@ -316,7 +339,11 @@ public class MediaSession { ...@@ -316,7 +339,11 @@ public class MediaSession {
*/ */
@Override @Override
public MediaSession build() { public MediaSession build() {
return new MediaSession(context, id, player, sessionActivity, callback, extras); if (bitmapLoader == null) {
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
}
return new MediaSession(
context, id, player, sessionActivity, callback, extras, checkNotNull(bitmapLoader));
} }
} }
...@@ -487,14 +514,15 @@ public class MediaSession { ...@@ -487,14 +514,15 @@ public class MediaSession {
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
Callback callback, Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
BitmapLoader bitmapLoader) {
synchronized (STATIC_LOCK) { synchronized (STATIC_LOCK) {
if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) { if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) {
throw new IllegalStateException("Session ID must be unique. ID=" + id); throw new IllegalStateException("Session ID must be unique. ID=" + id);
} }
SESSION_ID_TO_SESSION_MAP.put(id, this); SESSION_ID_TO_SESSION_MAP.put(id, this);
} }
impl = createImpl(context, id, player, sessionActivity, callback, tokenExtras); impl = createImpl(context, id, player, sessionActivity, callback, tokenExtras, bitmapLoader);
} }
/* package */ MediaSessionImpl createImpl( /* package */ MediaSessionImpl createImpl(
...@@ -503,8 +531,10 @@ public class MediaSession { ...@@ -503,8 +531,10 @@ public class MediaSession {
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
Callback callback, Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
return new MediaSessionImpl(this, context, id, player, sessionActivity, callback, tokenExtras); BitmapLoader bitmapLoader) {
return new MediaSessionImpl(
this, context, id, player, sessionActivity, callback, tokenExtras, bitmapLoader);
} }
/* package */ MediaSessionImpl getImpl() { /* package */ MediaSessionImpl getImpl() {
...@@ -741,6 +771,12 @@ public class MediaSession { ...@@ -741,6 +771,12 @@ public class MediaSession {
impl.setSessionExtras(controller, sessionExtras); impl.setSessionExtras(controller, sessionExtras);
} }
/** Returns the {@link BitmapLoader}. */
@UnstableApi
public BitmapLoader getBitmapLoader() {
return impl.getBitmapLoader();
}
/** /**
* Sends a custom command to a specific controller. * Sends a custom command to a specific controller.
* *
...@@ -1218,6 +1254,7 @@ public class MediaSession { ...@@ -1218,6 +1254,7 @@ public class MediaSession {
/* package */ C callback; /* package */ C callback;
/* package */ @Nullable PendingIntent sessionActivity; /* package */ @Nullable PendingIntent sessionActivity;
/* package */ Bundle extras; /* package */ Bundle extras;
/* package */ @MonotonicNonNull BitmapLoader bitmapLoader;
public BuilderBase(Context context, Player player, C callback) { public BuilderBase(Context context, Player player, C callback) {
this.context = checkNotNull(context); this.context = checkNotNull(context);
...@@ -1252,6 +1289,12 @@ public class MediaSession { ...@@ -1252,6 +1289,12 @@ public class MediaSession {
return (U) this; return (U) this;
} }
@SuppressWarnings("unchecked")
public U setBitmapLoader(BitmapLoader bitmapLoader) {
this.bitmapLoader = bitmapLoader;
return (U) this;
}
public abstract T build(); public abstract T build();
} }
} }
...@@ -116,6 +116,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; ...@@ -116,6 +116,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
private final PendingIntent mediaButtonIntent; private final PendingIntent mediaButtonIntent;
@Nullable private final BroadcastReceiver broadcastReceiver; @Nullable private final BroadcastReceiver broadcastReceiver;
private final Handler applicationHandler; private final Handler applicationHandler;
private final BitmapLoader bitmapLoader;
@Nullable private PlayerListener playerListener; @Nullable private PlayerListener playerListener;
...@@ -139,7 +140,8 @@ import org.checkerframework.checker.initialization.qual.Initialized; ...@@ -139,7 +140,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
Player player, Player player,
@Nullable PendingIntent sessionActivity, @Nullable PendingIntent sessionActivity,
MediaSession.Callback callback, MediaSession.Callback callback,
Bundle tokenExtras) { Bundle tokenExtras,
BitmapLoader bitmapLoader) {
this.context = context; this.context = context;
this.instance = instance; this.instance = instance;
...@@ -152,6 +154,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; ...@@ -152,6 +154,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
applicationHandler = new Handler(player.getApplicationLooper()); applicationHandler = new Handler(player.getApplicationLooper());
this.callback = callback; this.callback = callback;
this.bitmapLoader = bitmapLoader;
playerInfo = PlayerInfo.DEFAULT; playerInfo = PlayerInfo.DEFAULT;
onPlayerInfoChangedHandler = new PlayerInfoChangedHandler(player.getApplicationLooper()); onPlayerInfoChangedHandler = new PlayerInfoChangedHandler(player.getApplicationLooper());
...@@ -357,6 +360,10 @@ import org.checkerframework.checker.initialization.qual.Initialized; ...@@ -357,6 +360,10 @@ import org.checkerframework.checker.initialization.qual.Initialized;
} }
} }
public BitmapLoader getBitmapLoader() {
return bitmapLoader;
}
public void setAvailableCommands( public void setAvailableCommands(
ControllerInfo controller, SessionCommands sessionCommands, Player.Commands playerCommands) { ControllerInfo controller, SessionCommands sessionCommands, Player.Commands playerCommands) {
if (sessionStub.getConnectedControllersManager().isConnected(controller)) { if (sessionStub.getConnectedControllersManager().isConnected(controller)) {
......
...@@ -418,10 +418,10 @@ public class DefaultMediaNotificationProviderTest { ...@@ -418,10 +418,10 @@ public class DefaultMediaNotificationProviderTest {
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class); BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
SettableFuture<Bitmap> bitmapFuture = SettableFuture.create(); SettableFuture<Bitmap> bitmapFuture = SettableFuture.create();
when(mockBitmapLoader.loadBitmap(any())).thenReturn(bitmapFuture); when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(bitmapFuture);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
DefaultMediaNotificationProvider defaultMediaNotificationProvider = DefaultMediaNotificationProvider defaultMediaNotificationProvider =
new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext()) new DefaultMediaNotificationProvider.Builder(ApplicationProvider.getApplicationContext())
.setBitmapLoader(mockBitmapLoader)
.build(); .build();
// Ask the notification provider to create a notification twice. Use separate callback instances // Ask the notification provider to create a notification twice. Use separate callback instances
...@@ -456,6 +456,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -456,6 +456,9 @@ public class DefaultMediaNotificationProviderTest {
DefaultMediaNotificationProvider defaultMediaNotificationProvider = DefaultMediaNotificationProvider defaultMediaNotificationProvider =
new DefaultMediaNotificationProvider.Builder(context).build(); new DefaultMediaNotificationProvider.Builder(context).build();
MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY); MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY);
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
DefaultActionFactory defaultActionFactory = DefaultActionFactory defaultActionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
...@@ -487,6 +490,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -487,6 +490,9 @@ public class DefaultMediaNotificationProviderTest {
.setChannelName(/* channelNameResourceId= */ R.string.media3_controls_play_description) .setChannelName(/* channelNameResourceId= */ R.string.media3_controls_play_description)
.build(); .build();
MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY); MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY);
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
DefaultActionFactory defaultActionFactory = DefaultActionFactory defaultActionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
...@@ -521,6 +527,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -521,6 +527,9 @@ public class DefaultMediaNotificationProviderTest {
.setChannelName(/* channelNameResourceId= */ R.string.media3_controls_play_description) .setChannelName(/* channelNameResourceId= */ R.string.media3_controls_play_description)
.build(); .build();
MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY); MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY);
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
DefaultActionFactory defaultActionFactory = DefaultActionFactory defaultActionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
...@@ -542,6 +551,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -542,6 +551,9 @@ public class DefaultMediaNotificationProviderTest {
DefaultActionFactory defaultActionFactory = DefaultActionFactory defaultActionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY); MediaSession mockMediaSession = createMockMediaSessionForNotification(MediaMetadata.EMPTY);
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
MediaNotification notification = MediaNotification notification =
defaultMediaNotificationProvider.createNotification( defaultMediaNotificationProvider.createNotification(
...@@ -574,6 +586,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -574,6 +586,9 @@ public class DefaultMediaNotificationProviderTest {
MediaSession mockMediaSession = MediaSession mockMediaSession =
createMockMediaSessionForNotification( createMockMediaSessionForNotification(
new MediaMetadata.Builder().setTitle("title").build()); new MediaMetadata.Builder().setTitle("title").build());
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
MediaNotification notification = MediaNotification notification =
defaultMediaNotificationProvider.createNotification( defaultMediaNotificationProvider.createNotification(
...@@ -597,6 +612,9 @@ public class DefaultMediaNotificationProviderTest { ...@@ -597,6 +612,9 @@ public class DefaultMediaNotificationProviderTest {
MediaSession mockMediaSession = MediaSession mockMediaSession =
createMockMediaSessionForNotification( createMockMediaSessionForNotification(
new MediaMetadata.Builder().setArtist("artist").build()); new MediaMetadata.Builder().setArtist("artist").build());
BitmapLoader mockBitmapLoader = mock(BitmapLoader.class);
when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null);
when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader);
MediaNotification notification = MediaNotification notification =
defaultMediaNotificationProvider.createNotification( defaultMediaNotificationProvider.createNotification(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment