תגובות ללחצני מדיה

לחצני מדיה הם לחצני חומרה שקיימים במכשירי Android ובציוד היקפי אחר. למשל, לחצן ההשהיה/הפעלה באוזניות Bluetooth. כשמשתמש לוחץ על לחצן מדיה, מערכת Android יוצרת KeyEvent, שמכיל קוד מפתח שמזהה את הלחצן. קודי המפתח של לחצני מדיה הם קבועים שמתחילים ב-KEYCODE_MEDIA (לדוגמה, KEYCODE_MEDIA_PLAY).

צריכה להיות לאפליקציות אפשרות לטפל באירועים של לחצני מדיה בשלושה מקרים, בסדר הזה של עדיפות:

  • מתי הפעילות של ממשק המשתמש של האפליקציה גלויה
  • כאשר הפעילות בממשק המשתמש מוסתרת וסשן המדיה של האפליקציה פעיל
  • כשהפעילות בממשק המשתמש מוסתרת וסשן המדיה של האפליקציה לא פעיל וצריך להפעיל אותו מחדש

טיפול בלחצני מדיה בפעילות בחזית

הפעילות בחזית מקבלת את האירוע המרכזי של לחצן המדיה ב-onKeyDown() שלה . בהתאם לגרסה שפועלת של Android, יש שתי דרכים שבהן המערכת מנתבת את האירוע אל בקר מדיה:

  • אם במכשיר פועלת מערכת Android בגרסה 5.0 (רמת API 21) ואילך, יש להתקשר FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected. הפעולה הזו תגרור תיקרא באופן אוטומטי dispatchMediaButtonEvent(), שמתרגם את קוד המפתח לקריאה חוזרת (callback) בסשן מדיה.
  • לפני Android 5.0 (רמת API 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 (רמת API 26) ואילך, המערכת תנסה מוצאים את האפליקציה האחרונה באמצעות MediaSession שהופעלה אודיו באופן מקומי. אם הסשן עדיין פעיל, מערכת Android שולחת את האירוע ישירות אליו. אחרת, אם הסשן לא פעיל ויש בו מקלט מדיה, מערכת Android שולחת את האירוע של המקבל, שיפעיל מחדש את הסשן כדי שהוא יוכל לקבל את האירוע. (פרטים נוספים זמינים במאמר שימוש בלחצני מדיה כדי להפעיל מחדש סשן מדיה לא פעיל). אם אין בסשן מקלט של לחצני מדיה, המערכת מוחקת את המדיה אירוע של לחצן ושום דבר לא יקרה. הלוגיקה הזו מוצגת דיאגרמה:

  • לפני Android 8.0 (רמת API 26), המערכת תנסה לשלוח את האירוע סשן מדיה פעיל. אם יש כמה סשנים פעילים של מדיה, מערכת Android תנסה כדי לבחור סשן מדיה שמתכונן להפעלה (אגירת נתונים/התחברות), שמופעלת או מושהית, במקום להשתמש בסרטון שנעצר. (ראו טיפול בלחצני מדיה בסשן מדיה פעיל לקבלת פרטים נוספים). אם אין אף גרסה פעילה סשן, מערכת Android תנסה לשלוח את האירוע לסשן האחרון שהיה פעיל. (פרטים נוספים זמינים במאמר שימוש בלחצני מדיה כדי להפעיל מחדש סשן מדיה לא פעיל). הלוגיקה מוצגת בתרשים הבא:

טיפול בלחצני מדיה בסשן מדיה פעיל

ב-Android מגרסה 5.0 (רמת API 21) ואילך, מערכת Android שולחת אירועים של לחצני מדיה באופן אוטומטי לסשן המדיה הפעיל שלך, באמצעות התקשרות onMediaButtonEvent() כברירת מחדל, הקריאה החוזרת (callback) הזו מתרגמת את KeyEvent לשיטת הקריאה החוזרת של הסשן במדיה המתאימה שתואמת לקוד המפתח.

לפני Android 5.0 (רמת API 21), Android מטפל באירועים של לחצני מדיה על ידי שידור כוונה עם הפעולה ACTION_MEDIA_BUTTON. האפליקציה שלך צריכה לרשום BroadcastReceiver במטרה ליירט את הכוונות האלה. MediaButtonReceiver תוכנן במיוחד למטרה הזאת. זהו רמת נוחות ב-Android תואם למדיה מטפל ב-ACTION_MEDIA_BUTTON ומתרגם את ה-Intents הנכנסים קריאות מתאימות של שיטת MediaSessionCompat.Callback.

MediaButtonReceiver הוא שירות BroadcastReceiver לטווח קצר. היא מעבירה הודעות נכנסות כוונות לשירות שמנהל את סשן המדיה שלכם. אם רוצים להשתמש לחצני מדיה במערכות שקודמות ל-Android 5.0, חובה לכלול את ה-MediaButtonReceiver במניפסט עם מסנן Intent מסוג 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() של השירות. הפעולה הזו מתרגמת את קוד המפתח לשיטת הקריאה החוזרת (callback) המתאימה לסשן.

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 מזהה את סשן המדיה הפעיל האחרון, היא מנסה להתחיל מחדש את הסשן על ידי שליחת Intent מסוג ACTION_MEDIA_BUTTON לרכיב שרשום במניפסט (כמו שירות או BroadcastReceiver).

כך האפליקציה יכולה להפעיל מחדש את ההפעלה כשממשק המשתמש שלה לא גלוי. המצב הזה קורה ברוב אפליקציות האודיו.

ההתנהגות הזו מופעלת באופן אוטומטי כשמשתמשים ב-MediaSessionCompat. אם להשתמש ב-MediaSession של מסגרת Android או בספריית התמיכה בגרסה 24.0.0 עד 25.1.1 צריך להתקשר ל-setMediaButtonReceiver כדי לאפשר ללחצן מדיה להפעיל מחדש סשן מדיה לא פעיל.

ניתן להשבית את ההתנהגות הזו ב-Android 5.0 (רמת API 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);

התאמה אישית של רכיבי ה-handler של לחצני המדיה

פעולת ברירת המחדל של 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 על ידי הוספתו למניפסט של האפליקציה