谈一谈RingtonePickerActivity
来源:互联网 发布:域名过户需要手续费吗 编辑:程序博客网 时间:2024/06/08 02:09
- Ringtone 的两中类型三种形式
- 两种类型
- 三种形式
- 最常见的uri形式
- Settings数据库中的uri形式
- Android 44以后增加了document uri
- 返回给RingtonePickerActivity的uri处理
- authority是settings
- authority是comandroidproviders
- RingtonePickerActivity的默认铃声
- RingtonePickerActivity的初始铃声列表
- Ringtone 的两中类型三种形式
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.dbMediaStore.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_soundSettings.System.DEFAULT_RINGTONE_URI------content://settings/system/ringtoneSettings.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中。
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 BEGINprivate 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 BEGIN boolean ringtones = (lowpath.indexOf(SYS_RINGTONES_DIR) > 0); boolean notifications = (lowpath.indexOf(SYS_NOTIFICATIONS_DIR) > 0); //MOD END boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0); boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0); boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) || (!ringtones && !notifications && !alarms && !podcasts); ......
- 谈一谈RingtonePickerActivity
- 谈一谈
- 谈一谈mac
- 谈一谈ORCFile
- 谈一谈Xamarin
- 谈一谈GRUB
- 谈一谈float
- 谈一谈URL
- 谈一谈mmap
- 谈一谈对象
- 谈一谈stl的iterator
- 谈一谈系统架构
- 我来谈一谈线程
- 谈一谈软件开发
- 谈一谈前端开发工程师
- 谈一谈C++抽象类
- 谈一谈《BANCS系统“十日谈”》
- 谈一谈默认构造函数
- 五月 19, 2017 8:38:28 下午 org.hibernate.proxy.pojo.javassist.JavassistProxyFactory getProxy ERROR: HHH0
- Spark RDD 与 Pandas Dataframe
- 计算机网络系列(2)之网络层Internet Protocol (IP)
- 关于eclipse缺少maven,svn,server 插件的解决办法
- 《JavaScript ES6函数式编程入门经典》使用JavaScript ES6带你学习函数式编程。
- 谈一谈RingtonePickerActivity
- 1072. 开学寄语(20)
- 小型项目程序 ERP——沙盘模拟
- android高德地图定位
- struts2 问题 Dispatcher initialization failed Unable to load configuration.
- Activity的启动模式以及onNewIntent和onConfigurationChanged这两个生命周期方法的场景
- APK安装时的过滤方式:包名白名单、证书认证
- 欢迎使用CSDN-markdown编辑器
- js小记