将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卡( ...
随机推荐
- Django的安装
##pip pip是Python的包管理工具,用于快速安装配置所需要的拓展包,能够很好的解决包之间的依赖关系 当前ubuntu 系统上有两个Python环境,使用pip3 是指定Python3的环境 ...
- ES6知识总结
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了.它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应 ...
- 精练代码:一次Java函数式编程的重构之旅
摘要:通过一次并发处理数据集的Java代码重构之旅,展示函数式编程如何使得代码更加精练. 难度:中级 基础知识 在开始之前,了解"高阶函数"和"泛型"这两个概念 ...
- flask 使用Flask-Migrate迁移数据库(创建迁移环境、生成迁移脚本、更新数据库)
使用Flask-Migrate迁移数据库 在开发时,以删除表再重建的方式更新数据库简单直接,但明显的缺陷是会丢掉数据库中的所有数据.在生产环境下,没有人想把数据都删除掉,这时需要使用数据库迁移工具来完 ...
- [转载]Javascript .then()这个方法是什么意思?
then()方法是异步执行. 意思是:就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题. 语法:promise.then(onCompleted, ...
- 论文笔记【一】Chinese NER Using Lattice LSTM
论文:Chinese NER Using Lattice LSTM 论文链接:https://arxiv.org/abs/1805.02023 论文作者:Yue Zhang∗and Jie Yang∗ ...
- Weighted Quick Union
Weighted Quick Union即: 在Quick Union的基础上对结点加权(weighted),在parent[i]基础上增加一个size[i]. 用来存储该结点(site)的所有子结点 ...
- 浅谈Cocos2d-js cc.director
在cocos2d-x里面,游戏的任何时间,只有一个场景对象实例处于运行状态,该对象可以作为当前游戏内容的整体包对象. 环境设定 进入游戏之前,导演会设置游戏的运行环境: 设置游戏视图,包含视图的投射, ...
- 扩展的GM命令
命令 说明 例子 .rl all 重载核心所有自定义数据表 .rl item 重载item_template .backup a 备份Auth数据库 .backup c 备份Charact ...
- 运行Python出错,提示“丢失api-ms-win-crt-runtime-l1-1-0.dll”
运行python时出错,提示“丢失api-ms-win-crt-runtime-l1-1-0.dll”, 上网搜了一下说是本地api-ms-win-crt-runtime-l1-1-0.dll 版本过 ...