Enhance and fix WPS UI

- Fixes WPS usage for open network
- Exposes WPS on UI for easy access to push button and pin based techniques
- Adds support for cancelling WPS
- Adds a dialog that reports a progress since WPS can take quite a bit of time
to complete

The WpsDialog code is enhanced from contribution by yoshihiko.ikenaga@jp.sony.com
on partner source.

Change-Id: Ib0103507e0192e8195e7bfeb1c8e8855c20e23ca
This commit is contained in:
Irfan Sheriff
2012-02-27 16:20:29 -08:00
parent 6c9c305b28
commit 90380120e7
7 changed files with 406 additions and 222 deletions

View File

@@ -33,7 +33,6 @@ import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.ProxySettings;
import android.net.wifi.WifiConfiguration.Status;
import android.net.wifi.WifiInfo;
import android.net.wifi.WpsInfo;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
@@ -88,12 +87,6 @@ public class WifiConfigController implements TextWatcher,
private static final int DHCP = 0;
private static final int STATIC_IP = 1;
/* These values come from "wifi_network_setup" resource array */
public static final int MANUAL = 0;
public static final int WPS_PBC = 1;
public static final int WPS_KEYPAD = 2;
public static final int WPS_DISPLAY = 3;
/* These values come from "wifi_proxy_settings" resource array */
public static final int PROXY_NONE = 0;
public static final int PROXY_STATIC = 1;
@@ -106,7 +99,6 @@ public class WifiConfigController implements TextWatcher,
private static final String TAG = "WifiConfigController";
private Spinner mNetworkSetupSpinner;
private Spinner mIpSettingsSpinner;
private TextView mIpAddressView;
private TextView mGatewayView;
@@ -232,11 +224,6 @@ public class WifiConfigController implements TextWatcher,
}
/* Show network setup options only for a new network */
if (mAccessPoint.networkId == INVALID_NETWORK_ID && mAccessPoint.wpsAvailable) {
showNetworkSetupFields();
}
if (mAccessPoint.networkId == INVALID_NETWORK_ID || mEdit) {
showSecurityFields();
showIpConfigFields();
@@ -286,10 +273,8 @@ public class WifiConfigController implements TextWatcher,
boolean enabled = false;
boolean passwordInvalid = false;
/* Check password invalidity for manual network set up alone */
if (chosenNetworkSetupMethod() == MANUAL &&
((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
(mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8))) {
if ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
(mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8)) {
passwordInvalid = true;
}
@@ -484,35 +469,6 @@ public class WifiConfigController implements TextWatcher,
return 0;
}
int chosenNetworkSetupMethod() {
if (mNetworkSetupSpinner != null) {
return mNetworkSetupSpinner.getSelectedItemPosition();
}
return MANUAL;
}
WpsInfo getWpsConfig() {
WpsInfo config = new WpsInfo();
switch (mNetworkSetupSpinner.getSelectedItemPosition()) {
case WPS_PBC:
config.setup = WpsInfo.PBC;
break;
case WPS_KEYPAD:
config.setup = WpsInfo.KEYPAD;
break;
case WPS_DISPLAY:
config.setup = WpsInfo.DISPLAY;
break;
default:
config.setup = WpsInfo.INVALID;
Log.e(TAG, "WPS not selected type");
return config;
}
config.pin = ((TextView) mView.findViewById(R.id.wps_pin)).getText().toString();
config.BSSID = (mAccessPoint != null) ? mAccessPoint.bssid : null;
return config;
}
private void showSecurityFields() {
if (mInXlSetupWizard) {
// Note: XL SetupWizard won't hide "EAP" settings here.
@@ -583,33 +539,6 @@ public class WifiConfigController implements TextWatcher,
mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
}
}
private void showNetworkSetupFields() {
mView.findViewById(R.id.setup_fields).setVisibility(View.VISIBLE);
if (mNetworkSetupSpinner == null) {
mNetworkSetupSpinner = (Spinner) mView.findViewById(R.id.network_setup);
mNetworkSetupSpinner.setOnItemSelectedListener(this);
}
int pos = mNetworkSetupSpinner.getSelectedItemPosition();
/* Show pin text input if needed */
if (pos == WPS_KEYPAD) {
mView.findViewById(R.id.wps_fields).setVisibility(View.VISIBLE);
} else {
mView.findViewById(R.id.wps_fields).setVisibility(View.GONE);
}
/* show/hide manual security fields appropriately */
if ((pos == WPS_DISPLAY) || (pos == WPS_KEYPAD)
|| (pos == WPS_PBC)) {
mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
} else {
mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
}
}
private void showIpConfigFields() {
WifiConfiguration config = null;
@@ -785,8 +714,6 @@ public class WifiConfigController implements TextWatcher,
showSecurityFields();
} else if (parent == mEapMethodSpinner) {
showSecurityFields();
} else if (parent == mNetworkSetupSpinner) {
showNetworkSetupFields();
} else if (parent == mProxySettingsSpinner) {
showProxyFields();
} else {

View File

@@ -36,7 +36,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WpsResult;
import android.net.wifi.WpsInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -82,14 +82,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class WifiSettings extends SettingsPreferenceFragment
implements DialogInterface.OnClickListener {
private static final String TAG = "WifiSettings";
private static final int MENU_ID_SCAN = Menu.FIRST;
private static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 1;
private static final int MENU_ID_ADVANCED = Menu.FIRST + 2;
private static final int MENU_ID_CONNECT = Menu.FIRST + 3;
private static final int MENU_ID_FORGET = Menu.FIRST + 4;
private static final int MENU_ID_MODIFY = Menu.FIRST + 5;
private 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_ADD_NETWORK = Menu.FIRST + 2;
private static final int MENU_ID_ADVANCED = Menu.FIRST + 3;
private static final int MENU_ID_SCAN = Menu.FIRST + 4;
private static final int MENU_ID_CONNECT = Menu.FIRST + 5;
private static final int MENU_ID_FORGET = Menu.FIRST + 6;
private static final int MENU_ID_MODIFY = Menu.FIRST + 7;
private static final int WIFI_DIALOG_ID = 1;
private static final int WPS_PBC_DIALOG_ID = 2;
private static final int WPS_PIN_DIALOG_ID = 3;
// Combo scans can take 5-6s to complete - set to 10s.
private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
@@ -107,7 +111,7 @@ public class WifiSettings extends SettingsPreferenceFragment
private WifiManager.ActionListener mConnectListener;
private WifiManager.ActionListener mSaveListener;
private WifiManager.ActionListener mForgetListener;
private WifiManager.WpsListener mWpsListener;
private WifiEnabler mWifiEnabler;
// An access point being editted is stored here.
@@ -207,44 +211,6 @@ public class WifiSettings extends SettingsPreferenceFragment
}
};
class WpsListener implements WifiManager.WpsListener {
public void onStartSuccess(String pin) {
//TODO: Add progress bar instead
if (pin != null) {
AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.wifi_wps_setup_title)
.setPositiveButton(android.R.string.ok, null);
dialog.setMessage(getResources().getString(
R.string.wifi_wps_pin_output, pin));
dialog.show();
}
}
public void onCompletion() {
//TODO: Dismiss progress bar
}
public void onFailure(int reason) {
AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.wifi_wps_setup_title)
.setPositiveButton(android.R.string.ok, null);
switch (reason) {
case WifiManager.IN_PROGRESS:
dialog.setMessage(R.string.wifi_wps_in_progress);
dialog.show();
break;
case WifiManager.WPS_OVERLAP_ERROR:
Toast.makeText(getActivity(), R.string.wifi_wps_overlap_error,
Toast.LENGTH_SHORT).show();
break;
default:
dialog.setMessage(R.string.wifi_wps_failed);
dialog.show();
break;
}
}
}
mWpsListener = new WpsListener();
if (savedInstanceState != null
&& savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);
@@ -337,17 +303,23 @@ public class WifiSettings extends SettingsPreferenceFragment
// We don't want menus in Setup Wizard XL.
if (!mInXlSetupWizard) {
final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();
menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
//.setIcon(R.drawable.ic_menu_scan_network)
menu.add(Menu.NONE, MENU_ID_WPS_PBC, 0, R.string.wifi_menu_wps_pbc)
.setEnabled(wifiIsEnabled)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network)
.setEnabled(wifiIsEnabled)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan)
//.setIcon(R.drawable.ic_menu_scan_network)
.setEnabled(wifiIsEnabled)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(Menu.NONE, MENU_ID_WPS_PIN, 0, R.string.wifi_menu_wps_pin)
.setEnabled(wifiIsEnabled)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
//.setIcon(android.R.drawable.ic_menu_manage)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
}
}
super.onCreateOptionsMenu(menu, inflater);
}
@@ -369,6 +341,12 @@ public class WifiSettings extends SettingsPreferenceFragment
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_WPS_PBC:
showDialog(WPS_PBC_DIALOG_ID);
return true;
case MENU_ID_WPS_PIN:
showDialog(WPS_PIN_DIALOG_ID);
return true;
case MENU_ID_SCAN:
if (mWifiManager.isWifiEnabled()) {
mScanner.forceScan();
@@ -496,18 +474,26 @@ public class WifiSettings extends SettingsPreferenceFragment
@Override
public Dialog onCreateDialog(int dialogId) {
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;
}
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;
}
}
// If it's still 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);
}
// If it's still null, fine, it's for Add Network
mSelectedAccessPoint = ap;
mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);
return mDialog;
return super.onCreateDialog(dialogId);
}
private boolean requireKeyStore(WifiConfiguration config) {
@@ -780,35 +766,26 @@ public class WifiSettings extends SettingsPreferenceFragment
}
/* package */ void submit(WifiConfigController configController) {
int networkSetup = configController.chosenNetworkSetupMethod();
switch(networkSetup) {
case WifiConfigController.WPS_PBC:
case WifiConfigController.WPS_DISPLAY:
case WifiConfigController.WPS_KEYPAD:
mWifiManager.startWps(mChannel, configController.getWpsConfig(), mWpsListener);
break;
case WifiConfigController.MANUAL:
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& !requireKeyStore(mSelectedAccessPoint.getConfig())
&& mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
mWifiManager.connect(mChannel, mSelectedAccessPoint.networkId,
mConnectListener);
}
} else if (config.networkId != INVALID_NETWORK_ID) {
if (mSelectedAccessPoint != null) {
saveNetwork(config);
}
} else {
if (configController.isEdit() || requireKeyStore(config)) {
saveNetwork(config);
} else {
mWifiManager.connect(mChannel, config, mConnectListener);
}
}
break;
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& !requireKeyStore(mSelectedAccessPoint.getConfig())
&& mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
mWifiManager.connect(mChannel, mSelectedAccessPoint.networkId,
mConnectListener);
}
} else if (config.networkId != INVALID_NETWORK_ID) {
if (mSelectedAccessPoint != null) {
saveNetwork(config);
}
} else {
if (configController.isEdit() || requireKeyStore(config)) {
saveNetwork(config);
} else {
mWifiManager.connect(mChannel, config, mConnectListener);
}
}
if (mWifiManager.isWifiEnabled()) {

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2012 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 android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WpsInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import com.android.settings.R;
/**
* Dialog to show WPS progress.
*/
public class WpsDialog extends AlertDialog {
private final static String TAG = "WpsDialog";
private View mView;
private TextView mTextView;
private ProgressBar mTimeoutBar;
private ProgressBar mProgressBar;
private Button mButton;
private Timer mTimer;
private static final int WPS_TIMEOUT_S = 120;
private WifiManager mWifiManager;
private WifiManager.Channel mChannel;
private WifiManager.WpsListener mWpsListener;
private int mWpsSetup;
private final IntentFilter mFilter;
private BroadcastReceiver mReceiver;
private Context mContext;
private Handler mHandler = new Handler();
private enum DialogState {
WPS_INIT,
WPS_START,
WPS_COMPLETE,
CONNECTED, //WPS + IP config is done
WPS_FAILED
}
DialogState mDialogState = DialogState.WPS_INIT;
public WpsDialog(Context context, int wpsSetup) {
super(context);
mContext = context;
mWpsSetup = wpsSetup;
class WpsListener implements WifiManager.WpsListener {
public void onStartSuccess(String pin) {
if (pin != null) {
updateDialog(DialogState.WPS_START, String.format(
mContext.getString(R.string.wifi_wps_onstart_pin), pin));
} else {
updateDialog(DialogState.WPS_START, mContext.getString(
R.string.wifi_wps_onstart_pbc));
}
}
public void onCompletion() {
updateDialog(DialogState.WPS_COMPLETE,
mContext.getString(R.string.wifi_wps_complete));
}
public void onFailure(int reason) {
String msg;
switch (reason) {
case WifiManager.WPS_OVERLAP_ERROR:
msg = mContext.getString(R.string.wifi_wps_failed_overlap);
break;
case WifiManager.WPS_WEP_PROHIBITED:
msg = mContext.getString(R.string.wifi_wps_failed_wep);
break;
case WifiManager.WPS_TKIP_ONLY_PROHIBITED:
msg = mContext.getString(R.string.wifi_wps_failed_tkip);
break;
case WifiManager.IN_PROGRESS:
msg = mContext.getString(R.string.wifi_wps_in_progress);
break;
default:
msg = mContext.getString(R.string.wifi_wps_failed_generic);
break;
}
updateDialog(DialogState.WPS_FAILED, msg);
}
}
mWpsListener = new WpsListener();
mFilter = new IntentFilter();
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleEvent(context, intent);
}
};
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTitle(R.string.wifi_wps_setup_title);
mView = getLayoutInflater().inflate(R.layout.wifi_wps_dialog, null);
mTextView = (TextView) mView.findViewById(R.id.wps_dialog_txt);
mTextView.setText(R.string.wifi_wps_setup_msg);
mTimeoutBar = ((ProgressBar) mView.findViewById(R.id.wps_timeout_bar));
mTimeoutBar.setMax(WPS_TIMEOUT_S);
mTimeoutBar.setProgress(0);
mProgressBar = ((ProgressBar) mView.findViewById(R.id.wps_progress_bar));
mProgressBar.setVisibility(View.GONE);
mButton = ((Button) mView.findViewById(R.id.wps_dialog_btn));
mButton.setText(R.string.wifi_cancel);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mChannel = mWifiManager.initialize(mContext, mContext.getMainLooper(), null);
setView(mView);
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
/*
* increment timeout bar per second.
*/
mTimer = new Timer(false);
mTimer.schedule(new TimerTask() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
mTimeoutBar.incrementProgressBy(1);
}
});
}
}, 1000, 1000);
mContext.registerReceiver(mReceiver, mFilter);
WpsInfo wpsConfig = new WpsInfo();
wpsConfig.setup = mWpsSetup;
mWifiManager.startWps(mChannel, wpsConfig, mWpsListener);
}
@Override
protected void onStop() {
if (mDialogState != DialogState.WPS_COMPLETE) {
mWifiManager.cancelWps(mChannel, null);
}
if (mReceiver != null) {
mContext.unregisterReceiver(mReceiver);
mReceiver = null;
}
if (mTimer != null) {
mTimer.cancel();
}
}
private void updateDialog(DialogState state, String msg) {
if (mDialogState.ordinal() >= state.ordinal()) {
//ignore.
return;
}
mDialogState = state;
switch(state) {
case WPS_COMPLETE:
mTimeoutBar.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
break;
case CONNECTED:
case WPS_FAILED:
mButton.setText(mContext.getString(R.string.dlg_ok));
mTimeoutBar.setVisibility(View.GONE);
mProgressBar.setVisibility(View.GONE);
if (mReceiver != null) {
mContext.unregisterReceiver(mReceiver);
mReceiver = null;
}
break;
}
mTextView.setText(msg);
}
private void handleEvent(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
final NetworkInfo.DetailedState state = info.getDetailedState();
if (state == DetailedState.CONNECTED &&
mDialogState == DialogState.WPS_COMPLETE) {
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
if (wifiInfo != null) {
String msg = String.format(mContext.getString(
R.string.wifi_wps_connected), wifiInfo.getSSID());
updateDialog(DialogState.CONNECTED, msg);
}
}
}
}
}