`
u011721609
  • 浏览: 46480 次
社区版块
存档分类
最新评论

Android设置铃声分析

 
阅读更多

代码其实没有几行,这里简单记录下学习的过程.

Android系统启动时会扫描系统与SD卡中的对媒体文件,分别存入数据库sqlite中,以contentProvider的形式对外提供服务

路径:/data/data/com.android.providers.media/databases/XXX...

可以看到有2个db文件, 一个是系统的,一个是sd卡里的

用SQLite Expert打开internal.db,部分截图如下:

这里面记录了音频audio、视频video、图片images的相关数据信息,我们以音频audio为例,蓝色部分audio_meta就是audio数据表,打开之后就可以看到详细信息了,里面列出了系统内部的所有音频文件,各个字段在android.provider.MediaStore中都定义有相应的常量,如id ---MediaStore.Audio.Media._ID.

而这里面有想说下这四个字段

含义在源码里都有说明,看了一遍数据,发现这四个字段同时有且仅有一个字段为1,也就是对于一个多媒体文件只能是这四种中的一种,默认为0,如果是某种类型,则android系统默认置为1,所以也就明白了为什么很多扫描系统通知或者来电铃声的示例代码中,都会有一个类似的条件语句:is_notification = 1.

如:


/**
     * 扫描系统内部通知铃声
     */
    private void scannerMediaFile() {
        ContentResolver cr = this.getContentResolver();
        Cursor cursor = cr.query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
                new String[] { MediaStore.Audio.Media._ID,
                        MediaStore.Audio.Media.DATA,
                        MediaStore.Audio.Media.TITLE }, "is_notification != ?",
                new String[] { "0" }, "_id asc");

        if (cursor == null) {
            return;
        }

        while (cursor.moveToNext()) {
            data.add(cursor.getString(1));
        }
    }


这里 is_notification != 0,效果是一样的,除非哪天google再定义个2, 3 ......

上面扯了些其他的,关于设置铃声的方法,系统提供了一个铃声管理器android.provider.RingtoneManager,其中提供了获取与设置铃声的API

如:Uri uri = RingtoneManager.getActualDefaultRingtoneUri(MediaActivity.this, RingtoneManager.TYPE_NOTIFICATION);可以获取到当前系统的通知铃声uri

第二个参数可以指定获取的铃声类型,还有其他的TYPE_RINGTONE,TYPE_ALARM,TYPE_ALL

设置铃声的API:

RingtoneManager.setActualDefaultRingtoneUri(MediaActivity.this,
                        RingtoneManager.TYPE_NOTIFICATION, Uri.parse(data.get(position)));

第二个参数同上,最后一个是指定一个新的Uri, 这里的data.get(position)就是在上面的扫描代码扫描出的所有通知铃声path路径中选泽一个,然后在解析成一个URI对象传入即可

那么android是如何获取指定类型的系统铃声呢?

这涉及到另一个类android.provider.Settings

相关源码如下:

public static Uri getActualDefaultRingtoneUri(Context context, int type) {
//根据指定的类型获取Settings类中对应的类型,这里RingtoneManager.TYPE_NOTIFICATION对应的为Settings.System.NOTIFICATION_SOUND,其实也就是下面所说的system表中的一个name字段名
        String setting = getSettingForType(type);
        if (setting == null) return null;
//调用Settings类中静态内部类System中的相应方法
        final String uriString = Settings.System.getString(context.getContentResolver(), setting);
        return uriString != null ? Uri.parse(uriString) : null;
    }


public synchronized static String getString(ContentResolver resolver, String name) {
//MOVED_TO_SECURE是System类中定义的一个hashSet集合,在Android系统启动时,会初始化30(目前是30)条涉及系统安全的设置数据(如果http代理设置,wifi相关设置),并且存入数据库中,与多媒体的db不同,系统默认存放在settings.db中,路径为/data/data/com.android.providers.settings/databases,具体是存放在settings.db数据库实例的secure表中,用工具打开,可以看到此表中恰好有30条数据。说了那么多,其实这里是检查你所指定的类型也就是db中的字段在不在这个集合中,如果在,则会调用Settings类中的另一个静态内部类Secure中的getString(...)方法
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, returning read-only value.");
                return Secure.getString(resolver, name);
            }
//如果不在那个涉及系统安全的设置集合中,则调用Settings中定义的一个缓存类NameValueCache中的getString(...)
            if (sNameValueCache == null) {
                sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI,
                                                     CALL_METHOD_GET_SYSTEM);
            }
            return sNameValueCache.getString(resolver, name);
        }

//NameValueCache中getString()方法部分代码
Cursor c = null;
            try {
//mUri == "content://settings/system"在NameValueCache初始化时赋值,指定查询的是settings.db中的system表,同理上面提到的Secure类的getString(...)中调用的也是这个缓存类的同名方法,只不过mUri被指定为查询secure表(这2个表中除了id,只有name与value2个字段,分别指定设置的类型与对应的值)
                c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
                             new String[]{name}, null);
                if (c == null) {
                    Log.w(TAG, "Can't get key " + name + " from " + mUri);
                    return null;
                }

                String value = c.moveToNext() ? c.getString(0) : null;
                synchronized (this) {
//查询完讲name/value键值对放入mValues集合中,当然如果这个集合中已经存在这个键值对,那么也就不会执行这段操作db的代码了
                    mValues.put(name, value);
                }

settings.db结构如下:

上面示例中指定的TYPE_NOTIFICATION的数据如下(蓝色部分):

最后返回的就是file:///..........这个String数据,再转化成URI返回给调用者

OK,那么设置铃声的API, setAc.......执行的过程也类似:

public static boolean putString(ContentResolver resolver, String name, String value) {
//这里依然是检查设置的类型是否涉及到系统预置的安全设置集合,如果是,则直接返回false
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, value is unchanged.");
                return false;
            }
//这里执行的是另一个静态内部类NameValueTable中的方法
            return putString(resolver, CONTENT_URI, name, value);
        }

protected static boolean putString(ContentResolver resolver, Uri uri,
                String name, String value) {
            // The database will take care of replacing duplicates.
            try {
                ContentValues values = new ContentValues();
                values.put(NAME, name);
                values.put(VALUE, value);
//指定类型name与相应value插入db的system表中,如果表中已经存在指定的类型字段怎么办? 请看上面的源码注释...
                resolver.insert(uri, values);
                return true;
            } catch (SQLException e) {
                Log.w(TAG, "Can't set key " + name + " in " + uri, e);
                return false;
            }
        }

最后总结下,从整个过程可以看到android系统的一些设计思想

1,设置铃声之前,要先知道有哪些系统铃声,所以需要扫描,android提供了xxx.media这个contentProvider为此服务,对应的数据库为internal.db/external-xx.db

2,拿到铃声,真正需要设置的时候,提供了Setting类管理这个过程,其对应的数据库为settings.db

  2.1 首先检查是否涉及到系统的一些安全设置参数,这里定义了Secure类来管理,如果涉及到系统安全,那么又分为两种情况:

    2.1.1如果是查询,则操作secure 表查询

    2.1.2 如果是写操作,则直接return

  2.2 不涉及到系统安全,就属于正常设置,接着定义了System类管理

3,查询操作的实际操作类NameValueCache, 其中定义了

  缓存name/value键值对的集合,避免每次操作都去操作数据库

  可以由调用者指定的uri,便于根据uri决定去操作哪张表

以及写操作的NameValueTable类,因为写操作涉及到id, 所以继承了BaseColumns类


分享到:
评论

相关推荐

    Android铃声设置软件源代码

    本文将详细介绍Android铃声设置软件源代码的相关知识点,以及如何实现此类功能。 首先,我们需要了解Android的声音框架。Android的声音管理主要由AudioService负责,它是一个系统服务,提供了对音频硬件的访问和...

    Android手机铃声软件源码.zip

    学习和分析这个源码可以帮助开发者理解如何在Android平台上实现铃声管理功能,同时也能提高对Android系统API的使用技巧。对于初学者来说,这是一个很好的实践项目,可以学习到如何处理多媒体文件、管理用户界面以及...

    Android与蓝牙耳机建立连接的分析

    通过以上分析可以看出,Android系统与蓝牙耳机之间的连接建立过程涉及多个关键步骤:注册Profile、监听特定动作、根据动作采取相应措施(如建立或断开连接)。理解这些机制对于开发支持蓝牙功能的应用程序非常重要。...

    android设置系统音量、媒体音量Demo

    本文将深入探讨如何在Android中实现这一功能,以"android设置系统音量、媒体音量Demo"为例,我们将分析源码并讲解核心知识点。 1. **音量管理API** Android提供了`AudioManager`类来管理和控制设备的音量。它包含...

    Android锁屏与解屏相关代码分析

    - 从右向左滑动:会调用 `mAudioManager.setRingerMode()` 设置铃声模式,并更新右侧的声音图标。 - 从左向右滑动:会调用 `mCallback.goToUnlockScreen()` 进入解锁界面。 #### 三、解锁逻辑与组件关系 ##### 1...

    Android 设置情景模式源码.zip

    在Android系统中,情景模式是一种方便...综上所述,这个“Android 设置情景模式源码.zip”可能包含了以上所有知识点的实现,通过学习和分析源代码,开发者能够更好地理解如何在Android平台上开发和定制情景模式功能。

    Android电话模块分析.pdf

    Android 电话模块分析 Android 电话模块是 Android 系统中的一部分,负责处理电话相关的事件和信息。电话模块的主要组件包括 Phone 应用、Telephony 框架层和 CallManager。 Phone 应用是 Android 系统中的一个...

    Android 设置情景模式源码.rar

    12. **Android的AudioManager**:可能涉及到调整音量和铃声设置,这需要与AudioManager服务交互。 13. **Android的LocationService**:在某些情况下,情景模式可能基于地理位置自动切换,例如,当用户进入或离开...

    Android 手机铃声软件源码-IT计算机-毕业设计.zip

    通过分析这个源码,学生不仅能学习到Android应用开发的基本技巧,还能了解到实际项目中的一些最佳实践。这将有助于他们理解和完成自己的毕业设计,甚至撰写相关的学术论文。在深入研究源码的过程中,遇到不熟悉的...

    Android 手机铃声软件源码.zip

    Android手机铃声软件源码的分析与研究是一项深入了解Android应用开发的重要实践。这份源码提供了一个完整的Android应用实例,专门用于管理与设置手机铃声,是学习和理解Android音频处理、媒体库操作以及用户界面设计...

    Android源码AudioManager和RingerManager分析文档

    在Android源码的基础上分析 音频文件的的扫描,系统铃声的管理以及情景模式的切换

    android电话系统数据流程分析

    ### Android电话系统数据流程分析 #### 一、电话系统基本功能与管理机制 在深入了解Android电话系统的内部工作原理之前,我们需要先明确一个电话系统的基本功能。根据提供的描述,电话系统的核心功能可以归纳为: ...

    Android玲闹钟

    通过分析"DeskClockApp-4-10"源码,开发者不仅可以掌握上述技术点,还能了解到如何优化用户体验,如提供不同的闹钟音效选择、自定义振动模式、以及灵活的重复设置等。此外,学习源码还可以帮助开发者理解Android的...

    Android 手机铃声软件源码.rar

    通过分析这个Android手机铃声软件的源码,开发者不仅可以学习到如何在Android平台上实现一个完整的应用,还能深入理解Android系统的多媒体处理、用户界面设计以及权限管理等方面的知识,对于提升Android开发技能...

    Android实现手机音量最大值限制

    Android有多个音量流(Stream),如媒体音量、闹钟音量、铃声音量等,每个流有自己的独立调节和限制。开发者通常需要使用AudioManager类来操作这些音量流。 1. **AudioManager的使用**: - `getStreamMaxVolume...

Global site tag (gtag.js) - Google Analytics