1. 概述
在Android启动之后,我们通常需要根据自己的一些需要来设置一些符合我们使用习惯的属性。例如:来电铃声、锁屏时间、日期格式等等。而这些属性的设置通常是有Settings为入口,通过SettingsProvider来进行的。
2. 数据储存形式及位置
在Android5.0之前,SettingsProvider中系统设置是存储在settings.db数据库中;在Android6.0之后,SettingsProvider中系统设置改为由xml存储。改变存储方式主要是为了提高性能(400ms降低到10ms),还能为每一个用户独立储存偏好设置,同时限制了第三方app对偏好设置的写入,增加了安全性。
Android5.0之前
/data/data/com.android.providers.settings/databases/settings.dbAndroid6.0以后
/data/system/users//settings_system.xml
/data/system/users//settings_global.xml
/data/system/users//settings_secure.xml
Android M以前:
3. 数据分类
SettingsProvider对数据进行了分类,分别是Global、System和Secure三种类型:
- Global: 用户全局偏好设置
- System:用户系统偏好设置
- Secure:用户安全偏好设置
Settings.java类中分别声明了Global、Secure、System三个静态内部类,分别对应SettingsProvider中的Global、Secure、System三种数据类型。Global、System和Global类的VALIDATORS属性,可以查看各偏好设置的定义以及属性赋值过程。
4. 系统设置初始化
frameworks/base/packages/SettingsProvider/src/com/Android/providers/settings/DatabaseHelper.Java
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
在DatabaseHelper中通过三个函数来分别加载Global、System和Secure设置
- loadSystemSettings()
- loadSecureSettings()
- loadGlobalSettings()
通过读取defaults.xml对应的参数进行配置,其中支持的数据格式是
<string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
<bool name="def_auto_time">true</bool>
<integer name="def_screen_brightness">102</integer>
<fraction name="def_window_animation_scale">100%</fraction>
根据参数类型调用不同加载函数,最终通过loadSetting()最终将设置项转换为String类型存储起来
private void loadStringSetting(SQLiteStatement stmt, String key, int resid) {
loadSetting(stmt, key, mContext.getResources().getString(resid));
}
private void loadBooleanSetting(SQLiteStatement stmt, String key, int resid) {
loadSetting(stmt, key,
mContext.getResources().getBoolean(resid) ? "1" : "0");
}
private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) {
loadSetting(stmt, key,
Integer.toString(mContext.getResources().getInteger(resid)));
}
private void loadFractionSetting(SQLiteStatement stmt, String key, int resid, int base) {
loadSetting(stmt, key,
Float.toString(mContext.getResources().getFraction(resid, base, base)));
}
private void loadSetting(SQLiteStatement stmt, String key, Object value) {
stmt.bindString(1, key);
stmt.bindString(2, value.toString());
stmt.execute();
}
5. 修改默认设置
以默认输入法为例:
- 在defaults.xml中添加对应配置
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
+ <string name="enabled_input_methods" translatable="false">com.android.inputmethod.latin/.LatinIME:com.iflytek.inputmethod.google/com.iflytek.inputmethod.FlyIME:com.google.android.inputmethod.pinyin/.PinyinIME</string>
+ <string name="def_input_method" translatable="false">com.iflytek.inputmethod.google/com.iflytek.inputmethod.FlyIME</string>
- 在中导入配置
private void loadSecureSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
+ loadStringSetting(stmt, Settings.Secure.ENABLED_INPUT_METHODS,
+ R.string.enabled_input_methods);
+ loadStringSetting(stmt, Settings.Secure.DEFAULT_INPUT_METHOD,
+ R.string.def_input_method);
6. 使用adb 查看修改SettingProvider的值
adb shell settings
- 分别查看 System、Global和Secure的所有属性
adb shell settings list system
adb shell settings list global
adb shell settings list secure
对于一些设置参数不明确的设置项,可以先在机器上进行手动设置,然后用adb查看设置项后,再在源码中进行修改,以默认输入法为例子:
设置默认输入法: 首先在机器上安装相应的输入法并设置成默认,然后连接adb输入以下命令
$ adb shell settings get secure enabled_input_methods
com.android.inputmethod.latin/.LatinIME:com.iflytek.inputmethod.google/com.iflytek.inputmethod.FlyIME:com.google.android.inputmethod.pinyin/.PinyinIME
$ adb shell settings get secure default_input_method
com.iflytek.inputmethod.google/com.iflytek.inputmethod.FlyIME