首页 > 代码库 > Android 在frameworks中修改Setting中的默认值 (二)

Android 在frameworks中修改Setting中的默认值 (二)

修改设置->关于手机->法律信息 下有一些Item,如开放源代码许可、Google法律信息等,这里分析的是Android 4.4的代码

如下图所示,想添加“Google法律信息”选项

查看Settings的源码在/Settings/src/com/android/settings/DeviceInfoSettings.java文件初始化时有这样一段代码

@Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        addPreferencesFromResource(R.xml.device_info_settings);

        //............................................省略

        /*
         * Settings is a generic app and should not contain any device-specific
         * info.
         */
        final Activity act = getActivity();
        // These are contained in the "container" preference group
        PreferenceGroup parentPreference = (PreferenceGroup) findPreference(KEY_CONTAINER);
        Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_TERMS,
                Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
        Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_LICENSE,
                Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
        Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_COPYRIGHT,
                Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
        Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_TEAM,
                Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);

        //..............................................省略
    }
看加载的资源文件device_info_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the 
	Apache License, Version 2.0 (the "License"); you may not use this file except 
	in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
	Unless required by applicable law or agreed to in writing, software distributed 
	under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 
	OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
	the specific language governing permissions and limitations under the License. -->

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
	android:title="@string/about_settings">

	<!-- System update settings - launches activity -->
	<PreferenceScreen android:key="system_update_settings"
		android:title="@string/system_update_settings_list_item_title"
		android:summary="@string/system_update_settings_list_item_summary">
		<intent android:action="android.settings.SYSTEM_UPDATE_SETTINGS" />
	</PreferenceScreen>
	<PreferenceScreen android:key="software_update"
		android:title="@string/software_update">
	</PreferenceScreen>
	<PreferenceScreen android:key="mdm_fumo"
		android:title="@string/software_update">
	</PreferenceScreen>
	<!-- MOTA -->
        <PreferenceScreen android:key="mtk_system_update">
		<intent android:action="com.mediatek.intent.System_Update_Entry" />
	</PreferenceScreen>

	<!-- software update service -->
	<PreferenceScreen android:key="scomo"
		android:title="@string/scomo_settings_title" android:summary="@string/software_updates_scomo_summary">
		<intent android:action="android.intent.action.MAIN"
			android:targetPackage="com.mediatek.dm" android:targetClass="com.mediatek.dm.scomo.DmScomoActivity" />
	</PreferenceScreen>
	<PreferenceScreen android:key="mdm_scomo"
		android:summary="@string/software_updates_scomo_summary"
		android:title="@string/scomo_settings_title">
		<intent android:action="android.intent.action.MAIN"
			android:targetClass="com.mediatek.mediatekdm.scomo.DmScomoActivity"
			android:targetPackage="com.mediatek.mediatekdm" />
	</PreferenceScreen>

	<PreferenceScreen android:key="additional_system_update_settings"
		android:title="@string/additional_system_update_settings_list_item_title">
		<intent android:action="android.intent.action.MAIN"
			android:targetPackage="@string/additional_system_update"
			android:targetClass="@string/additional_system_update_menu" />
	</PreferenceScreen>

	<!-- More Software updates - launches activity -->
	<PreferenceScreen android:key="more_software_updates"
		android:title="@string/software_updates_more_title" android:summary="@string/software_updates_more_summary">
		<intent android:targetPackage="com.android.settings"
			android:targetClass="com.mediatek.settings.deviceinfo.SoftwareUpdates" />
	</PreferenceScreen>

	<!-- Device status - launches activity -->
	<PreferenceScreen android:key="status_info"
		android:title="@string/device_status" android:summary="@string/device_status_summary">
		<intent android:action="android.intent.action.MAIN"
			android:targetPackage="com.android.settings" android:targetClass="com.android.settings.deviceinfo.Status" />
	</PreferenceScreen>

	<!-- Gemini Device status - launches Gemini activity -->
	<PreferenceScreen android:key="status_info_gemini"
		android:title="@string/device_status" android:summary="@string/device_status_summary">
		<intent android:action="android.intent.action.MAIN"
			android:targetPackage="com.android.settings" android:targetClass="com.mediatek.settings.deviceinfo.StatusGemini" />
	</PreferenceScreen>

	<!-- Legal Information -->
	<PreferenceScreen android:key="container"
		android:title="@string/legal_information">

		<!-- Note: The titles given here probably won't be used. Instead, we programmatically 
			fill the title with the label of the activity with the corresponding action. 
			If there is not an activity for an action, the item will be removed from 
			the list. -->

		<!-- Copyright information -->
		<PreferenceScreen android:key="copyright"
			android:title="@string/copyright_title">
			<intent android:action="android.settings.COPYRIGHT" />
		</PreferenceScreen>

		<!-- License information -->
		<PreferenceScreen android:key="license"
			android:title="@string/license_title">
			<intent android:action="android.settings.LICENSE" />
		</PreferenceScreen>

		<!-- Terms and conditions -->
		<PreferenceScreen android:key="terms" android:title="@string/terms_title">
			<intent android:action="android.settings.TERMS" />
		</PreferenceScreen>

	</PreferenceScreen>

	<PreferenceScreen android:key="safetylegal"
		android:title="@string/settings_safetylegal_title">
		<intent android:action="android.settings.SAFETY" />
	</PreferenceScreen>

	<!-- Contributors -->
	<!-- <PreferenceScreen android:key="contributors" android:title="@string/contributors_title"> 
		<intent android:action="android.settings.TEAM" /> </PreferenceScreen> -->

        <PreferenceScreen
                android:key="regulatory_info"
                android:title="@string/regulatory_information">
            <intent android:action="android.settings.SHOW_REGULATORY_INFO" />
        </PreferenceScreen>

	<!-- Device hardware model -->
	<Preference android:key="device_model"
		style="?android:preferenceInformationStyle" android:title="@string/model_number"
		android:summary="@string/device_info_default" />

	<!-- Device firmware version -->
	<Preference android:key="firmware_version"
		style="?android:preferenceInformationStyle" android:title="@string/firmware_version"
		android:summary="@string/device_info_default" />

	<!-- Device FCC equipment id -->
	<Preference android:key="fcc_equipment_id"
		style="?android:preferenceInformationStyle" android:title="@string/fcc_equipment_id"
		android:summary="@string/device_info_default" />

	<!-- Device Baseband version -->
	<Preference android:key="baseband_version"
		style="?android:preferenceInformationStyle" android:title="@string/baseband_version"
		android:summary="@string/device_info_default" />

	<!-- Device 2nd Baseband version -->
	<Preference android:key="baseband_version_2"
		style="?android:preferenceInformationStyle" android:title="@string/baseband_version"
		android:summary="@string/device_info_default" />

	<!-- Device Kernel version -->
	<Preference android:key="kernel_version"
		style="?android:preferenceInformationStyle" android:title="@string/kernel_version"
		android:summary="@string/device_info_default" />

	<!-- Detailed build version -->
	<Preference android:key="build_number"
		style="?android:preferenceInformationStyle" android:title="@string/build_number"
		android:summary="@string/device_info_default" />

	<!-- Detailed customer build version -->
	<Preference android:key="custom_build_version"
		style="?android:preferenceInformationStyle" android:title="@string/custom_build_version"
		android:summary="@string/device_info_default" />

	<!-- SELinux status information -->
	<Preference android:key="selinux_status"
		style="?android:preferenceInformationStyle" android:title="@string/selinux_status"
		android:summary="@string/selinux_status_enforcing" />

