在做Android N的项目时遇到设置SD卡里的音乐为手机铃声后,把SD卡拨出,进入设置铃声里面查看铃声显示为“未知铃声”,而且来电响铃还是设置的SD卡铃声,而不是Android M之前的默认铃声,于是研究了一下Android N的铃声问题。
在手机里面设置铃声时调用的是
protected void onSaveRingtone(Uri ringtoneUri) {
RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri);
}
getRingtoneType()决定的是手机铃声、通知铃声、闹钟铃声,ringtoneUri为铃声的URI值;
而在frameworks\base\media\java\android\media\RingtoneManager.java中的setActualDefaultRingtoneUri如下:
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
final ContentResolver resolver = context.getContentResolver();
String setting = getSettingForType(type);
if (setting == null) return;
Settings.System.putStringForUser(resolver, setting,
ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());
// Stream selected ringtone into cache so it's available for playback
// when CE storage is still locked
if (ringtoneUri != null) {
final Uri cacheUri = getCacheForType(type);
try (InputStream in = openRingtone(context, ringtoneUri);
OutputStream out = resolver.openOutputStream(cacheUri)) {
Streams.copy(in, out);
} catch (IOException e) {
Log.w(TAG, "Failed to cache ringtone: " + e);
}
}
Log.i(TAG, "Set actual default ringtone uri= " + ringtoneUri);
}
Settings.System.putStringForUser(resolver, setting, ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());保存的是此铃声在铃声数据库的uri,而
if (ringtoneUri != null) {
final Uri cacheUri = getCacheForType(type);
try (InputStream in = openRingtone(context, ringtoneUri);
OutputStream out = resolver.openOutputStream(cacheUri)) {
Streams.copy(in, out);
} catch (IOException e) {
Log.w(TAG, "Failed to cache ringtone: " + e);
}
}
是把当前的铃声copy下来保存到
/data/system_de\0\ringtones\目录下面,假如是手机铃声就保存到ringtone_cache文件里面,假如是通知铃声就保存到notification_sound_cache文件,假如是闹钟铃声就保存到alarm_alert_cache文件
而手机初始化的铃声也是通过frameworks\base\media\java\android\media\RingtoneManager.java中的setActualDefaultRingtoneUri的方法保存的在
frameworks\base\media\java\android\media\MediaScanner.java文件中的setDefaultRingtoneFileNames方法读取默认设置的值
private void setDefaultRingtoneFileNames() {
mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.RINGTONE);
mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.NOTIFICATION_SOUND);
mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.ALARM_ALERT);
/// M: Adds log to debug setting ringtones.
if (DEBUG) {
Log.v(TAG, "setDefaultRingtoneFileNames: ringtone=" + mDefaultRingtoneFilename
+ ",notification=" + mDefaultNotificationFilename
+ ",alarm=" + mDefaultAlarmAlertFilename);
}
}
而在
frameworks\base\media\java\android\media\MediaScanner.java的setSettingIfNotSet方法中保存默认设置的铃声
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);
}
} else {
Log.e(TAG, "setSettingIfNotSet: name=" + settingName
+ " with value=" + existingSettingValue);
}
}
铃声的保存就写到这里了,Android N 的铃声读取请看“Android N的铃声问题(2)”