为了账号安全,请及时绑定邮箱和手机立即绑定

Android WiFi Setting App 源码阅读

标签:
Android

最近项目中需要用到Android WiFi相关功能,而API文档中对这方面语焉不详,所以决定来看一看Google工程师是怎么写的。

WiFi Setting App 在packages_app_settings中。从Github上下载下源码后,找到WifiSettings.java文件(这里推荐下listary这个功能强大的文件查找操作软件),这就是WIFI设置的所在了。

首先看下它的继承链,WifiSettings extends RestrictedSettingsFragment,RestrictedSettingsFragment extends SettingsPreferenceFragment。SettingsPreferenceFragment也被很多App用在自己的设置页面。

继续看它的构造函数:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

public WifiSettings() {

        super(DISALLOW_CONFIG_WIFI);

        mFilter   = new IntentFilter();

        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);

        mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);

        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);

        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);

        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);

        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);

        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);

 

        mReceiver   = new BroadcastReceiver() {

            @Override

            public   void onReceive(Context context, Intent intent) {

                handleEvent(intent);

            }

        };

 

        mScanner   = new Scanner(this);

    }

 

new了个BroadcastReceiver接收一系列广播。WIFI_STATE_CHANGED_ACTION事件当WIFI功能开启或关闭时会收到,SCAN_RESULTS_AVAILABLE_ACTION事件当手机扫描到有可用的WIFI连接时会收到,SUPPLICANT_STATE_CHANGED_ACTION事件当连接请求状态发生改变时会收到,NETWORK_STATE_CHANGED_ACTION事件当网络状态发生变化时会收到。Broadcast Receiver中使用handleEvent()来处理接收到的广播。

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

private void handleEvent(Intent intent) {

       String action   = intent.getAction();

       if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action))   {

           updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,

                   WifiManager.WIFI_STATE_UNKNOWN));

                   //WIFI功能开启或关闭或正在开启/正在关闭/未知

                   //则更新WIFI状态

       } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)   ||

               WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)   ||

               WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action))   {

               updateAccessPoints();

               //ScanResults有结果了 或 添加/更新/删除了一个网络 或 连接的网络配置改变(?)

               //则更新APs

       } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action))   {

           NetworkInfo   info = (NetworkInfo) intent.getParcelableExtra(

                   WifiManager.EXTRA_NETWORK_INFO);

           mConnected.set(info.isConnected());

           changeNextButtonState(info.isConnected());

           updateAccessPoints();

           updateNetworkInfo(info);

           //WIFI网络连接的变化             

           //

       } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action))   {

           updateNetworkInfo(null);

           //正在连接的WIFI信号强度变化

       }

   }

 

里面接受广播后调用了相应的几个函数来更新相关状态,有updateWifiState(), updateAccessPoints(), updateNetworkInfo()。

先来看updateAccessPoints()

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

private void updateAccessPoints() {

        //   Safeguard from some delayed event handling

        if (getActivity()   == null) return;

 

        if (isUiRestricted())   {

            //ezio:   WTF?

            addMessagePreference(R.string.wifi_empty_list_user_restricted);

            return;

        }

        final int   wifiState = mWifiManager.getWifiState();

 

        //when   we update the screen, check if verbose logging has been turned on or off

        mVerboseLogging   = mWifiManager.getVerboseLoggingLevel();

 

        switch (wifiState)   {

            case   WifiManager.WIFI_STATE_ENABLED:

                //   AccessPoints are automatically sorted with TreeSet.

                final   Collection<accesspoint> accessPoints =

                //ezio

                        constructAccessPoints(getActivity(),   mWifiManager, mLastInfo,

                                mLastNetworkInfo);

                getPreferenceScreen().removeAll();

                if   (accessPoints.size() == 0) {

                    //ezio:如果空,显示提示信息

                    addMessagePreference(R.string.wifi_empty_list_wifi_on);

                }

 

                for   (AccessPoint accessPoint : accessPoints) {

                    //   Ignore access points that are out of range.

                    //ezio:如果accessPoints不为空,则弄一个PrefList装进去,忽略范围外的ap

                    if   (accessPoint.getLevel() != -1) {

                        getPreferenceScreen().addPreference(accessPoint);

                    }

                }

                break;

 

            case   WifiManager.WIFI_STATE_ENABLING:

                getPreferenceScreen().removeAll();

                break;

 

            case   WifiManager.WIFI_STATE_DISABLING:

                addMessagePreference(R.string.wifi_stopping);

                break;

 

            case   WifiManager.WIFI_STATE_DISABLED:

                setOffMessage();

                break;

        }

    }</accesspoint>

 

