文章目录

  • Ringtone 的两中类型三种形式
    • 两种类型
    • 三种形式
      • 1 最常见的uri形式
      • 2 Settings数据库中的uri形式
      • 3 Android 4.4以后增加了document uri
  • 返回给RingtonePickerActivity的uri处理
    • authority是settings
    • authority是com.android.providers...
  • RingtonePickerActivity的默认铃声
  • RingtonePickerActivity的初始铃声列表

Ringtone 的两中类型三种形式

两种类型

指的是:external.db和internal.db中对应的MediaStore.Audio.Media.EXTERNAL_CONTENT_URI和MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

三种形式

1 最常见的uri形式

content://media/external/audio/media/id 和 content://media/internal/audio/media/id
id就是其在MediaProvider中对应的数据库中的id

MediaStore.Audio.Media.EXTERNAL_CONTENT_URI---content://media/external/audio/media/id
对应的数据库:/data/data/com.android.providers.media/databases/external.db
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI---content://media/internal/audio/media/id
对应的数据库:/data/data/com.android.providers.media/databases/internal.db

authority是media

2 Settings数据库中的uri形式

content://setting/system/***

Settings.System.DEFAULT_NOTIFICATION_URI----content://setting/system/notification_sound
Settings.System.DEFAULT_RINGTONE_URI------content://settings/system/ringtone
Settings.System.DEFAULT_ALARM_ALERT_URI-----content://settings/system/alarm_alert

authority是settings

android M以前对应的数据库data\data\com.android.providers.settings\databases\这个目录下的Settings.db (如android L)

android M SettingsProvider数据库的变化,变化如下,之前系统修改的数据最后是存储在data/data/com.android.providers.settings/databases目录下,现在该目录下存放了一个backup数据库,里面的数据不是当前系统设置的全部数据,只有一部分内容,另一个是journal数据库,无数据。现在的数据库真正的数据存储目录在data/system/users/userId(我们没开启多用户,userid为0),数据存储形式不是以db的形式,如下截图,为数据三个表分别对应system,secure和global,查看相应数据可以导出对应的xml。

settings_system.xml中存储的就有content://setting/system/..,存储的value是第一种形式,所以其本质是把第一种数据uri形式存储在settings_system.xml中。

settings_system.xml 所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
settings_global.xml 包含各种各样的用户偏好系统设置;
settings_secure.xml 安全性的用户偏好系统设置,第三方APP有读没有写的权限

这里可以直接adb修改配置值,方便开发人员测试:
adb shell settings put system xxxx 1
adb shell settings get system xxx
adb shell settings put global xxx 0

3 Android 4.4以后增加了document uri

content://com.android.providers.media.documents/document/audio%3A82482
content://com.android.providers.downloads.documents/document/audio%3A82556
content://com.android.externalstorage.documents//document/audio%8N584645

authority是com.android.providers.*.documents
其DocumentsContract.getDocumentId(uri)进行String串的处理获取id转化为第一种形式,本质上是对第一种形式的包装

  if (isMediaDocument(uri)) {final String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");final String id = split[1];Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://media/external/audio/media/"), Long.valueOf(id));return contentUri;...

不管那种类型或形式都是下面这种格式:

content://authority/path/id

返回给RingtonePickerActivity的uri处理

返回给RingtonePickerActivity的uri如果不是第三中形式需要对uri处理转化为第一种形式

authority是settings

通过访问settings_system.xml获取对应的value,也就是存储的第一种形式的content uri的String形式

String uriString = Settings.System.getString(context.getContentResolver(), Settings.System.RINGTONE.toString());

authority是com.android.providers…

返回给RingtonePickerActivity的uri如果不是第三中形式需要对uri处理转化为第一种形式 authority是com.android.providers…
这种有三种,需要分别处理如下:

    /*** Gets the content:// URI from the given corresponding path to a file** @param context* @param path* @return content Uri*/private static Uri getContentUriWithPath(ContentResolver resolver, String path) {Cursor cursor = null;String filePath = path;try {cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,new String[] { MediaStore.Audio.Media._ID },MediaStore.Audio.Media.DATA + "=? ",new String[] { filePath }, null);if (cursor != null && cursor.moveToFirst()) {int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));Uri baseUri = Uri.parse("content://media/external/audio/media");return Uri.withAppendedPath(baseUri, "" + id);} else {if (filePath != null) {ContentValues values = new ContentValues();values.put(MediaStore.Audio.Media.DATA, filePath);return resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);} else {return null;}}}finally {if (cursor != null)cursor.close();}}public static String getDataColumn(ContentResolver resolver, Uri uri, String selection,String[] selectionArgs) {Cursor cursor = null;final String column = "_data";final String[] projection = { column };try {cursor = resolver.query(uri, projection, selection, selectionArgs,null);if (cursor != null && cursor.moveToFirst()) {final int index = cursor.getColumnIndexOrThrow(column);//Log.d(TAG, "cursor.getString(index) =  " + cursor.getString(index));return cursor.getString(index);}} finally {if (cursor != null)cursor.close();}return null;}private Uri getContentUri(ContentResolver resolver, Uri uri){if (DocumentsContract.isDocumentUri(this, uri)) {if (isMediaDocument(uri)) {final String docId = DocumentsContract.getDocumentId(uri);final String[] split = docId.split(":");final String id = split[1];Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://media/external/audio/media/"), Long.valueOf(id));return contentUri;}else if (isExternalStorageDocument(uri)){//Log.d(TAG, "****ExternalStorageDocument****");final String docId = DocumentsContract.getDocumentId(uri);//Log.d(TAG, "getContentUri: docId =  " + docId);final String[] split = docId.split(":");final String type = split[0];String path = null;if ("primary".equalsIgnoreCase(type)) {path = Environment.getExternalStorageDirectory() + "/" + split[1];//Log.d(TAG, "getContentUri: primary   path =  " + path);}else{path = "/storage/" + split[0] + "/" + split[1];//Log.d(TAG, "getContentUri: path =  " + path);}return getContentUriWithPath(resolver,path);}else if (isDownloadsDocument(uri)){Log.d(TAG, "****DownloadsDocument****");final String id = DocumentsContract.getDocumentId(uri);//Log.d(TAG, "getContentUri ,getDocumentId: Id =  " + id);final Uri downloadsUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));//Log.d(TAG, "downloadsUri:" + downloadsUri.toString());String path = getDataColumn(resolver, downloadsUri, null, null);return getContentUriWithPath(resolver,path);}}return uri;}/*** @param uri The Uri to check.* @return Whether the Uri authority is ExternalStorageProvider.*/public static boolean isExternalStorageDocument(Uri uri) {return "com.android.externalstorage.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is DownloadsProvider.*/public static boolean isDownloadsDocument(Uri uri) {return "com.android.providers.downloads.documents".equals(uri.getAuthority());}/*** @param uri The Uri to check.* @return Whether the Uri authority is MediaProvider.*/public static boolean isMediaDocument(Uri uri) {return "com.android.providers.media.documents".equals(uri.getAuthority());}

RingtonePickerActivity的默认铃声

/platform/build / target/product/full_base.mk

PRODUCT_PROPERTY_OVERRIDES := \ro.config.ringtone=Ring_Synth_04.ogg \ro.config.notification_sound=pixiedust.ogg......

RingtonePickerActivity的初始铃声列表

/platform/build / target/product/full_base.mk中会copy一部分internal ringtone

$(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)

AllAudio.mk会把audio资源copy到系统Ringtones、Notifications、Alarms目录下,也可在vendor下定制自己的铃声列表和默认铃声

在MediaScanner扫描文件时,判断到如果文件的路径含有Ringtones,则认为它是铃声,并将其在database的is_ringtone这个属性的栏位置为1,RingtonePickerActivity的初始铃声列表就是这些is_ringtone属性为1的资源

铃声列表查询铃声时,使用的过滤条件就是is_ringtone 为1的铃声,所以会将所有is_ringtone 为1的铃声过滤出来,Hangouts Call /Hangouts Message在应用的Ringtones目录中且is_ringtone 属性为1,也会在“铃声列表“中被过滤出来因此Hangouts Call.ogg /Hangouts Message.ogg会出现在ringtones中,出现在Notification中是同样的原因。
可以去除Hangouts Call /Hangouts Message显示在初始铃声列表:
frameworks / base/media/java/android/media/MediaScanner.java

//ADD BEGIN
private static final String SYS_RINGTONES_DIR = "system/media/audio/ringtones/";
private static final String SYS_NOTIFICATIONS_DIR = "system/media/audio/notifications/";
//ADD END
......
public Uri doScanFile(String path, String mimeType, long lastModified,long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {Uri result = null;try {...if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {if (noMedia) {result = endFile(entry, false, false, false, false, false);} else {String lowpath = path.toLowerCase(Locale.ROOT);//MOD BEGINboolean ringtones = (lowpath.indexOf(SYS_RINGTONES_DIR) > 0);boolean notifications = (lowpath.indexOf(SYS_NOTIFICATIONS_DIR) > 0);//MOD ENDboolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||(!ringtones && !notifications && !alarms && !podcasts);......

Ringtone的两种类型三种形式相关推荐

  1. 辨别DVI接口连接线三种类型五种规格

    DVI(Digital Visual Interface),即数字视频接口.它是1999年由Silicon Image.Intel(英特尔).Compaq(康柏).IBM.HP(惠普).NEC.Fuj ...

  2. StatsD 五种类型数据发送形式拟测试

    statsd 五种类型数据发送形式拟测试 StatsD Metric Types Counting gorets:1|c This is a simple counter. Add 1 to the ...

  3. htc one android版本,四种版本三种双卡 行货版HTC One发布

    四种版本三种双卡 行货版HTC One真机试玩 和国际版HTC One不同的是,中国大陆的用户会意外的发现,行货版的HTC One不仅支持中国的三大3G网络,而且均增加了双卡双待的功能,当然还有一个支 ...

  4. html文档类型三种,XHTML DTD三种文件类型声明

    XHTML 1.0 的三种 XML 文档类型 XHTML 1.0 规定了三种 XML 文档类型,以对应上述三种 DTD. XHTML 1.0 Strict 严格 如果您打算严格使用层叠样式表(CSS) ...

  5. Redis五大基本类型三种特殊数据类型事务操作(悲观锁,乐观锁)

    Redis五大基本类型 Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件.它支持多种类型的数据 结构,如字符串(strings),散列(hashes) ...

  6. html的文档类型三种,XHTML文档类型

    xhtml1.0支持三种DTD(文档类型定义)声明:过渡性(Transitional).严格型(Strict)和框架型(Frameset). 过渡型 过渡型文档类型对于标签和属性的语法要求不是很严格, ...

  7. HTML中怎样把文字分两栏显示,word设置一页分两栏的三种方法

    我们在阅读报纸的时候,经常看到分栏的现象,这就是通过Word当中的"分栏"功能进行设置的,那么下面就由学习啦小编给大家分享下word设置一页分两栏的技巧,希望能帮助到您. word ...

  8. 矢量数编码有哪几种类型_6种最理想的编码工作(以及吸引每个人的类型)

    矢量数编码有哪几种类型 by David Venturi 大卫·文图里(David Venturi) 6种最理想的编码工作(以及吸引每个人的类型) (The 6 most desirable codi ...

  9. SQL 审核到底审了个什么 ? 三种角度三种格局

    最近在搞SQL 审核的工作,从开始到目前有3个月的时间, 随着时间的推移从想法很简单认为这个事情很简单,到目前 的认知,还是希望能分享一下. 首先SQL审核到底是从技术入手,还是从规范入手,甚至从 管 ...

最新文章

  1. Script:优化crs_stat命令的输出
  2. 2020年最全最简单KMP算法讲解
  3. 机器学习实战之k-近邻算法
  4. python现有两个磁盘文件a和b_有两个磁盘文件A和B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列), 输出到一个新文件C中Python实例...
  5. Python Revisited Day 07 (文件处理)
  6. 张一鸣:做CEO要避免理性的自负
  7. pom.xml 如果使用 mvn exec:exec 命令运行项目
  8. 源码编译安装PHP7.4,解决openssl,libxml2,libcurl依赖的问题
  9. html添加兄弟元素,jquery插入兄弟节点的操作方法
  10. python包管理多个版本,python多版本以及各种包管理
  11. JDBC与数据库连接池
  12. Win10系统怎么映射网络驱动器?
  13. CEH学习笔记之渗透测试框架
  14. 刚刚,华为发布白皮书,重新定义智慧园区!
  15. 各国市场分析(越南,智利)
  16. 透明网桥算法c++实现
  17. 甘超波:NLP潜意识和意识
  18. Clojure入门教程
  19. 信念、信仰、理想、梦想
  20. 端游开发用什么技术可以让用户更短时间内体验游戏?端游分发...

热门文章

  1. c语言复数运算 除法,c语言 复数的运算
  2. CMU 15-445/645 Lab3-Query Execution
  3. 老子·道德经白话文解释
  4. 用模拟器在电脑上玩王者荣耀手游最流畅教程
  5. linux入门常用知识点part1(干货系列小郭学习Linux的第一天)
  6. 如果你看不懂KMP算法,那就看一看这篇文章( 绝对原创,绝对通俗易懂)
  7. c语言.h文件实例,C 语言项目中.h文件和.c文件的关系
  8. Android 无线调试+检测usb外部设备插入并打开app
  9. 多旋翼飞行器设计与控制·Pixhawk4以及外部设备接线(笔记004)
  10. 从红包到支付-----支付宝还是微信