Применение стилей контента

После создания иерархии контента с использованием элементов, доступных для просмотра или воспроизведения, примените стили контента, чтобы определить, как эти элементы отображаются в автомобиле. Используйте следующие стили контента:

Список товаров

Рисунок 1. В элементах списка приоритет отдается заголовкам и метаданным, а не изображениям.

Элементы сетки

Рисунок 2. В элементах сетки приоритет отдается изображениям, а не заголовкам и метаданным.

Установить стили контента по умолчанию

Вы можете установить глобальные параметры по умолчанию для отображения ваших медиафайлов. Для этого включите определенные константы в пакет дополнительных параметров BrowserRoot , возвращаемый реализацией onGetRoot вашего сервиса, и найдите эти константы, чтобы определить соответствующий стиль.

Эти дополнительные элементы можно использовать в качестве ключей в комплекте:

Эти клавиши могут сопоставляться с этими целочисленными константными значениями, влияя на отображение этих элементов:

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM : Соответствующие элементы, представленные в виде элементов списка.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM : Соответствующие элементы, представленные в виде элементов сетки.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM : Соответствующие элементы отображаются как элементы списка «категории», аналогично обычным элементам списка, но вокруг значков элементов применяются поля. Это улучшает внешний вид маленьких значков. Значки должны быть векторными изображениями с возможностью изменения цвета. Предполагается, что эта подсказка будет предоставляться только для элементов, доступных для просмотра.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM : Соответствующие элементы представлены как элементы сетки «категории» и похожи на обычные элементы сетки, но вокруг значков элементов применяются поля. Это улучшает внешний вид маленьких значков. Значки должны быть векторными изображениями с возможностью изменения цвета. Предполагается, что эта подсказка будет предоставляться только для элементов, доступных для просмотра.

Этот фрагмент кода показывает, как установить стиль содержимого по умолчанию для просматриваемых элементов в виде сеток, а для воспроизводимых элементов — в виде списков:

Котлин

import androidx.media.utils.MediaConstants

@Nullable
override fun onGetRoot(
    @NonNull clientPackageName: String,
    clientUid: Int,
    @Nullable rootHints: Bundle
): BrowserRoot {
    val extras = Bundle()
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
    return BrowserRoot(ROOT_ID, extras)
}

Java

import androidx.media.utils.MediaConstants;

@Nullable
@Override
public BrowserRoot onGetRoot(
    @NonNull String clientPackageName,
    int clientUid,
    @Nullable Bundle rootHints) {
    Bundle extras = new Bundle();
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM);
    return new BrowserRoot(ROOT_ID, extras);
}

Задайте стили содержимого для каждого элемента.

Вы можете переопределить стиль содержимого по умолчанию для потомков любого просматриваемого медиафайла, а также для любого другого медиафайла. Чтобы переопределить стиль по умолчанию для потомков просматриваемого медиафайла, создайте пакет дополнительных элементов в MediaDescription медиафайла и добавьте те же подсказки, что и ранее:

  • DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE применяется к играбельным потомкам этого предмета.

  • DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE применяется к просматриваемым потомкам этого элемента.

Чтобы переопределить значение по умолчанию для конкретного медиафайла (но не для его потомков), создайте пакет дополнительных материалов в MediaDescription медиафайла (MediaDescription). Затем добавьте подсказку с ключом DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM . Используйте те же значения, что и ранее, для указания способа отображения этого элемента.

Этот фрагмент кода показывает, как создать просматриваемый элемент MediaItem , который переопределяет стиль содержимого по умолчанию для себя и своих потомков. Он стилизует себя как элемент списка категорий, свои просматриваемые потомки — как элементы списка, а свои воспроизводимые потомки — как элементы сетки.

Котлин

import androidx.media.utils.MediaConstants

private fun createBrowsableMediaItem(
    mediaId: String,
    folderName: String,
    iconUri: Uri
): MediaBrowser.MediaItem {
    val mediaDescriptionBuilder = MediaDescription.Builder()
    mediaDescriptionBuilder.setMediaId(mediaId)
    mediaDescriptionBuilder.setTitle(folderName)
    mediaDescriptionBuilder.setIconUri(iconUri)
    val extras = Bundle()
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM)
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM)
    mediaDescriptionBuilder.setExtras(extras)
    return MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)
}

Java

import androidx.media.utils.MediaConstants;

