Android Settings 数据库生成、监听与默认值调整

一、Settings 数据库生成机制​

  1. 传统数据库生成(Android 6.0 前)​
  • 路径​:/data/data/com.android.providers.settings/databases/settings.db
  • 创建流程​:
    • SQL 脚本初始化​:通过 sqlite 工具创建数据库文件并执行 SQL 脚本定义表结构(如 secure、system、global)
    • ADB 推送​:生成 .db 文件后,通过 adb push 推送至设备 /data/system/ 目录
    • 重启服务​:执行 adb shell stop && adb shell start 使配置生效
  1. 新版 XML 存储(Android 6.0 及以后)​
  • 数据迁移​:首次启动或恢复出厂设置时,若检测到旧数据库,系统会将其迁移至 XML 文件(如 /data/system/users/0/settings_global.xml)
  • 文件结构​:
    • Global​:settings_global.xml(全局设置):所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
    • System​:settings_system.xml(用户偏好):包含各种各样的用户偏好系统设置,第三方APP有读没有写的权限;
    • Secure​:settings_secure.xml(安全设置):安全性的用户偏好系统设置,第三方APP有读没有写的权限;
二、数据监听实现
  1. ContentObserver 机制
  • 监听原理​:通过注册 ContentObserver 监听特定 URI 的变动(如 Settings.Global.CONTENT_URI)
// 自定义观察者类private class SettingsObserver extends ContentObserver {    public SettingsObserver(Handler handler) { super(handler); }     @Override    public void onChange(boolean selfChange, Uri uri) {        // 处理设置变更逻辑(如读取新值并更新 UI)        int value = Settings.Global.getInt(getContentResolver(), "key_name", 0);    }}// 注册监听Uri uri = Settings.Global.getUriFor("key_name");getContentResolver().registerContentObserver(uri, false, new SettingsObserver(mHandler));

例如 以UUID为例

//首先我们先定义一个数据库的键值Key//比如我们定义一个保存设备uuid的键值为"device_uuid"private static final String KEY_DEVICE_UUID = "device_uuid"; //保存设备的uuidSettings.Secure.putString(getContentResolver(), LinspirerToolConstant.KEY_DEVICE_UUID, uuid) //读取设备的uuidString uuid = Settings.Secure.getString(getContentResolver(), LinspirerToolConstant.KEY_DEVICE_UUID );

获取UUID 的ContentResolver对象

//获取ContentResolver对象ContentResolver contentResolver = getContentResolver();//注册监听对应的数据库字段KeycontentResolver.registerContentObserver(Settings.Secure.getUriFor(LinspirerToolConstant.KEY_SHEEPMIE_UUID),true,new SettingsObserver(null));

自定义ContentObserver类,实现数据变化的回调方法

private final class SettingsObserver extends ContentObserver {  /**     * Creates a content observer.     * @param handler The handler to run {@link #onChange} on, or null if none.     */    public SettingsObserver(Handler handler) {        super(handler);    }     @Override    public void onChange(boolean selfChange) {        try {            String uuid = Settings.Secure.getString(getContentResolver(), KEY_DEVICE_UUID);            Log.w(" -- uuid被改变啦!!! == " + uuid);        } catch (Throwable e) {            e.printStackTrace();        }    }}
监听后 当UUID改变contentResolver则会监听到 然后ContentObserver就会做出反应

默认值配置详解

默认值定义文件
  • 路径​:frameworks/base/packages/SettingsProvider/res/values/defaults.xml
true       60000  24 设置时间格式 是12还是24
数据库初始化加载
com.android.providers.settings.DatabaseHelper.java onCreate()中​调用了loadSettings()
  • 代码入口​:DatabaseHelper.java 的 loadSettings() 方法

SettingsProvider的启动过程

frameworks\base\packages\settingsprovider\src\com\android\providers\settings\SettingsProvider.java

运行SettingsProvider,和Activity类似,会回调ContentProvider的生命周期方法,首先的,会调用OnCreate()方法,如下:

