Merge "Add UI for WPS"
diff --git a/res/layout/wifi_config_preference.xml b/res/layout/wifi_config_preference.xml
index b7f183f..095b94f 100644
--- a/res/layout/wifi_config_preference.xml
+++ b/res/layout/wifi_config_preference.xml
@@ -23,6 +23,47 @@
                   android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="vertical" />
+
+    <LinearLayout android:id="@+id/setup_fields"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+        <TextView
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/wifi_network_setup" />
+
+        <Spinner android:id="@+id/network_setup"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:prompt="@string/wifi_network_setup"
+                 android:entries="@array/wifi_network_setup" />
+
+      </LinearLayout>
+
+    <LinearLayout android:id="@+id/wps_fields"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:visibility="gone">
+
+        <TextView
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/wifi_wps_pin" />
+
+        <EditText android:id="@+id/wps_pin"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:inputType="textPassword" />
+
+    </LinearLayout>
+
+
+
     <LinearLayout android:id="@+id/type"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
@@ -50,7 +91,7 @@
                 android:entries="@array/wifi_security" />
     </LinearLayout>  <!-- android:id="@+id/type" -->
 
-    <LinearLayout android:id="@+id/fields"
+    <LinearLayout android:id="@+id/security_fields"
                   android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="vertical"
@@ -141,9 +182,9 @@
                   android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:text="@string/wifi_show_password" />
-    </LinearLayout>  <!-- android:id="@+id/fields" -->
+    </LinearLayout>  <!-- android:id="@+id/security_fields" -->
 
-    <LinearLayout android:id="@+id/ipfields"
+    <LinearLayout android:id="@+id/ip_fields"
                   android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="vertical"
@@ -154,7 +195,7 @@
             android:layout_height="wrap_content"
             android:text="@string/wifi_ip_settings" />
 
-        <Spinner android:id="@+id/ipsettings"
+        <Spinner android:id="@+id/ip_settings"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
                  android:prompt="@string/wifi_ip_settings"
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 8bf1fca..189f717 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -29,6 +29,49 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical" />
 
+        <LinearLayout android:id="@+id/setup_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView
+                    style="?android:attr/textAppearanceSmallInverse"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dip"
+                    android:text="@string/wifi_network_setup" />
+
+            <Spinner android:id="@+id/network_setup"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:prompt="@string/wifi_network_setup"
+                    android:entries="@array/wifi_network_setup" />
+
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/wps_fields"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+            <TextView
+                    style="?android:attr/textAppearanceSmallInverse"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dip"
+                    android:text="@string/wifi_wps_pin" />
+
+            <EditText android:id="@+id/wps_pin"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:inputType="textPassword" />
+
+        </LinearLayout>
+
+
         <LinearLayout android:id="@+id/type"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -62,7 +105,7 @@
                     android:entries="@array/wifi_security" />
         </LinearLayout>
 
-        <LinearLayout android:id="@+id/fields"
+        <LinearLayout android:id="@+id/security_fields"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
@@ -171,7 +214,7 @@
                     android:text="@string/wifi_show_password" />
         </LinearLayout>
 
-        <LinearLayout android:id="@+id/ipfields"
+        <LinearLayout android:id="@+id/ip_fields"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
@@ -184,7 +227,7 @@
                     android:layout_marginTop="8dip"
                     android:text="@string/wifi_ip_settings" />
 
-            <Spinner android:id="@+id/ipsettings"
+            <Spinner android:id="@+id/ip_settings"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:prompt="@string/wifi_ip_settings"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index e3acc10..5ec9a83 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -341,6 +341,17 @@
         <item>GTC</item>
     </string-array>
 
+    <!-- Wi-Fi set up options -->
+    <!-- Note that adding/removing/moving items will need wifi settings code change. -->
+    <string-array name="wifi_network_setup">
+        <!-- Manual wifi configuration [CHAR LIMIT=25]-->
+        <item>Manual</item>
+        <!-- WPS is a new standard that allowes secure connection establishment to a home wireless network using a simplified process. WPS push button based configuration involves pushing a button on the router and the device [CHAR LIMIT=25]-->
+        <item>WPS push button</item>
+        <!-- WPS pin method based configuration. This requires entering a pin obtained from the access point [CHAR LIMIT=25] -->
+        <item>WPS pin method</item>
+    </string-array>
+
     <!-- Wi-Fi IP settings. -->
     <string-array name="wifi_ip_settings">
         <!-- Do not translate. -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 89fee8d9..031f5a7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -878,6 +878,10 @@
     <string name="wifi_menu_modify">Modify network</string>
 
     <!-- Dialog for Access Points --> <skip />