private MediaBrowser.MediaItem createBrowsableMediaItem(
    String mediaId,
    String folderName,
    Uri iconUri) {
    MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
    mediaDescriptionBuilder.setMediaId(mediaId);
    mediaDescriptionBuilder.setTitle(folderName);
    mediaDescriptionBuilder.setIconUri(iconUri);
    Bundle extras = new Bundle();
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM);
    extras.putInt(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
        MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM);
    mediaDescriptionBuilder.setExtras(extras);
    return new MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE);
}

Группируйте элементы, используя подсказки в заголовках.

Для группировки связанных медиафайлов используйте подсказку для каждого элемента. Каждый медиафайл в группе должен объявить пакет дополнительных материалов (extras bundle) в своем MediaDescription . Этот пакет должен включать сопоставление с ключом DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE и идентичным строковым значением. Локализуйте эту строку, поскольку она используется в качестве заголовка группы.

Этот фрагмент кода показывает, как создать MediaItem с заголовком подгруппы Songs :

Котлин

import androidx.media.utils.MediaConstants

private fun createMediaItem(
    mediaId: String,
    folderName: String,
    iconUri: Uri
): MediaBrowser.MediaItem {
    val mediaDescriptionBuilder = MediaDescription.Builder()
    mediaDescriptionBuilder.setMediaId(mediaId)
    mediaDescriptionBuilder.setTitle(folderName)
    mediaDescriptionBuilder.setIconUri(iconUri)
    val extras = Bundle()
    extras.putString(
        MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
        "Songs")
    mediaDescriptionBuilder.setExtras(extras)
    return MediaBrowser.MediaItem(
        mediaDescriptionBuilder.build(), /* playable or browsable flag*/)
}

Java

import androidx.media.utils.MediaConstants;

private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) {
   MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
   mediaDescriptionBuilder.setMediaId(mediaId);
   mediaDescriptionBuilder.setTitle(folderName);
   mediaDescriptionBuilder.setIconUri(iconUri);
   Bundle extras = new Bundle();
   extras.putString(
       MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE,
       "Songs");
   mediaDescriptionBuilder.setExtras(extras);
   return new MediaBrowser.MediaItem(
       mediaDescriptionBuilder.build(), /* playable or browsable flag*/);
}

Ваше приложение должно передавать все медиафайлы, которые вы хотите сгруппировать вместе, как единый блок. Например, рассмотрите возможность отображения двух групп медиафайлов: «Песни» и «Альбомы», именно в таком порядке. Если ваше приложение передаст пять медиафайлов в таком порядке, Android Auto и AAOS интерпретируют их как четыре отдельные группы:

  • Медиафайл A с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл B с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  • Медиафайл C с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл D с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл E с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

В результате образуются следующие четыре группы:

  • Группа 1, называемая «Песни», содержит медиа-материал А.
  • Группа 2, называемая «Альбомы», содержит медиа-элемент B.
  • Группа 3, называемая «Песни», включает в себя медиа-материалы C и D.
  • Группа 4, называемая «Альбомы», содержит медиафайл E.

Для отображения этих элементов в двух группах ваше приложение должно передавать медиафайлы в следующем порядке:

  • Медиафайл A с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл C с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл D с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Медиафайл B с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  • Медиафайл E с extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Отобразить дополнительные индикаторы метаданных

Вы можете добавить дополнительные метаданные, чтобы предоставлять краткую информацию о контенте в дереве медиабраузера и во время воспроизведения.

В дереве просмотра Android Auto и AAOS считывают дополнительные параметры, связанные с элементом, и отображают соответствующие индикаторы. Во время воспроизведения мультимедиа Android Auto и AAOS считывают метаданные сеанса воспроизведения и ищут определенные константы, чтобы определить, какие индикаторы следует отобразить.

Просмотр воспроизведения с метаданными

Рисунок 3. Вид воспроизведения с метаданными.

Для просмотра невоспроизведенного контента используйте режим просмотра "Просмотр".

Рисунок 4. Просмотр невоспроизведенного контента.

Эти константы можно использовать как в дополнительных параметрах описания MediaItem , так и в дополнительных параметрах MediaMetadata :

  • EXTRA_DOWNLOAD_STATUS : Указывает статус загрузки элемента. Используйте эту константу в качестве ключа. Возможные значения для следующих констант типа long:

  • METADATA_KEY_IS_EXPLICIT : Указывает, что элемент содержит контент откровенного характера. Чтобы указать, что элемент содержит контент откровенного характера, используйте эту константу в качестве ключа, а длинное значение METADATA_VALUE_ATTRIBUTE_PRESENT в качестве значения.

