Áp dụng kiểu nội dung

Sau khi sử dụng các mục có thể xem hoặc có thể phát để xây dựng hệ thống phân cấp nội dung, hãy áp dụng kiểu nội dung để xác định cách các mục đó xuất hiện trên ô tô. Hãy sử dụng các kiểu nội dung sau:

Mục trong danh sách

Hình 1. Các mục trong danh sách ưu tiên tiêu đề và siêu dữ liệu hơn hình ảnh.

Mục trong lưới

Hình 2. Các mục trong lưới ưu tiên hình ảnh hơn tiêu đề và siêu dữ liệu.

Đặt kiểu nội dung mặc định

Bạn có thể đặt giá trị mặc định chung cho cách hiển thị mục nội dung đa phương tiện. Để làm như vậy, hãy thêm các hằng số cụ thể vào gói dữ liệu bổ sung BrowserRoot do quá trình triển khai onGetRoot của dịch vụ trả về và tìm các hằng số này để xác định kiểu phù hợp.

Bạn có thể dùng các dữ liệu bổ sung này làm khoá trong gói:

Các khoá này có thể liên kết với những giá trị hằng số nguyên sau đây để thay đổi cách trình bày các mục đó:

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM: Các mục tương ứng được trình bày ở dạng mục trong danh sách.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM: Các mục tương ứng được trình bày ở dạng mục trong lưới.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM: Các mục tương ứng được trình bày ở dạng mục trong danh sách "danh mục", tương tự như các mục trong danh sách thông thường, nhưng có đường viền bao quanh biểu tượng của các mục. Điều này giúp cải thiện giao diện của các biểu tượng nhỏ. Các biểu tượng phải là các vectơ vẽ được có thể phủ màu. Gợi ý này sẽ chỉ được cung cấp cho các mục có thể xem.

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM: Các mục tương ứng được trình bày ở dạng mục trong lưới "danh mục" và tương tự như các mục trong lưới thông thường, nhưng có đường viền bao quanh biểu tượng của các mục. Điều này giúp cải thiện giao diện của các biểu tượng nhỏ. Các biểu tượng phải là các vectơ vẽ được có thể phủ màu. Gợi ý này sẽ chỉ được cung cấp cho các mục có thể xem.

Đoạn mã này cho biết cách đặt kiểu nội dung mặc định cho các mục có thể xem thành lưới và các mục có thể phát thành danh sách:

Kotlin

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);
}

Đặt kiểu nội dung cho từng mục

Bạn có thể ghi đè kiểu nội dung mặc định cho mọi phần tử con của mục nội dung đa phương tiện có thể xem, cũng như cho mọi mục nội dung đa phương tiện. Để ghi đè giá trị mặc định cho các phần tử con của một mục nội dung đa phương tiện có thể xem, hãy tạo một gói dữ liệu bổ sung trong MediaDescription của mục nội dung đa phương tiện đó rồi thêm chính gợi ý đã đề cập trước đó:

  • DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE áp dụng cho các phần tử con có thể phát của mục đó.

  • DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE áp dụng cho các phần tử con có thể duyệt xem của mục đó.

Để ghi đè giá trị mặc định cho một mục nội dung đa phương tiện cụ thể (không phải mục con), hãy tạo một gói dữ liệu bổ sung trong MediaDescription của mục nội dung đa phương tiện đó. Sau đó, hãy thêm một gợi ý bằng khoá DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM. Hãy dùng chính các giá trị mô tả trước đó để chỉ định cách trình bày mục đó.

Đoạn mã này cho biết cách tạo một MediaItem có thể xem ghi đè kiểu nội dung mặc định cho chính nó và các phần tử con. Mục này sẽ định kiểu chính nó là một mục danh sách danh mục, phần tử con có thể xem là mục trong danh sách và phần tử con có thể phát là mục trong lưới.

Kotlin

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);
}

Nhóm các mục bằng gợi ý tiêu đề

Để nhóm các mục nội dung đa phương tiện có liên quan, hãy dùng gợi ý cho từng mục. Mọi mục nội dung đa phương tiện trong một nhóm đều phải khai báo một gói dữ liệu bổ sung trong MediaDescription. Gói này phải bao gồm một mối liên kết với khoá DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE và một giá trị chuỗi giống hệt. Hãy bản địa hoá chuỗi này vì chuỗi này được dùng cho tiêu đề của nhóm.

Đoạn mã này cho biết cách tạo MediaItem có tiêu đề nhóm con là Songs:

Kotlin

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*/);
}

