将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

     

原文地址:https://www.cnblogs.com/wangmengran/p/7525190.html