系统设置铃声从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; } }
- 系统设置铃声从mk到显示
- 调用系统铃声设置
- 调用系统铃声设置
- 设置系统铃声
- 设置SD卡中的铃声后拔出SD卡铃声显示为未知铃声
- andriod4.0如何设置系统默认铃声
- 我的Android进阶之旅------>Android系统设置默认来电铃声、闹钟铃声、通知铃声
- 设置铃声
- 设置铃声
- 【日历】铃声设置为SDcard铃声后卸载SDcard,提示音铃声显示为数字事件响应时无铃声输出
- 如何获取和设置android系统铃声和音量大小
- 如何获取和设置android系统铃声和音量大小
- android获取系统设置的铃声并播放
- 通过AudioManager 设置调整系统各项音量(铃声 媒体等)
- 通过AudioManager 设置调整系统各项音量(铃声 媒体等)
- 获取设置android系统手机的铃声和音量
- 从Activity跳转到系统的各个设置页面
- 从android应用程序跳转到系统的各个设置页面
- Android Https 相关完全解析 当OkHttp遇到Https
- 足球控(1) PagerSlidingTabStrip用法及解析
- Fragment执行SystemWebView,CordovaPlugin插件中onActivityResult()不执行
- Keepalived + nginx实现高可用性和负载均衡
- Js判断键盘按键
- 系统设置铃声从mk到显示
- android 按钮防止连续点击防止按钮重复点击
- MD5加密
- 关于uIP移植以及部分特性解析和勘误
- java继承是实现
- csdn网址大全
- Linq To Entity多条件or查询处理
- C语言概述
- springmvc