Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android系統APN配置詳解

Android系統APN配置詳解

編輯:關於Android編程

Android 系統APN配置詳解          這些天一直在調系統原生的Settings.apk裡面APN配置的問題,在設置裡面手動增加了APN配置選項,但是在界面上還是看不到。所以跟了下代碼,原以為就是簡單的頁面顯示的問題,這一跟不要緊,一下就快追到HAL層去了(NND).           首先看Settings.apk的源碼,位於packages/apps/Settings/src/com/android/settings/目錄下:首先找到ApnSettings類,繼承於PreferenceActivity,並實現了Preference.OnPreferenceChangeListener接口。PreferencesActivity是Android中專門用來實現程序設置界面及參數存儲的一個Activity,這裡就不再贅述了。            [java]   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上。       [java]   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等。           [java]   @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接口。 [java]   @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));           }   og.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();   }              
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved