الاستجابة لأزرار الوسائط

أزرار الوسائط هي أزرار الأجهزة التي توجد على أجهزة Android والأجهزة الملحقة الأخرى، على سبيل المثال، زر الإيقاف المؤقت/التشغيل في سماعة رأس بلوتوث. عندما يضغط المستخدم على زر وسائط، ينشئ Android رمز KeyEvent الذي يحتوي على رمز مفتاح يتعرَّف على الزر. الرموز الرئيسية لزر الوسائط الأحداث الرئيسية هي ثوابت تبدأ بـ KEYCODE_MEDIA (على سبيل المثال، KEYCODE_MEDIA_PLAY).

يجب أن تتمكن التطبيقات من التعامل مع أحداث أزرار الوسائط في ثلاث حالات، وفقًا لترتيب الأولوية التالي:

  • عندما يكون نشاط واجهة المستخدم للتطبيق مرئيًا
  • عندما يكون نشاط واجهة المستخدم مخفيًا وتكون جلسة وسائط التطبيق نشطة
  • عندما يكون نشاط واجهة المستخدم مخفيًا وتكون جلسة الوسائط في التطبيق غير نشطة ويجب إعادة تشغيلها

التعامل مع أزرار الوسائط في نشاط في المقدّمة

يتلقّى النشاط الذي يعمل في المقدّمة الحدث الرئيسي لزر الوسائط بطريقة onKeyDown(). اعتمادًا على إصدار Android قيد التشغيل، هناك طريقتان يوجِّه النظام من خلالهما الحدث إلى وحدة تحكُّم الوسائط:

  • إذا كان جهازك يعمل بالإصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) أو إصدار أحدث، يُرجى طلب الرمز FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected. وسيؤدي هذا تلقائيًا إلى استدعاء الإجراء dispatchMediaButtonEvent() الخاص بوحدة التحكّم في الوسائط، ما يحوّل رمز المفتاح إلى استدعاء جلسة وسائط.
  • قبل إصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، عليك تعديل onKeyDown() لمعالجة الحدث بنفسك. (راجع التعامل مع أزرار الوسائط في جلسة وسائط نشطة للحصول على التفاصيل). يعرض مقتطف الرمز التالي كيفية اعتراض رمز المفتاح واستدعاء dispatchMediaButtonEvent(). احرص على عرض true للإشارة إلى أن الحدث قد تمت معالجته:

    Kotlin

        fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                return super.onKeyDown(keyCode, event)
            }
            when (keyCode) {
                KeyEvent.KEYCODE_MEDIA_PLAY -> {
                    yourMediaController.dispatchMediaButtonEvent(event)
                    return true
                }
            }
            return super.onKeyDown(keyCode, event)
        }
        

    Java

        @Override
        boolean onKeyDown(int keyCode, KeyEvent event) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                  return super.onKeyDown(keyCode, event);
                }
                switch (keyCode) {
                  case KeyEvent.KEYCODE_MEDIA_PLAY:
                          yourMediaController.dispatchMediaButtonEvent(event);
                          return true;
                }
                return super.onKeyDown(keyCode, event);
        }
        

العثور على جلسة وسائط

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

  • إذا كان جهازك يعمل بالإصدار Android 8.0 (المستوى 26 لواجهة برمجة التطبيقات) أو إصدار أحدث، سيحاول النظام العثور على آخر تطبيق يتضمّن جلسة MediaSession شغّلت الصوت محليًا. إذا كانت الجلسة لا تزال نشطة، فسيرسل Android الحدث إليها مباشرةً. بخلاف ذلك، إذا كانت الجلسة غير نشطة وتضم جهاز استقبال زر الوسائط، يرسل Android الحدث إلى المُستلِم، ويعيد تشغيل الجلسة وبالتالي يمكنه تلقّي الحدث. (راجع استخدام أزرار الوسائط لإعادة تشغيل جلسة وسائط غير نشطة للحصول على التفاصيل.) إذا لم تكن الجلسة تحتوي على جهاز استقبال لزر الوسائط، فسيتجاهل النظام حدث زر الوسائط ولن يحدث شيء. يظهر المنطق في المخطط التالي:

  • قبل الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، يحاول النظام إرسال الحدث إلى جلسة وسائط نشطة. إذا كانت هناك عدة جلسات وسائط نشطة، سيحاول Android اختيار جلسة وسائط يتم إعدادها للتشغيل (جارٍ التخزين المؤقت/الاتصال) أو قيد التشغيل أو متوقّفة مؤقتًا، بدلاً من الجلسة المتوقفة. (راجِع التعامل مع أزرار الوسائط في جلسة وسائط نشطة للحصول على مزيد من التفاصيل.) وإذا لم تكن هناك جلسة نشطة، سيحاول Android إرسال الحدث إلى آخر جلسة نشطة. (راجع استخدام أزرار الوسائط لإعادة تشغيل جلسة وسائط غير نشطة للحصول على التفاصيل.) يظهر المنطق في الرسم التخطيطي التالي:

التعامل مع أزرار الوسائط في جلسة وسائط نشطة

في نظام التشغيل Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يرسِل Android تلقائيًا أحداث أزرار الوسائط إلى جلسة تشغيل الوسائط النشطة عن طريق الاتصال بـ onMediaButtonEvent(). تحوِّل استدعاء الاتصال هذا تلقائيًا حدث KeyEvent إلى طريقة معاودة الاتصال المناسبة لجلسة الوسائط والتي تتطابق مع رمز المفتاح.

