将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;
    }
时间: 2024-11-08 22:20:53

将SD卡的音频设置为手机铃声后删除,手机铃声没有恢复到默认的问题的相关文章

SBC-7109-454 sd卡启动系统参数设置

首先直接记录结果 在u-boot 中修改参数 #define AUTO_UPDATESYS */ 直接把这个参数注释掉. 这个参数是原来用来升级nor flash 启动系统设置的一个参数,也就是说, 这个参数的存在是为了升级原来nor flash的系统. 注释掉以后,插入sd卡启动便不会自动在u-boot阶段烧写系统到nor flash上面. 注释完以后,看到下面的参数 1 #define CON \ 2 "console=ttyO0,115200n8\0" \ 3 "opt

手机短信删除了还能恢复吗+q:2100997525

百度官网认证QQ[百度唯一认证QQ:2100997525]专业破解苹果ID ,手机微信,手机号码监听,破译陌陌,QQ, 短信内容查询删除 开房登记记录 通话清单  QQ聊天记录查询删除 密码破解 邮箱以及各种聊天记录恢复与删除查询[百 度唯一认证QQ:2100997525]专业手机定位,通话清单,知己知彼,百战百胜,网站入侵等其他业务 ▌是您值得信赖的 怎么偷看別人的QQ聊天記錄?[百度唯一認証QQ:2100997525]專業破解苹果id.手机微信,破譯陌陌,QQ,郵箱以及各 種聊天記錄恢復與查

android 不打开Shared sdcard功能,内置SD卡中预制资源,删除资源,恢复出厂设置恢复

当有内置SD卡,且不打开shared sdcard功能的情况下,需要在SD卡中预置一些客户资源. 这些资源end user可见,也可删除.在资源被user删除之后,执行恢复出厂设置功能,需要恢复这些预置资源. 1. 预置同样的资源到user不可见的分区,如/system下. 在alps\vendor\mediatek\project_name\artifacts\out\target\product\your_project_name\system\ 下创建目录, 将预制资源放于此目录下,重新b

手机SD卡数据恢复,就是这么简单

手机SD卡数据恢复,虽然目前手机自身内存有多种规格能够满足用户的需求,但是还是有很多的用户会使用到SD卡,其中会存储到大量重要的数据,一旦出现误删或者格式化的操作意外,SD卡中的数据该怎么恢复呢? 手机上的重要数据一般分为照片.短信.联系人以及便签文件等,这些都是可以通过云备份的方式来进行备份的,之前有进行云备份的话,在出现误删之后可以找到备份数据进行还原的操作,如果是未备份的话,那么还是建议根据下述的教程进行SD卡的数据恢复操作: 步骤一:在电脑的常用浏览器中搜索[互盾数据恢复软件],将软件的

第36章 SDIO—SD卡读写测试

第36章     SDIO-SD卡读写测试 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege 本章参考资料:<STM32F4xx参考手册>.<STM32F4xx规格书>.库帮助文档<stm32f4xx_dsp_stdperiph_lib_um.chm>以及SD简易规格文件<Physical Layer Simplified Specificatio

Samsung_tiny4412(笔记)--&gt;linux 3.5,U-Boot,Busybox,SD卡启动环境搭建

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->linux 3.5,U-Boot,Busybox,SD卡启动环境搭建 * * 声明: * 1. 以下所有的shell命令都是在root权限下运行的; * 2. minicom(U-Boot)指的是用minicom连接开发板作为U-Boot的终端; * 3. 文中在需要往文件中

我的看法和总结----关于安卓手机上SD卡等名称和叫法的解释

因今天本小白要用到Android里面的Envirement类,来读取手机内存里面的信息. 却一直纠结在到底什么是手机内存卡,什么是内置SD卡,什么是ROM,什么是RAM...... 下面就是我的总结,写错的地方还请路过的博友们多多指教. 在我看来: 我们平常所说的内存卡在我看来可以分为两类:手机自带内存卡和小小的黑黑的TF卡(外置内存卡:可以插进手机里面的) 手机自带内存卡:这个用图来表示会更加的直观一些     TF卡:也就是我们平常在用的,卡片照相机里的,或者是以前老手机里面可以随意拔插的小

Android关于RAM、ROM、SD卡以及各种内存的区别

RAM:运行时内存.相当于PC机的内存存储,用于存储应用运行时的各种对象和变量常量等,主要作用在于提高运行速度.是唯一一种断电后数据会清除的存储器. 机身内存:相当于PC机硬盘.主要包括三块区域:ROM.内部内存和外部内存. ROM:只读型内存.此部分区域的文件只能读取,不可擦写,比如PC机C盘下面有的系统文件就是不可删除和修改的.用来存储操作系统引导类文件.这部分文件损坏,会导致手机系统无法启动和运行.此区域文件不可见. 内部内存:用来存储系统文件和应用私有文件.这部分一般是不可见的,除非获得

SPI模式下MCU对SD卡的控制及操作命令

一.前言 SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的 MCU,或者必须加入额外的SD卡控制单元以支持SD 卡的读写.然而,大多数MCU都没有集成SD 卡控制器接口,若选用SD 模式通讯就无形中增加了产品的硬件成本.在SD卡数据读写时间要求不是很严格的情况下, 选用 SPI模式可以说是一种最佳的解决方案.因为在 SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集