Wifi源码学习(Android5.1)之wifi开关
Wifi源码学习(Android5.1)之wifi optionItem
Wifi源码学习(Android5.1)之wifi列表
optionitem 是什么?
看图:
闲话少说,直接上代码:
首先是简单的optionitem 添加的方法。
Settings\src\com\android\settings\wifi\WifiSettings.java
@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) {
//判断 wifi 是否可用
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) {
// 显示已经保存的 wifi(不一定连接成功过)
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 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_SCAN:
// 如果wifi可用,则进行搜索
if (mWifiManager.isWifiEnabled()) {
mScanner.forceScan();
}
return true;
case MENU_ID_ADD_NETWORK:
// 添加新的网络
if (mWifiManager.isWifiEnabled()) {
onAddNetworkPressed();
}
return true;
case MENU_ID_SAVED_NETWORK:
// 显示已经保存的 wifi 信息
// 如果是从设置中进入 则 执行 if 语句部分,如果是三方访问,则走else 部分
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);
}
wifi界面的optionitem就是下边四项,下边我们一个一个来梳理流程:
/* package */ void onAddNetworkPressed() {
// No exact access point is selected.
mSelectedAccessPoint = null;
showDialog(null, true);
}
private void showDialog(AccessPoint accessPoint, boolean edit) {
// 如果 dialog 已经存在,则现将前 dialog 移除掉,然后再创建新的 dialog
// 这种写法也是我们需要借鉴的,代码小细节
if (mDialog != null) {
removeDialog(WIFI_DIALOG_ID);
mDialog = null;
}
// Save the access point and edit mode
mDlgAccessPoint = accessPoint; // null
mDlgEdit = edit; // true
// 调用了“父亲的父亲”(注意加了引号,点击看详细解释)的方法,这儿就是体现了继承的好处,慢慢体会
showDialog(WIFI_DIALOG_ID);// WIFI_DIALOG_ID = 1
}
Settings\src\com\android\settings\SettingsPreferenceFragment.java
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));
Log.e("blb","----------------------------------------------------------------------------------"+getChildFragmentManager());
}
// 构造方法
public SettingsDialogFragment(DialogCreatable fragment, int dialogId) {
mDialogId = dialogId;
if (!(fragment instanceof Fragment)) {
throw new IllegalArgumentException("fragment argument must be an instance of "
+ Fragment.class.getName());
}
mParentFragment = (Fragment) fragment;
}
Settings\src\com\android\settings\wifi\WifiSettings.java
// 注意这里调用的是 WifiSettings.java 的方法,而不是 SettingsPreferenceFragment.java 的。
@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;
// 后边的代码暂时不需要,暂且省略
}
return super.onCreateDialog(dialogId);
}
Settings\src\com\android\settings\wifi\WifiDialog.java
然后看一下布局:
这个 dialog 比较复杂,我们现在看到的只是一小部分,我们暂且只看这一个简单界面
Settings\res\layout\wifi_dialog.xml
"match_parent"
android:layout_height="wrap_content"
style="@style/wifi_item" >
"wrap_content"
android:layout_height="wrap_content"
style="@style/wifi_item_label"
android:text="@string/wifi_ssid"
android:textDirection="locale" />
"@+id/ssid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/wifi_item_edit_content"
android:hint="@string/wifi_ssid_hint"
android:maxLength="32"
android:singleLine="true"
android:inputType="textNoSuggestions" />
</LinearLayout>
很明显,这个 EditText 就是我们上图中的输入框。
@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());
}
}
}
// 点击确定之后 保存 连接等
/* 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();
}
Settings\src\com\android\settings\wifi\SavedAccessPointsWifiSettings.java
在 onResume() 中,获取数据动态绘制
private void initPreferences() {
PreferenceScreen preferenceScreen = getPreferenceScreen();
final Context context = getActivity();
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
final List accessPoints = constructSavedAccessPoints(context, mWifiManager);
preferenceScreen.removeAll();
final int accessPointsSize = accessPoints.size();
// 类似于listView 的样子
for (int i = 0; i < accessPointsSize; ++i){
preferenceScreen.addPreference(accessPoints.get(i));
}
if(getPreferenceScreen().getPreferenceCount() < 1) {
Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
}
}
在 onPreferenceTreeClick() 方法中处理点击事件
@Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
if (preference instanceof AccessPoint) {
// 弹出 dialog ,流程与 添加 wifi 一样
showDialog((AccessPoint) preference, false);
return true;
} else{
return super.onPreferenceTreeClick(screen, preference);
}
}
点击每一行会弹出 dialog
@Override
public void onClick(DialogInterface dialogInterface, int button) {
// 如果点击了 forget ,则进行相应的处理操作
if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
mWifiManager.forget(mSelectedAccessPoint.networkId, null);
getPreferenceScreen().removePreference(mSelectedAccessPoint);
mSelectedAccessPoint = null;
}
}
// 这一部分和WifiSettings 的内部类 Scanner相关,在上一篇博客中已经做了介绍,此处不再赘述