تقع عناصر التحكم في الوسائط في Android بالقرب من "الإعدادات السريعة". ويتم ترتيب الجلسات من تطبيقات متعددة في لوحة عرض دوّارة قابلة للتمرير السريع. تسرد لوحة العرض الدوّارة الجلسات بهذا الترتيب:
- عمليات البث التي يتم تشغيلها محليًا على الهاتف
- أحداث البث عن بُعد، مثل البث الذي يتم رصده على أجهزة خارجية أو جلسات البث
- الجلسات السابقة القابلة للاستئناف، بالترتيب لآخر مرة تم تشغيلها بها
بدءًا من نظام التشغيل Android 13 (المستوى 33 لواجهة برمجة التطبيقات)، لضمان إمكانية وصول المستخدمين إلى
مجموعة غنية من عناصر التحكّم في الوسائط للتطبيقات التي تشغّل الوسائط، يتم اشتقاق أزرار الإجراءات على عناصر التحكّم في الوسائط من حالة Player
.
وبهذه الطريقة، يمكنك تقديم مجموعة متسقة من عناصر التحكم في الوسائط وتجربة تحكم أكثر سلاسة في الوسائط عبر الأجهزة.
يوضح الشكل 1 مثالاً على كيف يبدو هذا على هاتف وجهاز لوحي، على التوالي.
يعرض النظام ما يصل إلى خمسة أزرار إجراءات استنادًا إلى حالة Player
كما هو موضّح في الجدول التالي. في الوضع المكثّف، يتم عرض أول
ثلاث شرائح إجراءات فقط. ويتوافق هذا مع طريقة عرض عناصر التحكّم في الوسائط على منصات Android الأخرى، مثل Auto و"مساعد Google" وWear OS.
الشريحة الإعلانية | المعايير | الإجراء |
---|---|---|
1 |
السمة playWhenReady
خاطئة أو حالة
التشغيل الحالية هي STATE_ENDED .
|
تشغيل |
قيمة playWhenReady صحيحة وحالة التشغيل الحالية هي STATE_BUFFERING .
|
مؤشر سريان العمل | |
قيمة playWhenReady صحيحة وحالة التشغيل الحالية هي STATE_READY . |
إيقاف مؤقت | |
2 | يتوفّر أمر المشغّل COMMAND_SEEK_TO_PREVIOUS أو COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM . |
الصفحة السابقة |
لا يتوفّر أمر المشغّل COMMAND_SEEK_TO_PREVIOUS أو COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM ، كما يتوفّر أمر مخصّص من التنسيق المخصّص الذي لم يتم وضعه بعد لملء الخانة. |
قرض مخصص | |
(غير متوافقة بعد مع Media3) PlaybackState العناصر الإضافية تشمل قيمة منطقية true للمفتاح EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_PREV . |
ما مِن لاعبين | |
3 | يتوفّر أمر المشغّل COMMAND_SEEK_TO_NEXT أو COMMAND_SEEK_TO_NEXT_MEDIA_ITEM . |
التالي |
لا يتوفّر أمر المشغّل COMMAND_SEEK_TO_NEXT أو COMMAND_SEEK_TO_NEXT_MEDIA_ITEM ، كما يتوفّر أمر مخصّص من التنسيق المخصّص الذي لم يتم وضعه بعد لملء الخانة. |
قرض مخصص | |
(غير متوافقة بعد مع Media3) PlaybackState العناصر الإضافية تشمل قيمة منطقية true للمفتاح EXTRAS_KEY_SLOT_RESERVATION_SEEK_TO_NEXT . |
ما مِن لاعبين | |
4 | يتوفّر أمر مخصّص من التنسيق المخصّص الذي لم يتم وضعه بعد لملء الخانة. | قرض مخصص |
5 | يتوفّر أمر مخصّص من التنسيق المخصّص الذي لم يتم وضعه بعد لملء الخانة. | قرض مخصص |
يتم وضع الأوامر المخصصة بترتيب إضافتها إلى التنسيق المخصص.
تخصيص أزرار الأوامر
لتخصيص عناصر التحكّم في وسائط النظام باستخدام Jetpack Media3،
يمكنك ضبط التنسيق المخصّص للجلسة والأوامر المتاحة
لعناصر التحكّم وفقًا لذلك، عند تنفيذ MediaSessionService
:
في
onCreate()
، أنشِئMediaSession
وحدِّد التنسيق المخصَّص لأزرار الأوامر.في
MediaSession.Callback.onConnect()
، يمكنك تفويض وحدات التحكّم من خلال تحديد الأوامر المتاحة لها، بما في ذلك الأوامر المخصَّصة، فيConnectionResult
.في
MediaSession.Callback.onCustomCommand()
، استجِب للأمر المخصّص الذي اختاره المستخدم.
Kotlin
class PlaybackService : MediaSessionService() { private val customCommandFavorites = SessionCommand(ACTION_FAVORITES, Bundle.EMPTY) private var mediaSession: MediaSession? = null override fun onCreate() { super.onCreate() val favoriteButton = CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(customCommandFavorites) .build() val player = ExoPlayer.Builder(this).build() // Build the session with a custom layout. mediaSession = MediaSession.Builder(this, player) .setCallback(MyCallback()) .setCustomLayout(ImmutableList.of(favoriteButton)) .build() } private inner class MyCallback : MediaSession.Callback { override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { // Set available player and session commands. return AcceptedResultBuilder(session) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build() ) .setAvailableSessionCommands( ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(customCommandFavorites) .build() ) .build() } override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture{ if (customCommand.customAction == ACTION_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) } return super.onCustomCommand(session, controller, customCommand, args) } } }
Java
public class PlaybackService extends MediaSessionService { private static final SessionCommand CUSTOM_COMMAND_FAVORITES = new SessionCommand("ACTION_FAVORITES", Bundle.EMPTY); @Nullable private MediaSession mediaSession; public void onCreate() { super.onCreate(); CommandButton favoriteButton = new CommandButton.Builder() .setDisplayName("Save to favorites") .setIconResId(R.drawable.favorite_icon) .setSessionCommand(CUSTOM_COMMAND_FAVORITES) .build(); Player player = new ExoPlayer.Builder(this).build(); // Build the session with a custom layout. mediaSession = new MediaSession.Builder(this, player) .setCallback(new MyCallback()) .setCustomLayout(ImmutableList.of(favoriteButton)) .build(); } private static class MyCallback implements MediaSession.Callback { @Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { // Set available player and session commands. return new AcceptedResultBuilder(session) .setAvailablePlayerCommands( ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .build()) .setAvailableSessionCommands( ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(CUSTOM_COMMAND_FAVORITES) .build()) .build(); } public ListenableFutureonCustomCommand( MediaSession session, MediaSession.ControllerInfo controller, SessionCommand customCommand, Bundle args) { if (customCommand.customAction.equals(CUSTOM_COMMAND_FAVORITES.customAction)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture(new SessionResult(SessionResult.RESULT_SUCCESS)); } return MediaSession.Callback.super.onCustomCommand( session, controller, customCommand, args); } } }
للتعرّف على مزيد من المعلومات حول ضبط MediaSession
ليتمكّن العملاء مثل
النظام من الاتصال بتطبيق الوسائط، يمكنك الاطّلاع على
منح إمكانية التحكّم لبرامج أخرى.
باستخدام Jetpack Media3، عند تنفيذ MediaSession
، يتم تلقائيًا تحديث PlaybackState
باستخدام مشغّل الوسائط. وبالمثل، عند تنفيذ MediaSessionService
، تنشر المكتبة تلقائيًا إشعار MediaStyle
لك وتحرص على تحديثه بشكل مستمر.
الاستجابة لأزرار الإجراءات
عندما ينقر مستخدم على زر إجراء في عناصر التحكّم في وسائط النظام، يرسل MediaController
في النظام أمر تشغيل إلى MediaSession
. يفوّض
MediaSession
بعد ذلك هذه الأوامر وصولًا إلى المشغّل. تعالج جلسة الوسائط
الأوامر المحددة في واجهة Player
في Media3 تلقائيًا.
راجِع قسم إضافة أوامر مخصّصة للحصول على إرشادات حول كيفية الردّ على طلب مخصّص
السلوك قبل الإصدار 13 من نظام التشغيل Android
للتوافق مع الأنظمة القديمة، ستواصل واجهة مستخدم النظام توفير تنسيق بديل يستخدم إجراءات الإشعارات للتطبيقات التي لا يتم تحديثها لاستهداف الإصدار 13 من نظام التشغيل Android أو التي لا تتضمّن معلومات PlaybackState
. تنشأ أزرار الإجراءات من قائمة "Notification.Action
" المرفقة بإشعار "MediaStyle
". يعرض النظام ما يصل إلى خمسة إجراءات بالترتيب الذي تمت إضافتها به. في الوضع المكثّف، يظهر ما يصل إلى ثلاثة أزرار يتم تحديدها من خلال
القيم التي يتم تمريرها إلى setShowActionsInCompactView()
.
يتم ترتيب الإجراءات المخصّصة بترتيب إضافتها إلى
PlaybackState
.
يوضح مثال الرمز التالي كيفية إضافة إجراءات إلى إشعار نمط الوسائط :
Kotlin
import androidx.core.app.NotificationCompat import androidx.media3.session.MediaStyleNotificationHelper var notification = NotificationCompat.Builder(context, CHANNEL_ID) // Show controls on lock screen even when user hides sensitive content. .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) // Add media control buttons that invoke intents in your media service .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 // Apply the media style template .setStyle(MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build()
Java
import androidx.core.app.NotificationCompat; import androidx.media3.session.MediaStyleNotificationHelper; NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) .addAction(R.drawable.ic_next, "Next", nextPendingIntent) .setStyle(new MediaStyleNotificationHelper.MediaStyle(mediaSession) .setShowActionsInCompactView(1 /* #1: pause button */)) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();
استئناف تشغيل الوسائط
يتيح استئناف الوسائط للمستخدمين إعادة تشغيل الجلسات السابقة من لوحة العرض الدوّارة بدون الحاجة إلى بدء تشغيل التطبيق. وعند بدء التشغيل، يتفاعل المستخدم مع عناصر التحكّم في الوسائط بالطريقة المعتادة.
يمكن تشغيل ميزة استئناف التشغيل وإيقافها باستخدام تطبيق الإعدادات، ضمن خيارات الصوت > الوسائط. يمكن للمستخدم أيضًا الوصول إلى "الإعدادات" من خلال النقر على رمز الترس الذي يظهر بعد التمرير السريع على لوحة العرض الدوّارة الموسعة.
تقدّم Media3 واجهات برمجة تطبيقات لتسهيل إمكانية استئناف الوسائط. يمكنك الاطّلاع على مستندات استئناف التشغيل باستخدام Media3 للحصول على إرشادات حول تطبيق هذه الميزة.
استخدام واجهات برمجة التطبيقات القديمة للوسائط
يشرح هذا القسم كيفية الدمج مع عناصر التحكّم في وسائط النظام باستخدام واجهات برمجة تطبيقات MediaCompat القديمة.
يسترد النظام المعلومات التالية من MediaMetadata
الخاص بـ MediaSession
ويعرضها عند توفّرها:
METADATA_KEY_ALBUM_ART_URI
METADATA_KEY_TITLE
METADATA_KEY_DISPLAY_TITLE
METADATA_KEY_ARTIST
METADATA_KEY_DURATION
(إذا لم يتم ضبط المدة، لا يعرض شريط البحث مستوى التقدّم)
لضمان تلقّي إشعار صالح ودقيق للتحكّم في الوسائط،
اضبط قيمة البيانات الوصفية METADATA_KEY_TITLE
أو METADATA_KEY_DISPLAY_TITLE
على عنوان الوسائط التي يتم تشغيلها حاليًا.
ويعرض مشغّل الوسائط الوقت المنقضي للوسائط التي يتم تشغيلها حاليًا، بالإضافة إلى شريط بحث مرتبط بقيمة PlaybackState
MediaSession
.
ويعرض مشغّل الوسائط التقدم المحرز في الوسائط التي يتم تشغيلها حاليًا، بالإضافة إلى شريط بحث مرتبط بقيمة PlaybackState
في MediaSession
. يتيح شريط البحث
للمستخدمين تغيير الموضع وعرض الوقت المنقضي لعنصر الوسائط. لتفعيل شريط البحث، يجب تنفيذ PlaybackState.Builder#setActions
وتضمين ACTION_SEEK_TO
.
الشريحة الإعلانية | الإجراء | المعايير |
---|---|---|
1 | تشغيل |
الولاية الحالية من PlaybackState هي واحدة مما يلي:
|
مؤشر سريان العمل |
الحالة الحالية لـ PlaybackState هي واحدة مما يلي:
|
|
إيقاف مؤقت | حالة PlaybackState الحالية هي لا شيء مما سبق. |
|
2 | الصفحة السابقة | تشمل إجراءات PlaybackState ACTION_SKIP_TO_PREVIOUS . |
قرض مخصص | PlaybackState لا تشمل الإجراءات ACTION_SKIP_TO_PREVIOUS ، بينما تتضمّن الإجراءات المخصّصة PlaybackState إجراءً مخصّصًا لم يتم وضعه إلى الآن. |
|
ما مِن لاعبين | تتضمّن العناصر الإضافية في PlaybackState قيمة منطقية true للمفتاح SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV . |
|
3 | التالي | تشمل إجراءات PlaybackState ACTION_SKIP_TO_NEXT . |
قرض مخصص | PlaybackState لا تشمل الإجراءات ACTION_SKIP_TO_NEXT ، بينما تتضمّن الإجراءات المخصّصة PlaybackState إجراءً مخصّصًا لم يتم وضعه إلى الآن. |
|
ما مِن لاعبين | تتضمّن العناصر الإضافية في PlaybackState قيمة منطقية true للمفتاح SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT . |
|
4 | قرض مخصص | تتضمّن الإجراءات المخصّصة في PlaybackState إجراءً مخصّصًا لم يتم وضعه بعد. |
5 | قرض مخصص | تتضمّن الإجراءات المخصّصة في PlaybackState إجراءً مخصّصًا لم يتم وضعه بعد. |
إضافة إجراءات عادية
توضّح أمثلة الرموز التالية كيفية إضافة إجراءات PlaybackState
العادية والإجراءات المخصّصة.
للتشغيل والإيقاف المؤقت والسابق والتالي، اضبط هذه الإجراءات في PlaybackState
لجلسة الوسائط.
Kotlin
val session = MediaSessionCompat(context, TAG) val playbackStateBuilder = PlaybackStateCompat.Builder() val style = NotificationCompat.MediaStyle() // For this example, the media is currently paused: val state = PlaybackStateCompat.STATE_PAUSED val position = 0L val playbackSpeed = 1f playbackStateBuilder.setState(state, position, playbackSpeed) // And the user can play, skip to next or previous, and seek val stateActions = PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SEEK_TO // adding the seek action enables seeking with the seekbar playbackStateBuilder.setActions(stateActions) // ... do more setup here ... session.setPlaybackState(playbackStateBuilder.build()) style.setMediaSession(session.sessionToken) notificationBuilder.setStyle(style)
Java
MediaSessionCompat session = new MediaSessionCompat(context, TAG); PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder(); NotificationCompat.MediaStyle style = new NotificationCompat.MediaStyle(); // For this example, the media is currently paused: int state = PlaybackStateCompat.STATE_PAUSED; long position = 0L; float playbackSpeed = 1f; playbackStateBuilder.setState(state, position, playbackSpeed); // And the user can play, skip to next or previous, and seek long stateActions = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SEEK_TO; // adding this enables the seekbar thumb playbackStateBuilder.setActions(stateActions); // ... do more setup here ... session.setPlaybackState(playbackStateBuilder.build()); style.setMediaSession(session.getSessionToken()); notificationBuilder.setStyle(style);
إذا كنت لا تريد إضافة أي أزرار في الخانة السابقة أو التالية، لا تضِف
ACTION_SKIP_TO_PREVIOUS
أو ACTION_SKIP_TO_NEXT
، وبدلاً من ذلك تُضيف إضافات إلى
الجلسة:
Kotlin
session.setExtras(Bundle().apply { putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true) putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true) })
Java
Bundle extras = new Bundle(); extras.putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true); extras.putBoolean(SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true); session.setExtras(extras);
إضافة إجراءات مخصّصة
وبالنسبة إلى الإجراءات الأخرى التي تريد عرضها في عناصر التحكّم في الوسائط، يمكنك إنشاء
PlaybackStateCompat.CustomAction
وإضافته إلى PlaybackState
بدلاً من ذلك. تظهر هذه الإجراءات بترتيب
إضافتها.
Kotlin
val customAction = PlaybackStateCompat.CustomAction.Builder( "com.example.MY_CUSTOM_ACTION", // action ID "Custom Action", // title - used as content description for the button R.drawable.ic_custom_action ).build() playbackStateBuilder.addCustomAction(customAction)
Java
PlaybackStateCompat.CustomAction customAction = new PlaybackStateCompat.CustomAction.Builder( "com.example.MY_CUSTOM_ACTION", // action ID "Custom Action", // title - used as content description for the button R.drawable.ic_custom_action ).build(); playbackStateBuilder.addCustomAction(customAction);
الاستجابة لإجراءات حالة التشغيل
عندما ينقر المستخدم على زر، يستخدم SystemUI
MediaController.TransportControls
لإرسال أمر مرة أخرى إلى MediaSession
. تحتاج إلى تسجيل معاودة اتصال يمكنها الاستجابة
بشكل صحيح لهذه الأحداث.
Kotlin
val callback = object: MediaSession.Callback() { override fun onPlay() { // start playback } override fun onPause() { // pause playback } override fun onSkipToPrevious() { // skip to previous } override fun onSkipToNext() { // skip to next } override fun onSeekTo(pos: Long) { // jump to position in track } override fun onCustomAction(action: String, extras: Bundle?) { when (action) { CUSTOM_ACTION_1 -> doCustomAction1(extras) CUSTOM_ACTION_2 -> doCustomAction2(extras) else -> { Log.w(TAG, "Unknown custom action $action") } } } } session.setCallback(callback)
Java
MediaSession.Callback callback = new MediaSession.Callback() { @Override public void onPlay() { // start playback } @Override public void onPause() { // pause playback } @Override public void onSkipToPrevious() { // skip to previous } @Override public void onSkipToNext() { // skip to next } @Override public void onSeekTo(long pos) { // jump to position in track } @Override public void onCustomAction(String action, Bundle extras) { if (action.equals(CUSTOM_ACTION_1)) { doCustomAction1(extras); } else if (action.equals(CUSTOM_ACTION_2)) { doCustomAction2(extras); } else { Log.w(TAG, "Unknown custom action " + action); } } };
استئناف تشغيل الوسائط
لإظهار تطبيق المشغّل في قسم إعدادات الإعدادات السريعة،
يجب إنشاء إشعار MediaStyle
يحتوي على رمز مميّز صالح لـ MediaSession
.
لعرض عنوان إشعار MediaStyle، استخدِم
NotificationBuilder.setContentTitle()
.
لعرض رمز العلامة التجارية لمشغّل الوسائط، استخدِم
NotificationBuilder.setSmallIcon()
.
لإتاحة استئناف التشغيل، يجب أن تستخدم التطبيقات MediaBrowserService
وMediaSession
. على "MediaSession
" تنفيذ استدعاء onPlay()
.
تنفيذ "MediaBrowserService
"
بعد تشغيل الجهاز، يبحث النظام عن أحدث خمسة تطبيقات وسائط تم استخدامها، ويوفّر عناصر تحكّم يمكن استخدامها لإعادة تشغيل كل تطبيق.
يحاول النظام التواصل مع MediaBrowserService
من خلال اتصال من SystemUI. يجب أن يسمح تطبيقك بمثل هذه الاتصالات، وإلا لن يتيح
استئناف التشغيل.
يمكن تحديد الاتصالات من SystemUI والتحقّق منها باستخدام اسم الحزمة com.android.systemui
والتوقيع. يتم توقيع واجهة مستخدم النظام باستخدام
توقيع النظام الأساسي. يمكن العثور في تطبيق UAMP على مثال على طريقة التحقّق من توقيع النظام الأساسي.
لإتاحة استئناف التشغيل، يجب أن ينفّذ MediaBrowserService
السلوكَين التاليَين:
يجب أن تعرض الدالة
onGetRoot()
جذرًا غير فارغ بسرعة. يجب التعامل مع المنطق المعقد الآخر فيonLoadChildren()
عند استدعاء
onLoadChildren()
على معرّف الوسائط الجذر، يجب أن تحتوي النتيجة على عنصر FLAG_PLAYABLE ثانوي.من المفترض أن يعرض "
MediaBrowserService
" آخر عنصر وسائط تم تشغيله مؤخرًا عند تلقّي طلب بحث EXTRA_حديث. يجب أن تكون القيمة التي يتم عرضها عنصر وسائط فعليًا وليس دالة عامة.يجب أن توفّر السمة
MediaBrowserService
MediaDescription مناسب مع عنوان وترجمة غير فارغتين. يجب أيضًا ضبط معرّف الموارد المنتظم (URI) للرمز أو صورة نقطية للرمز.
توضّح أمثلة الرموز التالية كيفية تنفيذ onGetRoot()
.
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? { ... // Verify that the specified package is SystemUI. You'll need to write your // own logic to do this. if (isSystem(clientPackageName, clientUid)) { rootHints?.let { if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) { // Return a tree with a single playable media item for resumption. val extras = Bundle().apply { putBoolean(BrowserRoot.EXTRA_RECENT, true) } return BrowserRoot(MY_RECENTS_ROOT_ID, extras) } } // You can return your normal tree if the EXTRA_RECENT flag is not present. return BrowserRoot(MY_MEDIA_ROOT_ID, null) } // Return an empty tree to disallow browsing. return BrowserRoot(MY_EMPTY_ROOT_ID, null)
Java
@Override public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { ... // Verify that the specified package is SystemUI. You'll need to write your // own logic to do this. if (isSystem(clientPackageName, clientUid)) { if (rootHints != null) { if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) { // Return a tree with a single playable media item for resumption. Bundle extras = new Bundle(); extras.putBoolean(BrowserRoot.EXTRA_RECENT, true); return new BrowserRoot(MY_RECENTS_ROOT_ID, extras); } } // You can return your normal tree if the EXTRA_RECENT flag is not present. return new BrowserRoot(MY_MEDIA_ROOT_ID, null); } // Return an empty tree to disallow browsing. return new BrowserRoot(MY_EMPTY_ROOT_ID, null); }