قبل إصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، يعالج Android أحداث أزرار الوسائط من خلال بث هدف باستخدام الإجراء ACTION_MEDIA_BUTTON. يجب أن يسجّل التطبيق جهاز BroadcastReceivedr لاعتراض هذه الأهداف. وقد تم تصميم الفئة MediaButtonReceiver خصيصًا لهذا الغرض. وهي فئة ملائمة في مكتبة Media-compat على Android وتعالج ACTION_MEDIA_BUTTON وتترجم الأهداف الواردة إلى استدعاءات طريقة MediaSessionCompat.Callback المناسبة.

جهاز MediaButtonReceiver هو جهاز استقبال بث قصير الأجل. وهي تعيد توجيه النوايا الواردة إلى الخدمة التي تدير جلسة تشغيل الوسائط. إذا أردت استخدام أزرار الوسائط في الأنظمة التي تعمل بالإصدارات الأقدم من Android 5.0، يجب تضمين MediaButtonReceiver في البيان مع فلتر أهداف MEDIA_BUTTON.:

<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
   <intent-filter>
     <action android:name="android.intent.action.MEDIA_BUTTON" />
   </intent-filter>
 </receiver>

تعيد BroadcastReceiver توجيه عملية الشراء إلى خدمتك. لتحليل الغرض وإنشاء معاودة الاتصال لجلسة تشغيل الوسائط، يمكنك تضمين طريقة MediaButtonReceiver.handleIntent() في onStartCommand() الخاصة بخدمتك. ويؤدي هذا إلى ترجمة رمز المفتاح إلى طريقة معاودة الاتصال المناسبة للجلسة.

Kotlin

private val mediaSessionCompat: MediaSessionCompat = ...

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    MediaButtonReceiver.handleIntent(mediaSessionCompat, intent)
    return super.onStartCommand(intent, flags, startId)
}

Java

private MediaSessionCompat mediaSessionCompat = ...;

 public int onStartCommand(Intent intent, int flags, int startId) {
   MediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
   return super.onStartCommand(intent, flags, startId);
 }

استخدام أزرار الوسائط لإعادة تشغيل جلسة وسائط غير نشطة

إذا تمكّن نظام Android من التعرّف على آخر جلسة وسائط نشطة، يحاول إعادة تشغيل الجلسة من خلال إرسال ACTION_MEDIA_BUTTON Intent إلى مكوِّن مسجَّل في البيان (مثل خدمة أو BroadcastReceiver).

يتيح هذا لتطبيقك إعادة تشغيل التشغيل عندما تكون واجهة المستخدم غير مرئية، وهذا ما يحدث في معظم التطبيقات الصوتية.

ويتم تفعيل هذا السلوك تلقائيًا عند استخدام MediaSessionCompat. إذا كنت تستخدم الإصدار MediaSession من إطار عمل Android أو الإصدار 24.0.0 وحتى 25.1.1 من إطار عمل Android، عليك استدعاء setMediaButtonReceiver للسماح لزر الوسائط بإعادة تشغيل جلسة وسائط غير نشطة.

يمكنك إيقاف هذا السلوك في نظام التشغيل Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث من خلال ضبط جهاز استقبال زر وسائط فارغ:

Kotlin

// Create a MediaSessionCompat
mediaSession = MediaSessionCompat(context, LOG_TAG)
mediaSession.setMediaButtonReceiver(null)

Java

// Create a MediaSessionCompat
mediaSession = new MediaSessionCompat(context, LOG_TAG);
mediaSession.setMediaButtonReceiver(null);

تخصيص معالِجات أزرار الوسائط

يعمل السلوك التلقائي لـ onMediaButtonEvent() على استخراج رمز المفتاح واستخدام الحالة الحالية لجلسة الوسائط وقائمة الإجراءات المتوافقة لتحديد طريقة الاتصال. على سبيل المثال، يستدعي KEYCODE_MEDIA_PLAY السمة onPlay().

لتوفير تجربة زر وسائط متسقة في جميع التطبيقات، عليك استخدام السلوك التلقائي والانحراف لغرض محدّد فقط. إذا كان زر الوسائط بحاجة إلى معالجة مخصصة، يمكنك إلغاء طريقة onMediaButtonEvent() رد الاتصال، واستخراج KeyEvent باستخدام intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)، ومعالجة الحدث بنفسك، وعرض true.

ملخّص

للتعامل بشكل سليم مع أحداث زر الوسائط في جميع إصدارات Android، يجب تحديد FLAG_HANDLES_MEDIA_BUTTONS عند إنشاء جلسة وسائط.

بالإضافة إلى ذلك، ووفقًا لإصدارات Android التي تريد دعمها، يجب عليك أيضًا تلبية المتطلبات التالية:

عند استخدام الإصدار Android 5.0 أو إصدار أحدث:

  • الاتصال بـ "MediaControllerCompat.setMediaController()" من وحدة التحكّم في الوسائط onConnected() معاودة الاتصال
  • للسماح لزر وسائط بإعادة تشغيل جلسة غير نشطة، أنشئ MediaButtonReceiver ديناميكيًا من خلال استدعاء setMediaButtonReceiver() وتمريره PendingIntent

عند تشغيل الجهاز في أنظمة أقدم من الإصدار Android 5.0:

  • يمكنك إلغاء onKeyDown() في النشاط لمعالجة أزرار الوسائط.
  • إنشاء MediaButtonReceiver بشكل ثابت من خلال إضافته إلى بيان التطبيق