1. System settings homepage (first-level menu) :
1、Settings
The reason why an empty Activity is defined here is so that external applications can jump directly to the XX_SettingsActivity interface, because if it is just a fragment, the outside cannot jump to the fragment interface. When jumping to XX_SettingsActivity, its parent class will be executed. Method in SettingsActivity.java, and based on the registration information of XX_SettingsActivity in the manifest file and its meta-data value, find the fragment (XX_Settings) corresponding to XX_SettingsActivity, display the fragment interface, and implement backdooring.
2、AndroidManifest.xml
The main interface Activity of Settings uses Settings.java, and the sub-interface Activity uses SubSettings.java. The internal classes in Settings and SubSetting are all empty activities (the seven life cycle methods are not overridden), and they are all inherited from SettingsActivity.
From the AndroidManifest.xml file, we know that the main page is .homepage.SettingsHomepageActivity.
Take WifiSettings as an example
3、SettingsHomepageActivity
①onCreate
②showFragment
The implementation of loading fragment is implemented in the encapsulation method.
4、TopLevelSettings
TopLevelSettings inherits from the abstract class DashboardFragment, and implements the abstract method getPreferenceScreenResId() and returns the preference configuration file to complete the static configuration.
Another important thing in the TopLevelSettings class is that the onAttach() method of the parent class DashboardFragment is called in the onAttach() method. This method is mainly used to load preference controllers.
5、top_level_settings.xml
The main tag is a <PreferenceScreen> tag, which contains multiple <Preference> tags. Each <Preference> tag corresponds to each setting item on the home page.
key |
The primary key of the configuration item |
title |
The title of the configuration item |
summary |
Want the text below the title |
icon |
front icon |
order |
Used for sorting, the smaller the value, the higher the ranking. |
fragment |
Click on the item to jump to the interface |
controller |
The item's controller controls its content display, availability, and can also control its click events, etc. |
5、DashboardFragment
①onCreatePreferences
②refreshAllPreferences
③displayResourceTiles
The addPreferencesFromResource method adds all Preferences under preferenceScreen to the ArrayList, then builds and generates a PreferenceGroupAdapter based on this collection, and finally sets this adapter to the listview to complete data binding and thus complete the interface loading.
④refreshDashboardTiles
⑤onAttach
@Override public void onAttach(Context context) { super.onAttach(context); mSuppressInjectedTileKeys = Arrays.asList(context.getResources().getStringArray( R.array.config_suppress_injected_tile_keys)); mDashboardFeatureProvider = FeatureFactory.getFactory(context) .getDashboardFeatureProvider( context); // Load preference controllers from code //Load preference controllers from code final List<AbstractPreferenceController> controllersFromCode = createPreferenceControllers(context); // Load preference controllers from xml definition //Load preference controllers from xml definition final List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper .getPreferenceControllersFromXml(context, getPreferenceScreenResId()); // Filter xml-based controllers in case a similar controller is created from code already. Created a similar controller. final List<BasePreferenceController> uniqueControllerFromXml = PreferenceControllerListHelper.filterControllers( controllersFromXml, controllersFromCode); // Add unique controllers to list. //Add unique controllers to the list if (controllersFromCode != null) { mControllers.addAll(controllersFromCode); } mControllers.addAll(uniqueControllerFromXml); // And wire up with lifecycle. //And wire up with lifecycle. final Lifecycle lifecycle = getSettingsLifecycle(); uniqueControllerFromXml.forEach(controller -> { if (controller instanceof LifecycleObserver) { lifecycle.addObserver((LifecycleObserver) controller); } }); // Set metrics category for BasePreferenceController. // Set for BasePreferenceController Indicator category. final int metricCategory = getMetricsCategory(); mControllers.forEach(controller -> { if (controller instanceof BasePreferenceController) { ((BasePreferenceController) controller).setMetricsCategory(metricCategory); } }); mPlaceholderPreferenceController = new DashboardTilePlaceholderPreferenceController(context); mControllers.add(mPlaceholderPreferenceController); for (AbstractPreferenceController controller : mControllers) { addPreferenceController(controller); } }
2. Implementation of secondary menu of system settings
1、SubSettings
The secondary menu interface Activity of the system settings is the SubSettings class. Although the SubSettings class is an Activity, it is an empty Activity. It does not inherit the Activity7 life cycle.
2、SettingsActivity
①onCreate
Layout file: settings_main_prefs
Start Fragment
②getMetaData
Take WifiSettingsActivity as an example
③getIntent
④getStartingFragmentClass
⑤launchSettingFragment
⑥switchToFragment
3、settings_main_prefs.xml
The layout file consists of <SwitchBar> and <FrameLayout> and <RelativeLayout> tags. The <RelativeLayout> tag is hidden by default. According to the id of the <FrameLayout> tag, it can be judged that this tag is the main interface content of the secondary menu bar.
3. Load default brightness
1、top_level_settings.xml
2、AndroidManifest.xml
3、DisplaySettings
①getPreferenceScreenResId
②buildPreferenceControllers
4、display_settings.xml
5、AutoBrightnessPreferenceController
6、BrightnessLevelPreferenceController
①getCurrentBrightness
②convertLinearToGammaFloat
7、 Z:\k630_64\vendor\tinno\k630_64\trunk\etc\settings-config.xml
<setting type="system" name="screen_brightness_float" value="0.35896719"/>
8、/data/system/users/0/settings_system.xml
<setting id="491" name="screen_brightness_float" value="0.3597016" package="android" defaultValue="0.35896719" defaultSysSet="true" />
4. Font adjustment
1、display_settings
2、FontSizePreferenceController
3、ToggleFontSizePreferenceFragment
4、values-zh-rCN/arrays.xml
5、arrays.xml
6、Z:\k630_64\vendor\tinno\k630_64\trunk\etc\settings-config.xml
<setting type="system" name="font_scale" value="1.0"/>
5. Screen timeout
1、TimeoutPreferenceController
2、arrays.xml
3、Z:\k630_64\vendor\tinno\k630_64\trunk\etc\settings-config.xml
6. Display real-time power
1、top_level_settings.xml
2、AndroidManifest.xml
3、TopLevelBatteryPreferenceController
The configuration item is configured with the TopLevelBatteryPreferenceController controller, which inherits from AbstractPreferenceController. This abstract class is used to uniformly manage all menu items (such as showing or hiding, listening for click events, etc.).
public class TopLevelBatteryPreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop { // Battery change broadcast private final BatteryBroadcastReceiver mBatteryBroadcastReceiver; // Current configuration item private Preference mPreference; // Battery information private BatteryInfo mBatteryInfo; // Initialize battery change broadcast public TopLevelBatteryPreferenceController(Context context , String preferenceKey) { super(context, preferenceKey); mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext); mBatteryBroadcastReceiver.setBatteryChangedListener(type -> { BatteryInfo.getBatteryInfo(mContext, info -> { mBatteryInfo = info; updateState(mPreference); }, true /* shortString */); }); } // Control whether this item is available @Override public int getAvailabilityStatus() { return mContext.getResources().getBoolean(R.bool.config_show_top_level_battery) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); // Get the current configuration item mPreference = screen.findPreference(getPreferenceKey()); } @Override public void onStart() { // Register the broadcast mBatteryBroadcastReceiver.register (); } @Override public void onStop() { // Unregister the broadcast mBatteryBroadcastReceiver.unRegister(); } @Override public CharSequence getSummary() { // Return the battery overview return getDashboardLabel(mContext, mBatteryInfo); } // Get the battery information static CharSequence getDashboardLabel(Context context, BatteryInfo info) { if (info == null || context == null) { return null; } CharSequence label; if (!info.discharging && info.chargeLabel != null) { label = info.chargeLabel; } else if (info .remainingLabel == null) { label = info.batteryPercentString; } else { label = context.getString(R.string.power_remaining_settings_home_page, info.batteryPercentString, info.remainingLabel); } return label; } }
4. Summary
- Initialize the power change broadcast in the construction method
- Register and unregister broadcasts in onStart() and onStop()
- Once the power change broadcast is received, the power information is saved in mBatteryInfo.
- Then execute updateState(), which will call getSummary() to set the information to the current configuration item.
- In getSummary(), parse the power information saved by mBatteryInfo
7. System provider
Android system setting data is stored in /data/data/com.android.providers.settings/databases/settings.db
Is there a default value
When looking for the default value of a switch, you must first understand whether there is a default value for the switch, and whether the switch status has a status saved (generally the status is stored in the settings db). Judgment conditions: The default value can be found only after the switch status is still saved after reboot or the switch status is restored to the default after reset (restore factory settings) .
The switch status is still saved after reboot, which means the status is stored in the db. After reset, the switch state returns to the default, indicating that the state has a default value.
For example, wiif switches, Bluetooth switches, GPS switches, etc. all have default values, and the status values are saved in the db.
As for the WiFi hotspot switch, the status is not saved after reboot, so don’t waste your efforts to find its default value or status storage value.
Modify default value
Most of the switch status is stored in the db of SettingProvider. There are three files related to the status value.
- /frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java: The status value is stored in this file
- /frameworks/base/packages/SettingsProvider/res/values/defaults.xml: defines the default value of the switch state
- /frameworks/base/core/java/android/provider/Settings.java: defines the key corresponding to the default value storage of each switch state.
- Z:\k630_64\vendor\tinno\k630_64\trunk\etc\settings-config.xml Default values for brightness, font size, lock screen and other settings are set here
Take screen timeout as an example
1、TimeoutPreferenceController
@Override public void updateState(Preference preference) { final TimeoutListPreference timeoutListPreference = (TimeoutListPreference) preference; //系统没有提供SCREEN_OFF_TIMEOUT才使用FALLBACK_SCREEN_TIMEOUT_VALUE final long currentTimeout = Settings.System.getLong(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE); }
2、DatabaseHelper
Not all default values are set by reading defaults.xml, and some are set directly in DatabaseHelper.java.
For example, loadSetting(stmt, Settings.Secure.ADB_ENABLED, 1); This ADB Debugging switch is written directly in the database file.
Regarding the USB Debugging switch, you can also set it in the systemui/usb/StorageNotification.java file of systemui to determine whether there is an IMEI number.
When analyzing the code, if you find that this item cannot be found in defaults.xml, search directly in the DatabaseHelper.java file.
private void loadSystemSettings(SQLiteDatabase db) { //数据库名 private static final String DATABASE_NAME = "settings.db"; SQLiteStatement stmt = null; try { stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)" + " VALUES(?,?);"); //SCREEN_OFF_TIMEOUT设置def_screen_off_timeout //def_screen_off_timeout在defaults.xml中 loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT, R.integer.def_screen_off_timeout); ..... private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) { // loadSetting(stmt, key, Integer.toString(mContext.getResources().getInteger(resid))); } } private void loadSetting(SQLiteStatement stmt, String key, Object value) { // stmt.bindString(1, key); stmt.bindString(2, value.toString()); stmt.execute(); } ..... static final String PARTNER_SETTINGS_PATH ="etc/settings-config.xml"; private void updateSystemSecureSettings(SQLiteDatabase db) { FileReader settingsReader; final File settingsFile = new File(Environment.getRootDirectory(), PARTNER_SETTINGS_PATH); try { settingsReader = new FileReader(settingsFile); } catch (FileNotFoundException e) { Log.w(TAG, "Can't open " + Environment.getRootDirectory() + "/" + PARTNER_SETTINGS_PATH); return; }
3、defaults.xml
<resources> <bool name="def_dim_screen">true</bool> //对应SCREEN_OFF_TIMEOUT <integer name="def_screen_off_timeout">15000</integer> <integer name="def_sleep_timeout">-1</integer> <bool name="def_airplane_mode_on">false</bool> ......
4、Settings.java
/** * The amount of time in milliseconds before the device goes to sleep or begins * to dream after a period of inactivity. This value is also known as the * user activity timeout period since the screen isn't necessarily turned off * when it expires. * * <p> * This value is bounded by maximum timeout set by * {@link android.app.admin.DevicePolicyManager#setMaximumTimeToLock(ComponentName, long)}. */ //使用adb命令获取得到,区分大小写:screen_off_timeout public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
5、settings-config.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <resources> <setting type="global" name="auto_time" value="1"/> <setting type="global" name="auto_time_zone" value="1"/> <setting type="system" name="time_12_24" value="24"/> <setting type="system" name="date_format" value="dd/MM/yyyy"/> <setting type="system" name="accelerometer_rotation" value="0"/> //屏幕锁定时间 <setting type="system" name="screen_off_timeout" value="120000"/> <setting type="system" name="sound_effects_enabled" value="0"/> <setting type="system" name="haptic_feedback_enabled" value="0"/> <setting type="system" name="dtmf_tone" value="0"/> <setting type="system" name="lockscreen_sounds_enabled" value="0"/> <setting type="system" name="screen_brightness" value="56"/> <setting type="system" name="screen_brightness_mode" value="1"/> //字体大小 <setting type="system" name="font_scale" value="1.0"/> <setting type="system" name="status_bar_show_battery_percent" value="1"/> <setting type="global" name="install_non_market_apps" value="0"/> <setting type="secure" name="backup_enabled" value="0"/> <setting type="secure" name="charging_sounds_enabled" value="0"/> //屏幕亮度 <setting type="system" name="screen_brightness_float" value="0.35896719"/> <setting type="secure" name="backup_transport" value="com.google.android.backup/.BackupTransportService"/> <setting type="secure" name="default_input_method" value="com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME"/> <setting type="secure" name="enabled_input_methods" value="com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME:com.google.android.googlequicksearchbox/com.google.android.voicesearch.ime.VoiceInputMethodService:com.google.android.inputmethod.pinyin/.PinyinIME"/> <setting type="system" name="ipo_setting" value="0"/> <setting type="global" name="device_name" value="K630"/> <!-- <setting type="system" name="lowrawapp_optimize_white_packages" value="com.tencent.mm,com.tencent.mobileqq,com.facebook.katana,com.whatsapp,com.skype.rover,com.snapchat.android,com.tnmb.bootclean,com.ape.cubes,com.ape.folio,com.ape.retailmode,com.tinno.autotesttool,com.tinno.fieldtester,com.antutu.ABenchMark,com.antutu.benchmark.full,it.telecomitalia.cubovision,it.telecomitalia.selectedbytim,com.telecomitalia.cubomusica"/> <setting type="system" name="lowrawapp_optimize_limit_num" value="4"/> <setting type="system" name="lowrawapp_optimize_limit_sum" value="6"/> <setting type="system" name="lowrawapp_optimize_Custom_packages" value="com.kugou.android"/> <setting type="system" name="lowrawapp_optimize_cpuload_normal" value="12.5"/> <setting type="system" name="lowrawapp_optimize_cpuload_high" value="13.5"/> <setting type="system" name="lowrawapp_optimize_cpuload_ultrahigh" value="16.5"/> <setting type="system" name="lowrawapp_optimize_topPss_large" value="260000"/> <setting type="system" name="lowrawapp_optimize_topPss_resume" value="150000"/> <setting type="system" name="lowrawapp_optimize_topPss_ultralarge" value="340000"/> --> <!-- FEATURE_SINGLE_HAND hsg 20190904--> <setting type="global" name="enable_single_hand" value="1" /> <!-- TINNO END --> </resources>
6.Default value
value |
meaning |
key |
def_dim_screen |
0=no 1=yes: Whether to gradually dim the screen brightness |
Settings.System.DIM_SCREEN |
def_screen_off_timeout |
How many seconds does the screen go off after no operation? |
Settings.System.SCREEN_OFF_TIMEOUT |
def_sleep_timeout |
The number of seconds to sleep after no operation (this value is longer than the screen off time, because the screen will be off before sleeping) |
Settings.Secure.SLEEP_TIMEOUT |
def_airplane_mode_on |
Is airplane mode on by default? |
Settings.Global.AIRPLANE_MODE_ON |
def_theater_mode_on |
Is theater mode enabled by default? |
Settings.Global.THEATER_MODE_ON |
def_airplane_mode_radios |
List of switches that will be turned off when airplane mode is turned on (usually including Bluetooth, wifi, nfc, etc.) |
Settings.Global.AIRPLANE_MODE_RADIOS |
airplane_mode_toggleable_radios |
List of switches that users can manually turn on in airplane mode |
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS |
def_auto_time |
1=yes, 0=no Whether to automatically synchronize date, time and time zone from the network |
Settings.Global.AUTO_TIME |
def_auto_time_zone |
1=yes, 0=no Whether to automatically synchronize the time zone from the network |
Settings.Global.AUTO_TIME_ZONE |
def_accelerometer_rotation |
1=yes, 0=no Whether to turn on automatic rotation (that is, whether to rotate the screen direction according to the acceleration sensor) |
Settings.System.ACCELEROMETER_ROTATION |
def_screen_brightness |
Screen default brightness (value range is 0–255) |
Settings.System.SCREEN_BRIGHTNESS |
def_screen_brightness_automatic_mode |
Whether to turn on automatic adjustment of screen brightness |
Settings.System.SCREEN_BRIGHTNESS_MODE |
def_window_animation_scale |
1=yes, 0=no window animation scaling |
Settings.System.WINDOW_ANIMATION_SCALE |
def_window_transition_scale |
1=yes, 0=no window transparency |
Settings.System.TRANSITION_ANIMATION_SCALE |
def_haptic_feedback |
Whether to enable touch feedback, I don’t know what it means. |
Settings.System.HAPTIC_FEEDBACK_ENABLED |
def_bluetooth_on |
0=disabled. 1=enabled. Whether to turn on Bluetooth by default |
Settings.Global.BLUETOOTH_ON |
def_wifi_display_on |
0=disabled. 1=enabled. Whether to turn on wifi display |
Settings.Global.WIFI_DISPLAY_ON |
def_install_non_market_apps |
Whether to allow the installation of apps that are not downloaded from the app store: 1 = Allow installation through installation packages, 0 = Do not allow installation through installation packages |
Settings.Secure.INSTALL_NON_MARKET_APPS |
def_package_verifier_enable |
Perform certificate check before installing the app, 1 checks, 0 does not check |
Settings.Global.PACKAGE_VERIFIER_ENABLE |
def_location_providers_allowed |
Whether to enable gps. If the string is null, gps will not be enabled by default. You also need to use LOCATION_MODE to judge. |
Settings.Secure.LOCATION_PROVIDERS_ALLOWED |
assisted_gps_enabled |
Whether to enable auxiliary GPS applications |
Settings.Global.ASSISTED_GPS_ENABLED |
def_netstats_enabled |
Whether to enable traffic statistics |
Settings.Global.NETSTATS_ENABLED |
def_usb_mass_storage_enabled |
Whether to enable usb mass storage |
Settings.Global.USB_MASS_STORAGE_ENABLED |
def_wifi_on |
Is wifi enabled by default? |
Settings.Global.WIFI_ON |
def_wifi_sleep_policy |
Whether the wifi is sleeping (switching back and forth with the mobile network) is 0-never, 1-only when plugged in, 2-always |
Settings.Global.WIFI_SLEEP_POLICY |
def_networks_available_notification_on |
Whether to notify the user to open the network |
Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON |
def_backup_enabled |
0-disabled, 1-enabled whether to enable settings backup |
Settings.Secure.BACKUP_ENABLED |
def_backup_transport |
Transfer files for backup or recovery |
Settings.Secure.BACKUP_TRANSPORT |
def_notification_pulse |
When a notification comes, should the LED light flash repeatedly? |
Settings.System.NOTIFICATION_LIGHT_PULSE |
def_mount_play_notification_snd |
Whether to play notification ringtone when an event comes |
Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND |
def_mount_ums_autostart |
Whether to automatically start the host detection system |
Settings.Secure.MOUNT_UMS_AUTOSTART |
def_mount_ums_prompt |
Whether to display a notification when the host is detected |
Settings.Secure.MOUNT_UMS_PROMPT |
def_mount_ums_notify_enabled |
Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED |
当开启ums时是否显示通知 |
def_power_sounds_enabled |
电量过低时是否铃声通知 |
Settings.Global.POWER_SOUNDS_ENABLED |
def_low_battery_sound |
低电量时播放的铃声文件来源 |
Settings.Global.LOW_BATTERY_SOUND |
def_dock_sounds_enabled |
当插拔电源时是否播放声音 |
Settings.Global.DOCK_SOUNDS_ENABLED |
def_desk_dock_sound |
插上电源时播放的音频文件 |
Settings.Global.DESK_DOCK_SOUND |
def_desk_undock_sound |
拔下电源时播放的音频文件 |
Settings.Global.DESK_UNDOCK_SOUND |
def_car_dock_sound |
使用车载电源充电时播放的音频文件 |
Settings.Global.CAR_DOCK_SOUND |
def_car_undock_sound |
当从车载电源拔下时播放的音频文件 |
Settings.Global.CAR_UNDOCK_SOUND |
def_lockscreen_sounds_enabled |
当解锁或是锁屏时是否播放声音 |
Settings.System.LOCKSCREEN_SOUNDS_ENABLED |
def_lock_sound |
锁屏时播放的音频文件 |
Settings.Global.LOCK_SOUND |
def_unlock_sound |
解锁时播放的音频文件 |
Settings.Global.UNLOCK_SOUND |
def_trusted_sound |
在未解锁的情况下设备进入到可信任状态时播放的音频文件 |
Settings.Global.TRUSTED_SOUND |
def_wireless_charging_started_sound |
开启无线充电时播放声音 |
Settings.Global.WIRELESS_CHARGING_STARTED_SOUND |
def_lockscreen_disabled |
第一次开机时默认不锁屏(若要彻底去掉锁屏页面还需要在别的方法中设置) |
Settings.System.LOCKSCREEN_DISABLED |
def_device_provisioned |
设备是否已经被配置(该参数考虑的时多用户不同时刻使用同一个设备的情况) |
Settings.Global.DEVICE_PROVISIONED |
def_dock_audio_media_enabled |
使用dock音频输出媒体 |
Settings.Global.DOCK_AUDIO_MEDIA_ENABLED |
def_vibrate_in_silent |
静音模式下是否允许震动 |
Settings.System.VIBRATE_IN_SILENT |
def_accessibility_script_injection |
是否增强js的屏幕阅读性 |
Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION |
def_accessibility_speak_password |
访问模式下是否语音播报密码 |
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD |
def_low_battery_sound_timeout |
当经过一定时间后,如果低电量提醒为播放声音,则灭屏 |
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT |
def_lock_screen_show_notifications |
是否在锁屏界面显示通知 |
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS |
def_lock_screen_allow_private_notifications |
允许在锁屏界面上显示私有通知,就像是解锁状态下一样 |
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS |
def_wifi_scan_always_available |
设置-wlan-高级-随时扫描开关 |
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE |
7、adb命令获取/修改/设置值
C:\Users\jiabao.guan>adb shell settings get system screen_off_timeout 60000 C:\Users\jiabao.guan>adb shell settings put system guan 66 C:\Users\jiabao.guan>adb shell settings get system guan 66 C:\Users\jiabao.guan>adb shell settings put system screen_off_timeout 120000 C:\Users\jiabao.guan>adb shell settings get system screen_off_timeout 120000
八、添加辅助菜单
测试目标:
为系统设置最底部增加一项菜单项(title:辅助功能),进入辅助功能菜单项,设置一个<SwitchPreference>项(高对比度字体),和两个<Preference>项(颜色调整和多彩屏幕)。
1、top_level_settings.xml
在res/xml/top_level_settings.xml配置文件中增加一个<Preference>标签,并为<Preference>标签设置相关属性(fragment属性和controller属性需要配置该类的全限定类名)。
<Preference android:key="assistant_function" android:title="@string/assistant_function" android:summary="@string/assistant_summary" android:icon="@drawable/ic_homepage_support" android:order="30" android:fragment="com.android.settings.assistant.AssistantFunctionDashboardFragment" settings:controller="com.android.settings.assistant.AssistantFunctionPreferenceController"/>
2、assistant
配置好后创建com.android.settings.assistant包,在该包下创建这两个类。(AssistantFunctionDashboardFragment类和AssistantFunctionPreferenceController类)
3、AssistantFunctionDashboardFragment
package com.android.settings.assistant; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.SearchIndexableRaw; import com.android.settings.wiosfeature.firebase.ServiceUtils; import android.content.Context; import android.os.Bundle; import androidx.preference.Preference; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import android.provider.SearchIndexableResource; import java.util.ArrayList; import java.util.List; import android.util.Log; /** * @Author : 柒 * @Time : 2022/8/24 14:17 */ public class AssistantFunctionDashboardFragment extends SettingsPreferenceFragment { private static final Object TAG = "AssistantFunctionDashboardFragment"; private Context mContext; @Override public int getMetricsCategory() { return MetricsProto.MetricsEvent.SETTINGS_SYSTEM_CATEGORY; } //创建二级菜单 @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { super.onCreatePreferences(savedInstanceState, rootKey); addPreferencesFromResource(R.xml.assistant_function); } @Override public void onAttach(Context context) { super.onAttach(context); mContext = context; } // 为每个二级菜单项设置点击事件 @Override public boolean onPreferenceTreeClick(Preference preference) { String key = preference.getKey(); android.util.Log.i("AssistantFunctionDashboardFragment", "guan+onPreferenceTreeClick: " + key); switch (key){ case "color_adjustment": android.util.Log.i("AssistantFunctionDashboardFragment", "guan+color_adjustment: " + key); break; case "colorful_screen": android.util.Log.i("AssistantFunctionDashboardFragment", "guan+colorful_screen: " + key); break; } return true; } /** * For Search. */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.assistant_function) { @Override protected boolean isPageSearchEnabled(Context context) { return super.isPageSearchEnabled(context); } @Override public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) { return super.getXmlResourcesToIndex(context, enabled); } }; }
4、AssistantFunctionPreferenceController
package com.android.settings.assistant; import com.android.settings.core.BasePreferenceController; import android.content.Context; /** * @Author : 柒 * @Time : 2022/8/24 14:17 */ public class AssistantFunctionPreferenceController extends BasePreferenceController { //调用父类的构造方法 public AssistantFunctionPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } //实现该菜单项的显示 @Override public int getAvailabilityStatus() { return AVAILABLE; } }
5、AssistantFunctionDashboardActivity
在Settings目录下创建
package com.android.settings; /** * @Author : 柒 * @Time : 2022/8/24 15:11 */ public class AssistantFunctionDashboardActivity extends SettingsActivity{ }
6、assistant_function.xml
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/assistant_function" android:key="assistant_function_key"> <SwitchPreference android:key="high_contrast_font" android:title="@string/high_contrast_font" android:summary="@string/high_contrast_font_summary" /> <Preference android:key="color_adjustment" android:title="@string/color_adjustment" android:summary="@string/color_adjustment_summary"/> <Preference android:key="colorful_screen" android:title="@string/colorful_screen" android:summary="@string/colorful_screen_summary"/> </PreferenceScreen>
7、AndroidManifest.xml
<!--辅助功能--> <activity android:name="Settings$AssistantFunctionDashboardActivity" android:label="@string/assistant_function"> <intent-filter android:priority="12"> <action android:name="com.android.settings.action.SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.assistant.AssistantFunctionDashboardFragment" /> </activity>
8、Settings
public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
9、SettingsGateway
在SettingsGateway类的ENTRY_FRAGMENTS数组中加入AssistantFunctionDashboardFragment类名,在SETTINGS_FOR_RESTRICTED数组中加入AssistantFunctionPreferenceController类名
public static final String[] SETTINGS_FOR_RESTRICTED = { // Home page AssistantFunctionPreferenceController.class.getName(), ..... } public static final String[] ENTRY_FRAGMENTS = { AssistantFunctionDashboardFragment.class.getName(), .... }
10、strings
<string name="assistant_function">assistant & function</string> <string name="assistant_summary">assistant & summary</string> <string name="high_contrast_font">high_contrast & contrast_font</string> <string name="high_contrast_font_summary">high_contrast_font & summary</string> <string name="color_adjustment">color & adjustment</string> <string name="color_adjustment_summary">color_adjustment & summary</string> <string name="colorful_screen">colorful & screen</string> <string name="colorful_screen_summary">colorful_screen & summary</string>
<string name="assistant_function" msgid="3235725053332345774">"辅助功能"</string> <string name="assistant_summary" msgid="3235725053332345775">"高对比度字体、颜色调整、多彩屏幕"</string> <string name="high_contrast_font" msgid="3235725053332345776">"高对比度字体"</string> <string name="high_contrast_font_summary" msgid="3235725053332345777">"高对比度字体"</string> <string name="color_adjustment" msgid="3235725053332345778">"颜色调整"</string> <string name="color_adjustment_summary" msgid="3235725053332345779">"颜色调整"</string> <string name="colorful_screen" msgid="3235725053332345710">"多彩屏幕"</string> <string name="colorful_screen_summary" msgid="3235725053332345711">"多彩屏幕"</string>