android wifi系统源码,Android-WiFi开发之 Android 5.0 代码解析.

本文深入解析Android 5.0系统中关于WiFi设置的源码,包括开启/关闭WiFi、扫描热点、连接网络等功能。重点讨论了WifiSettings.java文件,并提供了关键代码段,帮助开发者理解和学习Android WiFi模块的实现。
摘要由CSDN通过智能技术生成

1. 前言:

Android 5.0 原生Settings代码路径: android-5.0.0/packages/apps/Settings.

代码架构: 和 4.4 基本相同, 重要的代码块全部集结在 WifiSettings.java 文件中.

WifiSettings.java 文件路径: android-5.0.0/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

2. Android 5.0 WiFi 部分的源码解析:

2.1 WIFI 模块整体的功能结构:

开启 WiFi.

关闭 WiFi.

获取 WiFi 列表.

持续扫描 WiFi 热点.

连接网络.

忘记网络.

添加网络.

网络高级设置等.

2.2 WiFi 整体功能示意图:

2b82fbca6417

image.png

2.4 由于代码结构和 4.4 版本的十分类似, 故此处不再分析流程和操作函数分析, 贴出源代码, 利于大家学习, 具体如下:

Settings.java 文件(Wifi模块的主界面). WifiSettings.java 在线代码

/*

* Copyright (C) 2010 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package com.android.settings.wifi;

import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;

import static android.os.UserManager.DISALLOW_CONFIG_WIFI;

import android.app.Activity;

import android.app.ActivityManager;

import android.app.Dialog;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.IntentFilter;

import android.content.SharedPreferences;

import android.content.res.Resources;

import android.content.res.TypedArray;

import android.location.LocationManager;

import android.net.ConnectivityManager;

import android.net.NetworkInfo;

import android.net.NetworkInfo.DetailedState;

import android.net.NetworkScoreManager;

import android.net.NetworkScorerAppManager;

import android.net.NetworkScorerAppManager.NetworkScorerAppData;

import android.net.wifi.ScanResult;

import android.net.wifi.WifiConfiguration;

import android.net.wifi.WifiInfo;

import android.net.wifi.WifiManager;

import android.net.wifi.WpsInfo;

import android.os.Build;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.os.UserHandle;

import android.preference.Preference;

import android.preference.PreferenceScreen;

import android.util.Log;

import android.view.ContextMenu;

import android.view.ContextMenu.ContextMenuInfo;

import android.view.LayoutInflater;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.AdapterView.AdapterContextMenuInfo;

import android.widget.Button;

import android.widget.TextView;

import android.widget.Toast;

import com.android.settings.R;

import com.android.settings.RestrictedSettingsFragment;

import com.android.settings.SettingsActivity;

import com.android.settings.search.BaseSearchIndexProvider;

import com.android.settings.search.Indexable;

import com.android.settings.search.SearchIndexableRaw;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.concurrent.atomic.AtomicBoolean;

/**

* Two types of UI are provided here.

*

* The first is for "usual Settings", appearing as any other Setup fragment.

*

* The second is for Setup Wizard, with a simplified interface that hides the action bar

* and menus.

*/

public class WifiSettings extends RestrictedSettingsFragment

