Android 系统APN配置具体解释

这些天一直在调系统原生的Settings.apk里面APN配置的问题。在设置里面手动添加了APN配置选项。可是在界面上还是看不到。所以跟了下代码。原以为就是简单的页面显示的问题。这一跟不要紧。一下就快追到HAL层去了(NND).

首先看Settings.apk的源代码,位于packages/apps/Settings/src/com/android/settings/文件夹下:首先找到ApnSettings类。继承于PreferenceActivity,并实现了Preference.OnPreferenceChangeListener接口。PreferencesActivity是Android中专门用来实现程序设置界面及參数存储的一个Activity。这里就不再赘述了。

public class ApnSettings extends PreferenceActivity implements
Preference.OnPreferenceChangeListener { // 恢复出厂设置的URI
public static final String RESTORE_CARRIERS_URI = "content://telephony/carriers/restore";
// 普通URI。用于ContentPrivoder保存着APN配置信息
public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; private static final Uri DEFAULTAPN_URI = Uri.parse(RESTORE_CARRIERS_URI);
private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); // 两个句柄。用于恢复出厂设置
private RestoreApnUiHandler mRestoreApnUiHandler;
private RestoreApnProcessHandler mRestoreApnProcessHandler; private String mSelectedKey; // 组播接收的Intent过滤器
private IntentFilter mMobileStateFilter; private final BroadcastReceiver mMobileStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(
TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
Phone.DataState state = getMobileDataState(intent);
switch (state) {
case CONNECTED:
if (!mRestoreDefaultApnMode) {
fillList();
} else {
showDialog(DIALOG_RESTORE_DEFAULTAPN);
}
break;
}
}
}
}; @Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
// 在activity创建的时候依据xml文件来配置视图。
// 实际上 res/xml/apn_settings.xml这个文件就是一个空的PreferenceScreen
addPreferencesFromResource(R.xml.apn_settings);
getListView().setItemsCanFocus(true); // 假设有List则获得焦点
// 这个创建一个Inter 过滤器。过滤的动作为 ACTION_ANY_DATA_CONNECTION_STATE_CHANGED
mMobileStateFilter = new IntentFilter(
TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
} @Override
protected void onResume() {
super.onResume();
// 注冊一个广播接受者
registerReceiver(mMobileStateReceiver, mMobileStateFilter);
if (!mRestoreDefaultApnMode) { // 假设不是恢复出厂设置
fillList(); // 填充Activity的ListView
} else {
showDialog(DIALOG_RESTORE_DEFAULTAPN);
}
}
}

1)    这里首先在onCreate()方法中,依据apn_settings.xml文件来配置界面的视图。实际上就是一个PreferenceScreen。创建一个Intent过滤器, 过滤动作为ACTION_ANY_DATA_CONNECTION_STATE_CHANGED。

2)    然后在onResume()方法中,注冊一个广播接受者。当收到上面的ACTION_ANY_DATA_CONNECTION_STATE_CHANGED动作时。调用

mMobileStateReceiver的onReceive()方法。其目的是为了,当我们进入APN设置的时候,这是再插上SIM卡能显示出APN的配置信息。然后推断是不是须要恢复出厂设置,假设不是。则调用fillList()方法填充当前Activity,显示出APN的配置信息。

3)   首先获取系统属性gsm.sim.operator.numeric,依据这个參数通过系统提供的ContentProvider查询数据库(位于/data/data/com.android.providers.Telephony下的telephony.db数据库中carriers表中)。获得相应的配置信息。然后将其填充到每个ApnPreference中,最后将每个ApnPreference显示到当前的PreferenceGroup上。

private void fillList() {
// 获取系统的gsm.sim.operator.numeric 属性
String where = "numeric=\"" + android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "")+ "\""; // 调用系统提供的ContentProvider查询数据库
Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
"_id", "name", "apn", "type"}, where, null,
Telephony.Carriers.DEFAULT_SORT_ORDER);
// 找到当前Activity中的PreferenceGroup
PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
apnList.removeAll(); ArrayList<Preference> mmsApnList = new ArrayList<Preference>(); mSelectedKey = getSelectedApnKey();
cursor.moveToFirst();
// 迭代查询数据库
while (!cursor.isAfterLast()) {
String name = cursor.getString(NAME_INDEX);
String apn = cursor.getString(APN_INDEX);
String key = cursor.getString(ID_INDEX);
String type = cursor.getString(TYPES_INDEX);
// 新建一个 ApnPreference,填充里面控件的值
ApnPreference pref = new ApnPreference(this); pref.setKey(key);
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(this); boolean selectable = ((type == null) || !type.equals("mms"));
pref.setSelectable(selectable);
if (selectable) {
if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
pref.setChecked();
}
apnList.addPreference(pref);
} else {
mmsApnList.add(pref);
}
cursor.moveToNext();
}
cursor.close(); for (Preference preference : mmsApnList) { // 将这个preference增加到apnList中
apnList.addPreference(preference);
}
}

这里的ApnPreference是我们自定义的一个类。继承于Preference。

这个类非常easy 就是依据R.layout.apn_preference_layout文件来对APN配置页面的每一项进行布局的。主要是两个TextView和一个RadioButton。

这里我们已经知道了进入APN设置后,系统是怎样将数据库中已经存在的APN条目读取出来并通过UI的形式显示出来的。

那么我们又怎么加入自定义的APN配置信息呢?这就要用到Options Menu了,在手机上当我们按下Menu键的时候弹出一个列表。单击这个列表每一项我们能够进入对应的Activity等。

    @Override
public boolean onCreateOptionsMenu(Menu menu) { // 当按下Menu键的时候调用
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_NEW, 0, // 添加两个条目,分别用于添加APN和恢复出厂设置
getResources().getString(R.string.menu_new))
.setIcon(android.R.drawable.ic_menu_add);
menu.add(0, MENU_RESTORE, 0,
getResources().getString(R.string.menu_restore))
.setIcon(android.R.drawable.ic_menu_upload);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { // 响应Menu按下的列表
case MENU_NEW: // 添加APN
addNewApn();
return true; case MENU_RESTORE: // 恢复出厂设置
restoreDefaultApn();
return true;
}
return super.onOptionsItemSelected(item);
} private void addNewApn() { // 启动新的Activity,动作为Intent.ACTION_INSERT
startActivity(new Intent(Intent.ACTION_INSERT, Telephony.Carriers.CONTENT_URI));
} // 响应 设置页面每一行条目的单击事件
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
int pos = Integer.parseInt(preference.getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
// 对当前选中页面进行编辑,也是启动一个Activity
startActivity(new Intent(Intent.ACTION_EDIT, url));
return true;
} public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.d(TAG, "onPreferenceChange(): Preference - " + preference
+ ", newValue - " + newValue + ", newValue type - "
+ newValue.getClass());
if (newValue instanceof String) {
setSelectedApnKey((String) newValue);
}
return true;
}

不管是添加APN还是对原有的APN条目进行编辑,我们都是通过进入一个新的Activity来完毕的。

以下我们找到匹配Intent.ACTION_EDIT。Intent.ACTION_INSERT

我们找到相应的Activity ApnEditor。ApnEditor也是一个继承与PreferenceActivity的类。同一时候实现了SharedPreferences.onSharedPreferenceChangeListener和Preference.OnPreferenceChangeListener接口。

    @Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle); addPreferencesFromResource(R.xml.apn_editor); sNotSet = getResources().getString(R.string.apn_not_set);