</PreferenceScreen>
在这个xml中配置的Action就是整个《关于手机》上的所有Item,从上面的信息中可以找到《法律信息》选项,有三个子项目

<!-- Legal Information -->
	<PreferenceScreen android:key="container"
		android:title="@string/legal_information">

		<!-- Note: The titles given here probably won't be used. Instead, we programmatically 
			fill the title with the label of the activity with the corresponding action. 
			If there is not an activity for an action, the item will be removed from 
			the list. -->

		<!-- Copyright information -->
		<PreferenceScreen android:key="copyright"
			android:title="@string/copyright_title">
			<intent android:action="android.settings.COPYRIGHT" />
		</PreferenceScreen>

		<!-- License information -->
		<PreferenceScreen android:key="license"
			android:title="@string/license_title">
			<intent android:action="android.settings.LICENSE" />
		</PreferenceScreen>

		<!-- Terms and conditions -->
		<PreferenceScreen android:key="terms" android:title="@string/terms_title">
			<intent android:action="android.settings.TERMS" />
		</PreferenceScreen>

	</PreferenceScreen>
以上选项是否会显示出来是由updatePreferenceToSpecificActivityOrRemove函数处理,这个函数在/Settings/src/com/android/settings/Utils.java

public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
            PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {

        Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
        if (preference == null) {
            return false;
        }

        Intent intent = preference.getIntent();
        if (intent != null) {
            // Find the activity that is in the system image
            PackageManager pm = context.getPackageManager();
            List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
            int listSize = list.size();
            for (int i = 0; i < listSize; i++) {
                ResolveInfo resolveInfo = list.get(i);
                if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
                        != 0) {

                    // Replace the intent with this specific activity
                    preference.setIntent(new Intent().setClassName(
                            resolveInfo.activityInfo.packageName,
                            resolveInfo.activityInfo.name));

                    if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
                        // Set the preference title to the activity's label
                        preference.setTitle(resolveInfo.loadLabel(pm));
                    }

                    return true;
                }
            }
        }

        // Did not find a matching activity, so remove the preference
        parentPreferenceGroup.removePreference(preference);

        return false;
    }