updateAccessPoints()当广播是WIFI已开启的时候,会构造APs,APs是放满AP的Collection。

找到constructAccessPoints()的实现,上方的注释已经给了我们提示,它能返回排序好的APs

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

/** Returns sorted list of access points */

    private static List<accesspoint>   constructAccessPoints(Context context,

            WifiManager   wifiManager, WifiInfo lastInfo, NetworkInfo lastNetworkInfo) {

        ArrayList<accesspoint>   accessPoints = new ArrayList<accesspoint>();

        /**   Lookup table to more quickly update AccessPoints by only considering objects   with the

         *   correct SSID.  Maps SSID -> List of AccessPoints with the given   SSID.  */

 

        //multimap是Guava: Google Core Libraries的api

        Multimap<string,   accesspoint=""> apMap = new Multimap<string,   accesspoint="">();

 

        final List<wificonfiguration>   configs = wifiManager.getConfiguredNetworks();

        if (configs   != null) {

            //如果有configuredNetwork

            //   Update "Saved Networks" menu option.

            if   (savedNetworksExist != (configs.size() > 0)) {

                //如果savedNetworksExist为false,则反转

                savedNetworksExist   = !savedNetworksExist;

                if   (context instanceof Activity) {

 

                    ((Activity)   context).invalidateOptionsMenu();

                }

            }

            for   (WifiConfiguration config : configs) {

                if   (config.selfAdded && config.numAssociation == 0) {

 

                    continue;

                }

 

                AccessPoint   accessPoint = new AccessPoint(context, config);

                if   (lastInfo != null && lastNetworkInfo != null) {

                    accessPoint.update(lastInfo,   lastNetworkInfo);

                }

                accessPoints.add(accessPoint);

                apMap.put(accessPoint.ssid,   accessPoint);

            }

        }

 

        final List<scanresult>   results = wifiManager.getScanResults();

        if (results   != null) {

            for   (ScanResult result : results) {

                //   Ignore hidden and ad-hoc networks.

                if   (result.SSID == null || result.SSID.length() == 0 ||

                        result.capabilities.contains("[IBSS]"))   {

                    continue;

                //continue:如果ssid==null或者length==0,则忽略这一个直接进行下一次for循环

                }

 

                boolean   found = false;

                for   (AccessPoint accessPoint : apMap.getAll(result.SSID)) {

                    //ezio:apMap?

                    if   (accessPoint.update(result))

                        found   = true;

                }

                if   (!found) {

                    AccessPoint   accessPoint = new AccessPoint(context, result);

                    if   (lastInfo != null && lastNetworkInfo != null) {

                        accessPoint.update(lastInfo,   lastNetworkInfo);

                    }

                    accessPoints.add(accessPoint);

                    apMap.put(accessPoint.ssid,   accessPoint);

                }

            }

        }

 

        //   Pre-sort accessPoints to speed preference insertion

        Collections.sort(accessPoints);

        return accessPoints;

    }</scanresult></wificonfiguration></string,></string,></accesspoint></accesspoint></accesspoint>

 

其中用到了另一个类AccessPoint.java
在包中找到AccessPoint.java类,它有三个构造函数:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

AccessPoint(Context context, WifiConfiguration config)   {

        super(context);

        loadConfig(config);

        refresh();

    }

 

    AccessPoint(Context context,   ScanResult result) {

        super(context);

        loadResult(result);

        refresh();

    }

 

    AccessPoint(Context context,   Bundle savedState) {

        super(context);

 

        mConfig   = savedState.getParcelable(KEY_CONFIG);

        if (mConfig   != null) {

            loadConfig(mConfig);

        }

        mScanResult   = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);

        if (mScanResult   != null) {

            loadResult(mScanResult);

        }

        mInfo =   (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);

        if (savedState.containsKey(KEY_NETWORKINFO))   {

            mNetworkInfo   = savedState.getParcelable(KEY_NETWORKINFO);

        }

        update(mInfo,   mNetworkInfo);

    }

 

        private   void loadConfig(WifiConfiguration config) {

        //如果SSID为null则将其赋值为空字符串,不为空则。。

        ssid =   (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));

        bssid =   config.BSSID;

        security   = getSecurity(config);

        networkId   = config.networkId;

        mConfig   = config;

    }

 

    private void loadResult(ScanResult   result) {

        ssid =   result.SSID;

        bssid =   result.BSSID;

        security   = getSecurity(result);

        wpsAvailable   = security != SECURITY_EAP &&   result.capabilities.contains("WPS");

        if (security   == SECURITY_PSK)

            pskType   = getPskType(result);

        mRssi =   result.level;

        mScanResult   = result;

        if (result.seen   > mSeen) {

            mSeen   = result.seen;

        }

    }

 

AP类构造函数中调用loadConfig和loadResult两个函数来初始化成员变量,然后调用refresh来刷新。

接下来看用户点击WIFI会发生什么。在WifiSetting中找到

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

@Override

   public boolean onPreferenceTreeClick(PreferenceScreen   screen, Preference preference) {

       if (preference   instanceof AccessPoint) {

           mSelectedAccessPoint   = (AccessPoint) preference;

           //bypass:绕过

           /**   Bypass dialog for unsecured, unsaved, and inactive networks */

           if   (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&

                   mSelectedAccessPoint.networkId   == INVALID_NETWORK_ID &&

                   !mSelectedAccessPoint.isActive())   {

               //生成一个不加密的WifiConfigration

               mSelectedAccessPoint.generateOpenNetworkConfig();

               if   (!savedNetworksExist) {

                   //如果不存在

                   savedNetworksExist   = true;

                   //改为存在

                   getActivity().invalidateOptionsMenu();

                   //重新生成OptionsMenu

               }

               connect(mSelectedAccessPoint.getConfig());

           }   else {

               showDialog(mSelectedAccessPoint,   false);

           }

       } else {

           return   super.onPreferenceTreeClick(screen, preference);

       }

       return true;

   }

 

再追入AP中的generateOpenNetworkConfig

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

/**

     * Generate and save a   default wifiConfiguration with common values.

     * Can only be called for   unsecured networks.

     * @hide

     */

    protected void generateOpenNetworkConfig()   {

        if (security   != SECURITY_NONE)

            throw   new IllegalStateException();

        if (mConfig   != null)

            return;

        mConfig   = new WifiConfiguration();

        mConfig.SSID   = AccessPoint.convertToQuotedString(ssid);

        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);

    }

 

会生成一个开放网络的Config
接下来会调用connect连接选中的WIFI

[代码]java代码:

?

1

2

3

4

5

6

7

protected void connect(final WifiConfiguration config)   {

        mWifiManager.connect(config,   mConnectListener);

    }

 

    protected void connect(final int   networkId) {

        mWifiManager.connect(networkId,   mConnectListener);

    }

 

找到WifiManager中的connect方法,喜闻乐见的是hide方法,API中没有

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

/**

    * Connect to a network with the   given configuration. The network also

    * gets added to the supplicant   configuration.

    *

    * For a new network, this   function is used instead of a

    * sequence of addNetwork(),   enableNetwork(), saveConfiguration() and

    * reconnect()

    *

    * @param config the set of   variables that describe the configuration,

    *              contained in a {@link WifiConfiguration} object.

    * @param listener for callbacks   on success or failure. Can be null.

    * @throws IllegalStateException   if the WifiManager instance needs to be

    * initialized again

    *

    * @hide

    */

   public void connect(WifiConfiguration   config, ActionListener listener) {

       if (config ==   null) throw new IllegalArgumentException("config cannot be null");

       validateChannel();

       // Use   INVALID_NETWORK_ID for arg1 when passing a config object

       // arg1 is   used to pass network id when the network already exists

       sAsyncChannel.sendMessage(CONNECT_NETWORK,   WifiConfiguration.INVALID_NETWORK_ID,

               putListener(listener),   config);

   }

 

   /**

    * Connect to a network with the   given networkId.

    *

    * This function is used instead   of a enableNetwork(), saveConfiguration() and

    * reconnect()

    *

    * @param networkId the network   id identifiying the network in the

    *                  supplicant configuration list

    * @param listener for callbacks   on success or failure. Can be null.

    * @throws IllegalStateException   if the WifiManager instance needs to be

    * initialized again

    * @hide

    */

   public void connect(int networkId,   ActionListener listener) {

       if (networkId   < 0) throw new IllegalArgumentException("Network id cannot be   negative");

       validateChannel();

       sAsyncChannel.sendMessage(CONNECT_NETWORK,   networkId, putListener(listener));

   }

 

然后回到WifiSettings中的onPreferenceTreeClick,如果不是开放网络,会调用showDialog()

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

