Restrict CommandButton.iconUri to content Uris

These Uris are not widely supported yet and were only meant to be
used with content Uris. Restricting this more tightly allows
controllers to use these Uris more easily as they have a stricter
guarentee on what it's needed to load these Uris. Media session
apps with different types of Uris can convert them by setting up
a ContentProvider if needed.

Issue: androidx/media#1783
PiperOrigin-RevId: 683539747
This commit is contained in:
tonihei 2024-10-08 02:51:37 -07:00 committed by Copybara-Service
parent 7c9fede3ad
commit bd192c17ca
7 changed files with 26 additions and 21 deletions

View File

@ -105,6 +105,7 @@
Browse actions of AAOS</a>.
* Fix bug where a Media3 controller was sometimes unable to let a session
app start a foreground service after requesting `play()`.
* Restrict `CommandButton.Builder.setIconUri` to only accept content Uris.
* UI:
* Make the stretched/cropped video in
`PlayerView`-in-Compose-`AndroidView` workaround opt-in, due to issues

View File

@ -20,6 +20,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
@ -424,8 +425,8 @@ public final class CommandButton {
/**
* [will be deprecated] Use {@link #Builder(int)} instead to define the {@link Icon} for this
* button. A separate resource id via {@link #setIconResId(int)} or {@link #setIconUri} is no
* longer required unless for {@link #ICON_UNDEFINED}.
* button. A separate resource id via {@link #setIconResId(int)} is no longer required unless
* for {@link #ICON_UNDEFINED}.
*/
public Builder() {
this(ICON_UNDEFINED);
@ -519,11 +520,11 @@ public final class CommandButton {
}
/**
* Sets a {@link Uri} for the icon of this button.
* Sets a content {@link Uri} for the icon of this button.
*
* <p>Note that this {@link Uri} may be used when the predefined {@link Icon} is not available
* or set to {@link #ICON_UNDEFINED}. It can be used in addition or instead of {@link
* #setCustomIconResId} for consumers that are capable of loading the {@link Uri}.
* or set to {@link #ICON_UNDEFINED}. It can be used in addition to {@link #setCustomIconResId}
* for consumers that are capable of loading the content {@link Uri}.
*
* @param uri The uri to an icon.
* @return This builder for chaining.
@ -531,6 +532,9 @@ public final class CommandButton {
@UnstableApi
@CanIgnoreReturnValue
public Builder setIconUri(Uri uri) {
checkArgument(
Objects.equal(uri.getScheme(), ContentResolver.SCHEME_CONTENT),
"Only content Uris are supported for CommandButton");
this.iconUri = uri;
return this;
}
@ -606,11 +610,11 @@ public final class CommandButton {
@DrawableRes public final int iconResId;
/**
* The {@link Uri} for the icon of the button that is used when the predefined {@link #icon} is
* not available or set to {@link #ICON_UNDEFINED}. Can be {@code null}.
* The content {@link Uri} for the icon of the button that is used when the predefined {@link
* #icon} is not available or set to {@link #ICON_UNDEFINED}. Can be {@code null}.
*
* <p>Note that this value can be used in addition or instead of {@link #iconResId} for consumers
* that are capable of loading the {@link Uri}.
* <p>Note that this value can be used in addition to {@link #iconResId} for consumers that are
* capable of loading the content {@link Uri}.
*/
@UnstableApi @Nullable public final Uri iconUri;
@ -809,7 +813,7 @@ public final class CommandButton {
if (playerCommand != Player.COMMAND_INVALID) {
builder.setPlayerCommand(playerCommand);
}
if (iconUri != null) {
if (iconUri != null && Objects.equal(iconUri.getScheme(), ContentResolver.SCHEME_CONTENT)) {
builder.setIconUri(iconUri);
}
return builder

View File

@ -364,7 +364,7 @@ public class CommandButtonTest {
.setDisplayName("name")
.setEnabled(true)
.setIconResId(R.drawable.media3_notification_small_icon)
.setIconUri(Uri.parse("http://test.test"))
.setIconUri(Uri.parse("content://test"))
.setExtras(extras)
.setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
.build();
@ -373,7 +373,7 @@ public class CommandButtonTest {
.setDisplayName("name")
.setEnabled(true)
.setIconResId(R.drawable.media3_notification_small_icon)
.setIconUri(Uri.parse("http://test.test"))
.setIconUri(Uri.parse("content://test"))
.setExtras(extras)
.setPlayerCommand(Player.COMMAND_GET_METADATA)
.build();

View File

@ -145,7 +145,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest
.getString(
androidx.media3.session.legacy.MediaConstants
.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI))
.isEqualTo("http://www.example.com/icon/playlist_add");
.isEqualTo("content://playlist_add");
assertThat(
mediaItemCommandButtons
.get(0)
@ -174,7 +174,7 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest
.getString(
androidx.media3.session.legacy.MediaConstants
.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI))
.isEqualTo("http://www.example.com/icon/radio");
.isEqualTo("content://radio");
assertThat(
mediaItemCommandButtons
.get(1)

View File

@ -142,14 +142,14 @@ public class MediaBrowserListenerWithMediaBrowserServiceCompatTest {
CommandButton playlistAddButton =
new CommandButton.Builder()
.setDisplayName("Add to playlist")
.setIconUri(Uri.parse("https://www.example.com/icon/playlist_add"))
.setIconUri(Uri.parse("content://playlist_add"))
.setSessionCommand(
new SessionCommand(MediaBrowserConstants.COMMAND_PLAYLIST_ADD, Bundle.EMPTY))
.build();
CommandButton radioButton =
new CommandButton.Builder()
.setDisplayName("Radio station")
.setIconUri(Uri.parse("https://www.example.com/icon/radio"))
.setIconUri(Uri.parse("content://radio"))
.setSessionCommand(
new SessionCommand(MediaBrowserConstants.COMMAND_RADIO, Bundle.EMPTY))
.build();
@ -192,7 +192,7 @@ public class MediaBrowserListenerWithMediaBrowserServiceCompatTest {
CommandButton playlistAddButton =
new CommandButton.Builder()
.setDisplayName("Add to playlist")
.setIconUri(Uri.parse("https://www.example.com/icon/playlist_add"))
.setIconUri(Uri.parse("content://playlist_add"))
.setSessionCommand(
new SessionCommand(MediaBrowserConstants.COMMAND_PLAYLIST_ADD, Bundle.EMPTY))
.build();

View File

@ -364,7 +364,7 @@ public class MockMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
"Add to playlist");
playlistAddBrowseAction.putString(
androidx.media3.session.legacy.MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
"https://www.example.com/icon/playlist_add");
"content://playlist_add");
playlistAddBrowseAction.putBundle(
androidx.media3.session.legacy.MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_EXTRAS,
playlistAddExtras);
@ -379,7 +379,7 @@ public class MockMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
"Radio station");
radioBrowseAction.putString(
androidx.media3.session.legacy.MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
"https://www.example.com/icon/radio");
"content://radio");
radioBrowseAction.putBundle(
androidx.media3.session.legacy.MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_EXTRAS,
radioExtras);

View File

@ -238,7 +238,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
ImmutableList.of(
new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD)
.setDisplayName("Add to playlist")
.setIconUri(Uri.parse("http://www.example.com/icon/playlist_add"))
.setIconUri(Uri.parse("content://playlist_add"))
.setSessionCommand(
new SessionCommand(
MediaBrowserConstants.COMMAND_PLAYLIST_ADD, Bundle.EMPTY))
@ -246,7 +246,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
.build(),
new CommandButton.Builder(CommandButton.ICON_RADIO)
.setDisplayName("Radio station")
.setIconUri(Uri.parse("http://www.example.com/icon/radio"))
.setIconUri(Uri.parse("content://radio"))
.setSessionCommand(
new SessionCommand(MediaBrowserConstants.COMMAND_RADIO, Bundle.EMPTY))
.setExtras(radioExtras)