+    <!-- Label for network setup [CHAR LIMIT=50] -->
+    <string name="wifi_network_setup">Network Setup</string>
+    <!-- Label for the text view for WPS pin input [CHAR LIMIT=50] -->
+    <string name="wifi_wps_pin">Enter pin from access point</string>
     <!-- Label for the SSID of the network -->
     <string name="wifi_ssid">Network SSID</string>
     <!-- Label for the security of the connection -->
@@ -920,6 +924,8 @@
     <string name="wifi_not_in_range">Not in range</string>
     <!-- Summary for the secured network. -->
     <string name="wifi_secured">Secured with <xliff:g id="wifi_security">%1$s</xliff:g></string>
+    <!-- Summary for the secured network with WPS being available [CHAR LIMIT=50]-->
+    <string name="wifi_secured_with_wps">Secured with <xliff:g id="wifi_security">%1$s</xliff:g> (WPS available)</string>
     <!-- Summary for the secured and remembered network. Status can be "Remembered", "Disabled" or "Not in range". -->
     <string name="wifi_secured_with_status"><xliff:g id="wifi_status">%2$s</xliff:g>, secured with <xliff:g id="wifi_security">%1$s</xliff:g></string>
     <!-- Button label to connect to a Wi-Fi network -->
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
index fcc9eb2..054c6ff 100644
--- a/src/com/android/settings/wifi/AccessPoint.java
+++ b/src/com/android/settings/wifi/AccessPoint.java
@@ -69,8 +69,10 @@
     static final int SECURITY_EAP = 3;
 
     final String ssid;
+    final String bssid;
     final int security;
     final int networkId;
+    boolean wpsAvailable = false;
 
     private WifiConfiguration mConfig;
     private int mRssi;
@@ -104,6 +106,7 @@
         super(context);
         setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
         ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+        bssid = config.BSSID;
         security = getSecurity(config);
         networkId = config.networkId;
         mConfig = config;
@@ -114,7 +117,10 @@
         super(context);
         setWidgetLayoutResource(R.layout.preference_widget_wifi_signal);
         ssid = result.SSID;
+        bssid = result.BSSID;
         security = getSecurity(result);
+        wpsAvailable = security != SECURITY_NONE && security != SECURITY_EAP &&
+                result.capabilities.contains("WPS");
         networkId = -1;
         mRssi = result.level;
     }
@@ -218,8 +224,13 @@
             if (security == SECURITY_NONE) {
                 setSummary(status);
             } else {
-                String format = context.getString((status == null) ?
-                        R.string.wifi_secured : R.string.wifi_secured_with_status);
+                String format;
+                if (wpsAvailable && mConfig == null) {
+                    format = context.getString(R.string.wifi_secured_with_wps);
+                } else {
+                    format = context.getString((status == null) ?
+                            R.string.wifi_secured : R.string.wifi_secured_with_status);
+                }
                 String[] type = context.getResources().getStringArray(R.array.wifi_security);
                 setSummary(String.format(format, type[security], status));
             }
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index d9fb239..b3375a4 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -25,6 +25,7 @@
 import android.net.wifi.WifiConfiguration.IpAssignment;
 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
+import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
 import android.net.wifi.WifiInfo;
 import android.security.Credentials;
 import android.security.KeyStore;
@@ -73,6 +74,13 @@
     private TextView mEapAnonymousView;
 
     private static final String STATIC_IP = "Static";
