Phản hồi các nút đa phương tiện

Nút nội dung đa phương tiện là các nút phần cứng trên thiết bị Android và các thiết bị ngoại vi khác, chẳng hạn như nút tạm dừng/phát trên tai nghe Bluetooth. Khi người dùng nhấn vào một nút nội dung nghe nhìn, Android sẽ tạo một KeyEvent chứa mã khoá xác định nút đó. Mã khoá cho nút nội dung đa phương tiện KeyEvents là các hằng số bắt đầu bằng KEYCODE_MEDIA (ví dụ: KEYCODE_MEDIA_PLAY).

Ứng dụng có thể xử lý các sự kiện nút đa phương tiện trong 3 trường hợp, theo thứ tự ưu tiên sau:

  • Khi hoạt động trên giao diện người dùng của ứng dụng hiển thị
  • Khi hoạt động trên giao diện người dùng bị ẩn và phiên phát nội dung đa phương tiện của ứng dụng đang hoạt động
  • Khi hoạt động trên giao diện người dùng bị ẩn và phiên phát nội dung đa phương tiện của ứng dụng không hoạt động và cần được khởi động lại

Xử lý các nút đa phương tiện trong một hoạt động trên nền trước

Hoạt động trên nền trước sẽ nhận được sự kiện khoá nút nội dung đa phương tiện trong phương thức onKeyDown(). Tuỳ thuộc vào phiên bản Android đang chạy, có 2 cách để hệ thống chuyển sự kiện đến trình điều khiển nội dung nghe nhìn:

  • Nếu bạn đang chạy Android 5.0 (API cấp 21) trở lên, hãy gọi FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected. Thao tác này sẽ tự động gọi dispatchMediaButtonEvent() của trình điều khiển nội dung đa phương tiện để chuyển mã khoá thành lệnh gọi lại phiên phát nội dung đa phương tiện.
  • Trước Android 5.0 (API cấp 21), bạn cần sửa đổi onKeyDown() để tự xử lý sự kiện này. (Xem bài viết Xử lý các nút đa phương tiện trong một phiên phát nội dung nghe nhìn đang hoạt động để biết thông tin chi tiết.) Đoạn mã sau đây cho biết cách chặn mã khoá và gọi dispatchMediaButtonEvent(). Hãy nhớ trả về true để cho biết sự kiện đã được xử lý:

    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);
        }
        

Tìm một phiên nội dung nghe nhìn

Nếu hoạt động trên nền trước không xử lý sự kiện đó, thì Android sẽ cố gắng tìm một phiên phát nội dung đa phương tiện có thể xử lý sự kiện đó. Xin nhắc lại, tuỳ thuộc vào phiên bản Android đang chạy, có 2 cách để tìm kiếm phiên phát nội dung đa phương tiện:

  • Nếu bạn đang chạy Android 8.0 (API cấp 26) trở lên, hệ thống sẽ cố gắng tìm ứng dụng cuối cùng có MediaSession đã phát âm thanh cục bộ. Nếu phiên hoạt động vẫn đang hoạt động, thì Android sẽ trực tiếp gửi sự kiện đó đến phiên đó. Ngược lại, nếu phiên không hoạt động và có trình nhận nút đa phương tiện, Android sẽ gửi sự kiện cho trình nhận. Quá trình này sẽ khởi động lại phiên và có thể nhận sự kiện. (Xem bài viết Sử dụng các nút nội dung nghe nhìn để khởi động lại một phiên nội dung nghe nhìn không hoạt động để biết thông tin chi tiết.) Nếu phiên không có trình nhận nút đa phương tiện, hệ thống sẽ loại bỏ sự kiện nút đa phương tiện và sẽ không có gì xảy ra. Logic này được thể hiện trong sơ đồ sau:

  • Trước Android 8.0 (API cấp 26), hệ thống sẽ cố gắng gửi sự kiện này đến một phiên phát nội dung nghe nhìn đang hoạt động. Nếu có nhiều phiên phát nội dung đa phương tiện đang hoạt động, Android sẽ cố gắng chọn một phiên phát nội dung đa phương tiện đang chuẩn bị phát (lưu vào bộ đệm/kết nối), phát hoặc tạm dừng thay vì phiên đang dừng. (Xem bài viết Xử lý các nút đa phương tiện trong một phiên phát nội dung nghe nhìn đang hoạt động để biết thêm thông tin chi tiết.) Nếu không có phiên hoạt động nào đang hoạt động, Android sẽ cố gắng gửi sự kiện đến phiên hoạt động gần đây nhất. (Xem bài viết Sử dụng các nút nội dung nghe nhìn để khởi động lại một phiên nội dung nghe nhìn không hoạt động để biết thông tin chi tiết.) Logic được thể hiện trong sơ đồ sau đây:

Xử lý các nút nội dung nghe nhìn trong một phiên nội dung nghe nhìn đang hoạt động

Trên Android 5.0 (API cấp 21) trở lên, Android sẽ tự động gửi các sự kiện nút đa phương tiện đến phiên phát nội dung nghe nhìn đang hoạt động bằng cách gọi onMediaButtonEvent(). Theo mặc định, lệnh gọi lại này sẽ chuyển KeyEvent thành phương thức Gọi lại phiên phát nội dung đa phương tiện thích hợp khớp với mã khoá.

Trước Android 5.0 (API cấp 21), Android xử lý các sự kiện của nút đa phương tiện bằng cách truyền phát một ý định bằng thao tác ACTION_MEDIA_BUTTON. Ứng dụng của bạn phải đăng ký một BroadcastReceiver để chặn các ý định này. Lớp MediaButtonReceiver được thiết kế riêng cho mục đích này. Đây là một lớp tiện lợi trong thư viện Android media-compat xử lý ACTION_MEDIA_BUTTON và chuyển đổi các Ý định đến thành các lệnh gọi phương thức MediaSessionCompat.Callback thích hợp.

MediaButtonReceiver là một BroadcastReceiver ngắn hạn. Lớp này sẽ chuyển tiếp các ý định đến đến dịch vụ đang quản lý phiên phát nội dung đa phương tiện của bạn. Nếu muốn sử dụng nút nội dung đa phương tiện trong các hệ thống cũ hơn Android 5.0, bạn phải đưa MediaButtonReceiver vào tệp kê khai bằng bộ lọc ý định 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 chuyển tiếp ý định đến dịch vụ của bạn. Để phân tích cú pháp ý định và tạo lệnh gọi lại cho phiên phát nội dung đa phương tiện của bạn, hãy đưa phương thức MediaButtonReceiver.handleIntent() vào onStartCommand() của dịch vụ. Thao tác này sẽ chuyển mã khoá thành phương thức gọi lại phiên thích hợp.

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);
 }

Sử dụng các nút nội dung nghe nhìn để khởi động lại một phiên nội dung nghe nhìn không hoạt động

Nếu xác định được phiên phát nội dung đa phương tiện hoạt động gần đây nhất, Android sẽ cố gắng khởi động lại phiên đó bằng cách gửi Ý định ACTION_MEDIA_BUTTON đến một thành phần đã đăng ký tệp kê khai (chẳng hạn như một dịch vụ hoặc BroadcastReceiver).

Việc này cho phép ứng dụng bắt đầu phát lại trong khi giao diện người dùng của ứng dụng không hiển thị. Đây là trường hợp áp dụng cho hầu hết các ứng dụng âm thanh.

Hành vi này được tự động bật khi bạn sử dụng MediaSessionCompat. Nếu sử dụng MediaSession của khung Android hoặc Thư viện hỗ trợ 24.0.0 đến 25.1.1, bạn phải gọi setMediaButtonReceiver để cho phép nút nội dung đa phương tiện khởi động lại một phiên phát nội dung đa phương tiện không hoạt động.

Bạn có thể vô hiệu hoá hành vi này trong Android 5.0 (API cấp 21) trở lên bằng cách đặt trình nhận nút đa phương tiện rỗng:

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);

Tuỳ chỉnh trình xử lý nút đa phương tiện

Hành vi mặc định của onMediaButtonEvent() sẽ trích xuất mã khoá và sử dụng trạng thái hiện tại của phiên phát nội dung đa phương tiện cũng như danh sách hành động được hỗ trợ để xác định phương thức cần gọi. Ví dụ: KEYCODE_MEDIA_PLAY gọi onPlay().

Để mang lại trải nghiệm nhất quán cho nút nội dung đa phương tiện trên mọi ứng dụng, bạn nên sử dụng hành vi mặc định và chỉ dành cho một mục đích cụ thể. Nếu nút nội dung đa phương tiện cần xử lý tuỳ chỉnh, hãy ghi đè phương thức onMediaButtonEvent() của lệnh gọi lại, trích xuất KeyEvent bằng intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT), tự xử lý sự kiện và trả về true.

Tóm tắt

Để xử lý đúng cách các sự kiện nút đa phương tiện trong mọi phiên bản Android, bạn phải chỉ định FLAG_HANDLES_MEDIA_BUTTONS khi tạo phiên phát nội dung nghe nhìn.

Ngoài ra, tuỳ thuộc vào phiên bản Android mà bạn dự định hỗ trợ, bạn cũng phải đáp ứng các yêu cầu sau:

Khi chạy trên Android 5.0 trở lên:

  • Gọi MediaControllerCompat.setMediaController() từ lệnh gọi lại onConnected() của trình điều khiển nội dung nghe nhìn
  • Để cho phép nút nội dung đa phương tiện khởi động lại một phiên không hoạt động, hãy tạo MediaButtonReceiver một cách linh động bằng cách gọi setMediaButtonReceiver() và truyền vào đó một PendingIntent

Khi chạy trong các hệ thống trước Android 5.0:

  • Ghi đè onKeyDown() của hoạt động để xử lý các nút đa phương tiện
  • Tạo MediaButtonReceiver tĩnh bằng cách thêm nó vào tệp kê khai của ứng dụng