将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卡( ...
随机推荐
- VKD224B触摸芯片调试笔记
1.通过阅读datasheet了解芯片怎么使用,一般datasheet会提供参考电路.和相应的电气参数. 通过上面的表格可以知道芯片的供电,所需电流. 这个芯片可以通过引脚选择模式.通过上面的选项设置 ...
- springMVC学习之路2-文件上传
springMVC的上传文件方式一共有两种,下面听我简单介绍一下: 1.1 首先配置springAnnotation-servlet.xml,新增一个multipartResolver处理器,并定义默 ...
- 树莓派(centos7)安装mysql
yum install mysql mysql-server 或者 yum install mariadb mariadb-server 安装完后启动mysql systemctl start mar ...
- index read-only
系统重启后,Eleastisearch6.5.0在给 Eleastisearch 更新索引的时候报了一个错误:ClusterBlockException[blocked by: [FORBIDDEN/ ...
- Ubuntu 16.04下vsftpd 安装配置实例
从https://www.linuxidc.com/Linux/2017-06/144807.htm转载 第一步:安装VSFTPD sudo apt-get install vsftpd 安装完成后启 ...
- mvc 之 配置EF+oralce
只需要在项目中加载nuGet包就可以了 操作:工具--nuGet包管理器--程序包管理器控制台 在 PM>处输入 install-package entityframework 加载sqlser ...
- 测试是否支持辨别tex公式
1.首先启动博客园公式编写支持(latex) 2.编写公式 3.结果 $a+b=5$ $c+d=7$
- ng工程升级cli版本
全局更新ng 然后在工程里 ng update @angular/cli @angular/core
- MySQL中的decimal
MySQL DECIMAL数据类型用于在数据库中存储精确的数值.我们经常将DECIMAL数据类型用于保留准确精确度的列,例如会计系统中的货币数据. 要定义数据类型为DECIMAL的列,请使用以下语法: ...
- 音乐推荐与Audioscrobbler数据集
1. Audioscrobbler数据集 数据下载地址: http://www.iro.umontreal.ca/~lisa/datasets/profiledata_06-May-2005.tar. ...