Android WLAN 开关和连接流程分析(一) 应用层

PS:基于Android P

首先在AndroidManifest.xml中定位WIfiSettings

android:value="com.android.settings.wifi.WifiSettings"

/packages/apps/settings/src/com/android/settings/wifi/...

此路径下为wifi应用层相关文件

我们找到WifiSettings.java分析代码

先看到wifi的开关

1. onStart()

 // On/off switch is hidden for Setup Wizard (returns null)
        mWifiEnabler = createWifiEnabler();
        if (mIsRestricted) {
            restrictUi();
            return;
        }
        onWifiStateChanged(mWifiManager.getWifiState());

实现了一个WifiEnabler也就是Wifi开关功能

onWifiStateChanged判断wifi状态并执行不同的操作

/** Called when the state of Wifi has changed. */
    @Override
    public void onWifiStateChanged(int state) {
        if (mIsRestricted) {
            return;
        }

        final int wifiState = mWifiManager.getWifiState();
        switch (wifiState) {
            case WifiManager.WIFI_STATE_ENABLED:
                updateAccessPointPreferences();
                break;

            case WifiManager.WIFI_STATE_ENABLING:
                removeConnectedAccessPointPreference();
                mAccessPointsPreferenceCategory.removeAll();
                addMessagePreference(R.string.wifi_starting);
                setProgressBarVisible(true);
                break;

            case WifiManager.WIFI_STATE_DISABLING:
                removeConnectedAccessPointPreference();
                mAccessPointsPreferenceCategory.removeAll();
                addMessagePreference(R.string.wifi_stopping);
                break;

            case WifiManager.WIFI_STATE_DISABLED:
                setOffMessage();
                setAdditionalSettingsSummaries();
                setProgressBarVisible(false);
                break;
        }
    }

createWifiEnabler()   new 了一个WifiEnabler对象

 /**
     * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
     */
    private WifiEnabler createWifiEnabler() {
        final SettingsActivity activity = (SettingsActivity) getActivity();
        return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),
            mMetricsFeatureProvider);
    }

找到对应java文件

/packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java

@Override
    public boolean onSwitchToggled(boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return true;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
        if (isChecked && !WirelessUtils.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/listener loop.
            mSwitchWidget.setChecked(false);
            return false;
        }

        if (isChecked) {
            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
        } else {
            // Log if user was connected at the time of switching off.
            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
                    mConnected.get());
        }
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitchWidget.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
        return true;
    }

在onSwitchToggled方法中调用了WifiManager的setWifiEnabled()方法

WIfiManager属于框架层放到下一节

下面先看Wifi如何连接

在连接之前,先要扫面wifi得到周边的WiFi信息

WifiSettings->onWifiStateChanged()->case  WifiManager.WIFI_STATE_ENABLED 执行updateAccessPointPreferences()方法

updateAccessPointPreferences()调用框架层的嗅探器获得可用接入点

   // AccessPoints are sorted by the WifiTracker
    final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();    

得到list后遍历设置preference属性并添加进mAccessPointsPreferenceCategory

       int numAccessPoints = accessPoints.size();
        for (; index < numAccessPoints; index++) {
            AccessPoint accessPoint = accessPoints.get(index);
            // Ignore access points that are out of range.
            if (accessPoint.isReachable()) {
                String key = accessPoint.getKey();
                hasAvailableAccessPoints = true;
                LongPressAccessPointPreference pref =
                        (LongPressAccessPointPreference) getCachedPreference(key);
                if (pref != null) {
                    pref.setOrder(index);
                    continue;
                }
                LongPressAccessPointPreference preference =
                        createLongPressAccessPointPreference(accessPoint);
                preference.setKey(key);
                preference.setOrder(index);
                if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
                        && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                    if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
                        onPreferenceTreeClick(preference);
                        mOpenSsid = null;
                    }
                }
                mAccessPointsPreferenceCategory.addPreference(preference);
                accessPoint.setListener(WifiSettings.this);
                preference.refresh();
            }
        }