mName = (EditTextPreference) findPreference("apn_name");
mApn = (EditTextPreference) findPreference("apn_apn");
mProxy = (EditTextPreference) findPreference("apn_http_proxy");
mPort = (EditTextPreference) findPreference("apn_http_port");
mUser = (EditTextPreference) findPreference("apn_user");
mServer = (EditTextPreference) findPreference("apn_server");
mPassword = (EditTextPreference) findPreference("apn_password");
mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
mMmsc = (EditTextPreference) findPreference("apn_mmsc");
mMcc = (EditTextPreference) findPreference("apn_mcc");
mMnc = (EditTextPreference) findPreference("apn_mnc");
mApnType = (EditTextPreference) findPreference("apn_type"); mAuthType = (ListPreference) findPreference(KEY_AUTH_TYPE);
mAuthType.setOnPreferenceChangeListener(this); mProtocol = (ListPreference) findPreference(KEY_PROTOCOL);
mProtocol.setOnPreferenceChangeListener(this); mRoamingProtocol = (ListPreference) findPreference(KEY_ROAMING_PROTOCOL);
// Only enable this on CDMA phones for now, since it may cause problems on other phone
// types. (This screen is not normally accessible on CDMA phones, but is useful for
// testing.)
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
if (tm.getCurrentPhoneType() == Phone.PHONE_TYPE_CDMA) {
mRoamingProtocol.setOnPreferenceChangeListener(this);
} else {
getPreferenceScreen().removePreference(mRoamingProtocol);
} mCarrierEnabled = (CheckBoxPreference) findPreference(KEY_CARRIER_ENABLED); mBearer = (ListPreference) findPreference(KEY_BEARER);
mBearer.setOnPreferenceChangeListener(this); mRes = getResources(); final Intent intent = getIntent();
final String action = intent.getAction(); mFirstTime = icicle == null; if (action.equals(Intent.ACTION_EDIT)) {
mUri = intent.getData();
Log.w(TAG, "llping Edit action:"+mUri.toString());
} else if (action.equals(Intent.ACTION_INSERT)) {
if (mFirstTime || icicle.getInt(SAVED_POS) == 0) {
mUri = getContentResolver().insert(intent.getData(), new ContentValues());
} else {
mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI,
icicle.getInt(SAVED_POS));
}
Log.w(TAG, "llping Insert action:"+mUri.toString());
mNewApn = true;
// If we were unable to create a new note, then just finish
// this activity. A RESULT_CANCELED will be sent back to the
// original activity if they requested a result.
if (mUri == null) {
Log.w(TAG, "Failed to insert new telephony provider into "
+ getIntent().getData());
finish();
return;
} // The new entry was created, so assume all will end well and
// set the result to be returned.
setResult(RESULT_OK, (new Intent()).setAction(mUri.toString())); } else {
finish();
return;
} mCursor = managedQuery(mUri, sProjection, null, null);
mCursor.moveToFirst(); fillUi();
}

版权声明:本文博客原创文章。博客,未经同意,不得转载。