+
+    /* 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_PIN = 2;
+
+    private Spinner mNetworkSetupSpinner;
     private Spinner mIpSettingsSpinner;
     private TextView mIpAddressView;
     private TextView mGatewayView;
@@ -140,7 +148,12 @@
                 }
             }
 
-            if (mAccessPoint.networkId == -1 || mEdit) {
+            /* 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();
             }
@@ -151,22 +164,20 @@
                 if (state == null && level != -1) {
                     mConfigUi.setSubmitButton(context.getString(R.string.wifi_connect));
                 } else {
-                    mView.findViewById(R.id.ipfields).setVisibility(View.GONE);
+                    mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
                 }
-                if (mAccessPoint.networkId != -1) {
+                if (mAccessPoint.networkId != INVALID_NETWORK_ID) {
                     mConfigUi.setForgetButton(context.getString(R.string.wifi_forget));
                 }
             }
         }
 
-        mIpSettingsSpinner = ((Spinner) mView.findViewById(R.id.ipsettings));
-        if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
             WifiConfiguration config = mAccessPoint.getConfig();
             if (config.ipAssignment == IpAssignment.STATIC) {
                 setSelection(mIpSettingsSpinner, STATIC_IP);
             }
         }
-        mIpSettingsSpinner.setOnItemSelectedListener(this);
 
         mConfigUi.setCancelButton(context.getString(R.string.wifi_cancel));
         if (mConfigUi.getSubmitButton() != null) {
@@ -184,7 +195,7 @@
     /* show submit button if the password is valid */
     private void enableSubmitIfAppropriate() {
         if ((mSsidView != null && mSsidView.length() == 0) ||
-            ((mAccessPoint == null || mAccessPoint.networkId == -1) &&
+            ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) &&
             ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
             (mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8)))) {
             mConfigUi.getSubmitButton().setEnabled(false);
@@ -194,7 +205,7 @@
     }
 
     /* package */ WifiConfiguration getConfig() {
-        if (mAccessPoint != null && mAccessPoint.networkId != -1 && !mEdit) {
+        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) {
             return null;
         }
 
@@ -205,7 +216,7 @@
                     mSsidView.getText().toString());
             // If the user adds a network manually, assume that it is hidden.
             config.hiddenSSID = true;
-        } else if (mAccessPoint.networkId == -1) {
+        } else if (mAccessPoint.networkId == INVALID_NETWORK_ID) {
             config.SSID = AccessPoint.convertToQuotedString(
                     mAccessPoint.ssid);
         } else {
@@ -299,19 +310,35 @@
         return config;
     }
 
+    int chosenNetworkSetupMethod() {
+        if (mNetworkSetupSpinner != null) {
+            return mNetworkSetupSpinner.getSelectedItemPosition();
+        }
+        return MANUAL;
+    }
+
+    int getWpsPin() {
+        try {
+            String wpsPin = ((TextView) mView.findViewById(R.id.wps_pin)).getText().toString();
+            return Integer.parseInt(wpsPin);
+        } catch (NumberFormatException e) {
+            return -1;
+        }
+    }
+
     private void showSecurityFields() {
         if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
-            mView.findViewById(R.id.fields).setVisibility(View.GONE);
+            mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
             return;
         }
-        mView.findViewById(R.id.fields).setVisibility(View.VISIBLE);
+        mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
 
         if (mPasswordView == null) {
             mPasswordView = (TextView) mView.findViewById(R.id.password);
             mPasswordView.addTextChangedListener(this);
             ((CheckBox) mView.findViewById(R.id.show_password)).setOnClickListener(this);
 
-            if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                 mPasswordView.setHint(R.string.wifi_unchanged);
             }
         }
@@ -333,7 +360,7 @@
             loadCertificates(mEapCaCertSpinner, Credentials.CA_CERTIFICATE);
             loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
 
-            if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                 WifiConfiguration config = mAccessPoint.getConfig();
                 setSelection(mEapMethodSpinner, config.eap.value());
                 setSelection(mPhase2Spinner, config.phase2.value());
@@ -347,16 +374,43 @@
         }
     }
 
+    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_PIN) {
+            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_PIN) || (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;
 
-        mView.findViewById(R.id.ipfields).setVisibility(View.VISIBLE);
+        mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
 
         if (mIpSettingsSpinner == null) {
-            mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ipsettings);
+            mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
+            mIpSettingsSpinner.setOnItemSelectedListener(this);
         }
 