Ứng dụng của bạn phải chuyển mọi mục nội dung đa phương tiện mà bạn muốn nhóm lại với nhau ở dạng khối liền kề. Ví dụ: hãy cân nhắc việc hiển thị 2 nhóm mục nội dung đa phương tiện: "Bài hát" và "Đĩa nhạc" theo thứ tự đó. Nếu ứng dụng của bạn truyền 5 mục nội dung nghe nhìn theo thứ tự này, Android Auto và AAOS sẽ diễn giải chúng thành 4 nhóm riêng biệt:

  • Mục nội dung đa phương tiện A với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện B với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  • Mục nội dung đa phương tiện C với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện D với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện E với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Điều này dẫn đến 4 nhóm sau:

  • Nhóm 1 có tên là "Bài hát", chứa mục nội dung đa phương tiện A
  • Nhóm 2 có tên là "Đĩa nhạc", chứa mục nội dung đa phương tiện B
  • Nhóm 3 có tên là "Bài hát", chứa các mục nội dung đa phương tiện C và D
  • Nhóm 4 có tên là "Đĩa nhạc", chứa mục nội dung đa phương tiện E

Để hiển thị các mục này trong 2 nhóm, ứng dụng của bạn phải chuyển các mục nội dung đa phương tiện theo thứ tự sau:

  • Mục nội dung đa phương tiện A với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện C với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện D với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
  • Mục nội dung đa phương tiện B với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
  • Mục nội dung đa phương tiện E với extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")

Cho thấy chỉ báo siêu dữ liệu bổ sung

Bạn có thể thêm chỉ báo siêu dữ liệu bổ sung để cung cấp thông tin nhanh về nội dung trong cây trình duyệt nội dung đa phương tiện và trong khi phát.

Trong cây duyệt qua, Android Auto và AAOS đọc dữ liệu bổ sung liên kết với một mục và hiển thị các chỉ báo. Trong khi phát nội dung đa phương tiện, Android Auto và AAOS sẽ đọc siêu dữ liệu của phiên phát nội dung đa phương tiện đó rồi tìm những hằng số cụ thể để xác định chỉ báo được xuất hiện.

Chế độ xem phát có siêu dữ liệu

Hình 3. Khung hiển thị phát có siêu dữ liệu.

Khung hiển thị duyệt qua cho nội dung chưa phát.

Hình 4. Khung hiển thị duyệt qua cho nội dung chưa phát.

Bạn có thể dùng các hằng số này trong cả dữ liệu bổ sung mô tả MediaItem lẫn dữ liệu bổ sung MediaMetadata:

Các hằng số này chỉ có thể được dùng trong dữ liệu bổ sung mô tả MediaItem:

Để cho thấy các chỉ báo khi người dùng đang duyệt qua cây trình duyệt nội dung đa phương tiện, hãy tạo một gói dữ liệu bổ sung bao gồm một hoặc nhiều hằng số này. Sau đó, hãy truyền gói đó đến phương thức MediaDescription.Builder.setExtras.

Đoạn mã này cho biết cách hiển thị chỉ báo cho một mục nội dung đa phương tiện tục tĩu đã phát 70%:

Kotlin

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 */);

Để cho thấy chỉ báo đối với mục nội dung đa phương tiện đang phát, hãy khai báo các giá trị cho METADATA_KEY_IS_EXPLICIT hoặc EXTRA_DOWNLOAD_STATUS trong MediaMetadataCompat của mediaSession.

Đoạn mã này cho biết cách cho biết rằng bài hát trong khung hiển thị phát là tục tĩu và đã được tải xuống:

Kotlin

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());

Cập nhật thanh tiến trình trong khung duyệt qua khi nội dung đang phát

Như đã đề cập trước đó, bạn có thể sử dụng dữ liệu bổ sung DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE để hiển thị thanh tiến trình của nội dung được phát một phần trong khung hiển thị duyệt qua. Tuy nhiên, nếu người dùng tiếp tục phát nội dung đã phát một phần, thì chỉ báo đó sẽ trở nên không chính xác theo thời gian.

Để Android Auto và AAOS luôn cập nhật thanh tiến trình, hãy cung cấp thêm thông tin trong MediaMetadataCompatPlaybackStateCompat để liên kết nội dung hiện tại với các mục nội dung đa phương tiện trong khung hiển thị duyệt qua.

Để một mục nội dung đa phương tiện có thanh tiến trình cập nhật tự động, bạn phải đáp ứng các yêu cầu sau:

Đoạn mã này cho biết cách cho biết rằng mục đang phát được liên kết với một mục trong khung hiển thị duyệt qua:

Kotlin

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());

P Ngay cả nội dung chưa phát hoặc đã phát toàn bộ cũng có thể hiển thị thanh tiến trình tự động cập nhật. Điều này xảy ra nếu các mục nội dung nghe nhìn tương ứng chứa dữ liệu bổ sung DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE có giá trị 0.0 (đối với nội dung chưa phát) hoặc 1.0 (đối với nội dung đã phát toàn bộ). Sau khi người dùng chọn các mục nội dung đa phương tiện này, Android Auto và AAOS sẽ hiển thị thanh tiến trình thay vì các chỉ báo tiến trình khác.