Android系统APN配置具体解释的更多相关文章

  1. Android系统定制——Download Android System 及加载system镜像文件

    定制android系统(配置及相关系统的镜像文件),具体可参考:Driver_All_in_One_V1.0——MT6735_6753.pdf文档,特别需要理解的是Download部分. 与之对应的软 ...

  2. Android系统固件定制方式

    target_product.mkAndroid系统在构建关于某种产品的固件时,一般会根据特定于该产品的具体target_product.mk来配置生成整个Android系统./target_prod ...

  3. Android Google Map v2具体解释:开发环境配置

    Android Google Map v2具体解释:开发环境配置                                       --转载请注明出处:coder-pig 说在前面: 说到地 ...

  4. 在Mac系统上配置Android真机调试环境

    在Mac系统上配置Android真机调试环境 mac上配置安卓环境还说挺方便的,真机调试也比win上要好一些.win上被各种软件强行安装了xxx助手. 在mac上就了一个干净的感觉. 下载Androi ...

  5. Android中实现全屏、无标题栏的两种办法(另附Android系统自带样式的解释)

    在进行UI设计时,我们经常需要将屏幕设置成无标题栏或者全屏.要实现起来也非常简单,主要有两种方法:配置xml文件和编写代码设置. 1.在xml文件中进行配置 在项目的清单文件AndroidManife ...

  6. Mac系统cocos2dx + android 开发环境配置

    Mac系统cocos2dx + android 开发环境配置 /****************************************************** 这遍文章主要转载自:htt ...

  7. Android APN配置

    APN概念 APN(Access Point Name),即“接入点名称”,用来标识GPRS的业务种类,目前分为两大类:CMWAP(通过GPRS访问WAP业务).CMNET(除了WAP以外的服务目前都 ...

  8. crt转cer ,6.0以上的android系统证书请求配置

    1.在服务器人员,给你发送的crt证书后,进到证书路径,执行下面语句  openssl x509 -in 你的证书.crt -out 你的证书.cer -outform der 这样你就可以得到cer ...

  9. Linux 桌面系统字体配置要略

    字体显示效果测试 这一段是为了测试宋体字的显示效果,包括宋体里面自带的英文字体,“This is english,how does it look like?”.这一行是小字.后面几个字是加粗的宋体. ...

随机推荐

  1. Python内置函数str()和repr()

    内建函数str()和repr() (representation.表达,表示)或反引號操作符(``)能够方便地以字符串的方式获取对象的内容.类型.数值属性等信息. str()函数得到的字符串可读性好( ...

  2. MySQLdb 连接Mysql 数据库出错解决

      #coding=utf-8 import MySQLdb if __name__ == "__main__": db = MySQLdb.connect(host=<sp ...

  3. Compass用法指南

    Compass用法指南   Sass是一种"CSS预处理器",可以让CSS的开发变得简单和可维护.但是,只有搭配Compass,它才能显出真正的威力. 本文介绍Compass的用法 ...

  4. hotmail邮箱pop3server设置方法

    hotmail邮箱 的POP3/SMTP功能仅仅向Hotmail Plus的用户开放,普通用户想要使用这一功能的话,得进行一些特别的设置.如今这一功能总算面向全部的用户开放了,虽然微软官方还没宣布这一 ...

  5. linux crontab定时执行shell脚本

    linux下使用crontab命令被用来提交和管理用户的需要周期性执行的任务,示例如下:crontab -e 编辑周期任务30 21 * * * /etc/init.d/smb restart 每晚的 ...

  6. 在Java中如何使用jdbc连接Sql2008数据库(转)

    我们在javaEE的开发中,肯定是要用到数据库的,那么在javaEE的开发中,是如何使用代码实现和SQL2008的连接的呢?在这一篇文章中,我将讲解如何最简单的使用jdbc进行SQL2008的数据库的 ...

  7. iPhone 6 首发无大陆,DevStore要去香港吗?

    iPhone 6 正式公布,微博已经被刷屏.iPhone 6 的各种信息都已经明了,先不说什么配置,什么设计,就说一点--iPhone6 首发地方是没有中国大陆的.这让我想起来最近參加的源代码大赛,这 ...

  8. for循环中一个不容小觑的问题

    for(int i=1;i<=100;i++) 作为程序猿,我们很喜欢使用这种for循环. 可是,当中隐含着一个重要的问题. 过多的编程经历可能使我们的思维产生了一些误解,在上面的for循环中, ...

  9. Oracle SQL Lesson (2) - 限制和排序数据

    重建scott用户@?/rdbms/admin/utlsampl.sql@--执行?--$ORACLE_HOME 字符区分大小写:SELECT last_name, job_id, departmen ...

  10. 主流芯片解决方案Ambarella的高清网络摄像机、德州仪器和控制海思

    (本文由四川艾普作为数码科技有限公司 苏斌.范清华 收集) 高清网络视频监控发展到今天.正的高清时代.诸多有实力的高清摄像机厂家的产品线也逐渐完好起来,高清网络视频监控的配套产品有更加丰富和成熟.与此 ...