-        if (mAccessPoint != null && mAccessPoint.networkId != -1) {
+        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
             config = mAccessPoint.getConfig();
         }
 
@@ -451,6 +505,8 @@
             mAccessPointSecurity = position;
             showSecurityFields();
             enableSubmitIfAppropriate();
+        } else if (parent == mNetworkSetupSpinner){
+            showNetworkSetupFields();
         } else {
             showIpConfigFields();
         }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 5f6294f..05aecaf 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -33,6 +33,7 @@
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
+import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -44,7 +45,6 @@
 import android.provider.Settings.Secure;
 import android.security.Credentials;
 import android.security.KeyStore;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Menu;
@@ -102,7 +102,7 @@
     private DetailedState mLastState;
     private WifiInfo mLastInfo;
 
-    private int mKeyStoreNetworkId = -1;
+    private int mKeyStoreNetworkId = INVALID_NETWORK_ID;
 
     // should Next button only be enabled when we have a connection?
     private boolean mEnableNextOnConnection;
@@ -198,10 +198,11 @@
             mWifiEnabler.resume();
         }
         getActivity().registerReceiver(mReceiver, mFilter);
-        if (mKeyStoreNetworkId != -1 && KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
+        if (mKeyStoreNetworkId != INVALID_NETWORK_ID &&
+                KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
             mWifiManager.connectNetwork(mKeyStoreNetworkId);
         }
-        mKeyStoreNetworkId = -1;
+        mKeyStoreNetworkId = INVALID_NETWORK_ID;
         if (mInXlSetupWizard) {
             // We show "Now scanning"
             final int wifiState = mWifiManager.getWifiState();
@@ -285,7 +286,7 @@
                         && mSelectedAccessPoint.getState() == null) {
                     menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
                 }
-                if (mSelectedAccessPoint.networkId != -1) {
+                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                     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);
                 }
@@ -300,7 +301,7 @@
         }
         switch (item.getItemId()) {
             case MENU_ID_CONNECT: {
-                if (mSelectedAccessPoint.networkId != -1) {
+                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                     if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {
                         mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
                     }
@@ -601,23 +602,36 @@
 
     /* package */ void submit() {
         final WifiConfigUiBase uiBase = (mDialog != null ? mDialog : mConfigPreference);
-        final WifiConfiguration config = uiBase.getController().getConfig();
+        final WifiConfigController configController = uiBase.getController();
 
-        if (config == null) {
-            if (mSelectedAccessPoint != null
-                    && !requireKeyStore(mSelectedAccessPoint.getConfig())) {
-                mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
-            }
-        } else if (config.networkId != -1) {
-            if (mSelectedAccessPoint != null) {
-                mWifiManager.saveNetwork(config);
-            }
-        } else {
-            if (uiBase.isEdit() || requireKeyStore(config)) {
-                mWifiManager.saveNetwork(config);
-            } else {
-                mWifiManager.connectNetwork(config);
-            }
+        switch(configController.chosenNetworkSetupMethod()) {
+            case WifiConfigController.WPS_PBC:
+                mWifiManager.startWpsPbc(mSelectedAccessPoint.bssid);
+                break;
+            case WifiConfigController.WPS_PIN:
+                int apPin = configController.getWpsPin();
+                mWifiManager.startWpsPin(mSelectedAccessPoint.bssid, apPin);
+                break;
+            case WifiConfigController.MANUAL:
+                final WifiConfiguration config = configController.getConfig();
+
+                if (config == null) {
+                    if (mSelectedAccessPoint != null
+                            && !requireKeyStore(mSelectedAccessPoint.getConfig())) {
+                        mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
+                    }
+                } else if (config.networkId != INVALID_NETWORK_ID) {
+                    if (mSelectedAccessPoint != null) {
+                        mWifiManager.saveNetwork(config);
+                    }
+                } else {
+                    if (uiBase.isEdit() || requireKeyStore(config)) {
+                        mWifiManager.saveNetwork(config);
+                    } else {
+                        mWifiManager.connectNetwork(config);
+                    }
+                }
+                break;
         }
 
         detachConfigPreference();