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

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

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

الشكل 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 ونظام التشغيل Android Automotive ‏(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 شريط التقدّم فوق مؤشرات التقدّم الأخرى.