zoukankan      html  css  js  c++  java
  • Android系统APN配置具体解释

     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();
        }


     

     

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

  • 相关阅读:
    mini2440移植uboot 2014.04(四)
    mini2440移植uboot 2014.04(三)
    【这些年】Linux C/C++软件开发用过的工具
    Valgrind的Memcheck快速入门
    《浪潮之巅》读后感
    三层浅析及示例分析
    C语言的代码内存布局详解
    超级立方体小记
    如何和项目经理沟通产品的交付?
    CentOS配置smaba与Windows共享文件
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4660965.html
Copyright © 2011-2022 走看看