Android原生Settings源码分析

最近要修改Settings相关的东西,就顺便研究下Setings的代码结构,特做个记录

 

由于修改的是Android4.4的平台,所以以下都是在Android4.4基础上分析的。

 

1、入口

从packages/apps/settings/AndroidManifestxml找到Settings模块的入口:


            
                
                
                
                
            
        


说明进入settings的第一个Activity为Settings.java

 

2、Settings extends PreferenceActivity

settings继承与preverenceActivity,所以我们要主要两个重载函数onBuildHeaders和setListAdapter

1)onBuildHeaders

onbuildHeaders负责加载xml布局文件,这里的xml文件settings_headers使用的是Preference Headers,没有使用传统的PreferenceScreen。

每个Header对应一个子界面,一般为Fragment

关于这点可以参考http://www.xuebuyuan.com/549370.html

@Override
    public void onBuildHeaders(List
headers) { if (!onIsHidingHeaders()) { loadHeadersFromResource(R.xml.settings_headers, headers); updateHeaderList(headers); } }


 

2)setListAdapter

PreferenceActivity继承于ListActivity,所以这里可以使用需要ListView创建Adapter,这里的自定义Adapter对不同子菜单的分别处理有关键性作用

 

@Override    public void setListAdapter(ListAdapter adapter) {        if (adapter == null) {            super.setListAdapter(null);        } else {            DevicePolicyManager dpm =                    (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);            super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));        }    }

 

自定义Adapter:

private static class HeaderAdapter extends ArrayAdapter
{ static final int HEADER_TYPE_CATEGORY = 0; static final int HEADER_TYPE_NORMAL = 1; static final int HEADER_TYPE_SWITCH = 2; static final int HEADER_TYPE_BUTTON = 3; private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1; private final WifiEnabler mWifiEnabler; private final BluetoothEnabler mBluetoothEnabler; private AuthenticatorHelper mAuthHelper; private DevicePolicyManager mDevicePolicyManager; private static class HeaderViewHolder { ImageView icon; TextView title; TextView summary; Switch switch_; ImageButton button_; View divider_; } private LayoutInflater mInflater; static int getHeaderType(Header header) { if (header.fragment == null && header.intent == null) { return HEADER_TYPE_CATEGORY; } else if (header.id == R.id.security_settings) { return HEADER_TYPE_BUTTON; } else { return HEADER_TYPE_NORMAL; } } @Override public int getItemViewType(int position) { Header header = getItem(position); return getHeaderType(header); } @Override public boolean areAllItemsEnabled() { return false; // because of categories } @Override public boolean isEnabled(int position) { return getItemViewType(position) != HEADER_TYPE_CATEGORY; } @Override public int getViewTypeCount() { return HEADER_TYPE_COUNT; } @Override public boolean hasStableIds() { return true; } public HeaderAdapter(Context context, List
objects, AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) { super(context, 0, objects); mAuthHelper = authenticatorHelper; mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Temp Switches provided as placeholder until the adapter replaces these with actual // Switches inflated from their layouts. Must be done before adapter is set in super mWifiEnabler = new WifiEnabler(context, new Switch(context)); mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context)); mDevicePolicyManager = dpm; } @Override public View getView(int position, View convertView, ViewGroup parent) { HeaderViewHolder holder; Header header = getItem(position); int headerType = getHeaderType(header); View view = null; if (convertView == null) { holder = new HeaderViewHolder(); switch (headerType) { case HEADER_TYPE_CATEGORY: view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle); holder.title = (TextView) view; break; case HEADER_TYPE_SWITCH: view = mInflater.inflate(R.layout.preference_header_switch_item, parent, false); holder.icon = (ImageView) view.findViewById(R.id.icon); holder.title = (TextView) view.findViewById(com.android.internal.R.id.title); holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary); holder.switch_ = (Switch) view.findViewById(R.id.switchWidget); break; case HEADER_TYPE_BUTTON: view = mInflater.inflate(R.layout.preference_header_button_item, parent, false); holder.icon = (ImageView) view.findViewById(R.id.icon); holder.title = (TextView) view.findViewById(com.android.internal.R.id.title); holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary); holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget); holder.divider_ = view.findViewById(R.id.divider); break; case HEADER_TYPE_NORMAL: view = mInflater.inflate( R.layout.preference_header_item, parent, false); holder.icon = (ImageView) view.findViewById(R.id.icon); holder.title = (TextView) view.findViewById(com.android.internal.R.id.title); holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary); break; } view.setTag(holder); } else { view = convertView; holder = (HeaderViewHolder) view.getTag(); } // All view fields must be updated every time, because the view may be recycled switch (headerType) { case HEADER_TYPE_CATEGORY: holder.title.setText(header.getTitle(getContext().getResources())); break; case HEADER_TYPE_SWITCH: // Would need a different treatment if the main menu had more switches if (header.id == R.id.wifi_settings) { mWifiEnabler.setSwitch(holder.switch_); } else { mBluetoothEnabler.setSwitch(holder.switch_); } updateCommonHeaderView(header, holder); break; case HEADER_TYPE_BUTTON: if (header.id == R.id.security_settings) { boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled(); if (hasCert) { holder.button_.setVisibility(View.VISIBLE); holder.divider_.setVisibility(View.VISIBLE); boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null; if (isManaged) { holder.button_.setImageResource(R.drawable.ic_settings_about); } else { holder.button_.setImageResource( android.R.drawable.stat_notify_error); } holder.button_.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent( android.provider.Settings.ACTION_MONITORING_CERT_INFO); getContext().startActivity(intent); } }); } else { holder.button_.setVisibility(View.GONE); holder.divider_.setVisibility(View.GONE); } } updateCommonHeaderView(header, holder); break; case HEADER_TYPE_NORMAL: updateCommonHeaderView(header, holder); break; } return view; }


3、settings设置数据的保存

虽然preference是可以记录状态,并保存在sharedpreference文件中,但是有很多状态值是全局的,比如wifi,蓝牙等。所以这里涉及到全局数据的保存

以蓝牙为例,蓝牙打开关闭的操作在BluetoothEnabler.java里面

当按下蓝牙开关时,调用mLocalAdapter.setBluetoothEnabled(isChecked);-->BluetoothAdapter.enable()-->BluetoothAdapter:mManagerService.enable();-->BluetoothManagerService:enable-->BluetoothManagerService:persistBluetoothSetting

 private void persistBluetoothSetting(int value) {
        Settings.Global.putInt(mContext.getContentResolver(),
                               Settings.Global.BLUETOOTH_ON,
                               value);
    }


最终改的是Settings.Global.BLUETOOTH_ON的值,而这个默认值则在DatabaseHelper.java中设置

loadBooleanSetting(stmt, Settings.Global.BLUETOOTH_ON,
                    R.bool.def_bluetooth_on);


其他的值,比如wifi开关,默认语言等,都类似于这个过程


 

 

 

你可能感兴趣的:(Android原生Settings源码分析)