Commit 006a519a by bachinger Committed by Marc Baechinger

Migrate media constants from androidx.media.util.MediaConstants

Adds root extras and metadata extras to MockMediaLibraryService and MockMediaBrowserCompatService and completed test cases for asserting
interoperability with a media1 or Media3 browser.

PiperOrigin-RevId: 480854842
parent 7e8f0f09
......@@ -40,7 +40,7 @@ project.ext {
androidxConstraintLayoutVersion = '2.0.4'
androidxCoreVersion = '1.7.0'
androidxFuturesVersion = '1.1.0'
androidxMediaVersion = '1.4.3'
androidxMediaVersion = '1.6.0'
androidxMedia2Version = '1.2.0'
androidxMultidexVersion = '2.0.1'
androidxRecyclerViewVersion = '1.2.1'
......
......@@ -15,18 +15,77 @@
*/
package androidx.media3.session;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaLibraryService.LibraryParams;
import androidx.media3.session.MediaLibraryService.MediaLibrarySession;
/** Constants that can be shared between media session and controller. */
public final class MediaConstants {
/**
* Bundle key to indicate a preference that a region of space for the skip to next control should
* always be blocked out in the UI, even when the seek to next standard action is not supported.
* The legacy error code for expired authentication.
*
* <p>Use this error code to indicate an expired authentication when {@linkplain
* LibraryResult#ofError(int, LibraryParams) creating a library result} for an unsuccessful
* service call.
*
* @see PlaybackStateCompat#ERROR_CODE_AUTHENTICATION_EXPIRED
*/
public static final int ERROR_CODE_AUTHENTICATION_EXPIRED_COMPAT = 3;
/**
* The extras key for the localized error resolution string.
*
* <p>Use this key to populate the extras bundle of the {@link LibraryParams} when {@linkplain
* LibraryResult#ofError(int, LibraryParams) creating a library result} for an unsuccessful
* service call.
*/
public static final String EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL_COMPAT =
androidx.media.utils.MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL;
/**
* The extras key for the error resolution intent.
*
* <p>Use this key to populate the extras bundle of the {@link LibraryParams} when {@linkplain
* LibraryResult#ofError(int, LibraryParams) creating a library result} for an unsuccessful
* service call.
*/
public static final String EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT_COMPAT =
androidx.media.utils.MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT;
/**
* {@link Bundle} key used to store a {@link PendingIntent}. When launched, the {@link
* PendingIntent} should allow users to resolve the current playback state error.
*
* <p>Applications must also set the error message and {@link
* #EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL_COMPAT} for cases in which the intent cannot be auto
* launched.
*
* <p>Use this key to populate the extras bundle of the {@link LibraryParams} when {@linkplain
* LibraryResult#ofError(int, LibraryParams) creating a library result} for an unsuccessful
* service call. Must be inserted {@linkplain Bundle#putParcelable(String, Parcelable) into the
* bundle as a parcelable}.
*
* <p>TYPE: {@link PendingIntent}.
*/
@UnstableApi
public static final String EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT_COMPAT =
androidx.media.utils.MediaConstants
.PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT;
/**
* {@link Bundle} key to indicate a preference that a region of space for the skip to next control
* should always be blocked out in the UI, even when the seek to next standard action is not
* supported.
*
* <p>This may be used when the session temporarily disallows {@link
* androidx.media3.common.Player#COMMAND_SEEK_TO_NEXT} by design.
......@@ -39,12 +98,12 @@ public final class MediaConstants {
* @see androidx.media3.common.Player#COMMAND_SEEK_TO_NEXT_MEDIA_ITEM
*/
public static final String EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT =
"android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
androidx.media.utils.MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT;
/**
* Bundle key to indicate a preference that a region of space for the skip to previous control
* should always be blocked out in the UI, even when the seek to previous standard action is not
* supported.
* {@link Bundle} key to indicate a preference that a region of space for the skip to previous
* control should always be blocked out in the UI, even when the seek to previous standard action
* is not supported.
*
* <p>This may be used when the session temporarily disallows {@link
* androidx.media3.common.Player#COMMAND_SEEK_TO_PREVIOUS} by design.
......@@ -57,43 +116,309 @@ public final class MediaConstants {
* @see androidx.media3.common.Player#COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM
*/
public static final String EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV =
"android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
androidx.media.utils.MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV;
/**
* The extras key for the localized error resolution string.
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate the playback completion
* status of the corresponding {@link MediaItem}.
*
* <p>Use this key to populate the extras bundle of the {@link LibraryParams} when {@link
* LibraryResult#ofError(int, LibraryParams) creating a LibraryResult} for an unsuccessful service
* call.
* <p>TYPE: int. Possible values are separate constants.
*
* @see
* androidx.media.utils.MediaConstants#PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
* @see #EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
* @see #EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
*/
public static final String EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL_COMPAT =
"android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
@UnstableApi
public static final String EXTRAS_KEY_COMPLETION_STATUS =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS;
/**
* The extras key for the error resolution intent.
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate that the corresponding
* {@link MediaItem} has not been played by the user.
*
* <p>Use this key to populate the extras bundle of the {@link LibraryParams} when {@link
* LibraryResult#ofError(int, LibraryParams) creating a LibraryResult} for an unsuccessful service
* call.
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_COMPLETION_STATUS
*/
@UnstableApi
public static final int EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED;
/**
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate that the corresponding
* {@link MediaItem} has been partially played by the user.
*
* @see
* androidx.media.utils.MediaConstants#PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_COMPLETION_STATUS
*/
public static final String EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT_COMPAT =
"android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
@UnstableApi
public static final int EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED =
androidx.media.utils.MediaConstants
.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
/**
* The legacy error code for expired authentication.
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate that the corresponding
* {@link MediaItem} has been fully played by the user.
*
* <p>Use this error code to indicate an expired authentication when {@link
* LibraryResult#ofError(int, LibraryParams) creating a LibraryResult} for an unsuccessful service
* call.
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_COMPLETION_STATUS
*/
@UnstableApi
public static final int EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED;
/**
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate an amount of completion
* progress for the corresponding {@link MediaItem}. This extra augments {@link
* #EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED the partially played status} by indicating how
* much has been played by the user.
*
* @see PlaybackStateCompat#ERROR_CODE_AUTHENTICATION_EXPIRED
* <p>TYPE: double, a value between 0.0 and 1.0, inclusive. 0.0 indicates no completion progress
* (item is not started) and 1.0 indicates full completion progress (item is fully played). Values
* in between indicate partial progress (for example, 0.75 indicates the item is 75% complete).
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
*/
public static final int ERROR_CODE_AUTHENTICATION_EXPIRED_COMPAT = 3;
@UnstableApi
public static final String EXTRAS_KEY_COMPLETION_PERCENTAGE =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE;
/**
* {@link Bundle} key used to indicate a preference about how playable instances of {@link
* MediaItem} are presented.
*
* <p>If exposed through {@link LibraryParams#extras} of the {@link LibraryResult} returned by
* {@link MediaBrowser#getLibraryRoot}, the preference applies to all playable items within the
* browse tree.
*
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#folderType
* browsable media item}, the preference applies to only the immediate playable children. It takes
* precedence over preferences received with {@link MediaBrowser#getLibraryRoot}.
*
* <p>TYPE: int. Possible values are separate constants.
*
* @see MediaBrowser#getLibraryRoot(LibraryParams)
* @see LibraryResult#params
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
*/
@UnstableApi
public static final String EXTRAS_KEY_CONTENT_STYLE_PLAYABLE =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE;
/**
* {@link Bundle} key used to indicate a preference about how browsable instances of {@link
* MediaItem} are presented.
*
* <p>If exposed through {@link LibraryParams#extras} of the {@link LibraryResult} returned by
* {@link MediaBrowser#getLibraryRoot}, the preference applies to all browsable items within the
* browse tree.
*
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#folderType
* browsable media item}, the preference applies to only the immediate browsable children. It
* takes precedence over preferences received with {@link
* MediaBrowser#getLibraryRoot(LibraryParams)}.
*
* <p>TYPE: int. Possible values are separate constants.
*
* @see MediaBrowser#getLibraryRoot(LibraryParams)
* @see LibraryResult#params
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
*/
@UnstableApi
public static final String EXTRAS_KEY_CONTENT_STYLE_BROWSABLE =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE;
/**
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate a preference about how the
* corresponding {@link MediaItem} is presented.
*
* <p>This preference takes precedence over those expressed by {@link
* #EXTRAS_KEY_CONTENT_STYLE_PLAYABLE} and {@link #EXTRAS_KEY_CONTENT_STYLE_BROWSABLE}.
*
* <p>TYPE: int. Possible values are separate constants.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
* @see #EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
*/
@UnstableApi
public static final String EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM;
/**
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate a preference that certain
* instances of {@link MediaItem} should be presented as list items.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
* @see #EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
*/
@UnstableApi
public static final int EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM;
/**
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate a preference that certain
* instances of {@link MediaItem} should be presented as grid items.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
* @see #EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
*/
@UnstableApi
public static final int EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM;
/**
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate a preference that
* browsable instances of {@link MediaItem} should be presented as "category" list items. This
* means the items provide icons that render well when they do <strong>not</strong> fill all of
* the available area.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
*/
@UnstableApi
public static final int EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM;
/**
* {@link Bundle} value used in {@link MediaMetadata#extras} to indicate a preference that
* browsable instances of {@link MediaItem} should be presented as "category" grid items. This
* means the items provide icons that render well when they do <strong>not</strong> fill all of
* the available area.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
* @see #EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
*/
@UnstableApi
public static final int EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM;
/**
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate that certain instances of
* {@link MediaItem} are related as a group, with a title that is specified through the bundle
* value. Items that are children of the same browsable node and have the same title are members
* of the same group. An app may present a group's items as a contiguous block and display the
* title alongside the group.
*
* <p>TYPE: String. Should be human readable and localized.
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
*/
@UnstableApi
public static final String EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE =
androidx.media.utils.MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE;
/**
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate that the corresponding
* {@link MediaItem} has explicit content (that is, user discretion is advised when viewing or
* listening to this content).
*
* <p>TYPE: long (to enable, use value {@link #EXTRAS_VALUE_ATTRIBUTE_PRESENT})
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
*/
@UnstableApi public static final String EXTRAS_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
/**
* {@link Bundle} key used in {@link MediaMetadata#extras} to indicate that the corresponding
* {@link MediaItem} is an advertisement.
*
* <p>TYPE: long (to enable, use value {@link #EXTRAS_VALUE_ATTRIBUTE_PRESENT})
*
* @see MediaMetadata.Builder#setExtras(Bundle)
* @see MediaMetadata#extras
*/
@UnstableApi
public static final String EXTRAS_KEY_IS_ADVERTISEMENT =
androidx.media.utils.MediaConstants.METADATA_KEY_IS_ADVERTISEMENT;
/**
* {@link Bundle} value used to indicate the presence of an attribute described by its
* corresponding key.
*/
@UnstableApi public static final long EXTRAS_VALUE_ATTRIBUTE_PRESENT = 1L;
/**
* {@link Bundle} key used in {@link LibraryParams#extras} passed to {@link
* MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession, MediaSession.ControllerInfo,
* LibraryParams)} to indicate the maximum number of children of the root node that can be
* supported by the {@link MediaBrowser}. Excess root children may be omitted or made less
* discoverable.
*
* <p>TYPE: int
*
* @see MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession,
* MediaSession.ControllerInfo, LibraryParams)
* @see LibraryParams#extras
*/
@UnstableApi
public static final String EXTRAS_KEY_ROOT_CHILDREN_LIMIT =
androidx.media.utils.MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT;
/**
* {@link Bundle} key used in {@link LibraryParams#extras} passed by the {@link MediaBrowser} as
* root hints to {@link MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession,
* MediaSession.ControllerInfo, LibraryParams)} to indicate the recommended size, in pixels, for
* media art bitmaps. Much smaller images may not render well, and much larger images may cause
* inefficient resource consumption.
*
* @see MediaBrowser#getLibraryRoot(LibraryParams)
* @see MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession,
* MediaSession.ControllerInfo, LibraryParams)
* @see LibraryParams#extras
*/
@UnstableApi
public static final String EXTRAS_KEY_MEDIA_ART_SIZE_PIXELS =
androidx.media.utils.MediaConstants.BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS;
/**
* {@link Bundle} key used to indicate that the media app that provides the service supports
* showing a settings page.
*
* <p>Use this key to populate the {@link LibraryParams#extras} of the {@link LibraryResult}
* returned by {@link MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession,
* MediaSession.ControllerInfo, LibraryParams)}. Use this key with {@link
* Bundle#putParcelable(String, Parcelable)} to put a {@link PendingIntent} that is created using
* {@code CarPendingIntent#getCarApp()}.
*
* <p>The {@link Intent} carried by the pending intent needs to have the component name set to a
* <a href="http://developer.android.com/training/cars/apps#create-carappservice">Car App Library
* service</a> that needs to exist in the same application package as the media browser service.
*
* <p>TYPE: {@link PendingIntent}.
*
* @see MediaLibrarySession.Callback#onGetLibraryRoot(MediaLibrarySession,
* MediaSession.ControllerInfo, LibraryParams)
* @see LibraryParams#extras
*/
@UnstableApi
public static final String EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT =
androidx.media.utils.MediaConstants
.BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT;
/* package */ static final String SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED =
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
......
......@@ -26,6 +26,8 @@ public class MediaBrowserConstants {
public static final String ROOT_ID = "rootId";
public static final Bundle ROOT_EXTRAS = new Bundle();
public static final String ROOT_EXTRAS_KEY = "root_extras_key";
public static final int ROOT_EXTRAS_VALUE = 4321;
public static final String MEDIA_ID_GET_BROWSABLE_ITEM = "media_id_get_browsable_item";
public static final String MEDIA_ID_GET_PLAYABLE_ITEM = "media_id_get_playable_item";
......@@ -71,7 +73,7 @@ public class MediaBrowserConstants {
public static final String CUSTOM_ACTION_ASSERT_PARAMS = "assertParams";
static {
ROOT_EXTRAS.putString(ROOT_ID, ROOT_ID);
ROOT_EXTRAS.putInt(ROOT_EXTRAS_KEY, ROOT_EXTRAS_VALUE);
CUSTOM_ACTION_EXTRAS.putString(CUSTOM_ACTION, CUSTOM_ACTION);
......
......@@ -24,6 +24,8 @@ public class MediaBrowserServiceCompatConstants {
public static final String TEST_CONNECT_REJECTED = "testConnect_rejected";
public static final String TEST_ON_CHILDREN_CHANGED_SUBSCRIBE_AND_UNSUBSCRIBE =
"testOnChildrenChanged_subscribeAndUnsubscribe";
public static final String TEST_GET_LIBRARY_ROOT = "getLibraryRoot_correctExtraKeyAndValue";
public static final String TEST_GET_CHILDREN = "getChildren_correctMetadataExtras";
private MediaBrowserServiceCompatConstants() {}
}
......@@ -15,6 +15,8 @@
*/
package androidx.media3.session;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
import static androidx.media3.test.session.common.CommonConstants.METADATA_ARTWORK_URI;
import static androidx.media3.test.session.common.CommonConstants.METADATA_DESCRIPTION;
import static androidx.media3.test.session.common.CommonConstants.METADATA_EXTRA_KEY;
......@@ -38,6 +40,8 @@ import static androidx.media3.test.session.common.MediaBrowserConstants.PARENT_I
import static androidx.media3.test.session.common.MediaBrowserConstants.PARENT_ID_LONG_LIST;
import static androidx.media3.test.session.common.MediaBrowserConstants.PARENT_ID_NO_CHILDREN;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_KEY;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_VALUE;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_ID;
import static androidx.media3.test.session.common.MediaBrowserConstants.SEARCH_QUERY;
import static androidx.media3.test.session.common.MediaBrowserConstants.SEARCH_QUERY_EMPTY_RESULT;
......@@ -67,6 +71,7 @@ import androidx.media3.test.session.common.TestUtils;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.ext.truth.os.BundleSubject;
import androidx.test.filters.LargeTest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
......@@ -96,6 +101,11 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest
});
connectAndWait();
assertThat(browserCompat.getRoot()).isEqualTo(ROOT_ID);
assertThat(
browserCompat
.getExtras()
.getInt(ROOT_EXTRAS_KEY, /* defaultValue= */ ROOT_EXTRAS_VALUE + 1))
.isEqualTo(ROOT_EXTRAS_VALUE);
// Note: Cannot use equals() here because browser compat's extra contains server version,
// extra binder, and extra messenger.
......@@ -202,22 +212,18 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest
@Test
public void getChildren() throws InterruptedException {
String testParentId = PARENT_ID;
connectAndWait();
CountDownLatch latch = new CountDownLatch(1);
List<MediaItem> receivedChildren = new ArrayList<>();
final String[] receivedParentId = new String[1];
browserCompat.subscribe(
testParentId,
new SubscriptionCallback() {
@Override
public void onChildrenLoaded(String parentId, List<MediaItem> children) {
assertThat(parentId).isEqualTo(testParentId);
assertThat(children).isNotNull();
assertThat(children.size()).isEqualTo(GET_CHILDREN_RESULT.size());
// Compare the given results with originals.
for (int i = 0; i < children.size(); i++) {
assertThat(children.get(i).getMediaId()).isEqualTo(GET_CHILDREN_RESULT.get(i));
}
receivedParentId[0] = parentId;
receivedChildren.addAll(children);
latch.countDown();
}
......@@ -226,7 +232,23 @@ public class MediaBrowserCompatWithMediaLibraryServiceTest
assertWithMessage("").fail();
}
});
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
assertThat(receivedParentId[0]).isEqualTo(testParentId);
assertThat(receivedChildren).hasSize(GET_CHILDREN_RESULT.size());
// Compare the given results with originals.
for (int i = 0; i < receivedChildren.size(); i++) {
MediaItem mediaItem = receivedChildren.get(i);
assertThat(mediaItem.getMediaId()).isEqualTo(GET_CHILDREN_RESULT.get(i));
assertThat(
mediaItem
.getDescription()
.getExtras()
.getInt(
EXTRAS_KEY_COMPLETION_STATUS,
/* defaultValue= */ EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED + 1))
.isEqualTo(EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
}
}
@Test
......
......@@ -17,12 +17,17 @@ package androidx.media3.session;
import static androidx.media3.session.LibraryResult.RESULT_ERROR_BAD_VALUE;
import static androidx.media3.session.LibraryResult.RESULT_SUCCESS;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA3_LIBRARY_SERVICE;
import static androidx.media3.test.session.common.MediaBrowserConstants.CUSTOM_ACTION_ASSERT_PARAMS;
import static androidx.media3.test.session.common.MediaBrowserConstants.LONG_LIST_COUNT;
import static androidx.media3.test.session.common.MediaBrowserConstants.NOTIFY_CHILDREN_CHANGED_EXTRAS;
import static androidx.media3.test.session.common.MediaBrowserConstants.NOTIFY_CHILDREN_CHANGED_ITEM_COUNT;
import static androidx.media3.test.session.common.MediaBrowserConstants.PARENT_ID;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_KEY;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_VALUE;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_ID;
import static androidx.media3.test.session.common.MediaBrowserConstants.SUBSCRIBE_ID_NOTIFY_CHILDREN_CHANGED_TO_ALL;
import static androidx.media3.test.session.common.MediaBrowserConstants.SUBSCRIBE_ID_NOTIFY_CHILDREN_CHANGED_TO_ALL_WITH_NON_SUBSCRIBED_ID;
......@@ -99,6 +104,45 @@ public class MediaBrowserListenerTest extends MediaControllerListenerTest {
}
@Test
public void getLibraryRoot_correctExtraKeyAndValue() throws Exception {
MediaBrowser browser = createBrowser();
LibraryResult<MediaItem> resultForLibraryRoot =
threadTestRule
.getHandler()
.postAndSync(() -> browser.getLibraryRoot(new LibraryParams.Builder().build()))
.get(TIMEOUT_MS, MILLISECONDS);
Bundle extras = resultForLibraryRoot.params.extras;
assertThat(extras.getInt(ROOT_EXTRAS_KEY, /* defaultValue= */ ROOT_EXTRAS_VALUE + 1))
.isEqualTo(ROOT_EXTRAS_VALUE);
}
@Test
public void getChildren_correctMetadataExtras() throws Exception {
LibraryParams params = MediaTestUtils.createLibraryParams();
MediaBrowser browser = createBrowser();
LibraryResult<ImmutableList<MediaItem>> libraryResult =
threadTestRule
.getHandler()
.postAndSync(
() -> browser.getChildren(PARENT_ID, /* page= */ 4, /* pageSize= */ 10, params))
.get(TIMEOUT_MS, MILLISECONDS);
assertThat(libraryResult.resultCode).isEqualTo(RESULT_SUCCESS);
assertThat(libraryResult.value).isNotEmpty();
for (MediaItem mediaItem : libraryResult.value) {
int status =
mediaItem.mediaMetadata.extras.getInt(
EXTRAS_KEY_COMPLETION_STATUS,
/* defaultValue= */ EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED + 1);
assertThat(status).isEqualTo(EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
}
}
@Test
public void getItem_browsable() throws Exception {
String mediaId = MediaBrowserConstants.MEDIA_ID_GET_BROWSABLE_ITEM;
......@@ -144,14 +188,15 @@ public class MediaBrowserListenerTest extends MediaControllerListenerTest {
}
@Test
public void getChildren() throws Exception {
String parentId = MediaBrowserConstants.PARENT_ID;
public void getChildren_correctLibraryResultWithExtras() throws Exception {
String parentId = PARENT_ID;
int page = 4;
int pageSize = 10;
LibraryParams params = MediaTestUtils.createLibraryParams();
MediaBrowser browser = createBrowser();
setExpectedLibraryParam(browser, params);
LibraryResult<ImmutableList<MediaItem>> result =
threadTestRule
.getHandler()
......@@ -159,7 +204,6 @@ public class MediaBrowserListenerTest extends MediaControllerListenerTest {
.get(TIMEOUT_MS, MILLISECONDS);
assertThat(result.resultCode).isEqualTo(RESULT_SUCCESS);
MediaTestUtils.assertLibraryParamsEquals(params, result.params);
MediaTestUtils.assertPaginatedListHasIds(
result.value, MediaBrowserConstants.GET_CHILDREN_RESULT, page, pageSize);
}
......
......@@ -16,8 +16,15 @@
package androidx.media3.session;
import static androidx.media3.session.LibraryResult.RESULT_SUCCESS;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
import static androidx.media3.test.session.common.CommonConstants.MOCK_MEDIA_BROWSER_SERVICE_COMPAT;
import static androidx.media3.test.session.common.MediaBrowserConstants.PARENT_ID;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_KEY;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS_VALUE;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_CONNECT_REJECTED;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_GET_CHILDREN;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_GET_LIBRARY_ROOT;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_ON_CHILDREN_CHANGED_SUBSCRIBE_AND_UNSUBSCRIBE;
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
import static com.google.common.truth.Truth.assertThat;
......@@ -25,13 +32,16 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.junit.Assert.assertThrows;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media.MediaBrowserServiceCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.session.MediaLibraryService.LibraryParams;
import androidx.media3.test.session.common.HandlerThreadTestRule;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import com.google.common.collect.ImmutableList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import org.junit.After;
......@@ -137,4 +147,56 @@ public class MediaBrowserListenerWithMediaBrowserServiceCompatTest {
// Wait for some time. Exception will be thrown in the listener if error happens.
Thread.sleep(TIMEOUT_MS);
}
@Test
public void getLibraryRoot_correctExtraKeyAndValue() throws Exception {
remoteService.setProxyForTest(TEST_GET_LIBRARY_ROOT);
MediaBrowser browser = createBrowser(/* listener= */ null);
LibraryResult<MediaItem> resultForLibraryRoot =
threadTestRule
.getHandler()
.postAndSync(() -> browser.getLibraryRoot(new LibraryParams.Builder().build()))
.get(TIMEOUT_MS, MILLISECONDS);
Bundle extras = resultForLibraryRoot.params.extras;
assertThat(extras.getInt(ROOT_EXTRAS_KEY, ROOT_EXTRAS_VALUE + 1)).isEqualTo(ROOT_EXTRAS_VALUE);
}
@Test
public void getChildren_correctMetadataExtras() throws Exception {
LibraryParams params = MediaTestUtils.createLibraryParams();
remoteService.setProxyForTest(TEST_GET_CHILDREN);
MediaBrowser browser = createBrowser(/* listener= */ null);
LibraryResult<ImmutableList<MediaItem>> libraryResult =
threadTestRule
.getHandler()
.postAndSync(
() -> browser.getChildren(PARENT_ID, /* page= */ 4, /* pageSize= */ 10, params))
.get(TIMEOUT_MS, MILLISECONDS);
assertThat(libraryResult.resultCode).isEqualTo(RESULT_SUCCESS);
assertThat(libraryResult.value).hasSize(MockMediaBrowserServiceCompat.MEDIA_ITEMS.size());
for (int i = 0; i < libraryResult.value.size(); i++) {
int status =
libraryResult
.value
.get(i)
.mediaMetadata
.extras
.getInt(
EXTRAS_KEY_COMPLETION_STATUS,
/* defaultValue= */ EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED + 1);
int expectedStatus =
MockMediaBrowserServiceCompat.MEDIA_ITEMS
.get(i)
.getDescription()
.getExtras()
.getInt(
EXTRAS_KEY_COMPLETION_STATUS,
/* defaultValue= */ EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED + 1);
assertThat(status).isEqualTo(expectedStatus);
}
}
}
......@@ -15,21 +15,33 @@
*/
package androidx.media3.session;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_EXTRAS;
import static androidx.media3.test.session.common.MediaBrowserConstants.ROOT_ID;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_CONNECT_REJECTED;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_GET_CHILDREN;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_GET_LIBRARY_ROOT;
import static androidx.media3.test.session.common.MediaBrowserServiceCompatConstants.TEST_ON_CHILDREN_CHANGED_SUBSCRIBE_AND_UNSUBSCRIBE;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.MediaSessionCompat.Callback;
import androidx.annotation.GuardedBy;
import androidx.media.MediaBrowserServiceCompat;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.test.session.common.IRemoteMediaBrowserServiceCompat;
import androidx.media3.test.session.common.MediaBrowserServiceCompatConstants;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
......@@ -38,6 +50,12 @@ import java.util.List;
@UnstableApi
public class MockMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
/**
* Immutable list of media items sent to controllers for {@link
* MediaBrowserServiceCompatConstants#TEST_GET_CHILDREN}.
*/
public static final ImmutableList<MediaItem> MEDIA_ITEMS = createMediaItems();
private static final String TAG = "MockMBSCompat";
private static final Object lock = new Object();
......@@ -226,6 +244,12 @@ public class MockMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
case TEST_ON_CHILDREN_CHANGED_SUBSCRIBE_AND_UNSUBSCRIBE:
setProxyForTestOnChildrenChanged_subscribeAndUnsubscribe();
break;
case TEST_GET_LIBRARY_ROOT:
setProxyForTestGetLibraryRoot_correctExtraKeyAndValue();
break;
case TEST_GET_CHILDREN:
setProxyForTestGetChildren_correctMetadataExtras();
break;
default:
throw new IllegalArgumentException("Unknown testName: " + testName);
}
......@@ -257,5 +281,54 @@ public class MockMediaBrowserServiceCompat extends MediaBrowserServiceCompat {
}
});
}
private void setProxyForTestGetChildren_correctMetadataExtras() {
setMediaBrowserServiceProxy(
new MockMediaBrowserServiceCompat.Proxy() {
@Override
public void onLoadChildren(String parentId, Result<List<MediaItem>> result) {
onLoadChildren(parentId, result, new Bundle());
}
@Override
public void onLoadChildren(
String parentId, Result<List<MediaItem>> result, Bundle bundle) {
result.sendResult(MEDIA_ITEMS);
}
});
}
private void setProxyForTestGetLibraryRoot_correctExtraKeyAndValue() {
setMediaBrowserServiceProxy(
new MockMediaBrowserServiceCompat.Proxy() {
@Override
public BrowserRoot onGetRoot(
String clientPackageName, int clientUid, Bundle rootHints) {
return new BrowserRoot(ROOT_ID, ROOT_EXTRAS);
}
});
}
}
private static ImmutableList<MediaItem> createMediaItems() {
int[] completionStates =
new int[] {
EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED,
EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED,
EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
};
ImmutableList.Builder<MediaItem> builder = new ImmutableList.Builder<>();
for (int i = 0; i < 3; i++) {
Bundle extras = new Bundle();
extras.putInt(EXTRAS_KEY_COMPLETION_STATUS, completionStates[i]);
builder.add(
new MediaBrowserCompat.MediaItem(
new MediaDescriptionCompat.Builder()
.setMediaId("media-id-" + i)
.setExtras(extras)
.build(),
/* flags= */ 0));
}
return builder.build();
}
}
......@@ -16,8 +16,10 @@
package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_COMPLETION_STATUS;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT_COMPAT;
import static androidx.media3.session.MediaConstants.EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL_COMPAT;
import static androidx.media3.session.MediaConstants.EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED;
import static androidx.media3.session.MediaTestUtils.assertLibraryParamsEquals;
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
import static androidx.media3.test.session.common.MediaBrowserConstants.CUSTOM_ACTION;
......@@ -63,7 +65,6 @@ import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.session.MediaLibraryService.MediaLibrarySession;
import androidx.media3.session.MediaSession.ControllerInfo;
import androidx.media3.test.session.common.CommonConstants;
import androidx.media3.test.session.common.TestHandler;
......@@ -425,10 +426,13 @@ public class MockMediaLibraryService extends MediaLibraryService {
}
private static MediaItem createPlayableMediaItem(String mediaId) {
Bundle extras = new Bundle();
extras.putInt(EXTRAS_KEY_COMPLETION_STATUS, EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
MediaMetadata mediaMetadata =
new MediaMetadata.Builder()
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
.setIsPlayable(true)
.setExtras(extras)
.build();
return new MediaItem.Builder().setMediaId(mediaId).setMediaMetadata(mediaMetadata).build();
}
......
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