主要实现功能:
一、通知栏播放显示和控制
二、系统下拉栏中播放模块显示同步
三、与其他播放器状态同步:本应用播放时暂停其他应用播放,进入其他应用播放时,暂停本应用的后台播放
通知栏播放的显示和控制:
通过Notification + RemoteViews + 广播实现,主要代码如下:
/**
* 初始化自定义通知栏 的按钮点击事件
*/
private void initRemoteViews() {
remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);
//通知栏控制器上一首按钮广播操作
Intent intentPrev = new Intent(ACTION_PRE_SONG);
PendingIntent prevPendingIntent = PendingIntent.getBroadcast(this, 5100, intentPrev, PendingIntent.FLAG_CANCEL_CURRENT);
//为prev控件注册事件
remoteViews.setOnClickPendingIntent(R.id.btn_notification_previous, prevPendingIntent);
//通知栏控制器播放暂停按钮广播操作 //用于接收广播时过滤意图信息
Intent intentPlay = new Intent(ACTION_PAUSE);
PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);
//为play控件注册事件
remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);
//通知栏控制器下一首按钮广播操作
Intent intentNext = new Intent(ACTION_NEXT_SONG);
PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 5102, intentNext, PendingIntent.FLAG_CANCEL_CURRENT);
//为next控件注册事件
remoteViews.setOnClickPendingIntent(R.id.btn_notification_next, nextPendingIntent);
//通知栏控制器关闭按钮广播操作
Intent intentClose = new Intent(ACTION_PLAY_CLOSE);
PendingIntent closePendingIntent = PendingIntent.getBroadcast(this, 5103, intentClose, 0);
//为close控件注册事件
remoteViews.setOnClickPendingIntent(R.id.btn_notification_close, closePendingIntent);
}
/**
* 初始化通知
*/
@SuppressLint("NotificationTrampoline")
private void initNotification() {
String channelId = "play_control";
String channelName = "播放控制";
int importance = NotificationManager.IMPORTANCE_HIGH;
createNotificationChannel(channelId, channelName, importance);
//点击整个通知时发送广播
Intent intent = new Intent(getApplicationContext(), NotificationClickReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
intent, FLAG_UPDATE_CURRENT);
//初始化通知
notification = new NotificationCompat.Builder(this, "play_control")
.setContentIntent(pendingIntent)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
// .setCustomContentView(remoteViews)
.setCustomBigContentView(remoteViews)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
// .setStyle(new NotificationCompat.BigTextStyle())
// .setStyle(new NotificationCompat.InboxStyle())
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setAutoCancel(false)
.setOnlyAlertOnce(true)
.setOngoing(true)
.build();
}
/**
* 创建通知渠道
*
* @param channelId 渠道id
* @param channelName 渠道名称
* @param importance 渠道重要性
*/
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel(String channelId, String channelName, int importance) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
channel.enableLights(false);
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
channel.setSound(null, null);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
通知栏整体点击跳转到播放界面:注册全局监听广播
public class NotificationClickReceiver extends BroadcastReceiver {
public static final String TAG = "NotificationClickReceiver";
@Override
public void onReceive(Context context, Intent intent) {
LogUtil.showLog(TAG,"通知栏点击");
//获取栈顶的Activity
// Activity currentActivity = ActivityManager.getCurrentActivity();
intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClass(context, MusicPlayerActivity.class);
intent.putExtra("from","notify");
// intent.putExtra("file",MyApplication.currentPlayMusic);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
context.startActivity(intent);
}
}
系统下拉栏媒体播放信息和状态同步:
通过MediaSession + MediaMetadata + PlaybackState实现
public void initMediaSession(){
mediaSession = new MediaSession(this, "music_player_session");
mediaSession.setCallback(new MediaSession.Callback() {
// 覆盖必要的回调方法,如onPlay, onPause等
@Override
public void onPause() {
super.onPause();
mediaSession.setPlaybackState(stateBuilder.setState(PlaybackState.STATE_PAUSED,mPlayer.getCurrentPosition(), 0.0f).build());
sendBroadcast(new Intent(ACTION_PAUSE));
}
@Override
public void onPlay() {
super.onPlay();
mediaSession.setPlaybackState(stateBuilder.setState(PlaybackState.STATE_PLAYING, mPlayer.getCurrentPosition(), 0.0f).build());
sendBroadcast(new Intent(ACTION_PLAY_SONG));
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
sendBroadcast(new Intent(ACTION_NEXT_SONG));
}
@Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
sendBroadcast(new Intent(ACTION_PRE_SONG));
}
});
mediaSession.setActive(true);
metaDataBuilder = new MediaMetadata.Builder();
//播放状态
stateBuilder = new PlaybackState.Builder();
stateBuilder.setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE
| PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS);
}
状态和信息同步:
/**
* 更改通知的信息和UI
*/
private Intent intentPlay;
private PendingIntent playPendingIntent;
public void updateNotificationShow() {
//通知栏控制器播放暂停按钮广播操作 //用于接收广播时过滤意图信息
intentPlay = new Intent(mPlayer.isPlaying()?ACTION_PAUSE:ACTION_PLAY_SONG);
playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);
//为play控件注册事件
remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);
//播放状态判断
if (mPlayer.isPlaying()) {
remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_pause);
} else {
remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_play);
}
//封面专辑
remoteViews.setImageViewResource(R.id.iv_album_cover,R.mipmap.ic_launcher);
//歌曲名
remoteViews.setTextViewText(R.id.tv_notification_song_name,defaultSongName.substring(0,defaultSongName.lastIndexOf(".")));
//歌手名
remoteViews.setTextViewText(R.id.tv_notification_singer,"");
remoteViews.setTextViewText(R.id.tv_duration,StringUtil.formatDuration(mPlayer.getDuration()));
remoteViews.setTextViewText(R.id.tv_current_time,StringUtil.formatDuration(mPlayer.getCurrentPosition()));
if(mPlayer.getDuration() > 0)
remoteViews.setProgressBar(R.id.seekbar,100,mPlayer.getCurrentPosition()*100/mPlayer.getDuration(),false);
//发送通知
manager.notify(NOTIFICATION_ID,notification);
WindowUtils.isNotifyShow = true;
//同步下拉栏播放控制区信息
metaDataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,defaultSongName.substring(0,defaultSongName.lastIndexOf(".")));
mediaSession.setMetadata(metaDataBuilder.build());
}
与其他应用播放器状态同步
通过AudioManager监听onAudioFocusChange音频焦点变化实现
/** 监测其他应用播放音视频 */
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
LogUtil.showLog(TAG,"==onAudioFocusChange=="+focusChange);
abandonAudioFocus(); //禁用音频
sendBroadcast(new Intent(ACTION_PAUSE));
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// TBD 继续播放
break;
case AudioManager.AUDIOFOCUS_LOSS:
// TBD 停止播放
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// TBD 暂停播放
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// TBD 混音播放
break;
default:
break;
}
}
};
//android 版本 5.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mAttribute = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
}
//android 版本 8.0
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setWillPauseWhenDucked(true)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener(mListener, mHandler)
.setAudioAttributes(mAttribute)
.build();
}
requestAudioFocus();//启动获取音频
效果图: