Ringtone的两种类型三种形式

Ringtone 的两中类型三种形式

两种类型

指的是:external.db和internal.db中对应的MediaStore.Audio.Media.EXTERNAL_CONTENT_URI和MediaStore.Audio.Media.EXTERNAL_CONTENT_URI

三种形式

1 最常见的uri形式

content://media/external/audio/media/id 和 content://media/internal/audio/media/id
id就是其在MediaProvider中对应的数据库中的id

MediaStore.Audio.Media.EXTERNAL_CONTENT_URI---content://media/external/audio/media/id
对应的数据库:/data/data/com.android.providers.media/databases/external.db
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI---content://media/internal/audio/media/id
对应的数据库:/data/data/com.android.providers.media/databases/internal.db

authority是media

2 Settings数据库中的uri形式

content://setting/system/***

Settings.System.DEFAULT_NOTIFICATION_URI----content://setting/system/notification_sound
Settings.System.DEFAULT_RINGTONE_URI------content://settings/system/ringtone
Settings.System.DEFAULT_ALARM_ALERT_URI-----content://settings/system/alarm_alert

authority是settings

android M以前对应的数据库data\data\com.android.providers.settings\databases\这个目录下的Settings.db (如android L)

android M SettingsProvider数据库的变化,变化如下,之前系统修改的数据最后是存储在data/data/com.android.providers.settings/databases目录下,现在该目录下存放了一个backup数据库,里面的数据不是当前系统设置的全部数据,只有一部分内容,另一个是journal数据库,无数据。现在的数据库真正的数据存储目录在data/system/users/userId(我们没开启多用户,userid为0),数据存储形式不是以db的形式,如下截图,为数据三个表分别对应system,secure和global,查看相应数据可以导出对应的xml。

这里写图片描述

settings_system.xml中存储的就有content://setting/system/..,存储的value是第一种形式,所以其本质是把第一种数据uri形式存储在settings_system.xml中。

settings_system.xml 所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
settings_global.xml 包含各种各样的用户偏好系统设置;
settings_secure.xml 安全性的用户偏好系统设置,第三方APP有读没有写的权限

这里可以直接adb修改配置值,方便开发人员测试:
adb shell settings put system xxxx 1
adb shell settings get system xxx
adb shell settings put global xxx 0

3 Android 4.4以后增加了document uri

content://com.android.providers.media.documents/document/audio%3A82482
content://com.android.providers.downloads.documents/document/audio%3A82556
content://com.android.externalstorage.documents//document/audio%8N584645

authority是com.android.providers.*.documents
其DocumentsContract.getDocumentId(uri)进行String串的处理获取id转化为第一种形式,本质上是对第一种形式的包装

  if (isMediaDocument(uri)) {
       final String docId = DocumentsContract.getDocumentId(uri);
       final String[] split = docId.split(":");
       final String id = split[1];
       Uri contentUri = ContentUris.withAppendedId(
               Uri.parse("content://media/external/audio/media/"), Long.valueOf(id));
       return contentUri;
       ...

不管那种类型或形式都是下面这种格式:

content://authority/path/id

返回给RingtonePickerActivity的uri处理

返回给RingtonePickerActivity的uri如果不是第三中形式需要对uri处理转化为第一种形式

authority是settings

通过访问settings_system.xml获取对应的value,也就是存储的第一种形式的content uri的String形式

String uriString = Settings.System.getString(
         context.getContentResolver(), Settings.System.RINGTONE.toString());

authority是com.android.providers…

返回给RingtonePickerActivity的uri如果不是第三中形式需要对uri处理转化为第一种形式 authority是com.android.providers…
这种有三种,需要分别处理如下:

    /**
     * Gets the content:// URI from the given corresponding path to a file
     *
     * @param context
     * @param path
     * @return content Uri
     */
    private static Uri getContentUriWithPath(ContentResolver resolver, String path) {
        Cursor cursor = null;
        String filePath = path;
        try {
            cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    new String[] { MediaStore.Audio.Media._ID },
                    MediaStore.Audio.Media.DATA + "=? ",
                    new String[] { filePath }, null);
            if (cursor != null && cursor.moveToFirst()) {
                int id = cursor.getInt(cursor.getColumnIndex(
                        MediaStore.MediaColumns._ID));
                Uri baseUri = Uri.parse("content://media/external/audio/media");
                return Uri.withAppendedPath(baseUri, "" + id);
            } else {
                if (filePath != null) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Audio.Media.DATA, filePath);
                    return resolver.insert(MediaStore.
                            Audio.Media.EXTERNAL_CONTENT_URI, values);
                } else {
                    return null;
                }
           }
        }finally {
            if (cursor != null)
                cursor.close();
        }
    }


    public static String getDataColumn(ContentResolver resolver, Uri uri, String selection,
                                       String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };

        try {
            cursor = resolver.query(uri, projection, selection, selectionArgs,
                    null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                //Log.d(TAG, "cursor.getString(index) =  " + cursor.getString(index));
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
      }

    private Uri getContentUri(ContentResolver resolver, Uri uri){
        if (DocumentsContract.isDocumentUri(this, uri)) {
            if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String id = split[1];
                Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://media/external/audio/media/"), Long.valueOf(id));
                return contentUri;
            }else if (isExternalStorageDocument(uri)){
                //Log.d(TAG, "****ExternalStorageDocument****");
                final String docId = DocumentsContract.getDocumentId(uri);
                //Log.d(TAG, "getContentUri: docId =  " + docId);
                final String[] split = docId.split(":");
                final String type = split[0];
                String path = null;
                if ("primary".equalsIgnoreCase(type)) {
                    path = Environment.getExternalStorageDirectory() + "/" + split[1];
                    //Log.d(TAG, "getContentUri: primary   path =  " + path);
                }else{
                    path = "/storage/" + split[0] + "/" + split[1];
                    //Log.d(TAG, "getContentUri: path =  " + path);
                }
                return getContentUriWithPath(resolver,path);
            }else if (isDownloadsDocument(uri)){
                Log.d(TAG, "****DownloadsDocument****");
                final String id = DocumentsContract.getDocumentId(uri);
                //Log.d(TAG, "getContentUri ,getDocumentId: Id =  " + id);
                final Uri downloadsUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                //Log.d(TAG, "downloadsUri:" + downloadsUri.toString());
                String path = getDataColumn(resolver, downloadsUri, null, null);
                return getContentUriWithPath(resolver,path);
            }
        }
        return uri;

    }
        /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

RingtonePickerActivity的默认铃声

/platform/build / target/product/full_base.mk

PRODUCT_PROPERTY_OVERRIDES := \
    ro.config.ringtone=Ring_Synth_04.ogg \
    ro.config.notification_sound=pixiedust.ogg
    ......

RingtonePickerActivity的初始铃声列表

/platform/build / target/product/full_base.mk中会copy一部分internal ringtone

$(call inherit-product-if-exists, frameworks/base/data/sounds/AllAudio.mk)

AllAudio.mk会把audio资源copy到系统Ringtones、Notifications、Alarms目录下,也可在vendor下定制自己的铃声列表和默认铃声

在MediaScanner扫描文件时,判断到如果文件的路径含有Ringtones,则认为它是铃声,并将其在database的is_ringtone这个属性的栏位置为1,RingtonePickerActivity的初始铃声列表就是这些is_ringtone属性为1的资源

铃声列表查询铃声时,使用的过滤条件就是is_ringtone 为1的铃声,所以会将所有is_ringtone 为1的铃声过滤出来,Hangouts Call /Hangouts Message在应用的Ringtones目录中且is_ringtone 属性为1,也会在“铃声列表“中被过滤出来因此Hangouts Call.ogg /Hangouts Message.ogg会出现在ringtones中,出现在Notification中是同样的原因。
可以去除Hangouts Call /Hangouts Message显示在初始铃声列表:
frameworks / base/media/java/android/media/MediaScanner.java

//ADD BEGIN
private static final String SYS_RINGTONES_DIR = "system/media/audio/ringtones/";
private static final String SYS_NOTIFICATIONS_DIR = 
        "system/media/audio/notifications/";