如在Settings中会调用

Utils.updatePreferenceToSpecificActivityOrRemove(act, parentPreference, KEY_TERMS, Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);

去查找是否存在安装在/system/app/目录下对应的Action,如果存在就不处理,否则就不显示该Item。

目前我的手机上没有显示《Google法律信息》选项,说明没有找到注册“android.settings.TERMS”这个Action的Activity,就不显示该Item,我们可以写个测试程序,去注册“android.settings.TERMS”

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cts_7301"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.example.cts_7301.activi"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name="com.example.cts_7301.termsActivity" >
            <intent-filter>
                <action android:name="android.settings.TERMS" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>
然后把这个Apk安装到/system/app/目录下

dzt@dzt-All-Series:~/workspace/cts_7301/bin$ ls
AndroidManifest.xml  classes  classes.dex  cts_7301.apk  dexedLibs  res  resources.ap_
dzt@dzt-All-Series:~/workspace/cts_7301/bin$ adb push cts_7301.apk /system/app/
3474 KB/s (549968 bytes in 0.154s)
dzt@dzt-All-Series:~/workspace/cts_7301/bin$ adb push cts_7301.apk /system/app/
3242 KB/s (549968 bytes in 0.165s)
dzt@dzt-All-Series:~/workspace/cts_7301/bin$ 
把Settings App完全关闭后再启动,此时就能看到刚刚注册的Action就能添加到Item


logcat

01-02 12:35:01.893 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=android.settings.TERMS } flags = 0 userId = 0
01-02 12:35:01.895 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = [ResolveInfo{42a88520 com.example.cts_7301/.termsActivity m=0x108000}]
01-02 12:35:01.897 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=android.settings.LICENSE } flags = 0 userId = 0
01-02 12:35:01.899 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = [ResolveInfo{42a91e68 com.android.settings/.SettingsLicenseActivity m=0x108000}]
01-02 12:35:01.901 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=android.settings.COPYRIGHT } flags = 0 userId = 0
01-02 12:35:01.902 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
01-02 12:35:01.902 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=android.settings.SYSTEM_UPDATE_SETTINGS } flags = 0 userId = 0
01-02 12:35:01.904 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
01-02 12:35:01.937 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=com.android.settings.OPERATOR_APPLICATION_SETTING } flags = 128 userId = 0
01-02 12:35:01.938 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
01-02 12:35:01.941 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=com.android.settings.MANUFACTURER_APPLICATION_SETTING } flags = 128 userId = 0
01-02 12:35:01.943 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
01-02 12:35:02.177 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=com.android.settings.OPERATOR_APPLICATION_SETTING } flags = 128 userId = 0
01-02 12:35:02.179 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
01-02 12:35:02.180 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser intent = Intent { act=com.android.settings.MANUFACTURER_APPLICATION_SETTING } flags = 128 userId = 0
01-02 12:35:02.181 I/dzt     (19718): ApplicationPackageManager---queryIntentActivitiesAsUser list = []
由于PackageManager是一个抽象类,调用queryIntentActivitiesAsUser最终会调用/frameworks/base/core/java/android/app/ApplicationPackageManager.java类的

@Override
    public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                                                   int flags, int userId) {
    	Log.i("dzt", "ApplicationPackageManager---queryIntentActivitiesAsUser intent = " + intent.toString() + " flags = "+flags + " userId = "+userId);
        try {
        	List<ResolveInfo> list = mPM.queryIntentActivities(
                    intent,
                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                    flags,
                    userId);
        	Log.i("dzt", "ApplicationPackageManager---queryIntentActivitiesAsUser list = " + list.toString());
            return list;
        } catch (RemoteException e) {
            throw new RuntimeException("Package manager has died", e);
        }
    }
这说明《法律信息》中的三个Item需要有Activity注册了对应的Action才会显示出来,不一定是Settings App也可以是其它的apk,但必需是安装在/system/app/目录下的才行。

Android 在frameworks中修改Setting中的默认值 (二)