The code actually does not have a few lines, here simply records the learning process.
Android system will scan the system and SD card on the media files, respectively in the database SQLite, in the form of ContentProvider to provide services
Path:/data/data/com.android.providers.media/databases/xxx ...
You can see that there are 2 db files, one is System, one is SD card
With SQLite expert open internal.db, part of the screenshot is as follows:
This recorded the audio audio, video videos, pictures images related data information, we take audio audio as an example, the blue part Audio_meta is the audio datasheet, open then you can see the details, which lists all the internal system of audio files, Each field is defined in Android.provider.MediaStore with the corresponding constant, such as ID---mediastore.audio.media._id.
And here's what I want to say about these four fields
The meaning is in the source code all have the explanation, looked at the data, found that these four fields and only one field is 1, that is, for a multimedia file can only be one of these four, the default is 0, if it is some type, then the Android system defaults to 1, So it's clear why a lot of the sample code for scanning system notifications or ringing calls has a similar conditional statement: Is_notification = 1.
Such as:
/**
* Scan system Internal notification ring
*/
code is as follows |
copy code |
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)); } } |
Here is_notification!= 0, the effect is the same, unless the day Google again define a 2, 3 ...
There's something else on it. For setting ringtones, the system provides a ringtone manager Android.provider.RingtoneManager, which provides an API for getting and setting ringtones
Such as:
The code is as follows |
Copy Code |
Uri uri = Ringtonemanager.getactualdefaultringtoneuri (Mediaactivity.this, ringtonemanager.type_notification); can get the notification ringtone URI to the current system |
The second parameter can specify the type of ringtone to be obtained, as well as other type_ringtone,type_alarm, Type_all
To set the ringtone API:
The code is as follows |
Copy Code |
Ringtonemanager.setactualdefaultringtoneuri (Mediaactivity.this, Ringtonemanager.type_notification, Uri.parse (data.get (position));
|
The second parameter is the same as the last one is to specify a new URI, where the data.get (position) is a selection of all the alert ringtones path paths scanned in the above scan code, and then the parse into a URI object is passed in
So how does Android get a specified type of system ringtone?
This involves another class of android.provider.Settings
Relevant source code is as follows:
code is as follows |
copy code |
public static Uri Getactualdefaultringtoneuri (context, int type) { / /Gets the corresponding type in the settings class according to the specified type, where ringtonemanager.type_notification corresponds to Settings.System.NOTIFICATION_SOUND, In fact, a name field name in the system table named String setting = Getsettingfortype (type ); if (setting = NULL) return null; //Call the corresponding method in the static inner class system in the settings class final String uristring = Settings.System.getString (Context.getcontentresolver (), setting); return uristring!= null? Uri.parse (uristring): null; } |
The code is as follows |
Copy Code |
Public synchronized static string getString (Contentresolver resolver, String name) { Moved_to_secure is a hashset set defined in the System class that initializes 30 (currently 30) to system-Safe settings data (if HTTP proxy settings, WiFi-related settings) and is stored in the database when the Android system starts , unlike the DB of multimedia, the system is stored in settings.db by default, and the path is/data/data/com.android.providers.settings/databases, In the secure table, which is stored in the Settings.db database instance, opened with a tool, you can see that there are exactly 30 data in this table. Say so much, in fact here is to check the type you specify is that the field in DB is not in this collection, and if it is, then the GetString (...) in the rest of the static inner class secure in the settings class is called. Method 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); } If you are not in the collection of settings that involve system security, call the GetString (...) in the cache class Namevaluecache defined in the settings. if (Snamevaluecache = = null) { Snamevaluecache = new Namevaluecache (sys_prop_setting_version, Content_uri, Call_method_get_system); } Return snamevaluecache.getstring (resolver, name); } Namevaluecache GetString () method part of code Cursor c = null; try { MUri = = "Content://settings/system" is assigned at Namevaluecache initialization, specifying that the query is the system table in Settings.db, and the same as the getstring of the secure class mentioned above ( ...) is called the same method for this cache class, except that the Muri is specified as the Query secure table (except for the ID in these 2 tables, with the name and Value2 fields, respectively, specifying the type of setting and the corresponding value) 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) { When the query is finished, the Name/value key value pair is put into the Mvalues collection, of course, if the key value pair already exists in this set, then the operation DB code will not be executed. Mvalues.put (name, value); } |
The SETTINGS.DB structure is as follows:
The data for the type_notification specified in the example above are as follows (blue section):
The last thing to return is file:///... This string data is then converted to a URI and returned to the caller
OK, so set the ringtone API, Setac ... The execution process is similar:
The code is as follows |
Copy Code |
public static Boolean putstring (Contentresolver Resolver, string name, String value) { Here is still the check whether the type of setup involves a set of security settings for the system preset, and if so, returns false directly 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; } This is another method in the static internal class namevaluetable. Return putstring (resolver, Content_uri, name, value); } Protected static Boolean putstring (Contentresolver resolver, Uri Uri, String name, String value) { The database would take care of replacing duplicates. try { Contentvalues values = new Contentvalues (); Values.put (name, name); Values.put (value, value); Specifies that the type name is in the system table with the corresponding value inserted into DB, what if the specified type field already exists in the table? Please look at the above source code comments ... Resolver.insert (URI, values); return true; catch (SQLException e) { LOG.W (TAG, "Can ' t set key" + Name + "in" + URI, E); return false; } } |
1, to set the ringtone before you know what system ringtones, so need to scan, Android provides xxx.media this contentprovider for this service, the corresponding database for internal.db/external-xx.db
2, get the ringtone, really need to set the time, provide the setting class management of this process, its corresponding database for settings.db
2.1 First check whether it involves some of the system security settings parameters, here defines the secure class to manage, if it involves system security, then divided into two situations:
2.1.1 If it is a query, operate the secure table query
2.1.2 If it is a write operation, direct return
2.2 Does not involve system security, it is a normal setting, and then the systems class management is defined
3, the actual operation of the query operation class Namevaluecache, which defines the
Cache the collection of Name/value key-value pairs to avoid manipulating the database for each operation
A URI that can be specified by the caller to make it easier to decide which table to manipulate based on the URI
and the Namevaluetable class of the write operation, because the write operation involves the ID, so inherits the Basecolumns class