Эти константы можно использовать только в дополнительных параметрах описания MediaItem :

Чтобы отображать индикаторы, которые появляются во время просмотра пользователем дерева медиафайлов, создайте пакет дополнительных материалов, включающий одну или несколько из этих констант. Затем передайте этот пакет методу MediaDescription.Builder.setExtras .

Этот фрагмент кода показывает, как отображать индикаторы для медиафайла, который готов на 70%:

Котлин

import androidx.media.utils.MediaConstants

val extras = Bundle()
extras.putLong(
    MediaConstants.METADATA_KEY_IS_EXPLICIT,
    MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
extras.putInt(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
    MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED)
extras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7)
val description =
    MediaDescriptionCompat.Builder()
        .setMediaId(/*...*/)
        .setTitle(resources.getString(/*...*/))
        .setExtras(extras)
        .build()
return MediaBrowserCompat.MediaItem(description, /* flags */)

Java

import androidx.media.utils.MediaConstants;

Bundle extras = new Bundle();
extras.putLong(
    MediaConstants.METADATA_KEY_IS_EXPLICIT,
    MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT);
extras.putInt(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
    MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
extras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7);
MediaDescriptionCompat description =
    new MediaDescriptionCompat.Builder()
        .setMediaId(/*...*/)
        .setTitle(resources.getString(/*...*/))
        .setExtras(extras)
        .build();
return new MediaBrowserCompat.MediaItem(description, /* flags */);

Чтобы отобразить индикаторы для воспроизводимого в данный момент медиафайла, объявите значения для METADATA_KEY_IS_EXPLICIT или EXTRA_DOWNLOAD_STATUS в MediaMetadataCompat вашего mediaSession .

Этот фрагмент кода показывает, как указать в окне воспроизведения, что песня является нецензурной и загруженной:

Котлин

import androidx.media.utils.MediaConstants

mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
            albumArtUri.toString())
        .putLong(
            MediaConstants.METADATA_KEY_IS_EXPLICIT,
            MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
        .putLong(
            MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS,
            MediaDescriptionCompat.STATUS_DOWNLOADED)
        .build())

Java

import androidx.media.utils.MediaConstants;

mediaSession.setMetadata(
    new MediaMetadataCompat.Builder()
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
        .putString(
            MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI,
            albumArtUri.toString())
        .putLong(
            MediaConstants.METADATA_KEY_IS_EXPLICIT,
            MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT)
        .putLong(
            MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS,
            MediaDescriptionCompat.STATUS_DOWNLOADED)
        .build());

В режиме просмотра контента индикатор выполнения обновляется во время воспроизведения.

Как уже упоминалось ранее, вы можете использовать дополнительный параметр DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE для отображения индикатора выполнения частично воспроизведенного контента в режиме просмотра. Однако, если пользователь продолжает воспроизведение частично воспроизведенного контента, этот индикатор со временем становится неточным.

Чтобы Android Auto и AAOS поддерживали актуальность индикатора выполнения, необходимо предоставлять дополнительную информацию в полях MediaMetadataCompat и PlaybackStateCompat для связи текущего контента с медиафайлами в режиме просмотра.

Для того чтобы медиафайл имел автоматически обновляемую полосу прогресса, необходимо соблюдение следующих требований:

Этот фрагмент кода показывает, как указать, что воспроизводимый элемент связан с элементом в режиме просмотра:

Котлин

import androidx.media.utils.MediaConstants

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
val mediaItemExtras = Bundle()
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25)
val description =
    MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build()
return MediaBrowserCompat.MediaItem(description, /* flags */)

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build())

val playbackStateExtras = Bundle()
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id")
mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build())

Java

import androidx.media.utils.MediaConstants;

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
Bundle mediaItemExtras = new Bundle();
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25);
MediaDescriptionCompat description =
    new MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build();
return new MediaBrowserCompat.MediaItem(description, /* flags */);

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    new MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build());

Bundle playbackStateExtras = new Bundle();
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id");
mediaSession.setPlaybackState(
    new PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build());

Даже для невоспроизведенного или полностью воспроизведенного контента может отображаться автоматически обновляющаяся полоса прогресса. Это происходит, если соответствующие медиафайлы содержат дополнительный параметр DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE со значением 0.0 (для невоспроизведенного контента) или 1.0 (для полностью воспроизведенного контента). После выбора пользователем этих медиафайлов Android Auto и AAOS отображают полосу прогресса поверх других индикаторов выполнения.