Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android4.4.2源碼分析之WiFi模塊(一)

Android4.4.2源碼分析之WiFi模塊(一)

編輯:關於Android編程

已經寫了幾篇關於Android源碼的,源碼代碼量太大,所以如果想分析某個模塊可能不知如何下手,說一下思路

1,分析源碼英文閱讀能力要夠,想要分析某個模塊一般找模塊對應的英文,就是模塊
2,找到之後首先查看清單配置文件Androidmani.fest,找到程序主界面activity
3,通過查看配置文件中的權限可以知道應用都有什麼用
大致通過以上三步就可以進入源碼進行分析

針對WiFi,我們通過清單文件可以知道,需要以下幾個權限,其含義如下注釋

<!-- 允許程序獲取WiFi狀態 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE">
    <!--允許程序改變WiFi狀態-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE">
    <!--允許程序獲取手機網絡狀態-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
    <!--允許程序改變網絡狀態-->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE">
    <!--允許程序訪問網絡-->
    <uses-permission android:name="android.permission.INTERNET"></uses-permission></uses-permission></uses-permission></uses-permission></uses-permission>

如果使用as做開發工具的話在使用WiFi時如果不加權限會有警告來提示你,感覺還是很人性化的,如果把as的所有警告都解決了那麼程序應該會很少出意料之外的bug,而且as的單步調試可以很好的去發現bug,界面美觀,忍不住強烈推薦。
因為是首次接觸WiFi源碼,我會按代碼順序分析,當然這樣可能會有些亂,完成全部分析後會再按照功能點分析,不過得等到下一篇博客喽。好了,閒話少敘,正式進入對WiFi源碼的分析,

\\


1,WifiSettings屬於fragment,實現了對話框的點擊事件接口,代碼如下
public class WifiSettings extends RestrictedSettingsFragment
        implements DialogInterface.OnClickListener 

在onCreateView方法中首先判斷應用是否是第一次運行,根據是否是第一次運行來設置不同的布局
1>,if(mSetupWizardMode) 則加載啟動布局
View view = inflater.inflate(R.layout.setup_preference, container, false);

否則加載正常布局
View v = inflater.inflate(R.layout.add_preference_list_fragment,null);

接著onActivityCreated方法中
2>
mP2pSupported = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);

這句代碼用來判斷是否支持WiFi直連:if the device supports Wi-Fi Direct networking or not
WiFi直連的含義是說:設備可以直接通過WiFi共享文件,圖片等,類似藍牙傳輸,實現點對點的連接,通信(要求兩設備必須位於同一網段)。可以看到判斷設備是否支持WiFi直連是通過PackageManager的hasSystemFeature
目錄為/android/external/robolectric/src/main/java/com/xtremelabs/robolectric/res/
 public boolean hasSystemFeature(String name) {
 return systemFeatureList.containsKey(name) ? systemFeatureList.get(name) : false;
   }

由源碼可知該方法會遍歷systemFeaturelist列表,判斷是否包含所傳入的feature,通過PackageManagerService中的readPermissionsFromXml(File f)傳入xml文件進行解析獲取到設備所支持的permission

3>,接下來獲取到WiFi的管理類對象mWifiManager,用於開啟/關閉WiFi,掃描WiFi,連接WiFi等等
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

4>,通過獲取到set_wifi_priority的值來對preference列表進行 不同顯示


if (getResources().getBoolean(R.bool.set_wifi_priority)) { addPreferencesFromResource(R.xml.wifi_sort_settings); mDefaultTrustAP = (PreferenceCategory)findPreference("default_trust_access_points"); mConfigedAP = (PreferenceCategory)findPreference("configed_access_points"); mUnKnownAP = (PreferenceCategory)findPreference("unknown_access_points"); } else { addPreferencesFromResource(R.xml.wifi_settings); } 

對於boolean值“set_wifi_priority”的值可以查看Z:\L7-A1\android\packages\apps\Settings\res\values\bools.xml文件\該值表示whether to show hotspot via the ap's classification接入點優先級設定即是否按照所搜索到的WiFi優先級來顯示Wifi列表,可以看到等級有三種:默認的信任接入點,信任接入點,未知接入點\因為在這裡boolean值被設置為false,所以不按優先級排序5>,接下來就是添加WiFi開關,至於通過代碼在導航欄actionbar添加switch的代碼類似藍牙,在此不再贅述,可以看到,藍牙開關switch傳入了WifiEnabler,所以對於Wifi的開關的管理位於WiFiEnablerswitch中
mWifiEnabler = new WifiEnabler(activity, actionBarSwitch);

進入WiFiEnabler可以看到,該類就做了兩件事,第一注冊廣播監聽WiFi的變化並隨之改變switch的狀態,第二為switch添加點擊監聽事件
廣播所監聽的事件有
//當WiFi狀態發生改變時會發送該廣播
 mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
        
 // The order matters! We really should not depend on this. :(
        mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
       //當設備網絡狀態發生改變時會發送該廣播
 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);

action WifiManager.SUPPLICANT_STATE_CHANGD_ACTION定義如下,表示正在創建連接的狀態發生改變,又有了新的連接可用,可用獲取到WiFi的具體的連接狀態,如果你只是對連接的整體狀態感興趣則該廣播無用
 /**
     * Broadcast intent action indicating that the state of establishing a connection to
     * an access point has changed.One extra provides the new
     * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
     * is not generally the most useful thing to look at if you are just interested in
     * the overall state of connectivity.
     * @see #EXTRA_NEW_STATE
     * @see #EXTRA_SUPPLICANT_ERROR
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String SUPPLICANT_STATE_CHANGED_ACTION =
        "android.net.wifi.supplicant.STATE_CHANGE";


接下來看廣播的處理
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
                //WiFi狀態生改變時去更新switch的狀態,WiFi的狀態存在於WifiManager.EXTRA_WIFI_STATE
                handleWifiStateChanged(intent.getIntExtra(
                        WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
              //needPrompt方法用於判斷是否是飛行模式以及飛行模式是否無效
           if (WifiSettings.needPrompt(context)) {
                    setSwitchChecked(false);
                }
            } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
            //連接發生改變時的更新,WifiManager.EXTRA_NEW_STATE存放改變後的狀態
             if (!mConnected.get()) {
                    handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
                            intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
                }
            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            //網絡狀態發生改變時的更新
           NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                        WifiManager.EXTRA_NETWORK_INFO);
                mConnected.set(info.isConnected());
                handleStateChanged(info.getDetailedState());
            }
        }
    };

當WiFi開關狀態發生改變時更新放啊如下:
 private void handleWifiStateChanged(int state) {
        switch (state) {
            case WifiManager.WIFI_STATE_ENABLING://正在打開WiFi
              mSwitch.setEnabled(false);
                break;
            case WifiManager.WIFI_STATE_ENABLED://WiFi已經打開
                setSwitchChecked(true);
                mSwitch.setEnabled(true);
                break;
            case WifiManager.WIFI_STATE_DISABLING://正在關閉WiFi
                mSwitch.setEnabled(false);
                break;
            case WifiManager.WIFI_STATE_DISABLED://WiFi已經關閉
                setSwitchChecked(false);
                mSwitch.setEnabled(true);
                break;
            default:
                setSwitchChecked(false);
                mSwitch.setEnabled(true);
                break;
        }
    }

對於網絡狀態發生改變時的更新方法,可以看到方法已經被注釋掉,因為不需要去更新preference的副標題

  private void handleStateChanged(@SuppressWarnings("unused") NetworkInfo.DetailedState state) {
        // After the refactoring from a CheckBoxPreference to a Switch, this method is useless since
        // there is nowhere to display a summary.
        // This code is kept in case a future change re-introduces an associated text.
        /*
        // WifiInfo is valid if and only if Wi-Fi is enabled.
        // Here we use the state of the switch as an optimization.
        if (state != null && mSwitch.isChecked()) {
            WifiInfo info = mWifiManager.getConnectionInfo();
            if (info != null) {
                //setSummary(Summary.get(mContext, info.getSSID(), state));
            }
        }
        */
    }

對於switch的點擊事件的監聽代碼如下
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return;
        }

        if (mContext.getResources().getBoolean(R.bool.wifi_to_cell)) {
            ConnectivityManager mConnService = (ConnectivityManager) mContext.
                    getSystemService(Context.CONNECTIVITY_SERVICE);
            if (mConnService != null) {
                NetworkInfo netInfo = (NetworkInfo) mConnService
                        .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                if (netInfo != null && netInfo.isConnected()) {
                    Settings.System.putInt(mContext.getContentResolver(), WIFI_IS_CONNECTED,
                            CONNECTED);
                } else {
                    Settings.System.putInt(mContext.getContentResolver(), WIFI_IS_CONNECTED,
                            DISCONNECTED);
                }
            }
        }

        // Show toast message if Wi-Fi is not allowed in airplane mode
         //判斷是否在飛行模式中WiFi是不允許的   
         if (isChecked
                && (WifiSettings.needPrompt(mContext) || !WirelessSettings.isRadioAllowed(
                        mContext, Settings.Global.RADIO_WIFI))) {
            Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
                    Toast.LENGTH_SHORT).show();
            // Reset switch to off. No infinite check/listenenr loop.
            buttonView.setChecked(false);
            return;
        }

        // Disable tethering if enabling Wifi
        int wifiApState = mWifiManager.getWifiApState();
        if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
                (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
            mWifiManager.setWifiApEnabled(null, false);
        }

        // shouldn't setWifiEnabled(true) in airplane mode.
        if (isChecked && WifiSettings.needPrompt(mContext)) {
            return;
        } else {
          //setWifiEnabled打開或者關閉WiFi的方法,會發送WiFi狀態改變的廣播:WIFI_STATE_CHANGED_ACTION
          if (mWifiManager.setWifiEnabled(isChecked)) {
                // Intent has been taken into account, disable until new state
                // is active
                mSwitch.setEnabled(false);
            } else {
                // Error
                Toast.makeText(mContext, R.string.wifi_error,
                        Toast.LENGTH_SHORT).show();
            }
        }
    }
對於mStateMachineEvent的值是在對switch進行設置時賦值,起開關保護的作用,保證當點擊switch的時候先將switch狀態設置成功再進入點擊事件方法
private void setSwitchChecked(boolean checked) {
        if (checked != mSwitch.isChecked()) {
            mStateMachineEvent = true;
            mSwitch.setChecked(checked);
            mStateMachineEvent = false;
        }
    }

打開或關閉WiFi的方法為,mWifiManager.setWifiEnabled(boolean enable),在打開時會發送廣播WifiManager.WIFI_STATE_CHANGED_ACTION,可監聽該廣播來改變UI


 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved