关于音乐播放器与系统功能联动功能梳理

主要实现功能:

一、通知栏播放显示和控制

二、系统下拉栏中播放模块显示同步

三、与其他播放器状态同步:本应用播放时暂停其他应用播放,进入其他应用播放时,暂停本应用的后台播放

通知栏播放的显示和控制:

通过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();//启动获取音频

效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/690945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RTKLIB之RTKPLOT画图工具

开源工具RTKLIB在业内如雷贯耳,其中的RTKPLOT最近正在学习,发现其功能之强大,前所未见,打开了新的思路。 使用思博伦GSS7000卫星导航模拟器,PosApp软件仿真一个载具位置 1,RTKPLOT支持DUT 串口直接输出的NMEA数据并…

基于深度学习的中文标点预测模型-中文标点重建(Transformer模型)【已开源】

基于深度学习的中文标点预测模型-中文标点重建(Transformer模型)提供模型代码和训练好的模型 前言 目前关于使用深度学习对文本自动添加标点符号的研究并不多见,已知的开源项目也较少,而对该领域的详细介绍更是稀缺。然而&#x…

苹果手机微信如何直接打印文件

在快节奏的工作和生活中,打印文件的需求无处不在。但你是否曾经遇到过这样的困扰:打印店价格高昂,让你望而却步?今天,我要给大家介绍一款神奇的微信小程序——琢贝云打印,让你的苹果手机微信直接变身移动打…

React Hooks路由传参

场景:如何把想要的参数带到跳转过去的页面里呢?很简单 上代码: 在你需要跳转的页面上 引入 Link用来跳转使用 Link跳转并携带参数 然后需要什么参数就带什么过去喽 这里record里面存的就是我的数据 我只需要id和state然后到你跳转过去的页面…

MySQL-备份(三)

备份作用:保证数据的安全和完整。 一 备份类别 类别物理备份 xtrabackup逻辑备份mysqldump对象数据库物理文件数据库对象(如用户、表、存储过程等)可移植性差,不能恢复到不同版本mysql对象级备份,可移植性强占用空间占…

【C语言】详解函数(上)(庖丁解牛版)

文章目录 1. 前言2. 函数的概念3.库函数3.1 标准库和头文件3.2 库函数的使用3.2.1 头文件的包含3.2.2 实践 4. 自定义函数4.1 自定义函数的语法形式4.2 函数的举例 5. 形参和实参5.1 实参5.2 形参5.3 实参和形参的关系 6. return 语句6. 总结 1. 前言 一讲到函数这块&#xff…

算法—字符串操作

