(1)概述
(A)
SettingsProvider顾名思义是一个提供设置数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方,如:
- SettingsProvider只接受int、float、string等基本类型的数据;
- SettingsProvider由Android系统framework进行了封装,使用更加快捷方便;
- SettingsProvider的数据由键值对组成;
(B)
SettingsProvider有点类似Android的SystemProperties。SystemProperties除具有SettingsProvider以上的三个特性,SettingsProvider和SystemProperties的不同点在于:
- 数据保存方式不同:SystemProperties的数据保存属性文件中(/system/build.prop等),开机后会被加载到system properties store,SettingsProvider的数据保存在文件/data/system/users/0/settings_***.xml和数据库settings.db中;
- 作用范围不同:SystemProperties可以实现跨进程、跨层次调用,即底层的c/c++可以调用,java层也可以调用,SettingProvider只能在java层(APP)使用;
在Android 6.0版本时,SettingsProvider被重构,Android从性能、安全等方面考虑,把SettingsProvider中原本保存在settings.db中的数据,目前全部保存在XML文件中。
(C)
SettingsProvider对数据进行了分类,分别是Global、System、Secure三种类型,它们的区别如下:
- Global:所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
- System:包含各种各样的用户偏好系统设置;
- Secure:安全性的用户偏好系统设置,第三方APP有读没有写的权限;
上面对Global、System、Secure分别生成一个File对象实例,它们的File对象分别对应的文件是:
/data/system/users/0/settings_global.xml
/data/system/users/0/settings_system.xml
/data/system/users/0/settings_secure.xml
也就是说,Global类型的数据保存在文件settings_global.xml中,System类型的数据保存在文件settings_system.xml中,Secure类型的数据保存在文件settings_secure.xml中。
(2)AndroidManifest.xml
//frameworks/base/packages/SettingsProvider/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.providers.settings"
coreApp="true"
android:sharedUserId="android.uid.system">
<application android:allowClearUserData="false"
android:label="@string/app_label"
android:process="system"
android:backupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
android:restoreAnyVersion="true"
android:icon="@mipmap/ic_launcher_settings"
android:defaultToDeviceProtectedStorage="true"
android:forceQueryable="true"
android:directBootAware="true">
<provider android:name="SettingsProvider"
android:authorities="settings"
android:multiprocess="false"
android:exported="true"
android:singleUser="true"
android:initOrder="100"
android:visibleToInstantApps="true" />
</application>
</manifest>
由上面Manifest配置的sharedUserId可知,SettingsProvider运行在系统进程中,定义的ContentProvider实现类是SettingsProvider。
(3)Code位置
在frameworks中跟Setting默认值相关的几个文件:
- /frameworks/base/packages/SettingsProvider/res/values/defaults.xml
- /frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
- /frameworks/base/core/java/android/provider/Settings.java
(4)defaults.xml 在defaults.xml文件中定义了相关的值,DatabaseHelper.java会把相应的值读取出来保存到ContentProvider。
//frameworks/base/packages/SettingsProvider/res/values/defaults.xml
<resources>
<bool name="def_dim_screen">true</bool>
<integer name="def_screen_off_timeout">60000</integer>
<integer name="def_sleep_timeout">-1</integer>
<bool name="def_airplane_mode_on">false</bool>
<bool name="def_theater_mode_on">false</bool>
<string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
<string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
<string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
<bool name="def_auto_time">true</bool>
<bool name="def_auto_time_zone">true</bool>
<bool name="def_accelerometer_rotation">false</bool>
<integer name="def_screen_brightness">102</integer>
<bool name="def_screen_brightness_automatic_mode">false</bool>
<fraction name="def_window_animation_scale">100%</fraction>
<fraction name="def_window_transition_scale">100%</fraction>
<bool name="def_haptic_feedback">true</bool>
<bool name="def_bluetooth_on">true</bool>
<bool name="def_wifi_display_on">false</bool>
<bool name="def_install_non_market_apps">false</bool>
<integer name="def_location_mode">3</integer>
<bool name="assisted_gps_enabled">true</bool>
<bool name="def_netstats_enabled">true</bool>
<bool name="def_usb_mass_storage_enabled">true</bool>
<bool name="def_wifi_on">false</bool>
<integer name="def_wifi_sleep_policy">2</integer>
<bool name="def_wifi_wakeup_enabled">true</bool>
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
<string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string>
<bool name="def_notification_pulse">true</bool>
<bool name="def_mount_play_notification_snd">true</bool>
<bool name="def_mount_ums_autostart">false</bool>
<bool name="def_mount_ums_prompt">true</bool>
<bool name="def_mount_ums_notify_enabled">true</bool>
<integer name="def_power_sounds_enabled">1</integer>
<string name="def_low_battery_sound" translatable="false">/product/media/audio/ui/LowBattery.ogg</string>
<integer name="def_dock_sounds_enabled">0</integer>
<integer name="def_dock_sounds_enabled_when_accessibility">0</integer>
<string name="def_desk_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
<string name="def_desk_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
<string name="def_car_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string>
<string name="def_car_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string>
<integer name="def_lockscreen_sounds_enabled">1</integer>
<string name="def_lock_sound" translatable="false">/product/media/audio/ui/Lock.ogg</string>
<string name="def_unlock_sound" translatable="false">/product/media/audio/ui/Unlock.ogg</string>
<string name="def_trusted_sound" translatable="false">/product/media/audio/ui/Trusted.ogg</string>
<string name="def_wireless_charging_started_sound" translatable="false">/product/media/audio/ui/WirelessChargingStarted.ogg</string>
<string name="def_charging_started_sound" translatable="false">/product/media/audio/ui/ChargingStarted.ogg</string>
<integer name="def_max_sound_trigger_detection_service_ops_per_day" translatable="false">1000</integer>
<integer name="def_sound_trigger_detection_service_op_timeout" translatable="false">15000</integer>
<bool name="def_lockscreen_disabled">false</bool>
<bool name="def_device_provisioned">false</bool>
<integer name="def_dock_audio_media_enabled">1</integer>
<bool name="def_notifications_use_ring_volume">true</bool>
<bool name="def_vibrate_in_silent">true</bool>
<bool name="def_sync_parent_sounds">true</bool>
<bool name="def_accessibility_speak_password">true</bool>
<bool name="def_touch_exploration_enabled">false</bool>
<fraction name="def_accessibility_display_magnification_scale">200%</fraction>
<bool name="def_accessibility_display_magnification_enabled">false</bool>
<bool name="def_accessibility_display_magnification_auto_update">true</bool>
<integer name="def_user_rotation">0</integer>
<integer name="def_download_manager_max_bytes_over_mobile">-1</integer>
<integer name="def_download_manager_recommended_max_bytes_over_mobile">-1</integer>
<integer name="def_long_press_timeout_millis">400</integer>
<integer name="def_multi_press_timeout_millis">300</integer>
<bool name="def_show_ime_with_hard_keyboard">false</bool>
<integer name="def_pointer_speed">0</integer>
<bool name="def_dtmf_tones_enabled">true</bool>
<bool name="def_sound_effects_enabled">true</bool>
<bool name="def_stay_on_while_plugged_in">false</bool>
<integer name="def_max_dhcp_retries">9</integer>
<bool name="def_user_setup_complete">false</bool>
<integer name="def_low_battery_sound_timeout">0</integer>
<string name="def_immersive_mode_confirmations" translatable="false"></string>
<integer name="def_wifi_scan_always_available">0</integer>
<integer name="def_lock_screen_show_notifications">1</integer>
<bool name="def_lock_screen_allow_private_notifications">true</bool>
<integer name="def_heads_up_enabled">1</integer>
<string name="def_device_name">%1$s %2$s</string>
<string name="def_device_name_simple">%1$s</string>
<bool name="def_wake_gesture_enabled">true</bool>
<bool name="def_double_tap_to_wake">true</bool>
<string name="def_nfc_payment_component"></string>
<bool name="def_add_users_from_lockscreen">false</bool>
<integer name="def_end_button_behavior">0x2</integer>
<bool name="def_restrict_background_data">false</bool>
<string name="def_backup_manager_constants"></string>
<bool name="def_mobile_data_always_on">true</bool>
<string name="def_backup_local_transport_parameters"></string>
<integer name="def_zen_duration">0</integer>
<string name="def_backup_agent_timeout_parameters"></string>
<bool name="def_vibrate_when_ringing">false</bool>
<bool name="def_apply_ramping_ringer">false</bool>
<bool name="def_charging_vibration_enabled">true</bool>
<bool name="def_charging_sounds_enabled">true</bool>
<bool name="def_notification_bubbles">true</bool>
<bool name="def_aware_enabled">false</bool>
<bool name="def_skip_gesture">false</bool>
<bool name="def_silence_gesture">false</bool>
<bool name="def_aware_lock_enabled">false</bool>
<bool name="def_hdmiControlAutoDeviceOff">false</bool>
</resources>
(5)DatabaseHelper.java
class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "SettingsProvider";
private static final String DATABASE_NAME = "settings.db";
private static final int DATABASE_VERSION = 118;
private static final String DATABASE_BACKUP_SUFFIX = "-backup";
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
private void createSecureTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE secure (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT UNIQUE ON CONFLICT REPLACE," +
"value TEXT" +
");");
db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
}
private void createGlobalTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE global (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT UNIQUE ON CONFLICT REPLACE," +
"value TEXT" +
");");
db.execSQL("CREATE INDEX globalIndex1 ON global (name);");
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE system (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT UNIQUE ON CONFLICT REPLACE," +
"value TEXT" +
");");
db.execSQL("CREATE INDEX systemIndex1 ON system (name);");
createSecureTable(db);
if (mUserHandle == UserHandle.USER_SYSTEM) {
createGlobalTable(db);
}
db.execSQL("CREATE TABLE bluetooth_devices (" +
"_id INTEGER PRIMARY KEY," +
"name TEXT," +
"addr TEXT," +
"channel INTEGER," +
"type INTEGER" +
");");
db.execSQL("CREATE TABLE bookmarks (" +
"_id INTEGER PRIMARY KEY," +
"title TEXT," +
"folder TEXT," +
"intent TEXT," +
"shortcut INTEGER," +
"ordering INTEGER" +
");");
db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);");
db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");
boolean onlyCore = false;
try {
onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
"package")).isOnlyCoreApps();
} catch (RemoteException e) {
}
if (!onlyCore) {
loadBookmarks(db);
}
loadVolumeLevels(db);
loadSettings(db);
}
private void loadSettings(SQLiteDatabase db) {
loadSystemSettings(db);
loadSecureSettings(db);
if (mUserHandle == UserHandle.USER_SYSTEM) {
loadGlobalSettings(db);
}
}
private void loadSystemSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ " VALUES(?,?);");
loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
R.bool.def_dim_screen);
loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
R.integer.def_screen_off_timeout);
loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
loadSetting(stmt, Settings.System.HEARING_AID, 0);
loadSetting(stmt, Settings.System.TTY_MODE, 0);
loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
R.integer.def_screen_brightness);
loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault);
loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
R.bool.def_screen_brightness_automatic_mode);
loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
R.bool.def_accelerometer_rotation);
loadDefaultHapticSettings(stmt);
loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
R.bool.def_notification_pulse);
loadUISoundEffectsSettings(stmt);
loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
R.integer.def_pointer_speed);
} finally {
if (stmt != null) stmt.close();
}
}
}
在DatabaseHelper.java的方法中用于加载defaults.xml定义的相关字段。
(6)封装SettingsProvider接口(Settings.java)
对ContentProvider的一些接口进行封装,以保证在整个Android的java层任何一个地方都能方便、快捷的使用SettingsProvider进行数据查询,数据更新和数据插入。所以,framework有一个类Settings.java对SettingsProvider进行了封装。如下:
public final class Settings {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_USER_SETTINGS =
"android.settings.USER_SETTINGS";
public static final class Global extends NameValueTable {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");
public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
public static final String THEATER_MODE_ON = "theater_mode_on";
}
public static final class System extends NameValueTable {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/system");
}
public static final class Secure extends NameValueTable {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/secure");
}
上面的代码中,分别声明了Global、Secure、System三个静态内部类,分别对应SettingsProvider中的Global、Secure、System三种数据类型。Global、Secure、System三个静态内部类会分别持有NameValueCache的实例变量,进而通过AIDL远程调用IContentProvider。
查询数据需要经过NameValueCache的getStringForUser()方法,插入数据需要经过putStringForUser()方法。
(7)操作SettingsProvider
由于Settings.java对SettingsProvider进行了封装,所以,使用起来相当简单简洁。Global、Secure、System三种数据类型的使用是几乎相同。
String globalValue = Settings.Global.getString(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON);
boolean isSuccess = Settings.System.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
(8)第三方APP使用SettingsProvider
第三方APP可以通过framework的Settings.java查询SettingsProvider中的设置项,第三APP是否可以修改SettingsProvider的设置项?Android系统不允许第三方APP修改SettingsProvider中的设置项。
查阅SettingsProvider的设置项不需要声明任何权限。 修改SettingsProvider需要权限:
- android.permission.WRITE_SETTINGS
- android.permission.WRITE_SECURE_SETTINGS
|