将SD卡的音频设置为手机铃声后删除,手机铃声没有恢复到默认的问题
1. Android7.0,将存储卡中MP3设置为铃声,删除该MP3后,settings中的铃声没有变化,来电铃声也没有变化。
原因:android7.0的新特性
google 默认如此设计,在选择铃声的过程中,会将删除的铃声进行缓存,在删除铃声后,播放为缓存文件
1. google 目前将铃声分为actual default ringtone和cache ringtone,前者以ringtone为key将文件uri存储在xml文件里,后者是以stream file的形式存储在 ringtone_cache 的resource中。
2. 在铃声初始化的时候,铃声是初始化在actual default ringtone里,这个是可变的。不再是N版本之前把default铃声写死。
3. 设置铃声时,会同时写actual default ringtone 和 ringtone_cache。
4. 响铃时,mediaplayer.java会优先播放ringtone_cache里的stream resource文件,所以就算原音乐档被删除,依旧会响该备份铃声。
5. 闹铃、通知音等,原理同上。
解决办法:如果需要在删除MP3后将来电铃声恢复为默认铃声,可以这么做:
1.从settings中进入铃声选择界面,会调用getActualDefaultRingtoneUri,获取当前的铃声uri。那么我们需要在每次获取uri的时候,进行判断,该uri的音乐是否还存在。判断方法:
public static boolean isRingtoneExist(Context context, Uri uri) {
if (uri == null) {
Log.e(TAG, "Check ringtone exist with null uri!");
return false;
}
boolean exist = false;
try {
AssetFileDescriptor fd = context.getContentResolver().openAssetFileDescriptor(uri, "r");
if (fd == null) {
exist = false;
} else {
fd.close();
exist = true;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
exist = false;
} catch (IOException e) {
e.printStackTrace();
exist = true;
}
Log.d(TAG, uri + " is exist " + exist);
return exist;
}
public static boolean isRingtoneExistByQueryDb(Context context, Uri uri){
if (uri == null) {
Log.e(TAG, "isRingtoneExistByQueryDb --> Check ringtone exist with null uri!");
return false;
}
boolean exist = false;
try {
Cursor cursor = context.getContentResolver().query(uri
,new String[]{MediaStore.Files.FileColumns.DATA},null,null,null);
if (cursor != null && cursor.moveToFirst()) {
int path_index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA);
String path = cursor.getString(path_index);
Log.d(TAG,"isRingtoneExistByQueryDb path = " + path);
if(path != null && !"".equals(path)){
exist = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG,"isRingtoneExistByQueryDb " + uri + " is exist = " + exist);
return exist;
}
代码路径:/frameworks/base / media/java/android/media/RingtoneManager.java
如果该uri音乐已经不存在,那么将默认uri设置为铃声。由于7.0的默认铃声不再写死,是可变的(亲测是这样,但没具体看是怎么做的),因此我们需要自己将第一次开机时读到的默认uri存起来。
private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
ContentResolver cr = mContext.getContentResolver();
String existingSettingValue = Settings.System.getString(cr, settingName);
// if (TextUtils.isEmpty(existingSettingValue)) {
// final Uri settingUri = Settings.System.getUriFor(settingName);
// final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId);
// RingtoneManager.setActualDefaultRingtoneUri(mContext,
// RingtoneManager.getDefaultType(settingUri), ringtoneUri);
// /// M: Adds log to debug setting ringtones.
// if (DEBUG) {
// Log.v(TAG, "setSettingIfNotSet: name="
// + settingName + ",value=" + rowId);
// }
// }
if (TextUtils.isEmpty(existingSettingValue)) {
// Set the setting to the given URI
Settings.System.putString(mContext.getContentResolver(), settingName,
ContentUris.withAppendedId(uri, rowId).toString());
/// M: Adds log to debug setting ringtones.
Log.v(TAG, "setSettingIfNotSet: name=" + settingName + ",value=" + rowId);
} else {
/// M: Adds log to debug setting ringtones.
Log.e(TAG, "setSettingIfNotSet: name=" + settingName + " with value=" + existingSettingValue);
}
}
代码路径:/frameworks/base / media/java/android/media/MediaScanner.java
该settingsProvider字段是我们自己定义的,在RingtoneManager.java中。
/// M: Add for store and get default ringtone @{
/**
* M: The key used to store the default ringtone of voice call.
* @hide
* @internal
*/
public static final String KEY_DEFAULT_RINGTONE = "mtk_audioprofile_default_ringtone";
/**
* M: The key used to store the default notification sound.
* @hide
* @internal
*/
public static final String KEY_DEFAULT_NOTIFICATION = "mtk_audioprofile_default_notification";
/**
* M:The key used to store the default alarm sound.
* @hide
*/
public static final String KEY_DEFAULT_ALARM = "mtk_audioprofile_default_alarm";
/// @}
public static Uri getDefaultRingtoneUri(Context context, int type) {
Uri defaultUri = null;
String uriString = null;
ContentResolver resolver = context.getContentResolver();
switch (type) {
case TYPE_RINGTONE:
uriString = Settings.System.getString(resolver, KEY_DEFAULT_RINGTONE);
break;
case TYPE_NOTIFICATION:
uriString = Settings.System.getString(resolver, KEY_DEFAULT_NOTIFICATION);
break;
case TYPE_ALARM:
uriString = Settings.System.getString(resolver, KEY_DEFAULT_ALARM);
break;
default:
Log.e(TAG, "getDefaultRingtoneUri with unsupport type!");
return null;
}
defaultUri = (uriString == null ? null : Uri.parse(uriString));
Log.d(TAG, "getDefaultRingtoneUri: type = " + type + ", default uri = " + defaultUri);
return defaultUri;
}
那么最后,就可以在getActualDefaultRingtoneUri()中进行判断啦!
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
setting, context.getUserId());
try{
boolean isExist = isRingtoneExist(context, Uri.parse(uriString)) || isRingtoneExistByQueryDb(context, Uri.parse(uriString));
Log.d(TAG,"getActualDefaultRingtoneUri isExist = "+isExist);
if (uriString != null && !isExist){
Log.i(TAG, "Get actual default setdefaultURi= " + uriString);
Uri defaultUri = getDefaultRingtoneUri(context,type);
setActualDefaultRingtoneUri(context,type,defaultUri);
return defaultUri;
}
Log.d(TAG,"getActualDefaultRingtoneUri 2222 uriString = "+uriString);
}catch(Exception ex){
Log.d(TAG, ex.getMessage());
}
Log.i(TAG, "Get actual default ringtone uri= " + uriString);
return uriString != null ? Uri.parse(uriString) : null;
}
============================================================
另外多说一嘴,怎么样可以直接在settings中的铃声选择里,加上存储卡音乐的选择呢(回想起在zs工作的时候,直接把铃声选择做到了settings里,可是埋了很大的坑)
/// M: Get whether to show the 'More Ringtones' item
mHasMoreRingtonesItem = intent.getBooleanExtra(
RingtoneManager.EXTRA_RINGTONE_SHOW_MORE_RINGTONES, true);
原生的参数是false,改成true即可,直接的接口可以用,敲方便!
代码路径:packages/providers/MediaProvider / src/com/android/providers/media/RingtonePickerActivity.java
将SD卡的音频设置为手机铃声后删除,手机铃声没有恢复到默认的问题的更多相关文章
- android 读写sd卡的权限设置
原文:android 读写sd卡的权限设置 在Android中,要模拟SD卡,要首先使用adb的mksdcard命令来建立SD卡的镜像,如何建立,大家上网查一下吧,应该很容易找到,这里不说这个问题. ...
- am335x sd卡启动系统参数设置
首先直接记录结果 在u-boot 中修改参数 #define AUTO_UPDATESYS */ 直接把这个参数注释掉. 这个参数是原来用来升级nor flash 启动系统设置的一个参数,也就是说, ...
- sd卡无法启动及zc706更改主频后可以进入uboot无法启动kernel的坑
好长的标题 +_+ 1.sd卡无法启动 起因:kernel底下通过dd测试速度,擦写了sd卡,再启动时发现无法启动 于是重新格式化,再将BOOT.bin 相关dtb u-rootfs zImage和u ...
- 第36章 SDIO—SD卡读写测试
第36章 SDIO—SD卡读写测试 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/f ...
- 第36章 SDIO—SD卡读写测试—零死角玩转STM32-F429系列
第36章 SDIO—SD卡读写测试 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/f ...
- Samsung_tiny4412(驱动笔记01)----linux 3.5,U-Boot,Busybox,SD卡启动环境搭建
/*********************************************************************************** * * linux 3.5,U ...
- linux(ubuntu)下分区和格式化sd卡
我的手机sd卡需要分成两个分区,在windowxp下面死活搞不成.主要的问题是,window只认识sd卡的第一个分区.有人用修改驱动程序,让windows把sd卡认成日立的microdisk,分区和格 ...
- SPI模式下MCU对SD卡的控制及操作命令
一.前言 SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的 MCU,或者必须加入额外的SD卡控制 ...
- 图文:TF卡和SD卡的区别及什么是TF卡?什么是SD卡
小型存储设备凭借低廉的价格.多样化的品种.实用等特性大量充斥在大家身边,比如智能手机手机上.数码照相机上.游戏机上(一般是掌机)等都小型电子设备都频繁的使用到这种统称为SD的产品,比如TF卡和SD卡( ...
随机推荐
- Sigleton bj
package com.bjsxt.base; class Sigleton{ private Sigleton(){}; private static Sigleton instance = new ...
- Linux LVS_NAT DR
一.lvs-nat LVS是Linux Virtual Server的简写,意即Linux虚拟服务器.是由章文嵩博士开发的一个在内核层面的负载均衡调度器. lvs是在netfilter的INPU ...
- sublime-text3按tab跳出括号
功能 通过按tab自动跳过右括号,右引号,虽然也可以按右方向键,但离得太远按起来太麻烦 在首选项->按键绑定里添加: { "keys": ["tab"], ...
- xshell 利用密钥登录
第一步:新建用户密钥 第二步:选择加密方式,密钥长度越长越安全 第三步:设置密钥名称和密码(密码可为0,这里是密钥的密码非服务器密码) 第四步:保存公钥到本地 第五步:导出私钥到本地 第六步:将公钥和 ...
- liunx 常用命令学习笔记
通过linux 命令pwd:显示当前所在的目录ls:显示当前目录下的文件cd:切换路径 cd..返回上一级路径mkdir:新建目录rmdir:删除目录 touch:新建文件rm:删除文件 gedit: ...
- tomcat启动闪退问题
tomcat的bin->setclasspath.bat文件中 将两个set加上,并且将if not “%JAVA_HOME%”放到%JRE_HOME%上面.
- Html fieldset、legend 标签
Html fieldset.legend 标签 <html> <body> <!-- fieldset 添加圈起标题框标签 --> <fieldset> ...
- flask --- 02. 路由, 初始化配置,蓝图
一.Flask 路由 1.添加路由的方式 ① ② 实例: ① @app.route("/my_de") def detail() ② def detail() app.add_ur ...
- Java核心技术梳理-泛型
一.引言 在学习集合的时候我们会发现一个问题,将一个对象丢到集合中后,集合并不记住对象的类型,统统都当做Object处理,这样我们取出来再使用时就得强制转换类型,导致代码臃肿,而且加入集合时都是以Ob ...
- 20175317 《Java程序设计》第一周学习总结
20175317 <Java程序设计>第一周学习总结 教材学习内容总结 本周学习了Java大致的开发步骤,完成了课件自带的习题. 学习了在windows与Linux系统下不同的编译方法,掌 ...