android 系统setting研究

本文深入探讨了Android系统的设置功能,主要关注其数据库`settings.db`的使用,包括system和secure两个表的操作。通过`Settings.System`和`Settings.Secure`类提供的接口,可以方便地进行数据读写。同时,文章提到了设置界面的构建,指出`Settings`类继承自`PreferenceActivity`,并解析了`settings_headers.xml`来展示左侧的tab。每个tab对应不同的设置项,如WiFi、蓝牙、声音等,通过不同的fragment进行内容展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

settings 数据管理了系统的普通设置,比如铃声uri,音量,用来保证下次用户开机时候和前次关机的配置信息一直的。保存信息在android是肯定用sqlite, 这个东西真是博大精深。对数据库还有很多不理解的地方。要加强。
我们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);
                }
            } 

android settings源代码分析(2)

应用对应的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>

application fragment的布局本质就是一个ViewPager,因此可以支持左右滑动,每一页对应一个tab的显示。
 MyPagerAdapter adapter = new MyPagerAdapter();
        mViewPager.setAdapter(adapter);
        mViewPager.setOnPageChangeListener(adapter);
这里会设置一个adapter,用来填充ViewPager里的内容。
 class MyPagerAdapter extends PagerAdapter
            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);
            }
        }
    }
此adapter中instantiateItem函数会初始化每一个子项,即每一页:

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());
           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值