系统设置铃声从mk到显示

来源:互联网 发布:mysql.exe一闪而过 编辑:程序博客网 时间:2024/06/08 13:44

系统默认来电铃声
作者: wangqx 日 期: 2016.6.1 QQ群 238696947

修订记录
日期 修订版本 描述 作者
2016/6/1 1.0 系统设置默认铃声显示

一、简介
本文内容以xxx(PROJECTXXX)项目,Android6.0为例,主要介绍默认铃声从在mk文件中添加ro.config.ringtone字段到系统设置中声音和振动项中手机铃声的显示。
二、mk文件介绍
1、文件修改
修改默认铃声(以下默认铃声均指来电默认铃声)的 mk文件中所在路径:

Z:\PROJECTXXX\android\device\qcom\Xxxx70\Xxxx70.mk(推荐)
Z:\PROJECTXXX\android\device\qcom\Xxxx70\hipad_config\ hipad_config.mk
Z:\PROJECTXXX\android\device\qcom\Xxxx70\hipad_config\ hipad_prop.mk

添加变量

PRODUCT_PROPERTY_OVERRIDES += \    ro.config.ringtone=Fantastic_Clang.ogg \    ro.config.ringtone_2=Jocosity.ogg \    ro.config.notification_sound=Notice.ogg \    ro.config.notification_sound_2=Curiosity.ogg \    ro.config.notification_sound_3=Curiosity.ogg \    ro.config.alarm_alert=New_Morning.ogg \    persist.sys.note_op_enable = true

2、注意事项及疑惑解答
注:以上路径Xxxx70为以项目为名称的文件夹,主要为了辨识。例:xxx项目在编译时选择项目时大家会选择21,即Xxxx70,mypro项目编译时选择项目名为M6xx,android\device\qcom\目录下会有与项目名对应的文件夹(文件夹名根据OEM厂商自定配置)。
mk文件主要记录当前要编译出的产品的信息,例版本号,项目名,基线,等设备配置信息及默认配置如默认铃声,默认数据流量开关,默认语言,默认输入法等软件配置信息。源码编译完成后会生成build.prop文件
Z:\PROJECTXXX\android\out\target\product\msm8909\system\build.prop,此文件内容为项目最终使用的默认配置信息。
小编同时在
Z:\PROJECTXXX\android\device\qcom\Xxxx70\Xxxx70.mk
Z:\PROJECTXXX\android\device\qcom\Xxxx70\hipad_config\ hipad_config.mk
Z:\PROJECTXXX\android\device\qcom\Xxxx70\hipad_config\ hipad_prop.mk
文件中设置不同的默认铃声(为ro.config.ringtone赋不同的铃声资源值),最终在build.prop文件中生成的是
Z:\PROJECTXXX\android\device\qcom\Xxxx70\Xxxx70.mk文件中的默认铃声信息,
故推荐在此文件中添加默认铃声信息。
注:并不是所有的配置信息都在此文件中添加而防止被覆盖,默认铃声之所以推荐在此文件中添加,是因为其他未知地方可能添加了默认铃声配置的信息,不同的参数在何处的mk文件中添加需开发自行斟酌。

注:mk文件中内容默认不允许有空格、换行符,换行时需添加“\”。
变量名PRODUCT_PROPERTY_OVERRIDES的由来,能不能换成其他的变量名

此变量名在Z:\PROJECTXXX\android\build\core\ product.mk中定义,是_product_var_list 数组的一个成员(小编这样理解),只需和此处对应即可。
至于为何写成ro.config.ringtone问题:
ro.config.ringtone中的ringtone能换成其他名称,只需与代码中使用处保持一致即可,ro.config.xxxx 前缀ro.config小编只知道此种写法涉及到android中权限问题,其他不知。
铃声名称Jocosity.ogg要与Z:\PROJECTXXX\android\frameworks\base\data\sounds\ringtones
来电铃声目录下的资源名相对应,Z:\PROJECTXXX\android\frameworks\base\data\sounds\目录为手机系统中使用的铃声资源,在编译过程中,会根据
AllAudio.mk文件将铃声资源copy到
Z:\PROJECTXXX\android\out\target\product\msm8909\system\media\audio目录,在手机中的目录为system\media\

三、默认铃声uri生成
本节主要讲系统扫描文件,将默认铃声资源文件对应的uri写入数据库

1、关键方法:setDefaultRingtoneFileNames()endFile()setSettingIfNotSet()2、方法详细Z:\PROJECTXXX\android\frameworks\base\media\java\android\media\MediaScanner.java中private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";/** Whether the scanner has set a default sound for the ringer ringtone. */private boolean mDefaultRingtoneSet;private boolean mDefaultRingtoneSet2;/** The filename for the default sound for the ringer ringtone. */private String mDefaultRingtoneFilename;private String mDefaultRingtoneFilename2;…(1)setDefaultRingtoneFileNamesprivate void setDefaultRingtoneFileNames() {        mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX                + Settings.System.RINGTONE);//获取铃声文件名并赋值给mDefaultRingtoneFilename变量mDefaultRingtoneFilename2 = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX                + Settings.System.RINGTONE_2);…    }注:ro.config.ringtone在代码中使用时是分开的,小编在看流程时通过命令grep  –C  1  ‘ro.config.ringtone’  .  –include=”*.java”  -rn没有搜索到结果,最后仔细想了下,有可能是分开了,花费了好长时间才找到此处。(2)endFileSystemProperties.get()方法主要用来获取系统属性FileEntry类中包含了文件的一些信息,如:格式,修改时间,路径,id等。private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications, boolean alarms, boolean music, boolean podcasts) throws RemoteException {…if (rowId == 0) {…if (mWasEmptyPriorToScan) {if (ringtones) {//扫描时,如果此文件是铃声资源文件        if ((TextUtils.isEmpty(mDefaultRingtoneFilename) ||              doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) && !mDefaultRingtoneSet) {             needToSetSettings = true;//置标示,需要设置          }          if ((TextUtils.isEmpty(mDefaultRingtoneFilename2) ||              doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename2)) && !mDefaultRingtoneSet2) {             needToSetSettings = true;          }      }}}…if(needToSetSettings) {…if (ringtones) {//扫描时,如果此文件是铃声资源文件    if (!mDefaultRingtoneSet && doesPathHaveFilename(entry.mPath,mDefaultRingtoneFilename)) {        setSettingIfNotSet(Settings.System.RINGTONE, tableUri,rowId);//将卡1铃声的uri写入数据库/* Settings.System.RINGTONE 为settings.db数据库下system表中对应的ringtone字段*//* tableUri  为扫描此文件后,此文件夹对应的uri,rowid为此文件夹下此文件对应的id,每一个文件分别对应一个rowId */        setSettingIfNotSet(Settings.System.DEFAULT_RINGTONE,tableUri, rowId);        mDefaultRingtoneSet = true; //标识默认铃声及卡1铃声Uri已经写入数据库    }    if (!mDefaultRingtoneSet2 && doesPathHaveFilename(entry.mPath,mDefaultRingtoneFilename2)) {        setSettingIfNotSet(Settings.System.RINGTONE_2,tableUri, rowId);/* Settings.System.RINGTONE 为settings.db数据库下system表中对应的ringtone_2字段*/        mDefaultRingtoneSet2 = true;//标识卡2铃声Uri已经写入数据库    }} }}(3)setSettingIfNotSetprivate void setSettingIfNotSet(String settingName, Uri uri, long rowId) {   String existingSettingValue = Settings.System.getString(mContext.getContentResolver(),settingName);   if (TextUtils.isEmpty(existingSettingValue)) {   // Set the setting to the given URI   //putString为将ContentUris.withAppendedId(uri, rowId).toString()的值写入到数据库中的settingName字段   Settings.System.putString(mContext.getContentResolver(), settingName, ContentUris.withAppendedId(uri, rowId).toString());   }}经过以上处理,default_ringtone、ringtone 、ringtone_2所对应的uri已分别写入settings.db数据库下,system表中。之所以添加default_ringtone字段是为了处理当卡1、卡2设置的自定义铃声资源被删除后,卡1、卡2的来电铃声能根据default_ringtone字段的值恢复到默认铃声。

四、设置中显示
烧机后或恢复出厂设置后,第一次开机

