在设置界面上,进入wifi选项,点击使能按键,设备开始扫描AP,更新AP 、选择AP后,弹出界面来配置AP,连接AP ,获取到IP地址,可以联网了。
WifiSettings调用类示意图如下:
1. wifi使能
WifiSettings.java
public void onStart() { super.onStart(); // On/off switch is hidden for Setup Wizard (returns null) mWifiEnabler = createWifiEnabler(); } /** * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard) */ /* package */ WifiEnabler createWifiEnabler() { final SettingsActivity activity = (SettingsActivity) getActivity(); return new WifiEnabler(activity, activity.getSwitchBar()); }
WifiEnabler和Switch 对象被创建。 看WifiEnabler函数, 进入WifiEnabler.java, 代码如下:
public class WifiEnabler implements SwitchBar.OnSwitchChangeListener { ......
private final IntentFilter mIntentFilter;
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)) {
handleWifiStateChanged(intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
}else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
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());
}
}
};
......
public WifiEnabler(Context context, SwitchBar switchBar) {
mContext= context;
mSwitchBar= switchBar;
mWifiManager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
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);
setupSwitchBar();
}
......
public void resume(Context context) {
mContext= context;
// Wi-Fi state is sticky, so just let the receiver update UI
mContext.registerReceiver(mReceiver, mIntentFilter);
if (!mListeningToOnSwitchChange) {
mSwitchBar.addOnSwitchChangeListener(this);
mListeningToOnSwitchChange= true;
}
}
......
}
mIntentFilter是个广播, 可以看到这里, 用了三条广播, WIFI_STATE_CHANGED_ACTION, SUPPLICANT_STATE_CHANGED_ACTION, NETWORK_STATE_CHANGED_ACTION.
private void handleWifiStateChanged(int state) { switch (state) { case WifiManager.WIFI_STATE_ENABLING: mSwitchBar.setEnabled(false); break; case WifiManager.WIFI_STATE_ENABLED: setSwitchBarChecked(true); mSwitchBar.setEnabled(true); updateSearchIndex(true); break; case WifiManager.WIFI_STATE_DISABLING: mSwitchBar.setEnabled(false); break; case WifiManager.WIFI_STATE_DISABLED: setSwitchBarChecked(false); mSwitchBar.setEnabled(true); updateSearchIndex(false); break; default: setSwitchBarChecked(false); mSwitchBar.setEnabled(true); updateSearchIndex(false); } }
当Wi-Fi功能被启用时,将收到WIFI_STATE_CHANGED_ACTION广播. 接下来开始扫描AP
2. 扫描AP
进入 WifiSettings.java
void resumeWifiScan() { mWifiTracker.resumeScanning(); }
WifiTracker.java
public void resumeScanning() { if (mScanner == null) { mScanner = new Scanner(); } mWorkHandler.sendEmptyMessage(WorkHandler.MSG_RESUME); if (mWifiManager.isWifiEnabled()) { mScanner.resume(); } mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS); }
发送消息MSG_UPDATE_ACCESS_POINTS, 开始更新AP
3. 更新AP
WifiTracker.java
public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_ACCESS_POINTS: updateAccessPoints(); break; case MSG_UPDATE_NETWORK_INFO: updateNetworkInfo((NetworkInfo) msg.obj); break; case MSG_RESUME: handleResume(); break; } } private void updateAccessPoints() { // Swap the current access points into a cached list. List<AccessPoint> cachedAccessPoints = getAccessPoints(); ArrayList<AccessPoint> accessPoints = new ArrayList<>(); // Clear out the configs so we don't think something is saved when it isn't. for (AccessPoint accessPoint : cachedAccessPoints) { accessPoint.clearConfig(); } /** 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<String, AccessPoint> apMap = new Multimap<String, AccessPoint>(); WifiConfiguration connectionConfig = null; if (mLastInfo != null) { connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId()); } final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); if (configs != null) { mSavedNetworksExist = configs.size() != 0; for (WifiConfiguration config : configs) { if (config.selfAdded && config.numAssociation == 0) { continue; } AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints); if (mLastInfo != null && mLastNetworkInfo != null) { if (config.isPasspoint() == false) { accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo); } } if (mIncludeSaved) { if (!config.isPasspoint() || mIncludePasspoints){ //sid.bao add for reset saved network's rssi. accessPoint.resetRssi(); accessPoints.add(accessPoint); } if (config.isPasspoint() == false) { apMap.put(accessPoint.getSsidStr(), accessPoint); } } else { // If we aren't using saved networks, drop them into the cache so that // we have access to their saved info. cachedAccessPoints.add(accessPoint); } } } final Collection<ScanResult> results = fetchScanResults(); 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; } boolean found = false; for (AccessPoint accessPoint : apMap.getAll(result.SSID)) { if (accessPoint.update(result)) { found = true; break; } } if (!found && mIncludeScans) { AccessPoint accessPoint = getCachedOrCreate(result, cachedAccessPoints); if (mLastInfo != null && mLastNetworkInfo != null) { accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo); } if (result.isPasspointNetwork()) { WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result); if (config != null) { accessPoint.update(config); } } if (mLastInfo != null && mLastInfo.getBSSID() != null && mLastInfo.getBSSID().equals(result.BSSID) && connectionConfig != null && connectionConfig.isPasspoint()) { /* This network is connected via this passpoint config */ /* SSID match is not going to work for it; so update explicitly */ accessPoint.update(connectionConfig); } accessPoints.add(accessPoint); apMap.put(accessPoint.getSsidStr(), accessPoint); } } } // Pre-sort accessPoints to speed preference insertion Collections.sort(accessPoints); // Log accesspoints that were deleted if (DBG) Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------"); for (AccessPoint prevAccessPoint : mAccessPoints) { if (prevAccessPoint.getSsid() == null) continue; String prevSsid = prevAccessPoint.getSsidStr(); boolean found = false; for (AccessPoint newAccessPoint : accessPoints) { if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid().equals(prevSsid)) { found = true; break; } } if (!found) if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan"); } if (DBG) Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----"); mAccessPoints = accessPoints; mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED); }
MSG_ACCESS_POINT_CHANGED 进入到 onAccessPointsChanged
/** * Shows the latest access points available with supplemental information like * the strength of network and the security for it. */ @Override public void onAccessPointsChanged() { // Safeguard from some delayed event handling if (getActivity() == null) return; if (isUiRestricted()) { addMessagePreference(R.string.wifi_empty_list_user_restricted); return; } final int wifiState = mWifiManager.getWifiState(); switch (wifiState) { case WifiManager.WIFI_STATE_ENABLED: // AccessPoints are automatically sorted with TreeSet. final Collection<AccessPoint> accessPoints = mWifiTracker.getAccessPoints(); getPreferenceScreen().removeAll(); boolean hasAvailableAccessPoints = false; int index = 0; for (AccessPoint accessPoint : accessPoints) { // Ignore access points that are out of range. if (accessPoint.getLevel() != -1) { hasAvailableAccessPoints = true; if (accessPoint.getTag() != null) { final Preference pref = (Preference) accessPoint.getTag(); pref.setOrder(index++); getPreferenceScreen().addPreference(pref); continue; } AccessPointPreference preference = new AccessPointPreference(accessPoint, getActivity(), mUserBadgeCache, false); preference.setOrder(index++); if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr()) && !accessPoint.isSaved() && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { onPreferenceTreeClick(getPreferenceScreen(), preference); mOpenSsid = null; } getPreferenceScreen().addPreference(preference); accessPoint.setListener(this); } } if (!hasAvailableAccessPoints) { setProgressBarVisible(true); addMessagePreference(R.string.wifi_empty_list_wifi_on); } else { setProgressBarVisible(false); } break; case WifiManager.WIFI_STATE_ENABLING: getPreferenceScreen().removeAll(); setProgressBarVisible(true); break; case WifiManager.WIFI_STATE_DISABLING: addMessagePreference(R.string.wifi_stopping); setProgressBarVisible(true); break; case WifiManager.WIFI_STATE_DISABLED: setOffMessage(); setProgressBarVisible(false); break; } // Update "Saved Networks" menu option. if (savedNetworksExist != mWifiTracker.doSavedNetworksExist()) { savedNetworksExist = !savedNetworksExist; getActivity().invalidateOptionsMenu(); } }
4. 配置AP
选择用到的AP,弹出的界面,开始配置密码等消息。
@Override public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { if (preference instanceof AccessPointPreference) { mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint(); /** Bypass dialog for unsecured, unsaved, and inactive networks */ if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE && !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) { mSelectedAccessPoint.generateOpenNetworkConfig(); if (!savedNetworksExist) { savedNetworksExist = true; getActivity().invalidateOptionsMenu(); } connect(mSelectedAccessPoint.getConfig()); } else if (mSelectedAccessPoint.isSaved()){ mDlgModify = false; showDialog(mSelectedAccessPoint, false); } else { mDlgModify = false; showDialog(mSelectedAccessPoint, true); } } else { return super.onPreferenceTreeClick(screen, preference); } return true; } private void showDialog(AccessPoint accessPoint, boolean edit) { if (accessPoint != null) { WifiConfiguration config = accessPoint.getConfig(); if (isEditabilityLockedDown(getActivity(), config) && accessPoint.isActive()) { final int userId = UserHandle.getUserId(config.creatorUid); final PackageManager pm = getActivity().getPackageManager(); final IPackageManager ipm = AppGlobals.getPackageManager(); String appName = pm.getNameForUid(config.creatorUid); try { final ApplicationInfo appInfo = ipm.getApplicationInfo(appName, /* flags */ 0, userId); final CharSequence label = pm.getApplicationLabel(appInfo); if (label != null) { appName = label.toString(); } } catch (RemoteException e) { // leave appName as packageName } final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(accessPoint.getSsid()) .setMessage(getString(R.string.wifi_alert_lockdown_by_device_owner, appName)) .setPositiveButton(android.R.string.ok, null) .show(); return; } } if (mDialog != null) { removeDialog(WIFI_DIALOG_ID); mDialog = null; } // Save the access point and edit mode mDlgAccessPoint = accessPoint; mDlgEdit = edit; showDialog(WIFI_DIALOG_ID); }
当设置完后, 点击【连接】按键, 设备开始连接AP,获取IP。
5. 联网
/* package */ void submit(WifiConfigController configController) { final WifiConfiguration config = configController.getConfig(); if (config == null) { if (mSelectedAccessPoint != null && mSelectedAccessPoint.isSaved()) { connect(mSelectedAccessPoint.getConfig()); } } else if (configController.isModify()) { mWifiManager.save(config, mSaveListener); } else { mWifiManager.save(config, mSaveListener); if (mSelectedAccessPoint != null) { // Not an "Add network" connect(config); } } mWifiTracker.resumeScanning(); }
判断config, 如果是配置, 保持并连接目标AP
protected void connect(final WifiConfiguration config) { MetricsLogger.action(getActivity(), MetricsLogger.ACTION_WIFI_CONNECT); mWifiManager.connect(config, mConnectListener); }
进入WifiManager.java
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); }
看到了熟悉的sAsyncChannel