การตอบสนองต่อปุ่มสื่อ

ปุ่มสื่อเป็นปุ่มฮาร์ดแวร์ที่พบในอุปกรณ์ Android และอุปกรณ์ต่อพ่วงอื่นๆ เช่น ปุ่มหยุดชั่วคราว/เล่นบนชุดหูฟังบลูทูธ เมื่อผู้ใช้กดปุ่มสื่อ Android จะสร้าง KeyEvent ซึ่งมีรหัสคีย์ที่ระบุปุ่มดังกล่าว รหัสคีย์สำหรับปุ่มสื่อ KeyEvent เป็นค่าคงที่ที่ขึ้นต้นด้วย KEYCODE_MEDIA (เช่น KEYCODE_MEDIA_PLAY)

แอปควรสามารถจัดการเหตุการณ์ปุ่มสื่อได้ใน 3 กรณี โดยเรียงตามลำดับดังนี้ ลำดับความสำคัญ:

  • เมื่อกิจกรรม UI ของแอปปรากฏ
  • เมื่อกิจกรรม UI ซ่อนอยู่และเซสชันสื่อของแอปทำงานอยู่
  • เมื่อกิจกรรม UI ซ่อนอยู่และเซสชันสื่อของแอปไม่มีการใช้งานและต้องรีสตาร์ท

การจัดการปุ่มสื่อในกิจกรรมที่ทำงานอยู่เบื้องหน้า

กิจกรรมเบื้องหน้าได้รับเหตุการณ์สำคัญของปุ่มสื่อในonKeyDown() มี 2 วิธีในการกำหนดเส้นทางเหตุการณ์ ทั้งนี้ขึ้นอยู่กับเวอร์ชัน 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 คุณสามารถค้นหาเซสชันสื่อได้ 2 วิธีดังนี้

  • หากคุณใช้ Android 8.0 (API ระดับ 26) ขึ้นไป ระบบจะพยายาม หาแอปล่าสุดที่มี MediaSession ที่เล่นเสียงในเครื่อง หากเซสชัน ยังคงใช้งานอยู่ Android จะส่งเหตุการณ์ไปยังเหตุการณ์โดยตรง มิเช่นนั้น หาก เซสชันไม่ได้ใช้งานอยู่และมีตัวรับปุ่มสื่อ Android จะส่งเหตุการณ์ ให้กับผู้รับ ซึ่งจะเริ่มต้นเซสชันใหม่และรับเหตุการณ์ได้ (โปรดดูรายละเอียดที่หัวข้อการใช้ปุ่มสื่อเพื่อเริ่มเซสชันสื่อที่ไม่ได้ใช้งานใหม่) หากเซสชันไม่มีตัวรับปุ่มสื่อ ระบบจะทิ้งสื่อนั้น เหตุการณ์ของปุ่มและจะไม่มีอะไรเกิดขึ้น ตรรกะจะแสดงในข้อมูลต่อไปนี้ แผนภาพ:

  • เวอร์ชันก่อนหน้า Android 8.0 (API ระดับ 26) ระบบจะพยายามส่งเหตุการณ์ไปยัง เซสชันสื่อที่ใช้งานอยู่ หากมีเซสชันสื่อที่ใช้งานอยู่หลายเซสชัน Android จะพยายาม เพื่อเลือกเซสชันสื่อที่กำลังเตรียมเล่น (บัฟเฟอร์/เชื่อมต่อ) วิดีโอหยุดเล่น หรือหยุดชั่วคราว มากกว่าวิดีโอที่หยุดเล่น (โปรดดู การจัดการปุ่มสื่อในเซสชันสื่อที่ใช้งานอยู่ เพื่อดูรายละเอียดเพิ่มเติม) หากไม่มีรายการที่ใช้งานอยู่ เซสชัน Android จะพยายามส่งเหตุการณ์ไปยังเซสชันที่ใช้งานล่าสุด (โปรดดูรายละเอียดที่หัวข้อการใช้ปุ่มสื่อเพื่อเริ่มเซสชันสื่อที่ไม่ได้ใช้งานใหม่) ตรรกะจะแสดงในแผนภาพต่อไปนี้

