Settings涉及的模块
四个部分:
WIRELESS & NETWORKS :SIM卡管理,流量使用情况,飞行模式,VPN,网络共享等
DEVICE : 情景模式,显示,存储,电池,应用程序
PERSONAL: 账户与同步,位置服务,安全,语言和输入法,备份和重置
SYSTEM: 日期和时间,定时开关及,辅助功能,开发人员选项,关于手机
1. com.android.settings.Settings类
1) Framgment机制
Fragment是我们在单个Activity上要切换多个UI界面,显示不同内容,对不同的界面不再使用不同的Activity。模块化这些UI面板以便提供给其他Acitivity使用便利。同时我们显示的Fragment也会受到当前的这个 Acitivity生命周期影响。
因为使用了Fragment机制,所有Settings的主要的Layout文件和2.3已经有很大不同。在res/xml/settings_headers.xml中可以找到settings中包含的选项,可以比较一下两者的不同:在2.3中layout文件为:(res/xml/settings.xml)<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/settings_label"
android:key="parent">
<!-- CustomizationSettings -->
<com.android.settings.IconPreferenceScreen
android:key="customization_settings"
android:title="@string/customization"
settings:icon="@drawable/ic_settings_customization">
</com.android.settings.IconPreferenceScreen>
...(以下略)
而在4.0中的layout文件为:
<preference-headers
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- WIRELESS andNETWORKS -->
<headerandroid:title="@string/header_category_wireless_networks" />
<!-- Sim management-->
<header
android:id="@+id/sim_settings"
android:icon="@drawable/ic_settings_dualsim"
android:fragment="com.android.settings.gemini.SimManagement"
android:title="@string/gemini_sim_management_title" />
两者的很大的不同就是在4.0中用了Fragment机制后,每个列表相应后不是重新启动一个Activity,而是在原来的Activity(Settings)上切换了一个UI界面,在<header …/>中通过以下方法指定每个模块设置相关的类: android:fragment="com.android.settings.****.****"
这些类都是继承自Fragment类。相关的模块设置的入口类如下:
SIM卡设置:com.android.settings.gemini.SimManagement
wifi设置:com.android.settings.wifi.WifiSettings
蓝牙设置:com.android.settings.bluetooth.BluetoothSettings
流量:com.android.settings.DataUsageSummary
更多(wireless):com.android.settings.WirelessSettings
情景模式:com.android.settings.audioprofile.AudioProfileSettings
显示:com.android.settings.DisplaySettings
存储:com.android.settings.deviceinfo.Memory
电池: com.android.settings.fuelgauge.PowerUsageSummary
应用程序:com.android.settings.applications.ManageApplications
账户与同步:com.android.settings.accounts.ManageAccountsSettings
位置:com.android.settings.LocationSettings
安全:com.android.settings.SecuritySettings
输入法与语言:com.android.settings.inputmethod.InputMethodAndLanguageSettings
日期时间设置:com.android.settings.DateTimeSettings
定时开关机:com.android.settings.schpwronoff.AlarmClock
开发人员选项:com.android.settings.DevelopmentSettings
关于手机:com.android.settings.DeviceInfoSettings
2) 实现onBuildHeaders()回调用来指定头文件
调用loadHeadersFromResource()方法对界面进行加载
@Override
public void onBuildHeaders(List<Header>headers) {
loadHeadersFromResource(R.xml.settings_headers,headers);
updateHeaderList(headers);
mHeaders = headers;
}
3) 显示界面
public voidsetListAdapter(ListAdapter adapter) {
if (mHeaders == null){
mHeaders = newArrayList<Header>();
// When the savedstate provides the list of headers, onBuildHeaders is not called
// Copy the list ofHeaders from the adapter, preserving their order
for (int i = 0; i< adapter.getCount(); i++) {
mHeaders.add((Header) adapter.getItem(i));
}
}
// Ignore the adapterprovided by PreferenceActivity and substitute ours instead
super.setListAdapter(newHeaderAdapter(this, mHeaders));
HeaderAdapter是Settings中的一个内部类。下面来看下HeaderAdapter这个适配类
private static class HeaderAdapter extends ArrayAdapter<Header>{
//三种 类型的header
static final intHEADER_TYPE_CATEGORY = 0;//分类
static final intHEADER_TYPE_NORMAL = 1;//一般的
static final intHEADER_TYPE_SWITCH = 2;//开关形式的
....
}
类的开头就定义了三个常量:这个代表Header的三种类型
HEADER_TYPE_CATEGORY代表一个分类,它不能点击,像这个:
HEADER_TYPE_NORMAL代表一个常规项,像这个:
HEADER_TYPE_SWITCH代表一种开头形式的类型,像这个:
getView()方法中也是根据三种不同的类型,加载不同的view以及数据。
4) 处理点击事件
PreferenceActivity重写了ListActivity的这个文法
[java] view plaincopy
@Override
protected voidonListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (mAdapter !=null) {
Object item =mAdapter.getItem(position);
if (iteminstanceof Header) onHeaderClick((Header) item, position);
}
}
再看onHeaderClick()方法
public void onHeaderClick(Header header, int position) {
if (header.fragment !=null) {
if (mSinglePane){
int titleRes =header.breadCrumbTitleRes;
int shortTitleRes= header.breadCrumbShortTitleRes;
if (titleRes ==0) {
titleRes =header.titleRes;
shortTitleRes = 0;
}
startWithFragment(header.fragment,header.fragmentArguments,
null, 0, titleRes, shortTitleRes);
} else {
switchToHeader(header);
}
} else if(header.intent != null) {
startActivity(header.intent);
}
}
2. 获取与设置系统属性
在android中,许多的系统属性都在settings应用当中进行设置的,如wifi,蓝牙状态,本机语言,屏幕亮度等一些相关的系统属性值。这些数据存储在数据库中,对应的两个主要的URI:content://settings/system和 content://settings/secure。
在settings应用中所获取或者修改属性都是调用了framework中的android.provider.settings中的Settings类对应的方法。在android.provider.settings.Settings里面,包含了System和Secure几个内部类,每个内部类对应了一张数据库表,也就是继承自BaseColumn类。System和Secure类分别对应着system和secure数据库表。里面包含了获取设置值的方法以及相关设置项的URI字串。
常见的获取和设置系统属性的方法有:
getString(param1,param2)<---> putString(param1,param2)
getInt(param1,param2) <---> putInt(param1,param2)
getLong(param1,param2) <---> putLong(param1,param2)
getConfiguration(param1,param2) <---> putConfiguration(param1,param2)
getFloat(param1,param2) <---> putFloat(param1,param2)
...
Example:settings应用中是如何对系统属性进行设置的。
当需要获得当前wifi状态的值,调用已封装的方法如下:
Settings.Secure.getInt(getContentResolver(), Settings.Secure.WIFI_ON);
修改wifi状态只需要调用对应的setInt方法就可以实现。
当需要获得当前时间日期自动获取,调用如下:
Settings.System.getInt(getContentResolver(), "auto_time");
修改也是调用对应的setInt方法。
3. language settings示例分析
通过分析language settings中的auto_caps(自动替换)设置来分析Settings中是怎么对系统属性进行基本设置的。
1)找到对应的JAVA类文件 InputMethodAndLanguageSettings
在 res./xml/settings_headers.xml中有:
<!-- Language -->
<header
android:id="@+id/language_settings"
android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings"
android:icon="@drawable/ic_settings_language"
android:title="@string/language_settings" />
2) 找到 R.xml.language_settings布局文件
在 InputMethodAndLanguageSettings.java中,我们找到:
publicvoid onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.language_settings); }
…
可以找到language_settings.xml文件.同样可以看到这里利用了Fragment机制。
在代码中我们找到自动替换的设置选项分析:
<CheckBoxPreference
android:key="auto_caps"
android:title="@string/auto_caps"
android:summaryOn="@string/auto_caps_summary"
android:summaryOff="@string/auto_caps_summary"
android:persistent="false"/>
3) 获取和设置属性
在com.android.settings.inputmethod.InputMethodAndLanguageSettings.java中:
在以下代码获得auto_replace的checkbox的key值:
private static final String[] sHardKeyboardKeys = {
"auto_replace", "auto_caps","auto_punctuate",
};
在onResume()中来初始化checkbox:四个循环分别为物理键盘的checkbox选项:
// Hard keyboard
if (mHaveHardKeyboard) {
for (int i = 0; i <sHardKeyboardKeys.length; ++i) {
/*以下获取Checkbox的对象*/
CheckBoxPreferencechkPref = (CheckBoxPreference)
mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i]);
/*利用Settings.System.getInt()来获取属性值*/
chkPref.setChecked(
System.getInt(getContentResolver(), sSystemSettingNames[i], 1) > 0);
}
}
我们可以看到Settings.System.getInt()方法的应用。
在onPreferenceClick()中可以看到对auto_cap选项的设置:
if (mHaveHardKeyboard) {
for (int i = 0; i <sHardKeyboardKeys.length; ++i) {
if (chkPref ==mHardKeyboardCategory.findPreference(sHardKeyboardKeys[i])) {
/*将设置的新的属性写如数据库*/
System.putInt(getContentResolver(), sSystemSettingNames[i],
chkPref.isChecked() ? 1 : 0);
return true;
}
}
}
我们可以看到Settings.System.putInt()方法的应用
4. 在辅助功能中添加自动生成短信
1) 首先根据setting_header.xml查到辅助功能的属性信息,找到com.android.settings.accessibility.AccessibilitySettings,
2) 根据AccessibilitySettings 的oncreate(),找到fragment Accessibility_settings.xml添加
<PreferenceScreen
android:key="message_auto_insert"
android:title="@string/message_auto_insert_title"/>
3) 在AccessibilitySettings 的onPreferenceTreeClick方法中添加
else if(preference.getKey().equals("message_auto_insert")){
Intent intent =new Intent(Intent.ACTION_MAIN);
intent.setClassName("com.huaqin.messageinsert",
"com.huaqin.messageinsert.MainActivity");
try {
startActivity(intent);
} catch (Exception e) {
Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
}
}
注:将自动生成短信的应用activity发布方式改为:DEFAULT,可以隐藏应用,只通过辅助功能去启动。