標籤:with print gif 解決辦法 通知 media dex work boolean
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; }
將SD卡的音頻設定為手機鈴聲後刪除,手機鈴聲沒有恢複到預設的問題