//ADD END
......
public Uri doScanFile(String path, String mimeType, long lastModified,
        long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {
     Uri result = null;
     try {
     ...
         if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
             if (noMedia) {
                 result = endFile(entry, false, false, false, false, false);
             } else {
                 String lowpath = path.toLowerCase(Locale.ROOT);
                 //MOD BEGIN
                 boolean ringtones = (lowpath.indexOf(SYS_RINGTONES_DIR) > 0);
                 boolean notifications = (lowpath.indexOf(SYS_NOTIFICATIONS_DIR) > 0);
                 //MOD END
                 boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
                 boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
                 boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
                            (!ringtones && !notifications && !alarms && !podcasts);
                 ......

发布了70 篇原创文章 · 获赞 46 · 访问量 13万+
展开阅读全文

Android用RIngToneManager设置铃声无法同时设置两个以上铃声

02-04

``` public void setMyRingtone(String path) { File sdfile = new File(path); ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath()); values.put(MediaStore.MediaColumns.TITLE, sdfile.getName()); values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*"); values.put(MediaStore.Audio.Media.IS_RINGTONE, true); values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false); values.put(MediaStore.Audio.Media.IS_ALARM, false); values.put(MediaStore.Audio.Media.IS_MUSIC, false); Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath()); Uri newUri = this.getContentResolver().insert(uri, values); RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, newUri); Toast.makeText( getApplicationContext (),"设置来电铃声成功!", Toast.LENGTH_SHORT ).show(); System.out.println("setMyRingtone()-----铃声"); } //设置--提示音的具体实现方法 public void setMyNotification(String path) { File sdfile = new File(path); ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath()); values.put(MediaStore.MediaColumns.TITLE, sdfile.getName()); values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*"); values.put(MediaStore.Audio.Media.IS_RINGTONE, false); values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true); values.put(MediaStore.Audio.Media.IS_ALARM, false); values.put(MediaStore.Audio.Media.IS_MUSIC, false); Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath()); Uri newUri = this.getContentResolver().insert(uri, values); RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION, newUri); Toast.makeText( getApplicationContext (),"设置通知铃声成功!", Toast.LENGTH_SHORT ).show(); System.out.println("setMyNOTIFICATION-----提示音"); } //设置--闹铃音的具体实现方法 public void setMyAlarm(String path) { File sdfile = new File(path); ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath()); values.put(MediaStore.MediaColumns.TITLE, sdfile.getName()); values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*"); values.put(MediaStore.Audio.Media.IS_RINGTONE, false); values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false); values.put(MediaStore.Audio.Media.IS_ALARM, true); values.put(MediaStore.Audio.Media.IS_MUSIC, false); Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath()); Uri newUri = this.getContentResolver().insert(uri, values); RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM, newUri); Toast.makeText( getApplicationContext (),"设置闹钟铃声成功!", Toast.LENGTH_SHORT ).show(); System.out.println("setMyNOTIFICATION------闹铃音"); } ``` 我本地有一个文件,设置铃声时是弹出对话框,供用户选择三项。用户选三个中的任意一个都可以设置,但是选择三项就只能设置一个(好像是最后一个)。不知道是什么原理,还请各位指点迷津啊。。 问答

android RingtoneManger 问题讨论

06-30

RingtoneManger 在部分机型上设置了通知铃声无效, 例如lenovo 4.2.2 ,但是在三星的4.2.2上面设置就成功,个人有点感觉跟uri有关,但是uri都有值,想问问有大神懂这问题吗? 测试代码如下 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private File[] files ; private int i = 0 ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); File sdDir = null ; if( Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){ sdDir = new File(Environment.getExternalStorageDirectory().getPath()+"/Audio/Soundrecorder"); files = sdDir.listFiles(); } findViewById(R.id.alterRing).setOnClickListener(this); } //设置为短信铃声 static void setMyMessage(Context context, String path) { Log.d("tag","absoultpath:"+path); File sdfile = new File(path); ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath()); values.put(MediaStore.MediaColumns.TITLE, sdfile.getName()); values.put(MediaStore.MediaColumns.SIZE, sdfile.length()); values.put(MediaStore.Audio.Media.IS_RINGTONE, false); values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true); values.put(MediaStore.Audio.Media.IS_ALARM, false); values.put(MediaStore.Audio.Media.IS_MUSIC, false); Uri uri = MediaStore.Audio.Media.getContentUriForPath(path); ContentResolver cr =context.getContentResolver(); Cursor cursor = cr.query(uri,new String[]{MediaStore.MediaColumns._ID},"_data = ? ",new String[]{path},null,null); cursor.moveToFirst(); int ringtoneID = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)); Uri newUri = ContentUris.withAppendedId(uri, Long.valueOf(ringtoneID)); RingtoneManager.setActualDefaultRingtoneUri(context,RingtoneManager.TYPE_NOTIFICATION,newUri); Intent i = new Intent("com.android.mms.change.ring"); i.putExtra("newUri", uri.toString()); context.sendBroadcast(i);//发一个广播到短信模块,让短信模块自己修改自己的SharedPreferences Toast.makeText(context, "setMessage-----"+sdfile.getName()+"---------------->", Toast.LENGTH_SHORT).show(); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.alterRing : setMyMessage(MainActivity.this,files[i].getAbsolutePath()) ; i++; break; } } } 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览