Android 多媒体控制 来电监听-耳机插拔监听-耳机按钮监听-MediaSession-MediaStyle
2016-11-10 09:04
1306 查看
这个系列仅仅包含控制部分 , 不包含音频操作代码 , 如 pauseAudio(); 我不会说这个方法里是怎么操作的 , 大家需要结合自己的音频播放处理来实现.
通过耳机按钮来控制歌曲 播放/暂停 上/下一首歌曲
当有线耳机/蓝牙耳机 断开连接和重新连接的时候 我们应该对应做出 暂停音频 恢复音频
使用系统提供的Notification.MediaStyle来控制歌曲 , 可以顺利兼容 android 4.x ~ android 7.x 现在的系统样式
[[广告]] https://github.com/ocwvar/DarkPurple
需要代码样例的同学可以在我的这个项目中查看 这个项目是个完整的音频播放器 这里的代码均是从里面提取 , 同时还有均衡器调节 频谱动画显示等.. 目前正在不断完善中 , 但由于上班 , 代码更新可能不及时.
###1. 创建 MediaSessionCompat 对象
在这个构造方法中 , 我们使用这个:
在**Android 4.x**的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152026146)
在**Android 5.x ~ 6.x** 的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152048581)
在**Android 7.0** 的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152312833)
MediaStyle使用的都是系统资源 , 除了布局之外 , 可以自定义的有:
> 封面图片 标题 副标题 按钮样式 背景颜色
使用MediaStyle的优点是不用担心因系统变化而导致布局的变化 , 以及可以使用MediaSession作为我们的控制中介 , 虽然这部分不能自定义但个人认为还是挺值得的 .
对应的一个还有一个是Style是 **DecoratedMediaCustomViewStyle** 这个是可以提供部分自定义 , 但是修改部分仅是标题文字那部分的布局而已 , 并没有什么太大的作用 .
####**Notification.MediaStyle 创建代码**
PS:我们分开一段段讲 ( 代码太长了不好排版…. )
####**Part.1 基础部分**
####**Part.3 设置显示歌曲信息**
最后就 builder.build(); 得到最终的成品 Notification
####耳机拔出/断开连接 广播接收器
最后用 registerReceiver() 来注册广播监听器即可
要使得能接受到通话状态 , 我们需要注册一个权限 android.permission.READ_PHONE_STATE 这个权限在Android 6.0+上是需要用户授予的
在代码端写完之后 , 我们还需要在注册清单中注册一下:
Android多媒体控制
一个完整的多媒体播放器应该有的基础功能:通过耳机按钮来控制歌曲 播放/暂停 上/下一首歌曲
当有线耳机/蓝牙耳机 断开连接和重新连接的时候 我们应该对应做出 暂停音频 恢复音频
使用系统提供的Notification.MediaStyle来控制歌曲 , 可以顺利兼容 android 4.x ~ android 7.x 现在的系统样式
[[广告]] https://github.com/ocwvar/DarkPurple
需要代码样例的同学可以在我的这个项目中查看 这个项目是个完整的音频播放器 这里的代码均是从里面提取 , 同时还有均衡器调节 频谱动画显示等.. 目前正在不断完善中 , 但由于上班 , 代码更新可能不及时.
###1. 创建 MediaSessionCompat 对象
MediaSessionCompat sessionCompat = new MediaSessionCompat();
在这个构造方法中 , 我们使用这个:
MediaSessionCompat(Context context, String tag, ComponentName mbrComponent, PendingIntent mbrIntent) //第一个参数 context: 这个没有什么好讲的,大家都懂的 //第二个参数 tag: 这个是用于调试用的,随便填写即可 //第三个参数 mbrComponent: 这个是用于API21以下的时候传递耳机按钮事件用的MediaSessionCompat. //第四个参数 mbrIntent: 这个是给API21以下传递的时候携带的,一般设为 NULL即可 //例如: //其中的HeadsetButtonReceiver是我们的API21以下实用的监听器 , 我们稍候再讲 ComponentName cn = new ComponentName(this.context.getApplicationContext().getPackageName(), HeadsetButtonReceiver.class.getName()) sessionCompat = new MediaSessionCompat(this.context.getApplicationContext(), "test", cn, null);
参数设置
sessionCompat = new MediaSessionCompat(...); //设置MediaSession回调监听,主要用于设置API21+的耳机按钮监听 sessionCompat.setCallback(new MediaSessionCallback()); //设置FLAG,FLAG的用途一看名字就知道了 sessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS); //设置MediaSession启动 (很重要,不启动则无法接受到数据) sessionCompat.setActive(true);
2. 耳机多媒体按钮监听
API 21+ 的方式 MediaSessionCompat.Callback
//创建完成后用MediaSessionCompat.setCallback设置上即可使用 private class MediaSessionCallback extends MediaSessionCompat.Callback { @Override public boolean onMediaButtonEvent(Intent mediaButtonEvent) { //接收到监听事件 } }
API21- 的方式 HeadsetButtonReceiver
//在代码中创建一个单独的类文件,而不能作为一个内部类 public class HeadsetButtonReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //接收到监听事件 } } //然后在注册文件中注册这个接收器 <receiver android:name=".HeadsetButtonReceiver"> <intent-filter> <action android:name="android.intent.action.MEDIA_BUTTON"/> </intent-filter> </receiver> //最后在创建MediaSessionCompat对象的时候使用即可
3. Notification.MediaStyle 的创建
MediaStyle是什么样子的Notification呢?在**Android 4.x**的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152026146)
在**Android 5.x ~ 6.x** 的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152048581)
在**Android 7.0** 的是这样的
![这里写图片描述](http://img.blog.csdn.net/20161107152312833)
MediaStyle使用的都是系统资源 , 除了布局之外 , 可以自定义的有:
> 封面图片 标题 副标题 按钮样式 背景颜色
使用MediaStyle的优点是不用担心因系统变化而导致布局的变化 , 以及可以使用MediaSession作为我们的控制中介 , 虽然这部分不能自定义但个人认为还是挺值得的 .
对应的一个还有一个是Style是 **DecoratedMediaCustomViewStyle** 这个是可以提供部分自定义 , 但是修改部分仅是标题文字那部分的布局而已 , 并没有什么太大的作用 .
####**Notification.MediaStyle 创建代码**
PS:我们分开一段段讲 ( 代码太长了不好排版…. )
####**Part.1 基础部分**
//创建 Notification 构建器 final NotificationCompat.Builder builder = new NotificationCompat.Builder(context); //创建 MediaStyle 对象 final NotificationCompat.MediaStyle mediaStyle = new NotificationCompat.MediaStyle(builder); //在折叠的视图中显示的按钮序号 根据下面设置的ACTION顺序相关 mediaStyle.setShowActionsInCompactView(0,1); //设置上面创建的MediaSession mediaStyle.setMediaSession(sessionCompat.getSessionToken()); //设置 MediaStyle 风格 builder.setStyle(mediaStyle); //不显示默认的通知开始时间 builder.setShowWhen(false); //仅通知一次 builder.setOnlyAlertOnce(true); //设置为当前正在运行状态,不能清除 builder.setOngoing(true); //设置点击时不隐藏Notification builder.setAutoCancel(false); //设置状态栏上面显示的小图标 builder.setSmallIcon(R.drawable.ic_action_small_icon); //设置锁屏是否显示 在 Android5.0+ 的锁屏界面可以隐藏Notification内容 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setVisibility(Notification.VISIBILITY_PUBLIC); } //设置通知优先度,让我们的 Notification 显示在最上面 builder.setPriority(Notification.PRIORITY_MAX); //设置通知类别为服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { builder.setCategory(Notification.CATEGORY_SERVICE); } //点击通知操作 使得用户点击Notification空白区域的时候打开指定的Activity Intent intent = new Intent(context, SelectMusicActivity.class); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); builder.setContentIntent(pendingIntent);
Part.2 创建和设置Action按钮
/** * 生成按钮Action * * @param icon 图标资源 * @param intentAction 按钮产生的广播Action * @return 按钮Action */ private NotificationCompat.Action generateAction(int icon, String intentAction ) { return new NotificationCompat.Action( icon, intentAction, PendingIntent.getBroadcast(context, 0, new Intent(intentAction), PendingIntent.FLAG_CANCEL_CURRENT) ); } //根据播放状态不同 , 设置不同主按钮样式 , 这里的设置顺序影响到折叠界面显示的顺序 //上一首 按钮ACTION builder.addAction(generateAction(android.R.drawable.ic_media_previous,MediaNotificationReceiver.BUTTON_PREV)); switch (audioStatus) { case Paused: //播放 按钮ACTION builder.addAction(generateAction(android.R.drawable.ic_media_play,MediaNotificationReceiver.BUTTON_PLAY)); break; case Playing: //暂停 按钮ACTION builder.addAction(generateAction(android.R.drawable.ic_media_pause,MediaNotificationReceiver.BUTTON_PAUSE)); break; } //下一首 按钮ACTION builder.addAction(generateAction(android.R.drawable.ic_media_next,MediaNotificationReceiver.BUTTON_NEXT));
####**Part.3 设置显示歌曲信息**
//更新标题 builder.setContentTitle(songItem.getTitle()); //更新作者 builder.setContentText(songItem.getArtist()); //更新封面 builder.setLargeIcon( 歌曲封面的Bitmap对象 );
最后就 builder.build(); 得到最终的成品 Notification
4.监听耳机插拔事件
我们需要在耳机拔出的时候 暂停音乐 在耳机重新插入的时候 恢复音乐耳机插入广播接收器
/** * 耳机插入广播接收器 */ public class HeadsetPlugInReceiver extends BroadcastReceiver { final IntentFilter filter; public HeadsetPlugInReceiver() { filter = new IntentFilter(); if (Build.VERSION.SDK_INT >= 21) { filter.addAction(AudioManager.ACTION_HEADSET_PLUG); } else { filter.addAction(Intent.ACTION_HEADSET_PLUG); } } @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.hasExtra("state") && AppConfigs.isResumeAudioWhenPlugin) { //通过判断 "state" 来知道状态 final boolean isPlugIn = intent.getExtras().getInt("state") == 1; } } }
####耳机拔出/断开连接 广播接收器
/** * 耳机拔出广播接收器 */ private class HeadsetReceiver extends BroadcastReceiver { final IntentFilter filter; final BluetoothAdapter bluetoothAdapter; public HeadsetReceiver() { filter = new IntentFilter(); filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); //有线耳机拔出变化 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); //蓝牙耳机连接变化 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @Override public void onReceive(Context context, Intent intent) { if (isRunningForeground) { //当前是正在运行的时候才能通过媒体按键来操作音频 switch (intent.getAction()) { case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: if ( bluetoothAdapter != null && BluetoothProfile.STATE_DISCONNECTED == bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) && core.getCurrectStatus() == AudioCore.AudioStatus.Playing ) { //蓝牙耳机断开连接 同时当前音乐正在播放 则将其暂停 pause(); } break; case AudioManager.ACTION_AUDIO_BECOMING_NOISY: if (core.getCurrectStatus() == AudioCore.AudioStatus.Playing) { //有线耳机断开连接 同时当前音乐正在播放 则将其暂停 pause(); } break; } } } }
最后用 registerReceiver() 来注册广播监听器即可
5.监听电话状态
我们需要在有电话来的时候和拨通电话的时候 暂停音频 , 在通话结束之后 恢复音频要使得能接受到通话状态 , 我们需要注册一个权限 android.permission.READ_PHONE_STATE 这个权限在Android 6.0+上是需要用户授予的
电话状态广播接收器
/** *电话状态广播接收器 */ public class PhoneStatusReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getExtras() != null){ final String status = intent.getStringExtra(TelephonyManager.EXTRA_STATE); switch (status){ // "IDLE" 则代表通话结束或振铃结束 case "IDLE": resume(); break; //其他状态包括了拨通电话和新来电振铃 default: pause(); break; } } } }
在代码端写完之后 , 我们还需要在注册清单中注册一下:
<receiver android:name=".PhoneStatusReceiver"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE"/> </intent-filter> </receiver>
教程完毕!!
相关文章推荐
- Android耳机线控详解,蓝牙耳机按钮监听(仿酷狗线控效果)
- 001 正式进入android分析hal层以上 apk监听耳机插拔事件
- Android如何监听蓝牙耳机和有线耳机的插拔
- Android的Usb设备的监听(Dev)外设端口的判定以及耳机的插拔
- android 耳机按钮监听
- android耳机插拔的监听
- Android的Usb设备的监听(Dev)外设端口的判定以及耳机的插拔
- android 耳机按钮监听
- android 耳机按钮监听
- android 2.1 监听电话状态并自动接听来电
- android-轻松监听来电和去电
- android 2.1 监听电话状态并自动接听来电
- android 2.1 监听电话状态并自动接听来电
- [AndroidTips]Android监听来电和去电
- android耳机插拔事件
- Android监听来电和去电
- 1.Android里如何【监听】按钮
- android之监听手机来电状态
- android监听返回按钮事件
- 如何实现android中监听来电并生成悬浮窗体提示