• 将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

         

  • 相关阅读:
    blender+threejs
    170112、solr从服务器配置整合到项目实战
    170111、MapperScannerConfigurer处理过程源码分析
    170110、Spring 事物机制总结
    170109、JSONP是什么
    170106、用9种办法解决 JS 闭包经典面试题之 for 循环取 i
    170105、MySQL 性能优化的最佳 20+ 条经验
    170104、js内置对象与原生对象
    170103、Redis官方集群方案 Redis Cluster
    161230、利用代理中间件实现大规模Redis集群
  • 原文地址:https://www.cnblogs.com/wangmengran/p/7525190.html
Copyright © 2020-2023  润新知