需求功能说明:

该定制需求在各个国家民族差异化为背景下产生的,要求在系统中增加一个新的分区如myimage,用以实现存放定制资源,以符合不同国家民族的用户的体验。例如在myimage下新建media文件夹用于存放定制的音频资源,如果系统myimage分区下,media目录下存在相关目录或文件,则系统摒弃系统重名默认资源,优先选择该分区下的定制资源。
注!
    本篇博文结合从系统启动完成之后系统对多媒体文件的扫描流程进行分析和修改。修改思路为:优先将扫描定制分区西下定制音频资源的结果插入相对应的数据库中。若定制分区下不存在资源目录或文件,则将系统默认资源的扫描结果插入相对应的数据库,若定制资源文件名与系统资源文件名相同,则优先插入定制资源。
参考代码:Android4.1.2_r2

1.当系统启动完成,MediaScannerReceiver接收到系统启动完成的广播,并调用scan()方法对内置存储设备进行扫描。

相关类:MediaScannerReceiver.java是一个BroadcastReceiver,接收广播,进行媒体扫描,是MediaScanner提供的接口,主要负责接收广播并启动MediaScannerService具体执行扫描工作。
方法调用流程:onReceiver()-->scan()-->scanDirectories()
具体代码如下:
public voidonReceive(Context context, Intent intent) {
......
   if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {//接收到系统启动完成的广播
        // 扫描内部存储设备,INTERNAL_VOLUME的值为"internal"
        scan(context, MediaProvider.INTERNAL_VOLUME);
    }
......
}
private voidscan(Context context, String volume) {
         Bundle args = new Bundle();
         args.putString("volume", volume);
        //通过startService()启动服务开始内部Media文件扫描,这里的参数volume的值为”internal”。
         context.startService(new Intent(context, MediaScannerService.class).putExtras(args));
}

2.MediaScannerService服务被启动,主要负责媒体扫描。详细来说MediaScannerService用于接收系统重启后、插拔SD卡、文件复制与拷贝等消息,收到消息后会启动一个handler去处理消息并扫描,最后会将扫描结果放到MediaProvider提供的数据库中去。这里我们先从onCreate生命周期函数开始分析。

主要方法如下:handleMessage()-->scan()
public voidonCreate(){
     PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
    //扫描期间保持屏幕常亮
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    ......
    //启动一个工作线程来处理大量的计算任务,由于MediaScannerService实现了Runnable,因此大量计算的任务都是在Runnable的run()方法中来执行的。
    Thread thr = new Thread(null, this, "MediaScannerService");
     thr.start();
    ......
}
//在Runnable.run()中执行消息循环,把通过Handler发送过来的消息在工作线程中执行。
public voidrun(){
         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_LESS_FAVORABLE);
         Looper.prepare();
         mServiceLooper = Looper.myLooper();
         mServiceHandler = new ServiceHandler();
         Looper.loop();
     }
//Service对象在被启动的时候,onStartCommand()会被调用。
public intonStartCommand(Intent intent, int flags, int startId){
        ....
         Message msg = mServiceHandler.obtainMessage();
         msg.arg1 = startId;
         msg.obj = intent.getExtras();
         mServiceHandler.sendMessage(msg);
         return Service.START_REDELIVER_INTENT;
}
private final classServiceHandlerextends Handler
     {
         @Override
         public void handleMessage(Message msg){
            ......
             Bundle arguments = (Bundle) msg.obj;
             String filePath = arguments.getString("filepath");
                     String volume = arguments.getString("volume");
                     String[] directories = null;
                    //根据前文我们知道这里的形参volume的值是“internal”,因此这里会默认扫描"system/media"路径。
                    if (MediaProvider.INTERNAL_VOLUME.equals(volume)) {
                         directories = new String[] {
                                   //注:根据需求这里我们新增加了一个新的分区如myimage用来存放我们需要定制的资源,因此在这里我们在对内部进行扫描的时候增加一个扫描路径,也就是“myimage/media”。此外,此处添加扫描定制分区会优先扫描定制分区。
                                  "myimage/media"
                                 Environment.getRootDirectory() + "/media",
                        };
                     }
                    if (directories != null) {
                        ......
                         scan(directories, volume);
                         ......
                     }
        ......
}
//从 getContentResolver获得一个ContentResover,然后直接插入根据AIDL,这个ContentResover的另一端是MediaProvider。这里主要获得了一个扫描URI。
private voidscan(String[] directories, String volumeName) {
         ContentValues values = new ContentValues();
         values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName);
         Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values);
        //这里不做任何修改以保持原有的数据库结构不发生变化。
         Uri uri = Uri.parse("file://" + directories[0]);
        //发送开始扫描的通知
         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));
         try {
             if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {
                 openDatabase(volumeName);
             }
             MediaScanner scanner = createMediaScanner();
            //扫描目录
             scanner.scanDirectories(directories, volumeName);
         } catch (Exception e) {
             Log.e(TAG, "exception in MediaScanner.scan()", e);
         }
         //删除扫描路径,以示扫描结束(这里由于时间问题不做验证,大概也就是会有地方捕捉该删除动作,并发出广播,以通知扫描结束)
         getContentResolver().delete(scanUri, null, null);
         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri));
         mWakeLock.release();
}