mAccessPointsPreferenceCategory 在addPreference()方法中被设置到界面,addPreference()在onCreate()中调用

   @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // TODO(b/37429702): Add animations and preference comparator back after initial screen is
        // loaded (ODR).
        setAnimationAllowed(false);

        addPreferences();

        mIsRestricted = isUiRestricted();
    }

    private void addPreferences() {
        addPreferencesFromResource(R.xml.wifi_settings);

        mConnectedAccessPointPreferenceCategory =
                (PreferenceCategory) findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
        mAccessPointsPreferenceCategory =
                (PreferenceCategory) findPreference(PREF_KEY_ACCESS_POINTS);
...
...

显示之后点击弹出dialog输入密码然后开始连接网络

复写父类的方法onPreferenceTreeClick()

@Override
    public boolean onPreferenceTreeClick(Preference preference) {
        // If the preference has a fragment set, open that
        if (preference.getFragment() != null) {
            preference.setOnPreferenceClickListener(null);
            return super.onPreferenceTreeClick(preference);
        }

        if (preference instanceof LongPressAccessPointPreference) {
            mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
            if (mSelectedAccessPoint == null) {
                return false;
            }
            if (mSelectedAccessPoint.isActive()) {
                return super.onPreferenceTreeClick(preference);
            }
            /**
             * Bypass dialog and connect to unsecured networks, or previously connected saved
             * networks, or Passpoint provided networks.
             */
            WifiConfiguration config = mSelectedAccessPoint.getConfig();
            if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
                mSelectedAccessPoint.generateOpenNetworkConfig();
                connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
            } else if (mSelectedAccessPoint.isSaved() && config != null
                    && config.getNetworkSelectionStatus() != null
                    && config.getNetworkSelectionStatus().getHasEverConnected()) {
                connect(config, true /* isSavedNetwork */);
            } else if (mSelectedAccessPoint.isPasspoint()) {
                // Access point provided by an installed Passpoint provider, connect using
                // the associated config.
                connect(config, true /* isSavedNetwork */);
            } else {
                showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
            }
        } else if (preference == mAddPreference) {
            onAddNetworkPressed();
        } else {
            return super.onPreferenceTreeClick(preference);
        }
        return true;
    }

如果第一次进入wifi没有连接过网络应该走的是走

showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);

  private void showDialog(AccessPoint accessPoint, int dialogMode) {
        if (accessPoint != null) {
            WifiConfiguration config = accessPoint.getConfig();
            if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) {
                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
                        RestrictedLockUtils.getDeviceOwner(getActivity()));
                return;
            }
        }

        if (mDialog != null) {
            removeDialog(WIFI_DIALOG_ID);
            mDialog = null;
        }

        // Save the access point and edit mode
        mDlgAccessPoint = accessPoint;
        mDialogMode = dialogMode;

        showDialog(WIFI_DIALOG_ID);
    }

这里只做对象传递

实际操作在覆写的父类方法onCreateDialog()中

@Override
    public Dialog onCreateDialog(int dialogId) {
        switch (dialogId) {
            case WIFI_DIALOG_ID:
                if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
                    // add new network
                    mDialog = WifiDialog
                            .createFullscreen(getActivity(), this, mDlgAccessPoint, mDialogMode);
                } else {
                    // modify network
                    if (mDlgAccessPoint == null) {
                        // restore AP from save state
                        mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
                        // Reset the saved access point data
                        mAccessPointSavedState = null;
                    }
                    mDialog = WifiDialog
                            .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode);
                }

                mSelectedAccessPoint = mDlgAccessPoint;
                return mDialog;
....
....

弹出dialog输入密码后点击连接会调用onSubmit()方法

此方法覆写于父类

实际上调用submit()方法

@Override
    public void onSubmit(WifiDialog dialog) {
        if (mDialog != null) {
            submit(mDialog.getController());
        }
    }

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

        final WifiConfiguration config = configController.getConfig();

        if (config == null) {
            if (mSelectedAccessPoint != null
                    && mSelectedAccessPoint.isSaved()) {
                connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
            }
        } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
            mWifiManager.save(config, mSaveListener);
        } else {
            mWifiManager.save(config, mSaveListener);
            if (mSelectedAccessPoint != null) { // Not an "Add network"
                connect(config, false /* isSavedNetwork */);
            }
        }

        mWifiTracker.resumeScanning();
    }

判断处理后调用connect()方法连接wifi

  protected void connect(final WifiConfiguration config, boolean isSavedNetwork) {
        // Log subtype if configuration is a saved network.
        mMetricsFeatureProvider.action(getVisibilityLogger(), MetricsEvent.ACTION_WIFI_CONNECT,
                isSavedNetwork);
        mWifiManager.connect(config, mConnectListener);
        mClickedConnect = true;
    }

    protected void connect(final int networkId, boolean isSavedNetwork) {
        // Log subtype if configuration is a saved network.
        mMetricsFeatureProvider.action(getActivity(), MetricsEvent.ACTION_WIFI_CONNECT,
                isSavedNetwork);
        mWifiManager.connect(networkId, mConnectListener);
    }

最终调用了框架层WifiManager的connect()方法

在wifi开关的流程中也是以该类结尾,可以发现WifiManager这个java类是wifi功能上层的一个核心类,下一节将具体分析该类及其他框架层相关。

猜你喜欢

转载自www.cnblogs.com/nextbug/p/12295729.html
今日推荐