private void showDialog(AccessPoint accessPoint,   boolean edit) {

        if (mDialog   != null) {

            removeDialog(WIFI_DIALOG_ID);

            mDialog   = null;

        }

 

        // Save   the access point and edit mode

        mDlgAccessPoint   = accessPoint;

        mDlgEdit   = edit;

 

        showDialog(WIFI_DIALOG_ID);

    }

 

最后一句调用了爷爷类的showDialog()

[代码]java代码:

?

1

2

3

4

5

6

7

protected void showDialog(int dialogId) {

        if (mDialogFragment   != null) {

            Log.e(TAG,   "Old dialog fragment not null!");

        }

        mDialogFragment   = new SettingsDialogFragment(this, dialogId);

        mDialogFragment.show(getChildFragmentManager(),   Integer.toString(dialogId));

    }

 

SettingsDialogFragment是SettingsPreferenceFragment中的一个静态内部类,继承自DialogFragment

下方还有个onCreateDialog()

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

@Override

    public Dialog   onCreateDialog(int dialogId) {

        switch (dialogId)   {

            case   WIFI_DIALOG_ID:

                AccessPoint   ap = mDlgAccessPoint; // For manual launch

                if   (ap == null) { // For re-launch from saved state

                    if   (mAccessPointSavedState != null) {

                        ap   = new AccessPoint(getActivity(), mAccessPointSavedState);

                        //   For repeated orientation changes

                        mDlgAccessPoint   = ap;

                        //   Reset the saved access point data

                        mAccessPointSavedState   = null;

                    }

                }

                //   If it's null, fine, it's for Add Network

                mSelectedAccessPoint   = ap;

                mDialog   = new WifiDialog(getActivity(), this, ap, mDlgEdit);

                return   mDialog;

            case   WPS_PBC_DIALOG_ID:

                return   new WpsDialog(getActivity(), WpsInfo.PBC);

            case   WPS_PIN_DIALOG_ID:

                return   new WpsDialog(getActivity(), WpsInfo.DISPLAY);

            case   WRITE_NFC_DIALOG_ID:

                if   (mSelectedAccessPoint != null) {

                    mWifiToNfcDialog   = new WriteWifiConfigToNfcDialog(

                            getActivity(),   mSelectedAccessPoint, mWifiManager);

                    return   mWifiToNfcDialog;

                }

 

        }

        return super.onCreateDialog(dialogId);

    }

 

这回Google的攻城狮终于肯写点注释了,看起来顺了很多。想检查mDlgAccessPoint是否为null,如果null就从SavedState生成个新的ap,最后new一个WifiDialog,这个Dialog就是我们将要看到的Dialog。
在包中找到WifiDialog.java,它有两个构造函数(带默认则是三个)

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

public WifiDialog(Context context,   DialogInterface.OnClickListener listener,

            AccessPoint   accessPoint, boolean edit, boolean hideSubmitButton) {

        this(context,   listener, accessPoint, edit);

        mHideSubmitButton   = hideSubmitButton;

    }

 

    public WifiDialog(Context   context, DialogInterface.OnClickListener listener,

            AccessPoint   accessPoint, boolean edit) {

        super(context);

        mEdit =   edit;

        mListener   = listener;

        mAccessPoint   = accessPoint;

        mHideSubmitButton   = false;

    }

 

可以看到之前调用的是4参数的,第二个参数是 DialogInterface.OnClickListener,之前传入的this,那我们去WifiSettings中找到实现的接口的函数

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

@Override

    public void onClick(DialogInterface   dialogInterface, int button) {

        if (button   == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {

            forget();

        } else if   (button == WifiDialog.BUTTON_SUBMIT) {

            if   (mDialog != null) {

                submit(mDialog.getController());

            }

        }

    }

 

很简单,判断了点击的是忘记网络还是连接WIFI。看下submit的代码

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

/* package */ void submit(WifiConfigController   configController) {

 

        final WifiConfiguration   config = configController.getConfig();

 

        if (config   == null) {

            if   (mSelectedAccessPoint != null

                    &&   mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

                connect(mSelectedAccessPoint.networkId);

            }

        } else if   (config.networkId != INVALID_NETWORK_ID) {

            if   (mSelectedAccessPoint != null) {

                mWifiManager.save(config,   mSaveListener);

            }

        } else {

            if   (configController.isEdit()) {

                mWifiManager.save(config,   mSaveListener);

            }   else {

                connect(config);

            }

        }

 

        if (mWifiManager.isWifiEnabled())   {

            mScanner.resume();

        }

        updateAccessPoints();

    }

原文链接:http://www.apkbus.com/blog-705730-61006.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消