实现手机来电铃声,通知铃声、警告铃声等音频定制化功能(一,添加扫描分区myimage)相关推荐

  1. 实现手机来电铃声,通知铃声、警告铃声等音频定制化功能(三,多媒体扫描结果定制处理)

    本篇博文主要是对MediaScanner中endFile方法的处理流程上的重构,以实现需求中的资源区域化定制.处理思路为首先扫描定制分区中的资源,在扫描系统分区下默认资源时判断定制分区西下是否已经存在 ...

  2. php显示动态通告信息方式,Joomla PHP通知,警告和错误指南

    网站不可避免地会出现问题.无论您使用的是Joomla还是其他产品,都需要发现并修复问题. Joomla使用PHP,当PHP有问题时,它将向您报告.但是,这些错误通常会出现在您的网站上,并且对访问者可见 ...

  3. 将迷你音箱用作手机来电铃声放大器

    注:图片来自各产品介绍页面 要看结论,跳至最后 前两天买了个带音频线的"jrc迷你小音响",让父母出去时插在手机耳机孔上,作为来电铃声放大器,这样他们就再也不会因为手机放在包里而总 ...

  4. 华为手机的备忘录提醒怎么改铃声设置

    华为手机上可以使用备忘录工具来添加记事和提醒,提醒事项到期后可通过铃声的方式发送提醒通知.那么华为手机的备忘录提醒怎么改铃声设置呢? 在华为手机自带的备忘录中,可通过待办功能设置时间提醒,在待办页面右 ...

  5. 将音乐文件设置为来电铃声,短信铃声以及联系人铃声

    http://www.eoeandroid.com/thread-263749-1-1.html 好久没有发帖了,这周做了个将音乐设置为来电铃声,短信铃声,联系人铃声这些小功能!额,具体说说方法吧 / ...

  6. iphone换android手机铃声,iphone12如何设置铃声?iphone12更换铃声方式分享[多图]

    今天小编为大家带来最新的iphone12更换铃声方式,为大家带来最新的手机玩法教程,对此感兴趣的小伙伴,快来看看吧.很多用户在购买这个手机以后,不知道要如何更换手机中的铃声,今天小编就会与大家一起来分 ...

  7. webview 禁止苹果自动下拉_苹果手机如何拥有百变铃声?酷狗铃声1分钟搞定!-时尚呼吸...

    众所周知,目前的智能手机分为安卓和苹果两大阵营,虽然各有优点,但是在设置来电铃声这方面,苹果手机的IOS系统真不如安卓灵活,许多人为此伤脑筋.其实苹果手机设置铃声并不难,酷狗铃声分分钟将它搞定! 不止 ...

  8. 微信能设置铃声吗?微信铃声怎么设置?

    使用微信这么久了,听提示音也听了这么久,多少会有点腻了吧,微信最近新出的功能,可以更换来电铃声了,以后朋友打视频或者语音过来就可以听到自己喜欢的音乐,那么微信铃声怎么设置呢?这里为大家整理了4个步骤, ...

  9. iphone铃声android铃声,iphone12如何设置铃声?iphone12更换铃声方式分享[多图]

    如果你不想额外花钱用Apple Music,想直接在网易云或者QQ音乐里把歌曲截取部分当做铃声,那么稍微麻烦一点点点的方法适合你. 基本思路便是利用音乐APP的制作铃声与库乐队的保存音乐两者结合,就可 ...

最新文章

  1. BZOJ 1612: [Usaco2008 Jan]Cow Contest奶牛的比赛【Floyd】
  2. 不使用先验知识与复杂训练策略,从头训练二值神经网络!
  3. Python编程基础:第四十节 类变量Class Variables
  4. 江山控股附属斥资3.02亿收购云阳新能源发电100%股权并偿债
  5. iOS开发之Xcode开发快捷键大全
  6. java怎么改运行图标,java修改进程图标
  7. 第二章 ARM体系结构与指令集——ARM
  8. 机械精度设计与检测|尺寸精度
  9. 如何证明pi是无理数
  10. jquery gotop插件
  11. 利用java中的Calendar类完成当前月份日历Calendar类小练习
  12. MMO手游地图同步方案总结
  13. 如何批量修改云服务器BCC实例名称
  14. java bfs 迷宫例子_51-迷宫(一)- java版dfs和bfs
  15. 【面试】Java 并发编程
  16. QPython+uiautomator2安卓手机自动化脚本编写
  17. 华为全屋智能战略再升级 用三把钥匙打开未来家的大门
  18. 小程序开发之瀑布流布局
  19. Android刘海屏适配
  20. 2022全球与中国瞬态发生器市场现状及未来发展趋势

热门文章

  1. 配置文件导入服务器什么意思,配置服务器需要什么意思
  2. 3D点云论文相关论文资料总结
  3. 论文阅读《PatchMatch Stereo - Stereo Matching with Slanted Support Windows》(PMS-双目立体匹配)
  4. 图的存储-邻接矩阵和邻接表之间的相互转化
  5. SEO快排是什么?怎样实现快排?
  6. 【网络】 输入www.baidu.com后的过程详解
  7. 本科科研经历(技术干货篇-论文发表流程)
  8. oracle vbo4582,4582是什么意思
  9. 七牛云 -数据的增加和删除(vue+egg+element-ui+axios)
  10. 抓包精灵NetCapture APP抓包教程《齐全》