Android媒体应用(六)--响应媒体按钮

原文地址:https://developer.android.google.cn/guide/topics/media-apps/mediabuttons.html

媒体按钮是Android设备和其他外围设备上的硬件按钮,例如蓝牙耳机上的暂停/播放按钮。当用户按下媒体按钮时,Android会生成一个KeyEvent,其中包含一个用于标识该按钮的 key code。媒体按钮KeyEvents的key code是以KEYCODE_MEDIA开头的常量(例如,KEYCODE_MEDIA_PLAY)。


在三种情况下,应用程序应该能够处理媒体按钮事件,按以下顺序排列:
  • 当应用程序的UI活动是可见的
  • 当UI活动被隐藏并且应用程序的媒体会话处于活动状态时
  • 当UI活动被隐藏并且应用程序的媒体会话处于非活动状态并需要重新启动时

处理前台Activity中的媒体

按钮前台活动在其onKeyDown()方法中接收媒体按钮键事件。根据Android的运行版本,系统可以通过两种方式将事件路由到媒体控制器:

  • 如果您正在运行Android 5.0(API级别21)或更高版本,请调用FLAG_HANDLES_MEDIA_BUTTONS MediaBrowserCompat.ConnectionCallback.onConnected。这将自动调用媒体控制器的dispatchMediaButtonEvent(),将密钥代码转换为媒体会话回调。
  • 在Android 5.0(API级别21)之前,您需要修改onKeyDown()来自己处理事件。 (请参阅处理活动媒体会话中的媒体按钮以获取详细信息)以下代码片段显示如何拦截键码并调用dispatchMediaButtonEvent()。请务必返回true以表明事件已处理:

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

寻找mediasession

如果前台Activity不处理事件,则Android将尝试查找可处理该事件的mediasession。 同样,根据Android的运行版本,有两种方法可以搜索mediasession:

  • 如果您运行的是Android 8.0(API级别26)或更高版本,则系统将尝试使用本地播放音频的MediaSession查找最后一个应用程序。 如果session仍然处于活动状态,则Android将直接向其发送事件。 否则,如果会话不是活动的,并且它有一个mediabutton接收器,则Android将事件发送给接收器,这将重新启动mediasession,因此它可以接收事件。 (有关详细信息,请参阅使用媒体按钮重新启动非活动媒体会话。)如果会话没有媒体按钮接收器,系统会放弃媒体按钮事件,并且不会发生任何事情。 逻辑如下图所示:
Android媒体应用(六)--响应媒体按钮_第1张图片

  • 在Android 8.0(API级别26)之前,系统尝试将事件发送到活动的媒体会话。 如果有多个活动媒体会话,则Android会尝试选择准备播放(缓冲/连接),正在播放或已暂停的媒体会话,而不是已停止的媒体会话。 (请参阅处理活动媒体会话中的媒体按钮以获取更多详细信息。)如果没有活动会话,则Android会尝试将事件发送到最近活动的会话。 (有关详细信息,请参阅使用媒体按钮重新启动不活动的媒体会话
逻辑如下图所示: Android媒体应用(六)--响应媒体按钮_第2张图片

处理活动媒体会话中的媒体按钮

在Android 5.0(API级别21)及更高版本上,Android会通过调用onMediaButtonEvent()自动将媒体按钮事件分派到活动媒体会话。默认情况下,该回调将KeyEvent转换为与key code相匹配的相应媒体会话回调方法。

在Android 5.0(API级别21)之前,Android通过广播action为ACTION_MEDIA_BUTTON的Intent来处理媒体按钮事件。你的应用程序必须注册一个BroadcastReceiver来拦截这些Intent。 MediaButtonReceiver类是专门为此目的而设计的。这是Android media-compat库中的一个便利类,它处理ACTION_MEDIA_BUTTON并将传入的Intents转换为适当的MediaSessionCompat.Callback方法调用。

MediaButtonReceiver是一个短暂的BroadcastReceiver。它将传入的Intent转发到管理媒体会话的服务。如果您想在Android 5.0之前的系统中使用媒体按钮,则必须使用MEDIA_BUTTON intent过滤器将MediaButtonReceiver包含在清单中:

   
     
   
 

BroadcastReceiver将Intent转发给您的服务。 为了解析Intent并生成对媒体会话的回调,请在服务的onStartCommand()中包含MediaButtonReceiver.handleIntent()方法。 这将 key code转换为适当的会话回调方法。
private MediaSessionCompat mMediaSessionCompat = ...;

 public int onStartCommand(Intent intent, int flags, int startId) {
   MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
   return super.onStartCommand(intent, flags, startId);
 }
注意:如果您没有MediaBrowserServiceCompat,则还可以将ACTION_MEDIA_BUTTON意图过滤器添加到任何服务。 有关更多信息,请参阅 MediaButtonReceiver文档。

使用媒体按钮重新启动非活动媒体会话

如果Android可以识别最后一个活动媒体会话,它会尝试通过发送一个ACTION_MEDIA_BUTTON Intent到清单注册的组件(如服务或BroadcastReceiver)来重新启动会话。
这可以让您的应用重新开始播放,而其UI不可见,这是大多数音频应用的情况。
当您使用MediaSessionCompat时,此行为将自动启用。 如果您使用Android框架的MediaSession或支持库24.0.0至25.1.1,则必须调用setMediaButtonReceiver以让媒体按钮重新启动不活动的媒体会话。

您可以通过设置空媒体按钮接收器来在Android 5.0(API级别21)及更高版本中禁用此行为:

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

注意:对于在早于Android 5.0(API级别21)的系统中运行的应用程序,注册以处理 active session的媒体按钮的MediaButtonReceiver在session处于非活动状态时也将接收媒体按钮事件。没有办法来禁用此行为。

自定义媒体按钮处理程序

onMediaButtonEvent()的默认行为将提取 key code,并使用媒体会话的当前状态和支持的操作列表来确定要调用的方法。例如,KEYCODE_MEDIA_PLAY调用onPlay()。

为了在所有应用中提供一致的媒体按钮体验,您应该使用默认行为,并且仅针对特定目的进行偏离。如果媒体按钮需要自定义处理,请覆盖您的回调的onMediaButtonEvent()方法,使用intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)提取KeyEvent,自己处理事件,并返回true。

概要

要正确处理所有Android版本的媒体按钮事件,必须在创建媒体会话时指定FLAG_HANDLES_MEDIA_BUTTONS。

另外,根据您计划支持的Android版本,您还必须满足以下要求:

在Android 5.0或更高版本中运行时:
  • 从媒体控制器onConnected()回调调用MediaControllerCompat.setMediaController()
  • 要允许媒体按钮重新启动非活动会话,请通过调用setMediaButtonReceiver()动态创建MediaButtonReceiver,并将其传递给PendingIntent


在早于Android 5.0的系统中运行时:
  • 覆盖活动的onKeyDownEvent()来处理媒体按钮
  • 通过将其添加到应用程序的清单静态创建一个MediaButtonReceiver

你可能感兴趣的:(android)