@Overridepublic boolean onCreate() {    // 标记当前运行在系统服务进程中,确保设置项的正确处理    Settings.setInSystemServer();     // 同步初始化关键组件,保证线程安全    synchronized (mLock) {        // 获取用户管理服务(处理多用户场景)        mUserManager = UserManager.get(getContext());                // 获取全局包管理服务(应用安装/权限管理)        mPackageManager = AppGlobals.getPackageManager();                // 获取系统配置管理服务(读取/system/etc配置)        mSysConfigManager = getContext().getSystemService(SystemConfigManager.class);         // 创建后台处理线程(优先级为BACKGROUND)        mHandlerThread = new HandlerThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND);        mHandlerThread.start();  // 启动线程                // 创建Handler绑定线程的Looper        mHandler = new Handler(mHandlerThread.getLooper());                // 初始化设置注册中心(核心数据结构)        mSettingsRegistry = new SettingsRegistry();    }     // 缓存系统包名和签名(优化后续鉴权性能)    SettingsState.cacheSystemPackageNamesAndSystemSignature(getContext());     // 同步处理数据迁移    synchronized (mLock) {        // 迁移旧版本设置数据(兼容性处理)        mSettingsRegistry.migrateAllLegacySettingsIfNeededLocked();                // 同步SSAID表(AndroidID关联处理)        mSettingsRegistry.syncSsaidTableOnStartLocked();    }     // 通过Handler异步执行(避免阻塞主线程)    mHandler.post(() -> {        // 注册广播接收器(监听用户切换/包变更等)        registerBroadcastReceivers();                // 监听用户限制变化(如企业策略更新)        startWatchingUserRestrictionChanges();    });     // 注册系统服务(核心服务暴露)    ServiceManager.addService("settings", new SettingsService(this));   // 设置服务入口    ServiceManager.addService("device_config", new DeviceConfigService(this));  // 设备配置服务     return true;  // 初始化成功}

在onCreate方法中,

1.先实例化了HandlerThread的对象mHandlerThread,优先级是THREAD_PRIORITY_BACKGROUND

2.然后实例化SettingsRegistry的实例mSettingsRegistry

3.接下来注册了一个广播接收器

SettingsRegistry的实例化过程

再回到onCreate()中

migrateAllLegacySettingsIfNeededLocked() 中

/​**​ * 迁移所有遗留设置数据(如果需要) *  * 该方法负责将旧版SQLite数据库中的设置项迁移到新版XML存储格式。 * 仅在首次启动或检测到未初始化时执行迁移。 *  * 同步要求:调用时必须持有mLock锁 */private void migrateAllLegacySettingsIfNeededLocked() {    // 检查全局设置文件是否已存在(避免重复迁移)    final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);    File globalFile = getSettingsFile(key);    if (SettingsState.stateFileExists(globalFile)) {        return;  // 已迁移则直接返回    }     // 记录当前构建ID(用于追踪迁移版本)    mSettingsCreationBuildId = Build.ID;     // 清除调用者身份(以系统权限执行迁移)    final long identity = Binder.clearCallingIdentity();    try {        // 获取所有活跃用户(包括多用户场景)        List users = mUserManager.getAliveUsers();         // 遍历每个用户执行迁移        final int userCount = users.size();        for (int i = 0; i < userCount; i++) {            final int userId = users.get(i).id;             // 初始化用户数据库帮助类(访问旧版SQLite)            DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);            SQLiteDatabase database = dbHelper.getWritableDatabase();                        // 执行核心迁移逻辑            migrateLegacySettingsForUserLocked(dbHelper, database, userId);             // 执行版本升级检查(处理非迁移的增量更新)            UpgradeController upgrader = new UpgradeController(userId);            upgrader.upgradeIfNeededLocked();             // 清理非活跃用户的内存状态(优化资源使用)            if (!mUserManager.isUserRunning(new UserHandle(userId))) {                removeUserStateLocked(userId, false);            }        }    } finally {        // 恢复原始调用者身份        Binder.restoreCallingIdentity(identity);    }}

1.首先通过makeKey获得key,这个key就是之前说过的Global、System、Secure三种类型,

2.获得之后通过getSettingsFile方法创建三种类型的File类型实例:

通过getSettingsFile生成的三种文件分别为:

/data/system/users/{id}/settings_global.xml 存放global

/data/system/users/{id}/settings_system.xml 存放 system

/data/system/users/{id}/settings_secure.xml 存放secure

然后 方法中又实例化了一个dbHelper

dbHelper中

@Overridepublic 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);     // Only create the global table for the singleton 'owner/system' user    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);");     // Populate bookmarks table with initial bookmarks    loadBookmarks(db);     // Load initial volume levels into DB    loadVolumeLevels(db);     // Load inital settings values    loadSettings(db);}

其中 通过 db.execSQL分别创建了 system,Secure,Global三个数据库表

然后通过loadVolumeLevels(db);方法 将系统默认的音量设置写到数据库的system的数据表中

LoadVolumeLevels(db):

/​**​ * 加载音频音量默认值到系统设置数据库 *  * 该方法用于初始化或重置音频相关的系统设置值,包括各音频流的默认音量级别 * 以及铃声模式影响的音频流配置。这些设置会被存储在系统的SQLite数据库中。 *  * @param db 可写的系统设置数据库实例 */private void loadVolumeLevels(SQLiteDatabase db) {    // 使用预编译SQL语句提高批量插入效率    SQLiteStatement stmt = null;    try {        // 创建INSERT OR IGNORE语句(避免重复插入)        stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value) VALUES(?,?);");         // 加载各音频流的默认音量设置(单位:音量等级)        loadSetting(stmt, Settings.System.VOLUME_MUSIC,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));      // 媒体音量        loadSetting(stmt, Settings.System.VOLUME_RING,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_RING));       // 铃声音量        loadSetting(stmt, Settings.System.VOLUME_SYSTEM,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));     // 系统音量        loadSetting(stmt, Settings.System.VOLUME_VOICE,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));  // 通话音量        loadSetting(stmt, Settings.System.VOLUME_ALARM,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_ALARM));      // 闹钟音量        loadSetting(stmt, Settings.System.VOLUME_NOTIFICATION,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));// 通知音量        loadSetting(stmt, Settings.System.VOLUME_BLUETOOTH_SCO,                AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO)); // 蓝牙SCO音量         /*          * 配置铃声模式影响的音频流(位掩码方式):         * - 默认情况下,铃声、通知和系统音量的音频流会受铃声模式影响         * - 在非语音设备(如平板)上,音乐音量也会受铃声模式影响         * - 在语音设备(如手机)上,仅铃声/通知/系统音量受影响         */        int ringerModeAffectedStreams = (1 << AudioManager.STREAM_RING) |                                      (1 << AudioManager.STREAM_NOTIFICATION) |                                      (1 << AudioManager.STREAM_SYSTEM) |                                      (1 << AudioManager.STREAM_SYSTEM_ENFORCED);                // 检查设备是否支持语音功能(config_voice_capable)        if (!mContext.getResources().getBoolean(                com.android.internal.R.bool.config_voice_capable)) {            ringerModeAffectedStreams |= (1 << AudioManager.STREAM_MUSIC); // 平板设备增加音乐流        }                // 将配置写入数据库        loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,                ringerModeAffectedStreams);         // 加载默认的静音影响流配置(来自AudioSystem常量)        loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,                AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED);    } finally {        // 确保关闭数据库语句,避免资源泄漏        if (stmt != null) stmt.close();    }}

最后调用loadSettings

到现在 以及加载许多默认值写入数据库中,这些默认值很大一部分定义在defaults.xml文件中,loadVolumlevels和loadSettings()的作用就是在手机第一次启动时,把手机编好设置的默认值写入到数据库settings.db中。

再回到com.android.providers.settings.SettingsProvider.SettingsRegistry.java migrateAllLegacySettingsIfNeededLocked()中

在DatabaseHelper和SQLiteDatabase创建完毕后,调用migrateLegacySettingsForUserLocked方法:

/​**​ * 迁移指定用户的遗留设置数据(从SQLite数据库到XML存储) *  * 该方法将系统设置、安全设置和全局设置(仅对主用户)从旧版SQLite数据库迁移到新版XML存储格式。 * 迁移完成后可选择删除或备份旧数据库。 *  * @param dbHelper 数据库帮助类实例,提供数据库访问能力 * @param database 可写的SQLite数据库实例 * @param userId 要迁移的用户ID *  * 同步要求:调用时必须持有mLock锁 */private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,        SQLiteDatabase database, int userId) {        // ==================== 系统设置迁移 ====================    final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);    ensureSettingsStateLocked(systemKey);  // 确保系统设置状态已初始化    SettingsState systemSettings = mSettingsStates.get(systemKey);    migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);  // 执行实际迁移    systemSettings.persistSyncLocked();  // 立即持久化到XML文件     // ==================== 安全设置迁移 ====================    final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);    ensureSettingsStateLocked(secureKey);  // 确保安全设置状态已初始化    SettingsState secureSettings = mSettingsStates.get(secureKey);    migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);  // 执行实际迁移    ensureSecureSettingAndroidIdSetLocked(secureSettings);  // 确保Android ID已正确设置    secureSettings.persistSyncLocked();  // 立即持久化到XML文件     // ==================== 全局设置迁移(仅主用户) ====================    if (userId == UserHandle.USER_SYSTEM) {        final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);        ensureSettingsStateLocked(globalKey);  // 确保全局设置状态已初始化        SettingsState globalSettings = mSettingsStates.get(globalKey);        migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);  // 执行实际迁移                // 如果是新创建的设置文件,记录构建ID(用于追踪迁移版本)        if (mSettingsCreationBuildId != null) {            globalSettings.insertSettingLocked(                    Settings.Global.DATABASE_CREATION_BUILDID,                    mSettingsCreationBuildId,                     null,                     true,                    SettingsState.SYSTEM_PACKAGE_NAME);        }        globalSettings.persistSyncLocked();  // 立即持久化到XML文件    }     // ==================== 旧数据库处理 ====================    if (DROP_DATABASE_ON_MIGRATION) {        dbHelper.dropDatabase();  // 配置为true时直接删除旧数据库    } else {        dbHelper.backupDatabase();  // 默认行为:备份旧数据库(保留回滚能力)    }}

1.首先调用了 ensureSettingsStateLocked(systemKey);

实例化了settingsState对象指向了sysytem的数据文件,然后将settingsState对象放到mSettingsStates中,然后回到migrateLegacySettingsForUserLocked继续调用migrateLegacySettingsLocked方法

2.再调用了 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);

/​**​ * 执行实际的遗留设置数据迁移(从SQLite表到SettingsState) *  * 该方法从指定的SQLite表中读取所有设置项,并将其插入到新的SettingsState存储中。 * 这是设置数据从SQLite迁移到XML格式的核心逻辑。 *  * @param settingsState 目标SettingsState实例(系统/安全/全局) * @param database 包含旧设置的SQLite数据库 * @param table 要迁移的源表名(system/secure/global) *  * 同步要求: * - 调用时必须持有外部mLock锁 * - SettingsState内部会维护自己的同步机制 */private void migrateLegacySettingsLocked(SettingsState settingsState,        SQLiteDatabase database, String table) {        // 构建SQL查询(全表扫描)    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();    queryBuilder.setTables(table);  // 设置查询表名     // 执行查询获取所有设置项(只查询name和value列)    Cursor cursor = queryBuilder.query(database, LEGACY_SQL_COLUMNS,            null, null, null, null, null);     // 空检查    if (cursor == null) {        return;  // 表不存在或查询失败时提前返回    }     try {        // 检查是否有数据        if (!cursor.moveToFirst()) {            return;  // 空表直接返回        }         // 获取列索引(优化后续访问性能)        final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);        final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);         // 记录数据库版本(用于兼容性管理)        settingsState.setVersionLocked(database.getVersion());         // 遍历游标逐条迁移数据        while (!cursor.isAfterLast()) {            // 读取设置项键值对            String name = cursor.getString(nameColumnIdx);            String value = cursor.getString(valueColumnIdx);                        // 插入到新的SettingsState存储            settingsState.insertSettingLocked(                    name,           // 设置项名称(如"volume_music")                    value,          // 设置项值(如"11")                    null,           // 默认tag为null                    true,           // makeDefault设为true                    SettingsState.SYSTEM_PACKAGE_NAME);  // 标记为系统设置                        cursor.moveToNext();  // 移动到下一条记录        }    } finally {        // 确保关闭游标释放资源        cursor.close();    }}

先查询出所有System的信息存入游标,然后在循环中作为insertSettingLocked方法的参数

再跳转到insertSettingLocked(String name, String value, String tag,

boolean makeDefault, boolean forceNonSystemPackage, String packageName,

boolean overrideableByRestore)方法中

/​**​ * 插入或更新设置项(线程安全) *  * 该方法用于修改设置项的当前值和/或默认值,包含内存管理、冲突检测和日志记录等完整逻辑。 * 是SettingsProvider核心的写操作方法。 *  * @param name 设置项名称(如"screen_brightness") * @param value 要设置的新值(如"120") * @param tag 可选标签,用于标记设置来源 * @param makeDefault 是否同时设为默认值 * @param forceNonSystemPackage 强制允许非系统应用修改 * @param packageName 发起修改的包名(用于权限控制) * @param overrideableByRestore 是否允许被系统恢复操作覆盖 * @return 是否成功修改 *  * 同步要求:调用时必须持有mLock锁 */@GuardedBy("mLock")public boolean insertSettingLocked(String name, String value, String tag,        boolean makeDefault, boolean forceNonSystemPackage, String packageName,        boolean overrideableByRestore) {        // 1. 参数校验    if (TextUtils.isEmpty(name)) {        return false;  // 拒绝空key    }     // 2. 获取旧值状态    Setting oldState = mSettings.get(name);    String oldValue = (oldState != null) ? oldState.value : null;    String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;    String newDefaultValue = makeDefault ? value : oldDefaultValue;     // 3. 内存使用检查(防止恶意应用耗尽内存)    int newSize = getNewMemoryUsagePerPackageLocked(packageName,            oldValue == null ? name.length() : 0 /* deltaKeySize */,            oldValue, value, oldDefaultValue, newDefaultValue);    checkNewMemoryUsagePerPackageLocked(packageName, newSize);     // 4. 创建/更新设置项    Setting newState;    if (oldState != null) {        // 4.1 更新现有项(包含权限校验)        if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage,                overrideableByRestore)) {            return false;  // 权限校验失败        }        newState = oldState;    } else {        // 4.2 创建新项        newState = new Setting(name, value, makeDefault, packageName, tag,                forceNonSystemPackage);        mSettings.put(name, newState);    }     // 5. 记录统计日志(用于分析设置项变更)    FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED,             name,                      // 设置项名称            value,                     // 新值            newState.value,            // 实际设置值(可能被修正)            oldValue,                  // 旧值            tag,                       // 操作标签            makeDefault,               // 是否设为默认            getUserIdFromKey(mKey),    // 用户ID            FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED);  // 操作类型     // 6. 记录历史操作(用于调试和恢复)    addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);     // 7. 更新内存计数器    updateMemoryUsagePerPackageLocked(packageName, newSize);     // 8. 触发持久化(异步写入磁盘)    scheduleWriteIfNeededLocked();     return true;}

将每个设置项放mSetting中。

所以 ensureSettingsStateLocked(systemKey);到 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);方法

首先创建了指向system的XML数据文件的对象SettingsState(com.android.providers.settings.SettingsState), 该对象中存在mSettings(MAP类型),

这个mSetting中封装了所有设置项name、value、packageName的对象setting。

所以settingState拥有了system的XML数据文件的所有设置项

最后再执行 systemSettings.persistSyncLocked();

1.移除旧的消息:从消息队列中移除 MSG_PERSIST_SETTINGS 消息,防止重复写入。

2.立即写入状态:调用 doWriteState() 立即执行设置的持久化操作。

其中doWriteState() 会将当前settingsState拥有的设置项从内存中序列化写入 XML文件中

然后至此结束 后面的方法 都是secure和global的XML文件的处理 最后 XML数据文件都由 SettingsState通过mSetting这个map持有

总结

在SetttngsProvider的启动过程中,会创建数据库,把默认设置的数据值写入数据库,然后将数据库中的数据全部迁移到xml文件中

然后为了通过Settings.java对使用SettingsProvider进行了封装

settings.java代码创建了三个静态内部类,System,Secure,Global,三个类都继承了NameValueCache,每个NameValueCache都有指向SettingsProvider中的SettingsProvider.java的AIDL远程调用IContentProvider(IContentProvider 是 Android 框架内部定义的 AIDL 接口,用于实现 ContentProvider 的跨进程通信。),因此,查询数据需要经过NameValueCache的getStringForUser()方法,插入数据需要经过putStringForUser()方法。同时,NameValueCache还持有一个变量mValues,用于保存查询过的设置项,以便下下次再次发起查询时,能够快速返回。

自动调节亮度为例子:

其对应的Fragment是:DisplaySettings.java;

加载布局:display_settings.xml:

所有的菜单项都在这里;

例如:则对应的是自动亮度(auto_brightness)选项:

com.android.settings.DisplaySettings中

获取该项对应的controller对象并将它添加到controllers中并返回;

该方法返回buildPreferenceControllers():

com.android.settings.display.AutoBrightnessPreferenceController中

状态读取(isChecked):从系统设置读取当前亮度模式,若与默认值不同(即自动模式已启用),返回 true。若没有存储该值,就返回 DEFAULT_VALUE(手动模式)。

状态写入(setChecked)​:根据开关状态,向系统设置写入自动 (1) 或手动 (0) 模式。

获取和修改的实质是对SettingsProvider的操作

设备的亮度模式SCREEN_BRIGHTNESS_MODE_AUTOMATIC(自动)和SCREEN_BRIGHTNESS_MODE_MANUAL(手动)都是通过SettingsProvider来操作的,可以看到自动亮度设置属于System系统属性

由于Settings.java对使用SettingsProvider进行了封装,所以,使用起来相当简单简洁

public static int getInt(ContentResolver cr, String name, int def) {    return getIntForUser(cr, name, def, UserHandle.myUserId());}

在getIntForUser方法中又调用了getStringForUser方法。

posted @ 2025-07-19 20:44  yfceshi  阅读(15)  评论(0)    收藏  举报