implements DialogInterface.OnClickListener, Indexable {

private static final String TAG = "WifiSettings";

private static final int REQUEST_ENABLE_WIFI_ASSISTANT = 1;

/* package */ static final int MENU_ID_WPS_PBC = Menu.FIRST;

private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1;

private static final int MENU_ID_SAVED_NETWORK = Menu.FIRST + 2;

/* package */ static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3;

private static final int MENU_ID_ADVANCED = Menu.FIRST + 4;

private static final int MENU_ID_SCAN = Menu.FIRST + 5;

private static final int MENU_ID_CONNECT = Menu.FIRST + 6;

private static final int MENU_ID_FORGET = Menu.FIRST + 7;

private static final int MENU_ID_MODIFY = Menu.FIRST + 8;

private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9;

private static final String KEY_ASSISTANT_DISMISS_PLATFORM = "assistant_dismiss_platform";

public static final int WIFI_DIALOG_ID = 1;

/* package */ static final int WPS_PBC_DIALOG_ID = 2;

private static final int WPS_PIN_DIALOG_ID = 3;

private static final int WRITE_NFC_DIALOG_ID = 6;

// Combo scans can take 5-6s to complete - set to 10s.

private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;

// Instance state keys

private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode";

private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";

private static boolean savedNetworksExist;

private final IntentFilter mFilter;

private final BroadcastReceiver mReceiver;

private final Scanner mScanner;

/* package */ WifiManager mWifiManager;

private WifiManager.ActionListener mConnectListener;

private WifiManager.ActionListener mSaveListener;

private WifiManager.ActionListener mForgetListener;

private WifiEnabler mWifiEnabler;

// An access point being editted is stored here.

private AccessPoint mSelectedAccessPoint;

private DetailedState mLastState;

private WifiInfo mLastInfo;

private final AtomicBoolean mConnected = new AtomicBoolean(false);

private WifiDialog mDialog;

private WriteWifiConfigToNfcDialog mWifiToNfcDialog;

private TextView mEmptyView;

// this boolean extra specifies whether to disable the Next button when not connected. Used by

// account creation outside of setup wizard.

private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";

// should Next button only be enabled when we have a connection?

private boolean mEnableNextOnConnection;

// Save the dialog details

private boolean mDlgEdit;

private AccessPoint mDlgAccessPoint;

private Bundle mAccessPointSavedState;

private View mWifiAssistantCard;

private NetworkScorerAppData mWifiAssistantApp;

/** verbose logging flag. this flag is set thru developer debugging options

* and used so as to assist with in-the-field WiFi connectivity debugging */

public static int mVerboseLogging = 0;

/* End of "used in Wifi Setup context" */

/** A restricted multimap for use in constructAccessPoints */

private static class Multimap {

private final HashMap> store = new HashMap>();

/** retrieve a non-null list of values with key K */

List getAll(K key) {

List values = store.get(key);

return values != null ? values : Collections.emptyList();

}

void put(K key, V val) {

List curVals = store.get(key);

if (curVals == null) {

curVals = new ArrayList(3);

store.put(key, curVals);

}

curVals.add(val);

}

}

private static class Scanner extends Handler {

private int mRetry = 0;

private WifiSettings mWifiSettings = null;

Scanner(WifiSettings wifiSettings) {

mWifiSettings = wifiSettings;

}

void resume() {

if (!hasMessages(0)) {

sendEmptyMessage(0);

}

}

void forceScan() {

removeMessages(0);

sendEmptyMessage(0);

}

void pause() {

mRetry = 0;

removeMessages(0);

}

@Override

public void handleMessage(Message message) {

if (mWifiSettings.mWifiManager.startScan()) {

mRetry = 0;

} else if (++mRetry >= 3) {

mRetry = 0;

Activity activity = mWifiSettings.getActivity();

if (activity != null) {

Toast.makeText(activity, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();

}

return;

}

sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);

}

}

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);

}

@Override

public void onActivityCreated(Bundle savedInstanceState) {

super.onActivityCreated(savedInstanceState);

mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

mConnectListener = new WifiManager.ActionListener() {

@Override

public void onSuccess() {

}

@Override

public void onFailure(int reason) {

Activity activity = getActivity();

if (activity != null) {

Toast.makeText(activity,

R.string.wifi_failed_connect_message,

Toast.LENGTH_SHORT).show();

}

}

};

mSaveListener = new WifiManager.ActionListener() {

@Override

public void onSuccess() {

}

@Override

public void onFailure(int reason) {

Activity activity = getActivity();

if (activity != null) {

Toast.makeText(activity,

R.string.wifi_failed_save_message,

Toast.LENGTH_SHORT).show();

}

}

};

mForgetListener = new WifiManager.ActionListener() {

@Override

public void onSuccess() {

}

@Override

public void onFailure(int reason) {

Activity activity = getActivity();

if (activity != null) {

Toast.makeText(activity,

R.string.wifi_failed_forget_message,

Toast.LENGTH_SHORT).show();

}

}

};

if (savedInstanceState != null) {

mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);

if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {

mAccessPointSavedState =

savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);

}

}

// if we're supposed to enable/disable the Next button based on our current connection

// state, start it off in the right state

Intent intent = getActivity().getIntent();

mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);

if (mEnableNextOnConnection) {

if (hasNextButton()) {

final ConnectivityManager connectivity = (ConnectivityManager)

getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);

if (connectivity != null) {

NetworkInfo info = connectivity.getNetworkInfo(

ConnectivityManager.TYPE_WIFI);

changeNextButtonState(info.isConnected());

}

}

}

addPreferencesFromResource(R.xml.wifi_settings);

prepareWifiAssistantCard();

mEmptyView = initEmptyView();

registerForContextMenu(getListView());

setHasOptionsMenu(true);

}

@Override

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {

if (requestCode == REQUEST_ENABLE_WIFI_ASSISTANT) {

if (resultCode == Activity.RESULT_OK) {

disableWifiAssistantCardUntilPlatformUpgrade();

getListView().removeHeaderView(mWifiAssistantCard);

mWifiAssistantApp = null;

}

} else {

super.onActivityResult(requestCode, resultCode, resultData);

}

}

@Override

public void onDestroyView() {

super.onDestroyView();

if (mWifiEnabler != null) {

mWifiEnabler.teardownSwitchBar();

}

}

@Override

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());

}

@Override

public void onResume() {

final Activity activity = getActivity();

super.onResume();

if (mWifiEnabler != null) {

mWifiEnabler.resume(activity);

}

activity.registerReceiver(mReceiver, mFilter);

updateAccessPoints();

}

@Override

public void onPause() {

super.onPause();

if (mWifiEnabler != null) {

mWifiEnabler.pause();

}

getActivity().unregisterReceiver(mReceiver);

mScanner.pause();

}

@Override

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

// If the user is not allowed to configure wifi, do not show the menu.

if (isUiRestricted()) return;

addOptionsMenuItems(menu);

super.onCreateOptionsMenu(menu, inflater);

}

/**

* @param menu

*/

void addOptionsMenuItems(Menu menu) {

final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();

TypedArray ta = getActivity().getTheme().obtainStyledAttributes(

new int[] {R.attr.ic_menu_add, R.attr.ic_wps});

menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network)

.setIcon(ta.getDrawable(0))

.setEnabled(wifiIsEnabled)

.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

if (savedNetworksExist) {

menu.add(Menu.NONE, MENU_ID_SAVED_NETWORK, 0, R.string.wifi_saved_access_points_label)

.setIcon(ta.getDrawable(0))

.setEnabled(wifiIsEnabled)

.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

}

menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.menu_stats_refresh)

.setEnabled(wifiIsEnabled)

.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)

.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

ta.recycle();

}

@Override

public void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

// If the dialog is showing, save its state.

if (mDialog != null && mDialog.isShowing()) {

outState.putBoolean(SAVE_DIALOG_EDIT_MODE, mDlgEdit);

if (mDlgAccessPoint != null) {

mAccessPointSavedState = new Bundle();

mDlgAccessPoint.saveWifiState(mAccessPointSavedState);

outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);

}

}

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// If the user is not allowed to configure wifi, do not handle menu selections.

if (isUiRestricted()) return false;

