Android4.4设置源码分析(一):设置主界面与各模块之间的联系

来源:互联网 发布:ps裁切快捷键 mac 编辑:程序博客网 时间:2024/05/16 12:23

Android4.4设置源码分析(一):设置主界面与各模块之间的联系

寻找一个apk入口最快捷的途径就是查找AndroidManifest.xml文件,设置的AndroidManifest.xml文件如下:
<application android:label="@string/settings_label"
            android:icon="@mipmap/ic_launcher_settings"
            android:taskAffinity=""
            android:theme="@style/Theme.Settings"
            android:hardwareAccelerated="true"
            android:requiredForAllUsers="true"
            android:supportsRtl="true">
        <!-- Settings -->
        <activity android:name="Settings"
                android:label="@string/settings_label_launcher"
                android:taskAffinity="com.android.settings"
                android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.settings.SETTINGS" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 这两个属性说明该设置主activity是Settings,对应的类是Settings.java;而进入里表中的某项设置后,

 不是进入到新的Activity,而是在原来的Activity上切换了一个UI界面而已。


 4.0上Settings使用了Framgment机制。Fragment是我们在单个Activity上要切换多 个UI界面,显示不同内容,
 对不同的界面不再使用不同的Activity。模块化这些UI面板以便提供给其他Acitivity使用便利。同时我们显示
 的Fragment也会受到当前的这个 Acitivity生命周期影响。
 在res/xml/settings_headers.xml中可以找到settings中包含的选项,
 如:
 <preference-headers
        xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- WIRELESS and NETWORKS -->
    <header android:id="@+id/wireless_section"
        android:title="@string/header_category_wireless_networks" />
    <!-- Wifi -->
    <header
        android:id="@+id/wifi_settings"
        android:fragment="com.android.settings.wifi.WifiSettings"
        android:title="@string/wifi_settings_title"
        android:icon="@drawable/ic_settings_wireless" />
    <!-- Bluetooth -->
    <header
        android:id="@+id/bluetooth_settings"
        android:fragment="com.android.settings.bluetooth.BluetoothSettings"
        android:title="@string/bluetooth_settings_title"
        android:icon="@drawable/ic_settings_bluetooth2" />
    <!-- Ethernet -->
    <header
        android:id="@+id/ethernet_settings"
        android:title="@string/eth_setting"
        android:icon="@drawable/ic_settings_ethernet"
        android:fragment="com.android.settings.ethernet.EthernetSettings"/>
 Settings继承自PreferenceActivity,Settings的主界面布局加载地方
 /**
  * Populate the activity with the top-level headers.
  */
    @Override
    public void onBuildHeaders(List<Header> headers) {
        if (!onIsHidingHeaders()) {
        Log.d(LOG_TAG,"!onIsHidingHeaders");
            loadHeadersFromResource(R.xml.settings_headers, headers);
            updateHeaderList(headers);
        }
    }
updateHeaderList(headers)方法有什么用呢?
private void updateHeaderList(List<Header> target) {
        final boolean showDev = mDevelopmentPreferences.getBoolean(
                DevelopmentSettings.PREF_SHOW,
                android.os.Build.TYPE.equals("eng"));
        int i = 0;
        final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
        mHeaderIndexMap.clear();
        while (i < target.size()) {
            Header header = target.get(i);
            // Ids are integers, so downcasting
            int id = (int) header.id;
            if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
                Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this,                      target, header);
            } else if (id == R.id.wifi_settings) {
                // Remove WiFi Settings if WiFi service is not available.
            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
                target.remove(i);
                }
可以看出,它的作用是根据当前平台是否支持某项功能,决定是否显示相应的选项;
Android 3.0之后,摒弃了传统的 PreferenceScreen 嵌套方法,而是采用了所谓的Preference Headers 方法,
该方法的要点是:在主屏中通过 headers xml 文件布局列出所有的主题设置项,而每个主题设置的详细设置则
由各自指定的 PreferenceFragment 负责,而各自的 PreferenceFragment 可以如传统的PreferenceActivity
一样布局自身的 PreferenceScreen。另外,为了能够显示出 headers 中的布局列表,需要在继承的
PreferenceActivity 类中实现 onBuildHeaders() 回调方法。

hasSystemFeature方法
详细讲解hasSystemFeature(PackageManager.FEATURE_WIFI)。
FEATURE_WIFI在frameworks/base/core/java/android/content/pm/PackageManager.java
public static final String FEATURE_WIFI = "android.hardware.wifi";
hasSystemFeature方法在frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
public boolean hasSystemFeature(String name) {
        synchronized (mPackages) {
            return mAvailableFeatures.containsKey(name);
        }
    }
mAvailableFeatures里面的内容是通过读取/system/etc/permissions下面的文档,如android.hardware.wifi.xml;
android4.0 及以上 版本里 ,如果在settings下看不到wifi和bluetooth两个菜单选项,这是因为在setting里,
对系统是否有特定的模块加上了判断,如果没有就不显示。android4.0的模块判断函数:hasSystemFeature(String string).
通过该函数判断系统是否有特定的模块功能。
例如判断是否有 wifi 和 蓝牙模块的具体代码:
getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
getPackageManager().hasSystemFe(PackageManager.FEATURE_BLUETOOTH);
PackageManager这些字符串 存在system/etc/permissions/xxxx.xml文件里,它们一般从/framework/base/data/etc/xxx.xml复制过来。
     PackageManager.FEATURE_BLUETOOTH = "android.hardware.wifi"
     PackageManager.FEATURE_BLUETOOTH = "android.hardware.bluetooth"

解决wifi和蓝牙不显示方法:

一、直接把包含对应 feature 的xml文件复制到system/etc/permissions/目录下,相当于加上系统所具有的具体模块的功能配置文件;
如蓝牙不显示,将android.hardware.bluetooth.xml放在system/etc/permissions/目录下即可。

二、修改product_copy.mk文件,添加相应的设备。

参考资料:Android Settings(系统设置)源码分析(一)

             android Device Admin以及hasSystemFeature(String string)

0 0
原创粉丝点击