`

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。这个类很简单 就是根据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();
    }


 

 

 

 

 

 

 

 

 

 

 

文章来源:http://www.itnose.net/detail/6024266.html
更多文章:http://www.itnose.net/type/85.html

分享到:
评论

相关推荐

    android APN开发流程

    Android APN开发流程涉及多个层次的协作,从高层的APN配置到低层的RIL通信,每一环节都紧密相连。理解这些细节对于深入掌握Android系统的数据连接机制至关重要,有助于开发者优化网络性能、解决连接问题以及开发更...

    安卓系统文件夹详细结构及其文件解析

    3. \system\etc 文件夹:从文件夹名称来看保存的都是系统的配置文件,比如 APN 接入点设置等核心配置。 在这个文件夹中,我们可以找到许多系统配置文件,如 apns-conf.xml、hosts 等。这些文件都是 Android 操作...

    华为me909s-821

    【华为ME909S-821:4G Android模块与Linux驱动配置详解】 华为ME909S-821是一款专为4G网络设计的通信模块,广泛应用于移动设备、工业路由器等场景。它基于Android系统,内含RIL(Radio Interface Layer)库和Linux...

    android MMS 原理

    ### Android MMS原理详解 多媒体信息服务(Multimedia Messaging Service,简称MMS)是移动通信领域的一项重要技术,它允许用户通过手机发送包含图像、音频、视频等多媒体内容的消息。随着智能手机的普及,Android...

    android ppp mms gprs

    ### Android PPP MMS GPRS详解 #### 一、概述 Android平台支持多种网络连接方式,包括但不限于Wi-Fi、蓝牙、蜂窝数据等。本篇文章主要针对Android中的PPP(Point-to-Point Protocol)、MMS(Multimedia Messaging ...

    Android数据连接流程分析

    ### Android数据连接流程详解 #### 一、引言 Android作为全球最受欢迎的移动操作系统之一,在其内部实现了一系列复杂的网络管理机制来确保用户可以顺畅地访问互联网。本文将深入探讨Android中的数据连接流程,重点...

    apndroid.zip

    用户可能可以使用它来快速改变APN配置,以适应不同的网络环境,比如从移动数据切换到Wi-Fi,或者在不同的运营商之间切换。 【标签】"apndroid" 作为一个自定义标签,可能是该项目或应用的特定标识,表明这与Android...

    安卓系统使用技巧整合

    【Android系统使用技巧详解】 Android系统作为全球最广泛使用的移动操作系统之一,拥有众多实用的技巧,可以帮助用户更好地管理和优化他们的设备。以下是一些基础和进阶的使用技巧,旨在帮助新手快速掌握Android...

    LG GW620 上网设置

    在这里,我们可以看到已经预设好的APN配置列表,选择“新建APN”或类似选项来创建一个新的APN配置。 - **输入3GNET APN参数**: - **APN名称**:3gnet - **APN地址**:3gnet - **代理服务器地址**:10.0.0.172 -...

    android小知识[借鉴].pdf

    3. **/system/etc**:该目录主要存放系统的配置文件,例如APN接入点设置等。 - **用途**:在调试网络连接问题时,这些配置文件可能会提供重要线索。 4. **/system/fonts**:字体文件夹,包含标准字体以及较大的...

    中国电信—彩信配置文件

    正确的APN配置能确保设备能够顺利地通过网络发送和接收彩信。 3. **彩信协议**:彩信服务基于WAP(Wireless Application Protocol)协议,而MMS协议是WAP2.0的一个扩展。发送彩信时,手机会通过APN连接到MMS代理...

    安卓软件开发--Android ROOM制作修改.docx

    ### 安卓软件开发——Android ROOM制作与修改详解 #### 一、理解ROM及系统文件结构 ROM(Read-Only Memory)在安卓设备中是指预装的操作系统及相关应用的集合。对于开发者而言,理解ROM的基本结构有助于进行更深入...

    手机彩信.doc

    【知识点详解】 1. 安卓系统彩信设置: - 手机彩信的配置涉及到网络连接,尤其是接入点名称(APN)的设定。 - 首先,确保设备能通过WIFI或GPRS上网,以验证网络是否正常。 - 进入手机的设置菜单,找到“无线和...

    黑马程序员 安卓学院 万元哥项目经理 分享220个代码实例

    |--android 设置apn |--android 调节屏幕亮度 |--android 资源uri |--android 还原短信 |--android 重启 |--android中anim文件特效 |--app信息menifest获取(如版本号) |--AsyncQueryHandler之异步查询Cursor处理 |--...

    ril&qcril;流程分析

    《Android RIL&QCRIL流程详解》 在Android系统中,Radio Interface Layer(RIL)扮演着至关重要的角色,它是操作系统与无线网络模块之间的桥梁,负责管理移动网络相关的功能,如电话、短信、数据连接等。QCRIL...

    红米1s的G卡上网破解补丁

    这是Android系统中的设置应用,它包含了系统的各种配置选项。通过修改这个应用的代码或资源,补丁可以改变手机对G卡的网络设置,例如修改APN(Access Point Name)设置,允许手机连接到更广泛的网络提供商,从而实现...

Global site tag (gtag.js) - Google Analytics