تطبيق أنماط المحتوى

بعد استخدام العناصر القابلة للتصفّح أو التشغيل لإنشاء التسلسل الهرمي للمحتوى، طبِّق أنماط المحتوى لتحديد طريقة عرض هذه العناصر في السيارة. استخدِم أنماط المحتوى التالية:

عناصر القائمة

الشكل 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: العناصر المطابقة المعروضة كعناصر شبكة "الفئة" تشبه عناصر الشبكة العادية، ولكن يتم تطبيق هوامش حول رموز العناصر. يؤدي ذلك إلى تحسين مظهر الرموز الصغيرة. يجب أن تكون الرموز رسومات متجهة قابلة للتلوين. من المتوقّع أن يتم تقديم هذه التلميحة للعناصر القابلة للتصفّح فقط.

تعرض مقتطفة الرمز البرمجي هذه كيفية ضبط نمط المحتوى التلقائي للعناصر القابلة للتصفح على شكل شبكات والعناصر القابلة للتشغيل على شكل قوائم:

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

ضبط أنماط المحتوى لكل عنصر

يمكنك تجاهل نمط المحتوى التلقائي لأي عنصر وسائط قابل للتصفّح من العناصر التابعة له، وكذلك لأي عنصر وسائط. لتجاوز الإعداد التلقائي الخاص بالعناصر التابعة لعنصر وسائط قابل للتصفّح، أنشئ حزمة إضافات في MediaDescription لعنصر الوسائط وأضِف التلميحات نفسها المذكورة سابقًا:

  • ينطبق DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE على العناصر التابعة القابلة للتشغيل لهذا العنصر.

  • ينطبق DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE على العناصر الفرعية القابلة للتصفّح لهذا العنصر.

لتجاوز الإعداد التلقائي لعنصر وسائط معيّن (وليس العناصر التابعة له)، أنشئ حزمة إضافات في MediaDescription لعنصر الوسائط. بعد ذلك، أضِف تلميحًا باستخدام المفتاح DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM. استخدِم القيم نفسها الموضّحة سابقًا لتحديد طريقة عرض السلعة.

تعرض مقتطفة الرمز هذه كيفية إنشاء MediaItem يمكن تصفّحه يتجاوز نمط المحتوى التلقائي لنفسه وللعناصر التابعة له. يتم تنسيقه كعنصر في قائمة فئات، ويتم تنسيق العناصر التابعة التي يمكن تصفّحها كعناصر في قائمة، ويتم تنسيق العناصر التابعة التي يمكن تشغيلها كعناصر في شبكة.

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

تجميع العناصر باستخدام تلميحات العناوين

لتجميع عناصر الوسائط ذات الصلة، استخدِم تلميحًا لكل عنصر. يجب أن يتضمّن كل عنصر وسائط في المجموعة حِزمة إضافات في MediaDescription. يجب أن تتضمّن هذه الحزمة عملية ربط بالمفتاح DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE وقيمة سلسلة مطابقة. يجب توفير نسخة مترجَمة من هذه السلسلة لأنّها تُستخدَم كعنوان للمجموعة.

يوضّح مقتطف الرمز هذا كيفية إنشاء MediaItem مع عنوان مجموعة فرعية 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*/);
}

يجب أن يمرِّر تطبيقك جميع عناصر الوسائط التي تريد تجميعها معًا ككتلة متجاورة. على سبيل المثال، لنفترض أنّك تريد عرض مجموعتَين من عناصر الوسائط، "الأغاني" و "الألبومات"، بهذا الترتيب. إذا كان تطبيقك يمرّر خمسة عناصر وسائط بهذا الترتيب، سيفسّرها 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، المسماة "الأغاني"، والتي تحتوي على وسائط العنصر A
  • المجموعة 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: تشير إلى حالة تنزيل أحد العناصر. استخدِم هذه القيمة الثابتة كمفتاح. في ما يلي القيم المحتمَلة لهذه الثوابت الطويلة:

  • METADATA_KEY_IS_EXPLICIT: يشير إلى أنّ السلعة تتضمّن محتوًى فاضحًا. للإشارة إلى أنّ السلعة تتضمّن محتوًى فاضحًا، استخدِم هذا الثابت كمفتاح والقيمة الطويلة METADATA_VALUE_ATTRIBUTE_PRESENT.

لا يمكن استخدام هذه الثوابت إلا في إضافات أوصاف MediaItem:

لعرض المؤشرات التي تظهر أثناء تصفّح المستخدم لشجرة تصفّح الوسائط، أنشئ حزمة إضافات تتضمّن واحدًا أو أكثر من هذه الثوابت. بعد ذلك، مرِّر هذه الحزمة إلى الطريقة MediaDescription.Builder.setExtras.

تعرض هذه المقتطفة كيفية عرض مؤشرات لعنصر وسائط فاضح تم إكماله بنسبة% 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 */);

لعرض مؤشرات لعنصر وسائط يتم تشغيله حاليًا، حدِّد قيمًا لـ METADATA_KEY_IS_EXPLICIT أو EXTRA_DOWNLOAD_STATUS في MediaMetadataCompat ضمن mediaSession.

يوضّح مقتطف الرمز البرمجي التالي كيفية الإشارة إلى أنّ الأغنية المعروضة في طريقة عرض التشغيل هي أغنية تتضمّن محتوًى فاضحًا وتم تنزيلها:

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

تعديل شريط التقدّم في طريقة العرض "تصفّح" أثناء تشغيل المحتوى

كما ذكرنا سابقًا، يمكنك استخدام الإضافة DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE لعرض شريط تقدّم للمحتوى الذي تم تشغيله جزئيًا في عرض التصفّح. ومع ذلك، إذا واصل المستخدم تشغيل المحتوى الذي تم تشغيله جزئيًا، سيصبح هذا المؤشر غير دقيق بمرور الوقت.

لكي يبقي Android Auto وAAOS شريط التقدّم محدّثًا، يجب توفير معلومات إضافية في MediaMetadataCompat وPlaybackStateCompat لربط المحتوى الجاري تشغيله بعناصر الوسائط في عرض التصفّح.

لكي يظهر شريط تقدّم يتم تعديله تلقائيًا في عنصر وسائط، يجب استيفاء المتطلبات التالية:

يوضّح مقتطف الرمز البرمجي هذا كيفية الإشارة إلى أنّ العنصر الذي يتم تشغيله مرتبط بعنصر في عرض التصفّح:

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 حتى المحتوى الذي لم يتم تشغيله أو الذي تم تشغيله بالكامل يمكن أن يعرض شريط تقدم يتم تعديله تلقائيًا. يحدث ذلك إذا كانت عناصر الوسائط المقابلة تتضمّن الإضافة DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE بالقيمة 0.0 (للمحتوى الذي لم يتم تشغيله) أو 1.0 (للمحتوى الذي تم تشغيله بالكامل). بعد أن يختار المستخدم عناصر الوسائط هذه، يعرض كل من Android Auto وAAOS شريط التقدم فوق مؤشرات التقدم الأخرى.