Add EAP/802.1X configuration for WiFi Setting.
1. Remove the isEnterprise() filter in Scanresult.
2. This requires the new fields such as identity, eap, certificate/key
to support EAP authentication in Wifi Settings.
3. Add simple file-based keystore to select the cert/key from UI.
-- Updated from the comments.
-- Fix the bug for passing null pointer for adding spinner items.
diff --git a/res/layout/wifi_ap_configure.xml b/res/layout/wifi_ap_configure.xml
index d786cff..ecd6337 100644
--- a/res/layout/wifi_ap_configure.xml
+++ b/res/layout/wifi_ap_configure.xml
@@ -24,11 +24,17 @@
android:padding="8dip"
android:orientation="vertical">
-
+ <LinearLayout
+ android:id="@+id/table"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+ </LinearLayout>
+
<!-- SSID -->
- <TextView
+ <TextView android:id="@+id/ssid_text"
style="?android:attr/textAppearanceSmallInverse"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -44,7 +50,7 @@
<!-- Security -->
- <TextView
+ <TextView android:id="@+id/security_text"
style="?android:attr/textAppearanceSmallInverse"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -55,9 +61,94 @@
<Spinner android:id="@+id/security_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
-
-
-
+
+ <!-- Enterprise Fields -->
+ <LinearLayout android:id="@+id/enterprise_wrapper"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dip"
+ android:orientation="vertical">
+ <TextView android:id="@+id/eap_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_select_eap" />
+ <Spinner android:id="@+id/eap_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/phase2_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_select_phase2" />
+ <Spinner android:id="@+id/phase2_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView android:id="@+id/identity_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_type_identity" />
+ <EditText android:id="@+id/identity_edit"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dip"
+ android:singleLine="true" />
+ <TextView android:id="@+id/anonymous_identity_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_type_anonymous_identity" />
+ <EditText android:id="@+id/anonymous_identity_edit"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dip"
+ android:singleLine="true" />
+ <TextView android:id="@+id/client_certificate_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_select_client_certificate" />
+ <Spinner android:id="@+id/client_certificate_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/ca_certificate_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_select_ca_certificate" />
+ <Spinner android:id="@+id/ca_certificate_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/private_key_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_select_private_key" />
+ <Spinner android:id="@+id/private_key_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/private_key_passwd_text"
+ style="?android:attr/textAppearanceSmallInverse"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:text="@string/please_type_private_key_passwd" />
+ <EditText android:id="@+id/private_key_passwd_edit"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dip"
+ android:singleLine="true" />
+ </LinearLayout>
+
<!-- Password -->
<TextView android:id="@+id/password_text"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 6cfa7f0..72f56e7 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -93,9 +93,13 @@
<!-- Do not translate. The Wi-Fi network has WEP security. -->
<item>WEP</item>
<!-- The Wi-Fi network has WPA personal security. WPA Personal is a tech term, and might be better left untranslated? -->
- <item>WPA Personal</item>
+ <item>WPA personal</item>
<!-- The Wi-Fi network has WPA2 personal security. WPA Personal is a tech term, and might be better left untranslated? -->
- <item>WPA2 Personal</item>
+ <item>WPA2 personal</item>
+ <!-- The Wi-Fi network has WPA EAP extensible authentication protocol. -->
+ <item>WPA-EAP</item>
+ <!-- IEEE 802.1X key management -->
+ <item>IEEE 802.1x</item>
</string-array>
<!-- Match this with code. --> <skip />
@@ -106,9 +110,14 @@
<!-- Do not translate. The Wi-Fi network has WEP security. -->
<item>WEP</item>
<!-- The Wi-Fi network has WPA personal security. WPA Personal is a tech term, and might be better left untranslated? -->
- <item>WPA Personal</item>
+ <item>WPA personal</item>
<!-- The Wi-Fi network has WPA2 personal security. WPA Personal is a tech term, and might be better left untranslated? -->
- <item>WPA2 Personal</item>
+ <item>WPA2 personal</item>
+ <!-- The Wi-Fi network has WPA enterprise security. WPA Enterprise is a tech term, and might be better left untranslated? -->
+ <!-- The Wi-Fi network has WPA EAP extensible authentication protocol. -->
+ <item>WPA-EAP</item>
+ <!-- IEEE 802.1X key management -->
+ <item>IEEE 802.1x</item>
</string-array>
<!-- Match this with code. --> <skip />
@@ -167,4 +176,20 @@
<item>Application Name</item>
</string-array>
+ <!-- EAP method -->
+ <string-array name="wifi_eap_entries">
+ <item>PEAP</item>
+ <item>TLS</item>
+ <item>TTLS</item>
+ </string-array>
+
+ <!-- Phase 2 options -->
+ <string-array name="wifi_phase2_entries">
+ <item>None</item>
+ <item>PAP</item>
+ <item>MSCHAP</item>
+ <item>MSCHAP2</item>
+ <item>GTC</item>
+ </string-array>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 62120fc..07bfe2f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -614,6 +614,11 @@
<string name="wifi_security_wpa">WPA</string>
<!-- Value for the wifi security -->
<string name="wifi_security_wpa2">WPA2</string>
+ <!-- Value for the wifi security -->
+ <string name="wifi_security_wpa_eap">WPA-EAP</string>
+ <!-- Value for the wifi security -->
+ <string name="wifi_security_ieee8021x">IEEE8021X</string>
+
<!-- Value for the wifi security when it is unknown -->
<string name="wifi_security_unknown">Unknown</string>
<!-- Verbose security type of a wifi network. Open means no security. -->
@@ -624,6 +629,10 @@
<string name="wifi_security_verbose_wpa">Secured with WPA</string>
<!-- Verbose security type of a wifi network. -->
<string name="wifi_security_verbose_wpa2">Secured with WPA2</string>
+ <!-- Verbose security type of a wifi network. -->
+ <string name="wifi_security_verbose_wpa_eap">Secured with WPA-EAP</string>
+ <!-- Verbose security type of a wifi network. -->
+ <string name="wifi_security_verbose_ieee8021x">Secured with IEEE 802.1x</string>
<!-- Wi-Fi IP addrress label -->
<string name="ip_address">IP address</string>
<!-- Label for the signal strength -->
@@ -648,6 +657,22 @@
<string name="connect">Connect</string>
<!-- Dialog title for when the user is trying to connect to a particular network-->
<string name="connect_to_blank">Connect to <xliff:g id="network_name">%1$s</xliff:g></string>
+ <!-- Caption for the eap method -->
+ <string name="please_select_eap">EAP method</string>
+ <!-- Caption for the phase2 -->
+ <string name="please_select_phase2">Phase 2 authentication</string>
+ <!-- Caption for the identity -->
+ <string name="please_type_identity">Identity</string>
+ <!-- Caption for the anonymous_identity -->
+ <string name="please_type_anonymous_identity">Anonymous identity</string>
+ <!-- Caption for the client_certificate -->
+ <string name="please_select_client_certificate">Client certificate</string>
+ <!-- Caption for the ca certificate -->
+ <string name="please_select_ca_certificate">CA certificate</string>
+ <!-- Caption for the Private Key -->
+ <string name="please_select_private_key">Private key</string>
+ <!-- Caption for the private key passwd -->
+ <string name="please_type_private_key_passwd">Private key password</string>
<!-- Caption for the wireless password -->
<string name="please_type_passphrase">Wireless password</string>
<!--Wi-Fi settings screen, connect to network dialog box, field label and hint text -->
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
index 919f7fc..dc2b389 100644
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ b/src/com/android/settings/wifi/AccessPointDialog.java
@@ -21,6 +21,7 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.res.Resources;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
@@ -71,6 +72,8 @@
private static final int SECURITY_WEP = 2;
private static final int SECURITY_WPA_PERSONAL = 3;
private static final int SECURITY_WPA2_PERSONAL = 4;
+ private static final int SECURITY_WPA_EAP = 5;
+ private static final int SECURITY_IEEE8021X = 6;
private static final int[] WEP_TYPE_VALUES = {
AccessPointState.WEP_PASSWORD_AUTO, AccessPointState.WEP_PASSWORD_ASCII,
@@ -92,15 +95,39 @@
// General views
private View mView;
+ private View mEnterpriseView;
private TextView mPasswordText;
private EditText mPasswordEdit;
private CheckBox mShowPasswordCheckBox;
+
+ // Enterprise fields
+ private TextView mEapText;
+ private Spinner mEapSpinner;
+ private TextView mPhase2Text;
+ private Spinner mPhase2Spinner;
+ private TextView mIdentityText;
+ private EditText mIdentityEdit;
+ private TextView mAnonymousIdentityText;
+ private EditText mAnonymousIdentityEdit;
+ private TextView mClientCertText;
+ private Spinner mClientCertSpinner;
+ private TextView mCaCertText;
+ private Spinner mCaCertSpinner;
+ private TextView mPrivateKeyText;
+ private Spinner mPrivateKeySpinner;
+ private TextView mPrivateKeyPasswdText;
+ private EditText mPrivateKeyPasswdEdit;
+ private EditText[] mEnterpriseTextFields;
+ private Spinner[] mEnterpriseSpinnerFields;
+
// Info-specific views
private ViewGroup mTable;
// Configure-specific views
private EditText mSsidEdit;
+ private TextView mSsidText;
+ private TextView mSecurityText;
private Spinner mSecuritySpinner;
private Spinner mWepTypeSpinner;
@@ -208,9 +235,17 @@
positiveButtonResId = R.string.wifi_save_config;
mSaveButtonPos = POSITIVE_BUTTON;
-
+
+ setEnterpriseFieldsVisible(false);
+
} else if (mMode == MODE_INFO) {
- setLayout(R.layout.wifi_ap_info);
+ if (isEnterprise() && !mState.configured) {
+ setLayout(R.layout.wifi_ap_configure);
+ defaultPasswordVisibility = false;
+ setEnterpriseFieldsVisible(true);
+ } else {
+ setLayout(R.layout.wifi_ap_info);
+ }
if (mState.isConnectable()) {
if (mCustomTitle == null) {
@@ -251,41 +286,131 @@
setButtons(positiveButtonResId, negativeButtonResId, neutralButtonResId);
}
+ private boolean isEnterprise() {
+
+ if(AccessPointState.WPA_EAP.equals(mState.security) ||
+ AccessPointState.IEEE8021X.equals(mState.security)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/** Called when we need to set our member variables to point to the views. */
private void onReferenceViews(View view) {
mPasswordText = (TextView) view.findViewById(R.id.password_text);
mPasswordEdit = (EditText) view.findViewById(R.id.password_edit);
-
+ mSsidText = (TextView) view.findViewById(R.id.ssid_text);
+ mSsidEdit = (EditText) view.findViewById(R.id.ssid_edit);
+ mSecurityText = (TextView) view.findViewById(R.id.security_text);
+ mSecuritySpinner = (Spinner) view.findViewById(R.id.security_spinner);
+ mWepTypeSpinner = (Spinner) view.findViewById(R.id.wep_type_spinner);
+ mEnterpriseView = mView.findViewById(R.id.enterprise_wrapper);
+
mShowPasswordCheckBox = (CheckBox) view.findViewById(R.id.show_password_checkbox);
if (mShowPasswordCheckBox != null) {
mShowPasswordCheckBox.setOnClickListener(this);
}
-
if (mMode == MODE_CONFIGURE) {
- mSsidEdit = (EditText) view.findViewById(R.id.ssid_edit);
- mSecuritySpinner = (Spinner) view.findViewById(R.id.security_spinner);
mSecuritySpinner.setOnItemSelectedListener(this);
- setSecuritySpinnerAdapter();
- mWepTypeSpinner = (Spinner) view.findViewById(R.id.wep_type_spinner);
-
+ mSecuritySpinner.setPromptId(R.string.security);
+ setSpinnerAdapter(mSecuritySpinner, mAutoSecurityAllowed ?
+ R.array.wifi_security_entries
+ : R.array.wifi_security_without_auto_entries);
} else if (mMode == MODE_INFO) {
mTable = (ViewGroup) view.findViewById(R.id.table);
}
-
+ /* for enterprise one */
+ if (mMode == MODE_CONFIGURE || (isEnterprise() && !mState.configured)) {
+ setEnterpriseFields(view);
+ mEapSpinner.setSelection(getSelectionIndex(
+ R.array.wifi_eap_entries, mState.getEap()));
+ Keystore ks = Keystore.getInstance();
+ mClientCertSpinner.setSelection(getSelectionIndex(
+ ks.getAllCertificateKeys(), mState.getEnterpriseField(
+ AccessPointState.CLIENT_CERT)));
+ mCaCertSpinner.setSelection(getSelectionIndex(
+ ks.getAllCertificateKeys(), mState.getEnterpriseField(
+ AccessPointState.CA_CERT)));
+ mPrivateKeySpinner.setSelection(getSelectionIndex(
+ ks.getAllUserkeyKeys(), mState.getEnterpriseField(
+ AccessPointState.PRIVATE_KEY)));
+ }
}
-
- private void setSecuritySpinnerAdapter() {
- Context context = getContext();
- int arrayResId = mAutoSecurityAllowed ? R.array.wifi_security_entries
- : R.array.wifi_security_without_auto_entries;
- ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context,
- android.R.layout.simple_spinner_item,
- context.getResources().getStringArray(arrayResId));
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mSecuritySpinner.setAdapter(adapter);
+ private void setEnterpriseFields(View view) {
+ mIdentityText = (TextView) view.findViewById(R.id.identity_text);
+ mIdentityEdit = (EditText) view.findViewById(R.id.identity_edit);
+ mAnonymousIdentityText =
+ (TextView) view.findViewById(R.id.anonymous_identity_text);
+ mAnonymousIdentityEdit =
+ (EditText) view.findViewById(R.id.anonymous_identity_edit);
+ mClientCertText =
+ (TextView) view.findViewById(R.id.client_certificate_text);
+ mCaCertText = (TextView) view.findViewById(R.id.ca_certificate_text);
+ mPrivateKeyText = (TextView) view.findViewById(R.id.private_key_text);
+ mPrivateKeyPasswdText =
+ (TextView) view.findViewById(R.id.private_key_passwd_text);
+ mPrivateKeyPasswdEdit =
+ (EditText) view.findViewById(R.id.private_key_passwd_edit);
+ mEapText = (TextView) view.findViewById(R.id.eap_text);
+ mEapSpinner = (Spinner) view.findViewById(R.id.eap_spinner);
+ mEapSpinner.setOnItemSelectedListener(this);
+ mEapSpinner.setPromptId(R.string.please_select_eap);
+ setSpinnerAdapter(mEapSpinner, R.array.wifi_eap_entries);
+
+ mPhase2Text = (TextView) view.findViewById(R.id.phase2_text);
+ mPhase2Spinner = (Spinner) view.findViewById(R.id.phase2_spinner);
+ mPhase2Spinner.setOnItemSelectedListener(this);
+ mPhase2Spinner.setPromptId(R.string.please_select_phase2);
+ setSpinnerAdapter(mPhase2Spinner, R.array.wifi_phase2_entries);
+
+ Keystore ks = Keystore.getInstance();
+
+ mClientCertSpinner =
+ (Spinner) view.findViewById(R.id.client_certificate_spinner);
+ mClientCertSpinner.setOnItemSelectedListener(this);
+ mClientCertSpinner.setPromptId(
+ R.string.please_select_client_certificate);
+ setSpinnerAdapter(mClientCertSpinner, ks.getAllCertificateKeys());
+
+ mCaCertSpinner =
+ (Spinner) view.findViewById(R.id.ca_certificate_spinner);
+ mCaCertSpinner.setOnItemSelectedListener(this);
+ mCaCertSpinner.setPromptId(R.string.please_select_ca_certificate);
+ setSpinnerAdapter(mCaCertSpinner, ks.getAllCertificateKeys());
+
+ mPrivateKeySpinner =
+ (Spinner) view.findViewById(R.id.private_key_spinner);
+ mPrivateKeySpinner.setOnItemSelectedListener(this);
+ mPrivateKeySpinner.setPromptId(R.string.please_select_private_key);
+ setSpinnerAdapter(mPrivateKeySpinner, ks.getAllUserkeyKeys());
+
+ mEnterpriseTextFields = new EditText[] {
+ mIdentityEdit, mAnonymousIdentityEdit, mPrivateKeyPasswdEdit
+ };
+
+ mEnterpriseSpinnerFields = new Spinner[] {
+ mClientCertSpinner, mCaCertSpinner, mPrivateKeySpinner
+ };
+
}
-
+
+ private void setSpinnerAdapter(Spinner spinner, String[] items) {
+ if (items != null) {
+ ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
+ getContext(), android.R.layout.simple_spinner_item, items);
+ adapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ }
+ }
+
+ private void setSpinnerAdapter(Spinner spinner, int arrayResId) {
+ setSpinnerAdapter(spinner,
+ getContext().getResources().getStringArray(arrayResId));
+ }
+
/** Called when the widgets are in-place waiting to be filled with data */
private void onFill() {
@@ -381,39 +506,51 @@
if (!replaceStateWithWifiLayerInstance()) {
Log.w(TAG, "Assuming connecting to a new network.");
}
-
- /*
- * If the network is secured and they haven't entered a password, popup
- * an error. Allow empty passwords if the state already has a password
- * set (since in that scenario, an empty password means keep the old
- * password).
- */
- String password = getEnteredPassword();
- boolean passwordIsEmpty = TextUtils.isEmpty(password);
-
- /*
- * When 'retry password', they can not enter a blank password. In any
- * other mode, we let them enter a blank password if the state already
- * has a password.
- */
- if (passwordIsEmpty && (!mState.hasPassword() || mMode == MODE_RETRY_PASSWORD)
- && (mState.security != null) && !mState.security.equals(AccessPointState.OPEN)) {
- new AlertDialog.Builder(getContext())
- .setTitle(R.string.error_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.wifi_password_incorrect_error)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- return;
+
+ if (isEnterprise()) {
+ if(!mState.configured) {
+ updateEnterpriseFields(
+ AccessPointState.WPA_EAP.equals(mState.security) ?
+ SECURITY_WPA_EAP : SECURITY_IEEE8021X);
+ }
+ } else {
+ updatePasswordField();
}
-
- if (!passwordIsEmpty) {
- mState.setPassword(password);
- }
-
- mWifiLayer.connectToNetwork(mState);
+ mWifiLayer.connectToNetwork(mState);
}
-
+
+ /*
+ * If the network is secured and they haven't entered a password, popup an
+ * error. Allow empty passwords if the state already has a password set
+ * (since in that scenario, an empty password means keep the old password).
+ */
+ private void updatePasswordField() {
+
+ String password = getEnteredPassword();
+ boolean passwordIsEmpty = TextUtils.isEmpty(password);
+ /*
+ * When 'retry password', they can not enter a blank password. In any
+ * other mode, we let them enter a blank password if the state already
+ * has a password.
+ */
+ if (passwordIsEmpty && (!mState.hasPassword() ||
+ mMode == MODE_RETRY_PASSWORD) &&
+ (mState.security != null) &&
+ !mState.security.equals(AccessPointState.OPEN)) {
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.error_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.wifi_password_incorrect_error)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ return;
+ }
+
+ if (!passwordIsEmpty) {
+ mState.setPassword(password);
+ }
+ }
+
private void handleSave() {
replaceStateWithWifiLayerInstance();
@@ -471,6 +608,61 @@
}
+ private int getSelectionIndex(String[] array, String selection) {
+ if(selection != null) {
+ for (int i = 0 ; i < array.length ; i++) {
+ if (selection.contains(array[i])) return i;
+ }
+ }
+ return 0;
+ }
+
+ private int getSelectionIndex(int arrayResId, String selection) {
+ return getSelectionIndex(
+ getContext().getResources().getStringArray(arrayResId), selection);
+ }
+
+ private void updateEnterpriseFields(int securityType) {
+ int i;
+ Keystore ks = Keystore.getInstance();
+ for (i = AccessPointState.IDENTITY ;
+ i < AccessPointState.MAX_ENTRPRISE_FIELD ; i++) {
+ String value;
+ if (i <= AccessPointState.PRIVATE_KEY_PASSWD) {
+ value = mEnterpriseTextFields[i].getText().toString();
+ } else {
+ Spinner spinner = mEnterpriseSpinnerFields[i -
+ AccessPointState.CLIENT_CERT];
+
+ if (i != AccessPointState.PRIVATE_KEY) {
+ value = ks.getCertificate(ks.getAllCertificateKeys()
+ [spinner.getSelectedItemPosition()]);
+ } else {
+ value = ks.getUserkey(ks.getAllUserkeyKeys()
+ [spinner.getSelectedItemPosition()]);
+ }
+ }
+ if (!TextUtils.isEmpty(value)) {
+ mState.setEnterpriseField(i, value);
+ }
+ }
+
+ switch (securityType) {
+ case SECURITY_WPA_EAP: {
+ mState.setSecurity(AccessPointState.WPA_EAP);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ case SECURITY_IEEE8021X: {
+ mState.setSecurity(AccessPointState.IEEE8021X);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ default:
+ mState.setSecurity(AccessPointState.OPEN);
+ }
+ }
+
/**
* Replaces our {@link #mState} with the equal WifiLayer instance. This is useful after
* we unparceled the state previously and before we are calling methods on {@link #mWifiLayer}.
@@ -516,7 +708,22 @@
mPasswordEdit.setVisibility(visibility);
mShowPasswordCheckBox.setVisibility(visibility);
}
-
+
+ private void setEnterpriseFieldsVisible(boolean visible) {
+ int visibility = visible ? View.VISIBLE : View.GONE;
+ mEnterpriseView.setVisibility(visibility);
+ if (visible) {
+ setWepVisible(false);
+ setGenericPasswordVisible(false);
+ }
+ if (mMode != MODE_CONFIGURE) {
+ mSsidText.setVisibility(View.GONE);
+ mSsidEdit.setVisibility(View.GONE);
+ mSecurityText.setVisibility(View.GONE);
+ mSecuritySpinner.setVisibility(View.GONE);
+ }
+ }
+
public void onItemSelected(AdapterView parent, View view, int position, long id) {
if (parent == mSecuritySpinner) {
handleSecurityChange(getSecurityTypeFromSpinner());
@@ -527,7 +734,7 @@
}
private void handleSecurityChange(int security) {
-
+ setEnterpriseFieldsVisible(false);
switch (security) {
case SECURITY_NONE: {
@@ -559,6 +766,11 @@
updatePasswordCaption(AccessPointState.WPA);
break;
}
+ case SECURITY_WPA_EAP:
+ case SECURITY_IEEE8021X: {
+ setEnterpriseFieldsVisible(true);
+ break;
+ }
}
}
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
index 2569802..d050767 100644
--- a/src/com/android/settings/wifi/AccessPointState.java
+++ b/src/com/android/settings/wifi/AccessPointState.java
@@ -43,6 +43,12 @@
public static final String WEP = "WEP";
public static final String OPEN = "Open";
+ /* For EAP Enterprise fields */
+ public static final String WPA_EAP = "WPA-EAP";
+ public static final String IEEE8021X = "IEEE8021X";
+
+ public static final String[] EAP_METHOD = { "PEAP", "TLS", "TTLS" };
+
/** String present in capabilities if the scan result is ad-hoc */
private static final String ADHOC_CAPABILITY = "[IBSS]";
/** String present in capabilities if the scan result is enterprise secured */
@@ -93,7 +99,19 @@
public static final int WEP_PASSWORD_ASCII = 1;
public static final int WEP_PASSWORD_HEX = 2;
private int mWepPasswordType;
-
+
+ /* Enterprise Fields */
+ public static final int IDENTITY = 0;
+ public static final int ANONYMOUS_IDENTITY = 1;
+ public static final int PRIVATE_KEY_PASSWD = 2;
+ public static final int CLIENT_CERT = 3;
+ public static final int CA_CERT = 4;
+ public static final int PRIVATE_KEY = 5;
+ public static final int MAX_ENTRPRISE_FIELD = 6;
+ private String mEnterpriseFields[] = new String[MAX_ENTRPRISE_FIELD];
+ private String mEap;
+ private String mPhase2;
+
private Context mContext;
/**
@@ -275,7 +293,9 @@
else if (security.equals(WEP)) return mContext.getString(R.string.wifi_security_wep);
else if (security.equals(WPA)) return mContext.getString(R.string.wifi_security_wpa);
else if (security.equals(WPA2)) return mContext.getString(R.string.wifi_security_wpa2);
-
+ else if (security.equals(WPA_EAP)) return mContext.getString(R.string.wifi_security_wpa_eap);
+ else if (security.equals(IEEE8021X)) return mContext.getString(R.string.wifi_security_ieee8021x);
+
return mContext.getString(R.string.wifi_security_unknown);
}
@@ -300,7 +320,7 @@
*/
public static String getScanResultSecurity(ScanResult scanResult) {
final String cap = scanResult.capabilities;
- final String[] securityModes = { WEP, WPA, WPA2 };
+ final String[] securityModes = { WEP, WPA, WPA2, WPA_EAP, IEEE8021X };
for (int i = securityModes.length - 1; i >= 0; i--) {
if (cap.contains(securityModes[i])) {
return securityModes[i];
@@ -347,7 +367,30 @@
mPassword = password;
mWepPasswordType = wepPasswordType;
}
-
+
+ /* For Enterprise Fields */
+ public void setEnterpriseField(int field, String value) {
+ if (value != null && field >= 0 && field < MAX_ENTRPRISE_FIELD) {
+ this.mEnterpriseFields[field] = value;
+ requestRefresh();
+ }
+ }
+
+ public void setEap(int method) {
+ mEap = EAP_METHOD[method];
+ requestRefresh();
+ }
+
+ public String getEap() {
+ return mEap;
+ }
+ public String getEnterpriseField(int field) {
+ if(field >=0 && field < MAX_ENTRPRISE_FIELD) {
+ return mEnterpriseFields[field];
+ }
+ return null;
+ }
+
public boolean hasPassword() {
return !TextUtils.isEmpty(mPassword) || mConfigHadPassword;
}
@@ -382,6 +425,10 @@
} else {
return OPEN;
}
+ } else if (wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+ return WPA_EAP;
+ } else if (wifiConfig.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ return IEEE8021X;
} else if (wifiConfig.allowedProtocols.get(Protocol.RSN)) {
return WPA2;
} else if (wifiConfig.allowedProtocols.get(Protocol.WPA)) {
@@ -442,7 +489,43 @@
config.priority = priority;
config.hiddenSSID = hiddenSsid;
config.SSID = convertToQuotedString(ssid);
-
+ config.eap = mEap;
+ if (!TextUtils.isEmpty(mEnterpriseFields[IDENTITY])) {
+ config.identity =
+ convertToQuotedString(mEnterpriseFields[IDENTITY]);
+ } else {
+ config.identity = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[ANONYMOUS_IDENTITY])) {
+ config.anonymousIdentity = convertToQuotedString(
+ mEnterpriseFields[ANONYMOUS_IDENTITY]);
+ } else {
+ config.anonymousIdentity = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[CLIENT_CERT])) {
+ config.clientCert = convertToQuotedString(
+ mEnterpriseFields[CLIENT_CERT]);
+ } else {
+ config.clientCert = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[CA_CERT])) {
+ config.caCert = convertToQuotedString(
+ mEnterpriseFields[CA_CERT]);
+ } else {
+ config.caCert = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[PRIVATE_KEY])) {
+ config.privateKey = convertToQuotedString(
+ mEnterpriseFields[PRIVATE_KEY]);
+ } else {
+ config.privateKey = null;
+ }
+ if (!TextUtils.isEmpty(mEnterpriseFields[PRIVATE_KEY_PASSWD])) {
+ config.privateKeyPasswd = convertToQuotedString(
+ mEnterpriseFields[PRIVATE_KEY_PASSWD]);
+ } else {
+ config.privateKeyPasswd = null;
+ }
setupSecurity(config);
}
@@ -509,6 +592,14 @@
} else if (security.equals(OPEN)) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
+ } else if (security.equals(WPA_EAP)) {
+ config.allowedGroupCiphers.set(GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(GroupCipher.CCMP);
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ } else if (security.equals(IEEE8021X)) {
+ config.allowedGroupCiphers.set(GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(GroupCipher.CCMP);
+ config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
}
}
@@ -716,6 +807,10 @@
return mContext.getString(R.string.wifi_security_verbose_wpa2);
} else if (OPEN.equals(security)) {
return mContext.getString(R.string.wifi_security_verbose_open);
+ } else if (WPA_EAP.equals(security)) {
+ return mContext.getString(R.string.wifi_security_verbose_wpa_eap);
+ } else if (IEEE8021X.equals(security)) {
+ return mContext.getString(R.string.wifi_security_verbose_ieee8021x);
} else {
return null;
}
diff --git a/src/com/android/settings/wifi/Keystore.java b/src/com/android/settings/wifi/Keystore.java
new file mode 100644
index 0000000..68af868
--- /dev/null
+++ b/src/com/android/settings/wifi/Keystore.java
@@ -0,0 +1,81 @@
+package com.android.settings.wifi;
+
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ */
+public abstract class Keystore {
+ public static final String TAG = "Keystore";
+
+ private static final String PACKAGE_PREFIX =
+ Keystore.class.getPackage().getName() + ".";
+
+ public static final String ACTION_KEYSTORE_CERTIFICATES =
+ PACKAGE_PREFIX + "CERTIFICATES";
+ public static final String ACTION_KEYSTORE_USERKEYS =
+ PACKAGE_PREFIX + "USERKEYS";
+
+ /**
+ */
+ public static Keystore getInstance() {
+ return new FileKeystore();
+ }
+
+ /**
+ */
+ public abstract String getUserkey(String key);
+
+ /**
+ */
+ public abstract String getCertificate(String key);
+
+ /**
+ */
+ public abstract String[] getAllCertificateKeys();
+
+ /**
+ */
+ public abstract String[] getAllUserkeyKeys();
+
+ private static class FileKeystore extends Keystore {
+ private static final String PATH = "/data/misc/keystore/";
+ private static final String USERKEY_PATH = PATH + "userkeys/";
+ private static final String CERT_PATH = PATH + "certs/";
+
+ @Override
+ public String getUserkey(String key) {
+ String path = USERKEY_PATH + key;
+ return (new File(path).exists() ? path : null);
+ }
+
+ @Override
+ public String getCertificate(String key) {
+ String path = CERT_PATH + key;
+ return (new File(path).exists() ? path : null);
+ }
+
+ @Override
+ public String[] getAllCertificateKeys() {
+ File dir = new File(CERT_PATH);
+ if (dir.exists()) {
+ return dir.list();
+ } else {
+ Log.v(TAG, "-------- cert directory does not exist!");
+ return null;
+ }
+ }
+
+ @Override
+ public String[] getAllUserkeyKeys() {
+ File dir = new File(USERKEY_PATH);
+ if (dir.exists()) {
+ return dir.list();
+ } else {
+ Log.v(TAG, "-------- userkey directory does not exist!");
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiLayer.java b/src/com/android/settings/wifi/WifiLayer.java
index b0857d2..751a5a3 100644
--- a/src/com/android/settings/wifi/WifiLayer.java
+++ b/src/com/android/settings/wifi/WifiLayer.java
@@ -1133,7 +1133,6 @@
* Hidden networks show up with empty SSID.
*/
if (AccessPointState.isAdhoc(scanResult)
- || AccessPointState.isEnterprise(scanResult)
|| TextUtils.isEmpty(scanResult.SSID)) {
continue;
}