394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string longestCommonPrefix(vector<string>& strs) { string retstrs[0];//***1***记得先要初始化ret&#xff0c;作为第一个比较值for(int i0;i<strs.size();i){retfoundcom…

聪明人社交的基本顺序:千万别搞反了,越早明白越好

聪明人社交的基本顺序&#xff1a;千万别搞反了&#xff0c;越早明白越好 国学文化 德鲁克博雅管理 2024-03-27 17:00 作者&#xff1a;方小格 来源&#xff1a;国学文化&#xff08;gxwh001&#xff09; 导语 比一个好的圈子更重要的&#xff0c;是自己优质的能力。 唐诗宋…

视觉SLAM十四讲:从理论到实践(Chapter9:后端1)

前言 学习笔记&#xff0c;仅供学习&#xff0c;不做商用&#xff0c;如有侵权&#xff0c;联系我删除即可 一、目标 1.理解后端的概念。 2.理解以EKF为代表的滤波器后端的工作原理。 3.理解非线性优化的后端&#xff0c;明白稀疏性是如何利用的。 4.使用g2o和Ceres实际操作…

代码随想录算法训练营第36期DAY49

DAY49 139单词拆分 没有思路。 回溯法 回溯怎么做呢&#xff1a;拼接str&#xff0c;看能不能拼出来。注意每个单词能用多次&#xff0c;不是用了就没。 但是语法还是难写。 自己的思路不好&#xff0c;题解思路&#xff1a;枚举所有分割字符串&#xff0c;判断是否在字典…

史上最有趣嫁妆:晋公盘的传奇

在遥远的春秋时代&#xff0c;晋国的晋文公为他的女儿用心打造了一件独特的嫁妆——晋公盘。 晋公盘由青铜制成&#xff0c;形状独特&#xff0c;工艺精湛。在晋公盘内底中央&#xff0c;一对精美的浮雕龙盘绕成圆形&#xff0c;盘上饰有鸟、龟、鱼、蛙等多种动物&#xff0c;最…

利用R包“Phenotype”对表型值进行检查

首先&#xff0c;你需要确保你已经安装了R和RStudio&#xff08;如果你想用RStudio的话&#xff09;。然后&#xff0c;你可以按照以下步骤进行操作&#xff1a; 加载数据&#xff1a;首先&#xff0c;你需要加载你的表型数据。如果你的数据是以CSV、Excel等格式保存的&#x…

设计模式-中介者(调停者)模式(行为型)

中介者模式 中介者模式是一种行为型模式&#xff0c;又叫调停者模式&#xff0c;它是为了解决多个对象之间&#xff0c;多个类之间通信的复杂性&#xff0c;定义一个中介者对象来封装一些列对象之间的交互&#xff0c;使各个对象之间不同持有对方的引用就可以实现交互&#xf…

LabVIEW伺服电机测控系统

LabVIEW伺服电机测控系统 开发了一个基于LabVIEW的伺服电机测控系统。系统主要用于精确控制电机的运动&#xff0c;以达到高效率和高精度的要求。通过使用LabVIEW软件和配套的硬件&#xff0c;开发者能够实现对伺服电机的实时监控和控制&#xff0c;进而提高整个系统的性能和可…

Linux-常用命令-常用设置

1.帮助类命令 1.man命令-获得帮助信息 man [命令或配置文件]例&#xff1a;查看ls命令的帮助信息 man ls输入 ZZ 退出帮助2.服务管理类命令 1.centos7语法 1.1 临时开关服务命令 开启服务&#xff1a; systemctl start 服务名 关闭服务&#xff1a; systemctl stop 服务…

LDR6020一拖二快充线:高效充电的新选择

LDR6020一拖二快充线&#xff1a;高效充电的新选择 随着移动设备的普及和功能的日益增强&#xff0c;电池续航成为了用户关注的重点之一。为了满足用户对于快速充电的需求&#xff0c;各大厂商纷纷推出了各种快充技术和产品。在这个背景下&#xff0c;LDR6020一拖二快充线凭借…

2024年6月8日 (周六) 叶子游戏新闻

万能嗅探: 实测 网页打开 某视频号、某音、某红薯、某站&#xff0c;可以做到无水印的视频和封面下载功能哦&#xff0c;具体玩法大家自行发挥吧。 《丝之歌》粉丝又要失望&#xff1a;大概率不会亮相Xbox发布会即将于后天举行的 Xbox 发布会预计将会有许多令人兴奋的消息。早些…

Linux shell编程学习笔记57:lshw命令 获取cpu设备信息

0 前言 在Linux中&#xff0c;获取cpu信息的命令很多&#xff0c;除了我们已经研究的 cat /proc/cpuinfo、lscpu、nproc、hwinfo --cpu 命令&#xff0c;还有 lshw命令。 1 lshw命令的功能 lshw命令源自英文list hardware&#xff0c;即列出系统的硬件信息&#xff0c;这些硬…

C++ 11 【线程库】【包装器】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;C修炼之路⏪   &#x1f69a;代码仓库:C高阶&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C知识   &#x1f51d;&#x1f51d; 目录 前言 一、thread类的简单介绍 get_id…

连山露【诗词】

连山露 雾隐黄山路&#xff0c;十步一松树。 树上惊松鼠&#xff0c;松子衔木屋。 松子青嫩芽&#xff0c;尖尖头探出。 卷挂白露珠&#xff0c;装映黄山雾。