Set ringtones for Android

Source: Internet
Author: User


 
There are actually a few lines of code. Here we will simply record the learning process.
When the Android system starts, It scans the system and SD card for media files, stores them in the sqlite database, and provides external services in the form of contentProvider.
Path:/data/com. android. providers. media/databases/XXX...

We can see two db files, one in the system and the other in the SD card.
Use SQLite Expert to open internal. db, as shown in the following section:

The audio, video, and image images data are recorded. We use the audio as an example. The blue audio_meta is the audio data table. After opening the table, we can see the detailed information, it lists all audio files in the system. Each field is in android. provider. mediaStore defines corresponding constants, such as id --- MediaStore. audio. media. _ ID.
 
Here I want to talk about these four fields.

The meaning is illustrated in the source code. After reading the data, we found that these four fields have one and only one field is 1, that is, a multimedia file can only be one of the four types. The default value is 0. If it is a type, the android system defaults to 1, therefore, I understand why many sample codes for scanning system notifications or calling ringtones have a similar condition statement: is_notification = 1.
For example:
 

/**
* Scan the system for internal notification ringtones
*/
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 google defines another 2, 3 ......
 
The system provides a ringtone manager android. provider. RingtoneManager, which provides APIs for obtaining and setting ringtones.
For example, Uri uri = RingtoneManager. getActualDefaultRingtoneUri (MediaActivity. this, RingtoneManager. TYPE_NOTIFICATION); you can get the notification ringtone uri of the current system.
The second parameter can be used to specify the retrieved ringtone type. Other types include TYPE_RINGTONE, TYPE_ALARM, and TYPE_ALL.
Set the ringtone API:
RingtoneManager. setActualDefaultRingtoneUri (MediaActivity. this,
RingtoneManager. TYPE_NOTIFICATION, Uri. parse (data. get (position )));
The second parameter is the same as above. The last parameter is to specify a new Uri. get (position) is to select one of all notification ringtones scanned by the scan code above, and then pass in the path parsed into a URI object.
 
So how does android get system ringtones of the specified type?
This involves another android. provider. Settings class.
The source code is as follows:
 
Public static Uri getActualDefaultRingtoneUri (Context context, int type ){
// Obtain the corresponding type in the Settings Class Based on the specified type. Here, RingtoneManager. TYPE_NOTIFICATION corresponds to Settings. System. icationication_sound, which is actually a name field name in the following system table.
String setting = getSettingForType (type );
If (setting = null) return null;
// Call the corresponding method www.2cto.com in the static internal class System of the Settings class.
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 is a set of hashsets defined in the System class. When the Android System is started, 30 (currently 30) sets of data related to System security will be initialized (if the http proxy is set, wifi settings), and stored in the database. Unlike multimedia databases, the system is stored in settings by default. in db, the path is/data/com. android. providers. settings/databases, which are stored in settings. open the secure table of the db database instance with a tool and you can see that this table has exactly 30 data records. If so, check that the database field of the specified type is not in this set, it will call getString (...) in another static internal class Secure in the Settings class (...) 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 it is not in the system security setting set, call getString (...) in NameValueCache, a cache class defined in Settings (...)
If (sNameValueCache = null ){
SNameValueCache = new NameValueCache (SYS_PROP_SETTING_VERSION, CONTENT_URI,
CALL_METHOD_GET_SYSTEM );
}
Return sNameValueCache. getString (resolver, name );
}
 
 
// Code of the getString () method in NameValueCache
Cursor c = null;
Try {
// MUri = "content: // settings/system" is assigned a value during NameValueCache initialization, specifying that settings is queried. the system table in db is also the getString (...) of the Secure class mentioned above (...) the same name method of the cache class is called, but mUri is specified as the query secure table (the two tables have only the name and value2 fields except the id field, specify the type and value respectively)
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 ){
// After querying the lecture name/value Key-value pair, put it into the mValues collection. Of course, if this key-value pair already exists in this collection, the database code of this operation will not be executed.
MValues. put (name, value );
}
 
The structure of settings. db is as follows:
 
The data of the specified TYPE_NOTIFICATION in the preceding example is as follows (in blue ):

The final returned data is file: // ...... This String data, which is converted into a URI and returned to the caller.
 
OK, so the process of setting the ringtone API, setAc ...... is similar:
 
 

Public static boolean putString (ContentResolver resolver, String name, String value ){
// Check whether the set type involves the preset security setting set. If yes, false is returned 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;
}
// The method in the static internal class NameValueTable is executed here.
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 );
// Insert the specified type name and corresponding value into the database system table. What if the specified type field already exists in the table? Please refer to the above source code comment...
Resolver. insert (uri, values );
Return true;
} Catch (SQLException e ){
Log. w (TAG, "Can't set key" + name + "in" + uri, e );
Return false;
}
}
 
 
Finally, we can see some design ideas of the android system from the whole process.
1, set the ringtone before, to precognition which 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. The Setting class management process is provided when you really need to set the ringtone. The corresponding database is settings. db.
2.1 First, check whether some System Security Settings parameters are involved. Here the Secure class is defined for management. If system security is involved, there are two situations:
2.1.1 if the query is performed, perform the secure Table query.
2.1.2 if it is a write operation, return directly
2.2 does not involve System security, it is a normal setting, and then defines the System class management.
3. The actual operation class NameValueCache of the query operation, which defines
Cache the set of name/value Key-value pairs to avoid operations on the database each time.
The uri specified by the caller is used to determine which table to operate based on the uri.
And the NameValueTable class of the write operation. Because the write operation involves the id, It inherits the BaseColumns class.

 

From my remarks _ Mo


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.