switch (item.getItemId()) {

case MENU_ID_WPS_PBC:

showDialog(WPS_PBC_DIALOG_ID);

return true;

/*

case MENU_ID_P2P:

if (getActivity() instanceof SettingsActivity) {

((SettingsActivity) getActivity()).startPreferencePanel(

WifiP2pSettings.class.getCanonicalName(),

null,

R.string.wifi_p2p_settings_title, null,

this, 0);

} else {

startFragment(this, WifiP2pSettings.class.getCanonicalName(),

R.string.wifi_p2p_settings_title, -1, null);

}

return true;

*/

case MENU_ID_WPS_PIN:

showDialog(WPS_PIN_DIALOG_ID);

return true;

case MENU_ID_SCAN:

if (mWifiManager.isWifiEnabled()) {

mScanner.forceScan();

}

return true;

case MENU_ID_ADD_NETWORK:

if (mWifiManager.isWifiEnabled()) {

onAddNetworkPressed();

}

return true;

case MENU_ID_SAVED_NETWORK:

if (getActivity() instanceof SettingsActivity) {

((SettingsActivity) getActivity()).startPreferencePanel(

SavedAccessPointsWifiSettings.class.getCanonicalName(), null,

R.string.wifi_saved_access_points_titlebar, null, this, 0);

} else {

startFragment(this, SavedAccessPointsWifiSettings.class.getCanonicalName(),

R.string.wifi_saved_access_points_titlebar,

-1 /* Do not request a result */, null);

}

return true;

case MENU_ID_ADVANCED:

if (getActivity() instanceof SettingsActivity) {

((SettingsActivity) getActivity()).startPreferencePanel(

AdvancedWifiSettings.class.getCanonicalName(), null,

R.string.wifi_advanced_titlebar, null, this, 0);

} else {

startFragment(this, AdvancedWifiSettings.class.getCanonicalName(),

R.string.wifi_advanced_titlebar, -1 /* Do not request a results */,

null);

}

return true;

}

return super.onOptionsItemSelected(item);

}

@Override

public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {

if (info instanceof AdapterContextMenuInfo) {

Preference preference = (Preference) getListView().getItemAtPosition(

((AdapterContextMenuInfo) info).position);

if (preference instanceof AccessPoint) {

mSelectedAccessPoint = (AccessPoint) preference;

menu.setHeaderTitle(mSelectedAccessPoint.ssid);

if (mSelectedAccessPoint.getLevel() != -1

&& mSelectedAccessPoint.getState() == null) {

menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);

}

if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {

menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);

}

menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);

if (mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) {

// Only allow writing of NFC tags for password-protected networks.

menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);

}

}

}

}

}

@Override

public boolean onContextItemSelected(MenuItem item) {

if (mSelectedAccessPoint == null) {

return super.onContextItemSelected(item);

}

switch (item.getItemId()) {

case MENU_ID_CONNECT: {

if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

connect(mSelectedAccessPoint.networkId);

} else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {

/** Bypass dialog for unsecured networks */

mSelectedAccessPoint.generateOpenNetworkConfig();

connect(mSelectedAccessPoint.getConfig());

} else {

showDialog(mSelectedAccessPoint, true);

}

return true;

}

case MENU_ID_FORGET: {

mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);

return true;

}

case MENU_ID_MODIFY: {

showDialog(mSelectedAccessPoint, true);

return true;

}

case MENU_ID_WRITE_NFC:

showDialog(WRITE_NFC_DIALOG_ID);

return true;

}

return super.onContextItemSelected(item);

}

@Override

public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {

if (preference instanceof AccessPoint) {

mSelectedAccessPoint = (AccessPoint) preference;

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

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

mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {

mSelectedAccessPoint.generateOpenNetworkConfig();

if (!savedNetworksExist) {

savedNetworksExist = true;

getActivity().invalidateOptionsMenu();

}

connect(mSelectedAccessPoint.getConfig());

} else {

showDialog(mSelectedAccessPoint, false);

}

} else {

return super.onPreferenceTreeClick(screen, preference);

}

return true;

}

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);

}

@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);

}

/**

* Shows the latest access points available with supplemental information like

* the strength of network and the security for it.

*/

private void updateAccessPoints() {

// 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();

//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 accessPoints =

constructAccessPoints(getActivity(), mWifiManager, mLastInfo, mLastState);

getPreferenceScreen().removeAll();

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

addMessagePreference(R.string.wifi_empty_list_wifi_on);

}

getListView().removeHeaderView(mWifiAssistantCard);

if (mWifiAssistantApp != null) {

getListView().addHeaderView(mWifiAssistantCard);

}

for (AccessPoint accessPoint : accessPoints) {

// Ignore access points that are out of range.

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;

}

}

/**

* Returns the Network Scorer for the Wifi Assistant App.

*/

public static NetworkScorerAppData getWifiAssistantApp(Context context) {

Collection scorers =

Ne

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值