การจัดการปุ่มสื่อในเซสชันสื่อที่ใช้งานอยู่

ใน Android 5.0 (API ระดับ 21) ขึ้นไป Android จะส่งเหตุการณ์ของปุ่มสื่อไปยังเซสชันสื่อที่ใช้งานอยู่โดยอัตโนมัติด้วยการเรียกใช้ onMediaButtonEvent() โดยค่าเริ่มต้น Callback นี้จะแปล KeyEvent เป็นเมธอด Callback ของเซสชันสื่อที่เหมาะสมซึ่งตรงกับโค้ดคีย์

เวอร์ชันก่อนหน้า Android 5.0 (API ระดับ 21) Android จัดการเหตุการณ์ปุ่มสื่อด้วยการประกาศความตั้งใจ ด้วยการดำเนินการ ACTION_MEDIA_BUTTON แอปของคุณต้องลงทะเบียน BroadcastReceiver เพื่อสกัดกั้นความตั้งใจเหล่านี้ MediaButtonReceiver ได้รับการออกแบบมาสำหรับ วัตถุประสงค์นี้ ซึ่งเป็นคลาสอำนวยความสะดวกใน Android ไลบรารีที่ทำงานร่วมกับสื่อนั้น จัดการ ACTION_MEDIA_BUTTON และแปลง Intent ที่เข้ามาใหม่เป็น ในการเรียกเมธอด MediaSessionCompat.Callback ที่เหมาะสม

MediaButtonReceiver เป็น BroadcastReceiver ที่มีอายุสั้น ส่งต่อขาเข้า บริการที่จัดการเซสชันสื่อของคุณ หากต้องการใช้ ปุ่มสื่อในระบบที่เก่ากว่า Android 5.0 คุณต้องมี MediaButtonReceiver ในไฟล์ Manifest ที่มีตัวกรอง 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 ส่งต่อ Intent ไปยังบริการของคุณ วิธีแยกวิเคราะห์ความตั้งใจ และสร้างการติดต่อกลับไปยังเซสชันสื่อของคุณ ให้รวมเมธอด 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 ไปยังคอมโพเนนต์ที่ลงทะเบียนไฟล์ Manifest (เช่น บริการหรือ BroadcastReceiver)

ซึ่งจะช่วยให้แอปรีสตาร์ทการเล่นโดยที่ UI ไม่ปรากฏ ซึ่งมักเป็นกรณีที่แอปเสียงส่วนใหญ่

ระบบจะเปิดใช้ลักษณะการทำงานนี้โดยอัตโนมัติเมื่อคุณใช้ MediaSessionCompat หากคุณ ใช้ MediaSession ของเฟรมเวิร์ก Android หรือ Support Library 24.0.0 ถึง 25.1.1 คุณต้องเรียกใช้ setMediaButtonReceiver เพื่อให้ปุ่มสื่อรีสตาร์ท เซสชันสื่อที่ไม่ได้ใช้งาน

คุณสามารถปิดลักษณะการทำงานนี้ใน Android 5.0 (API ระดับ 21) ขึ้นไปได้โดย การตั้งค่าตัวรับปุ่มสื่อ Null

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() จาก Callback onConnected() ของตัวควบคุมสื่อ
  • หากต้องการอนุญาตให้ปุ่มสื่อเริ่มเซสชันที่ไม่ได้ใช้งานอีกครั้ง ให้สร้าง MediaButtonReceiver แบบไดนามิกด้วยการเรียกใช้ setMediaButtonReceiver() และส่งต่อ PendingIntent

เมื่อทำงานในระบบที่เก่ากว่า Android 5.0:

  • ลบล้าง onKeyDown() ของกิจกรรมเพื่อจัดการปุ่มสื่อ
  • สร้าง MediaButtonReceiver แบบคงที่โดยเพิ่มลงในไฟล์ Manifest ของแอป