1. Android9.0,将存储卡中MP3设置为铃声,删除该MP3后,settings中的铃声没有变化,来电铃声也没有变化。
原因:android9.0的新特性
解决办法:如果需要在删除MP3后将来电铃声恢复为默认铃声,可以这么做:
/frameworks/base / media/java/android/media/MediaScanner.java
先在开机时候,将默认的系统铃声保存:
private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) {
if (wasRingtoneAlreadySet(settingName)) {
return;
}
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);
String defaultName = null;
switch (settingName) {
case Settings.System.NOTIFICATION_SOUND:
defaultName = RingtoneManager.KEY_DEFAULT_NOTIFICATION;
break;
case Settings.System.RINGTONE:
defaultName = RingtoneManager.KEY_DEFAULT_RINGTONE;
break;
case Settings.System.ALARM_ALERT:
defaultName = RingtoneManager.KEY_DEFAULT_ALARM;
break;
}
if (defaultName != null) {
Settings.System.putString(mContext.getContentResolver(), defaultName,
ContentUris.withAppendedId(uri, rowId).toString());
}
}
Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
}
当后续铃声不存在时候,则直接判断查找铃声:
frameworks/base / media/java/android/media/RingtoneManager.java
/**
* start to check ringtone exist
*
* @hide
*/
private 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;
}
/**
* check ringtone exist on Db
*
* @hide
*/
private 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;
}
/**
* get default ringtone uri
*
* @hide
*/
private 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;
}
/***
* finish to check ringtone exist
*/
/**
* Gets the current default sound's {@link Uri}. This will give the actual
* sound {@link Uri}, instead of using this, most clients can use
* {@link System#DEFAULT_RINGTONE_URI}.
*
* @param context A context used for querying.
* @param type The type whose default sound should be returned. One of
* {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
* {@link #TYPE_ALARM}.
* @return A {@link Uri} pointing to the default sound for the sound type.
* @see #setActualDefaultRingtoneUri(Context, int, Uri)
*/
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());
Uri ringtoneUri = uriString != null ? Uri.parse(uriString) : null;
//start to check ringtone exist
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());
}
//finish to check ringtone exist
// If this doesn't verify, the user id must be kept in the uri to ensure it resolves in the
// correct user storage
if (ringtoneUri != null
&& ContentProvider.getUserIdFromUri(ringtoneUri) == context.getUserId()) {
ringtoneUri = ContentProvider.getUriWithoutUserId(ringtoneUri);
}
return ringtoneUri;
}
当铃声不存在时候,会重新读取数据库文件找到对应的铃声,再次设置到系统中,而达到还原的效果。