1、关键方法:lookupRingtoneNames()updateRingtoneNameBySim()getActualRingtoneUriBySubId()getStaticDefaultRingtoneUriBySubId()2、方法详细(1) lookupRingtoneNamesZ:\PROJECTXXX\android\packages\apps\Settings\src\com\android\settings\notification\ NotificationSettings.java用户点击设置,进入声音和振动选项时,执行Notification中的public void onResume() {…lookupRingtoneNames();…}private void lookupRingtoneNames() {    AsyncTask.execute(mLookupRingtoneNames);//异步执行mLookupRingtoneNames接口中的run方法}private final Runnable mLookupRingtoneNames = new Runnable() { @Override public void run() {    if (mMultiSimRingtonePreference_sim1 != null) {      final CharSequence summary = updateRingtoneNameBySim(mContext, RingtoneManager.TYPE_RINGTONE,0);// RingtoneManager.TYPE_RINGTONE为铃声类型//0为subId      if (summary != null) {        mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE_SIM1, summary).sendToTarget();        //使用handler机制异步跟新,向目标线程发送UPDATE_PHONE_RINGTONE_SIM1消息      }    }if (mMultiSimRingtonePreference_sim2 != null) {// updateRingtoneNameBySim根据subid获取铃声名称字串      final CharSequence summary = updateRingtoneNameBySim(mContext, RingtoneManager.TYPE_RINGTONE,1);         if (summary != null) {         mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE_SIM2, summary).sendToTarget();         //获取铃声字串后,使用handler机制异步跟新,向目标线程发送UPDATE_PHONE_RINGTONE_SIM2消息         }      }   } };@Overridepublic void handleMessage(Message msg) {      switch (msg.what) {      …      case UPDATE_PHONE_RINGTONE_SIM1:        //主线程接收到消息后设置铃声显示名称        mMultiSimRingtonePreference_sim1.setSummary((CharSequence) msg.obj);            break;        case UPDATE_PHONE_RINGTONE_SIM2:            mMultiSimRingtonePreference_sim2.setSummary((CharSequence) msg.obj);            break;           }   }(2) updateRingtoneNameBySimZ:\PROJECTXXX\android\packages\apps\Settings\src\com\android\settings\notification\ NotificationSettings.javaprivate static CharSequence updateRingtoneNameBySim(Context context, int type,int SubId) {    if (context == null) {      Log.e(TAG, "Unable to update ringtone name, no context provided");      return null;    }Uri ringtoneUri = RingtoneManager.getActualRingtoneUriBySubId(context, SubId);//关键方法,通过subId获取铃声的uri,此默认铃声uri已在MediaScanner.java类endFile()中写入数据库    CharSequence summary = context.getString(com.android.internal.R.string.ringtone_unknown);    // Is it a silent ringtone?    if (ringtoneUri == null) {       summary = context.getString(com.android.internal.R.string.ringtone_silent);    } else {         Cursor cursor = null;         try {//通过ringtoneUri 获取此ringtoneUri对应的铃声名称            if (MediaStore.AUTHORITY.equals(ringtoneUri.getAuthority())) {              // Fetch the ringtone title from the media provider              cursor = context.getContentResolver().query(ringtoneUri, new String[] { MediaStore.Audio.Media.TITLE }, null, null, null);            } else if (ContentResolver.SCHEME_CONTENT.equals(ringtoneUri.getScheme())) {             cursor = context.getContentResolver().query(ringtoneUri, new String[] { OpenableColumns.DISPLAY_NAME }, null, null, null);             }           if (cursor != null) {             if (cursor.moveToFirst()) {               summary = cursor.getString(0);             }           }        } catch (SQLiteException sqle) {            // Unknown title for the ringtone            } catch (IllegalArgumentException iae) {                // Some other error retrieving the column from the provider            } finally {                if (cursor != null) {                    cursor.close();                }            }        }        return summary;//返回默认铃声名称}(3) getActualRingtoneUriBySubIdZ:\PROJECTXXX\android\frameworks\base\media\java\android\media\RingtoneManager.javapublic static Uri getActualRingtoneUriBySubId(Context context, int subId) {        if (!(subId >= 0 &&  subId < Settings.System.MAX_NUM_RINGTONES)) {            return null;        }        String setting;       //通过subId判断是卡1还是卡x铃声        if (subId == 0) {            //subId == 0对应卡1铃声            setting = Settings.System.RINGTONE;//ringtone        } else {//ringtone_x,subId ==1对应卡2铃声,卡2铃声字段为ringtone_2            setting = Settings.System.RINGTONE + "_" + (subId + 1);        }        //getString为获取setting字串ringtone或ringtone_x        final String uriString = Settings.System.getString(context.getContentResolver(), setting);        if (uriString == null) {            return null;        }        Uri ringToneUri = getStaticDefaultRingtoneUriBySubId(context,subId);//通过传入的subId获取默认的铃声uri        Cursor cursor = null;        try {            cursor = context.getContentResolver().query(Uri.parse(uriString), null, null, null, null);            if ((cursor != null) && (cursor.getCount() > 0)) {                ringToneUri = Uri.parse(uriString);            }        } catch (SQLiteException ex) {            Log.e(TAG, "ex " + ex);        } finally {            if (cursor != null) cursor.close();        }        return ringToneUri;}(4) getStaticDefaultRingtoneUriBySubIdZ:\PROJECTXXX\android\frameworks\base\media\java\android\media\RingtoneManager.javapublic static Uri getStaticDefaultRingtoneUriBySubId(Context context,int subId) {        if (!(subId >= 0 &&  subId < Settings.System.MAX_NUM_RINGTONES)) {            return null;        }        String setting;        if (subId == 0) {//getString为获取Settings.System.DEFAULT_RINGTONE.toString()字段在数据库中的值//对应MediaScanner.java中的setSettingIfNotSet方法中的putString            final String uriString_def =                    Settings.System.getString(context.getContentResolver(), Settings.System.DEFAULT_RINGTONE.toString());            return uriString_def != null ? Uri.parse(uriString_def) : null;        } else {             final String uriString =                    Settings.System.DEFAULT_RINGTONE.toString() + "_" + (subId + 1);             return uriString != null ? Uri.parse(uriString) : null;            }        }
0 0
原创粉丝点击