我们OEM厂商,出货后,用户第一次开机,系统保存了些默认的配置,是怎么来的呢。有settingprovider提供。
这个是个单独的apk ,就是用来共各个ap查询记录系统信息的。肯定用provider方式。在base/core/java/android/provider/settings.java这个文件提供了很多的接口用来操作数据。
相对来说即使不用看数据库的实现,只要简单操作这个类就够了。数据库名字是settings.db 创建了两个表 system, secure 要往某个表里写东西,可以直接叫到 Settings.System.put**() 跟上contentresolver。 键明,值,同样也可以Settings.System.get** 用法类似。
当然也可以Settings.secure.get put , 安全表主要用来记录一些网络配置信息。这个完全可以通过sqliteexpert打开看看。
第一开机时候,查询时候,会指定数据库名字版本
private static final String DATABASE_NAME = "settings.db";
// Please, please please. If you update the database version, check to make sure the
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
private static final int DATABASE_VERSION = 80;
然后oncreate时候,创建表,然后加载默认数据
loadSystemSettings(db); //nancy, 有问题多讨论。
loadSecureSettings(db);
insert or ignore into system values();
android settings源码分析
1.android settings源码的source code路径为:
kikat_4.4_CTS\packages\apps\Settings
2.settings主界面UI布局
Settings的启动类为:
/**
* Top-level settings activity to handle single pane and double pane UI layout.
*/
public class Settings extends PreferenceActivity
implements ButtonBarHandler, OnAccountsUpdateListener
从继承关系可以看出,Settings类继承于PreferenceActivity,因此具有Preference的一些属性和结构。
从Google settings的UI看出,左边是一些tab,右边是tab对应的内容,那么这些tab以及tab对应的内容主要是什么,以及如何显示的呢?
对于tab的显示,对应的code为:
/**
* Populate the activity with the top-level headers.
*/
@Override
public void onBuildHeaders(List<Header> headers) {
if (!onIsHidingHeaders()) {
loadHeadersFromResource(R.xml.settings_headers, headers);
updateHeaderList(headers);
}
}
可以看出,左边的tab实际是一些Header,从settings_headers.xml中获取这些header。settings_header.xml对应的code为:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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.
-->
<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 -->
<!-- MStar Android Patch Begin -->
<header
android:id="@+id/wifi_settings"
android:fragment="com.android.settings.wifi.TvWifiSettings"
android:title="@string/wifi_settings_title"
android:icon="@drawable/ic_settings_wireless" />
<!-- MStar Android Patch End -->
<!-- Ethernet -->
<header
android:id="@+id/ethernet_settings"
android:fragment="com.android.settings.ethernet.EthernetSettings"
android:title="@string/ethernet_status_title"
android:icon="@drawable/ic_settings_ethernet" />
<!-- Bluetooth -->
<header
android:id="@+id/bluetooth_settings"
android:fragment="com.android.settings.bluetooth.TvBluetoothSettings"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth2" />
<!-- Data Usage -->
<header
android:id="@+id/data_usage_settings"
android:fragment="com.android.settings.DataUsageSummary"
android:title="@string/data_usage_summary_title"
android:icon="@drawable/ic_settings_data_usage" />
<!-- Operator hook -->
<header
android:fragment="com.android.settings.WirelessSettings"
android:id="@+id/operator_settings">
<intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" />
</header>
<!-- Other wireless and network controls -->
<header
android:id="@+id/wireless_settings"
android:title="@string/radio_controls_title"
android:breadCrumbTitle="@string/wireless_networks_settings_title"
android:fragment="com.android.settings.WirelessSettings"
android:icon="@drawable/empty_icon" />
<!-- DEVICE -->
<header android:id="@+id/device_section"
android:title="@string/header_category_device" />
<!-- Home -->
<header
android:id="@+id/home_settings"
android:icon="@drawable/ic_settings_home"
android:fragment="com.android.settings.HomeSettings"
android:title="@string/home_settings" />
<!-- Sound -->
<header
android:id="@+id/sound_settings"
android:icon="@drawable/ic_settings_sound"
android:fragment="com.android.settings.SoundSettings"
android:title="@string/sound_settings" />
<!-- Display -->
<header
android:id="@+id/display_settings"
android:icon="@drawable/ic_settings_display"
android:fragment="com.android.settings.DisplaySettings"
android:title="@string/display_settings" />
<!-- Storage -->
<header
android:id="@+id/storage_settings"
android:fragment="com.android.settings.deviceinfo.Memory"
android:icon="@drawable/ic_settings_storage"
android:title="@string/storage_settings" />
<!-- Battery -->
<header
android:id="@+id/battery_settings"
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:icon="@drawable/ic_settings_battery"
android:title="@string/power_usage_summary_title" />
<!-- Application Settings -->
<header
android:fragment="com.android.settings.applications.ManageApplications"
android:icon="@drawable/ic_settings_applications"
android:title="@string/applications_settings"
android:id="@+id/application_settings" />
<!-- Manage users -->
<header
android:fragment="com.android.settings.users.UserSettings"
android:icon="@drawable/ic_settings_multiuser"
android:title="@string/user_settings_title"
android:id="@+id/user_settings" />
<!-- Manage NFC payment apps -->
<header
android:fragment="com.android.settings.nfc.PaymentSettings"
android:icon="@drawable/ic_settings_nfc_payment"
android:title="@string/nfc_payment_settings_title"
android:id="@+id/nfc_payment_settings" />
<!-- Manufacturer hook -->
<header
android:fragment="com.android.settings.WirelessSettings"
android:id="@+id/manufacturer_settings">
<intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />
</header>
<!-- PERSONAL -->
<header android:id="@+id/personal_section"
android:title="@string/header_category_personal" />
<!-- Location -->
<header
android:fragment="com.android.settings.location.LocationSettings"
android:icon="@drawable/ic_settings_location"
android:title="@string/location_settings_title"
android:id="@+id/location_settings" />
<!-- Security -->
<header
android:fragment="com.android.settings.SecuritySettings"
android:icon="@drawable/ic_settings_security"
android:title="@string/security_settings_title"
android:id="@+id/security_settings" />
<!-- 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" />
<!-- Backup and reset -->
<header
android:fragment="com.android.settings.PrivacySettings"
android:icon="@drawable/ic_settings_backup"
android:title="@string/privacy_settings"
android:id="@+id/privacy_settings" />
<!-- @Patch: GTV specific changes -->
<!-- MStar Android Patch Begin -->
<!-- Update -->
<header
android:id="@+id/update_settings"
android:fragment="com.android.settings.update.UpdateSettings"
android:title="@string/update_settings" />
<!-- MStar Android Patch End -->
<!-- ACCOUNTS section -->
<header
android:id="@+id/account_settings"
android:title="@string/account_settings" />
<header
android:id="@+id/account_add"
android:title="@string/add_account_label"
android:icon="@drawable/ic_menu_add_dark">
<intent
android:action="android.settings.ADD_ACCOUNT_SETTINGS"/>
</header>
<!-- SYSTEM -->
<header android:id="@+id/system_section"
android:title="@string/header_category_system" />
<!-- Date & Time -->
<header
android:id="@+id/date_time_settings"
android:fragment="com.android.settings.DateTimeSettings"
android:icon="@drawable/ic_settings_date_time"
android:title="@string/date_and_time_settings_title" />
<!-- Accessibility feedback -->
<header
android:id="@+id/accessibility_settings"
android:fragment="com.android.settings.accessibility.AccessibilitySettings"
android:icon="@drawable/ic_settings_accessibility"
android:title="@string/accessibility_settings" />
<!-- Print -->
<header
android:id="@+id/print_settings"
android:fragment="com.android.settings.print.PrintSettingsFragment"
android:icon="@*android:drawable/ic_print"
android:title="@string/print_settings" />
<!-- Development -->
<header
android:id="@+id/development_settings"
android:fragment="com.android.settings.DevelopmentSettings"
android:icon="@drawable/ic_settings_development"
android:title="@string/development_settings_title" />
<!-- About Device -->
<header
android:id="@+id/about_settings"
android:fragment="com.android.settings.DeviceInfoSettings"
android:icon="@drawable/ic_settings_about"
android:title="@string/about_settings" />
</preference-headers>
从上述xml可以看出,header的内容是通过fragment来显示,定义了每一个header对应的fragment。
在private void updateHeaderList(List<Header> target)函数中,会根据当前平台是否支持某项feature,决定是否显示对应的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);
}
} else if (id == R.id.bluetooth_settings) {
// Remove Bluetooth Settings if Bluetooth service is not available.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
target.remove(i);
}
}
应用对应的fragment为:
<header
android:fragment="com.android.settings.applications.ManageApplications"
android:icon="@drawable/ic_settings_applications"
android:title="@string/applications_settings"
android:id="@+id/application_settings" />
因此需要查看ManageApplications如何实现。
ManageApplications所在路径为:
kikat_4.4_CTS\packages\apps\Settings\src\com\android\settings\applications
从Application UI可以看出,fragment主要是一个tab,以及每一个tab下都会显示和存储相关的信息,比如RAM,SDCARD和内部存储空间的大小。接下来分析tab如何实现以及这些存储信息如何获取。
查看ManageApplications的onCreateView函数,可以看到:
View rootView = mInflater.inflate(R.layout.manage_applications_content,container, false);
这里会使用manage_applications_content.xml,我们查看xml的内容:
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2012, 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.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<android.support.v4.view.PagerTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textAppearance="@style/TextAppearance.PagerTabs"
android:padding="0dp">
</android.support.v4.view.PagerTabStrip>
</android.support.v4.view.ViewPager>
</LinearLayout>
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(adapter);
implements ViewPager.OnPageChangeListener {
int mCurPos = 0;
@Override
public int getCount() {
return mNumTabs;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TabInfo tab = mTabs.get(position);
View root = tab.build(mInflater, mContentContainer, mRootView);
container.addView(root);
root.setTag(R.id.name, tab);
return root;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
//return ((TabInfo)((View)object).getTag(R.id.name)).mListType;
}
@Override
public CharSequence getPageTitle(int position) {
return mTabs.get(position).mLabel;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurPos = position;
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
updateCurrentTab(mCurPos);
}
}
}
TabInfo tab = mTabs.get(position);
View root = tab.build(mInflater, mContentContainer, mRootView);
因此需要查看TabInfo中的build函数。
public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
if (mRootView != null) {
return mRootView;
}
mInflater = inflater;
mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING
? R.layout.manage_applications_running
: R.layout.manage_applications_apps, null);
mLoadingContainer = mRootView.findViewById(R.id.loading_container);
mLoadingContainer.setVisibility(View.VISIBLE);
mListContainer = mRootView.findViewById(R.id.list_container);
if (mListContainer != null) {
// Create adapter and list view here
View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
if (emptyView != null) {
lv.setEmptyView(emptyView);
}
lv.setOnItemClickListener(this);
lv.setSaveEnabled(true);
lv.setItemsCanFocus(true);
lv.setTextFilterEnabled(true);
mListView = lv;
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
mListView.setAdapter(mApplications);
mListView.setRecyclerListener(mApplications);
mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
if (mFilter == FILTER_APPS_SDCARD) {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.sd_card_storage));
} else {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.internal_storage));
}
applyCurrentStorage();
}
mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
R.id.running_processes);
if (mRunningProcessesView != null) {
mRunningProcessesView.doCreate(mSavedInstanceState);
}
return mRootView;
}
此函数中用来显示tab中listview和tab下对应的storage显示信息。
对于tab中listView的填充:
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView);
convertView = holder.rootView;
// Bind the data efficiently with the holder
ApplicationsState.AppEntry entry = mEntries.get(position);
synchronized (entry) {
holder.entry = entry;
if (entry.label != null) {
holder.appName.setText(entry.label);
}
mState.ensureIcon(entry);
if (entry.icon != null) {
holder.appIcon.setImageDrawable(entry.icon);
}
holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
holder.disabled.setVisibility(View.VISIBLE);
holder.disabled.setText(R.string.not_installed);
} else if (!entry.info.enabled) {
holder.disabled.setVisibility(View.VISIBLE);
holder.disabled.setText(R.string.disabled);
} else {
holder.disabled.setVisibility(View.GONE);
}
if (mFilterMode == FILTER_APPS_SDCARD) {
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setChecked((entry.info.flags
& ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
} else {
holder.checkBox.setVisibility(View.GONE);
}
}
mActive.remove(convertView);
mActive.add(convertView);
return convertView;
}
对于storage的获取,需要使用到IMediaContainerService,绑定此service的地方:
getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);
连接此service,每一个tab都会得到此service实例,通过此实例获取storage相关信息
private volatile IMediaContainerService mContainerService;
private final ServiceConnection mContainerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mContainerService = IMediaContainerService.Stub.asInterface(service);
for (int i=0; i<mTabs.size(); i++) {
mTabs.get(i).setContainerService(mContainerService);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mContainerService = null;
}
};
获取storage信息代码如下:
获取SD卡:
if (mFilter == FILTER_APPS_SDCARD) {if (mContainerService != null) {
try {
final long[] stats = mContainerService.getFileSystemStats(
Environment.getExternalStorageDirectory().getPath());