Merge "add frequency band control API"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9c72dec..ddfcb06 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -34,6 +34,7 @@
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
+import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -2835,6 +2836,16 @@
         public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
 
         /**
+         * The operational wifi frequency band
+         * Set to one of {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
+         * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ} or
+         * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}
+         *
+         * @hide
+         */
+        public static final String WIFI_FREQUENCY_BAND = "wifi_frequency_band";
+
+        /**
          * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
          * data connectivity to be established after a disconnect from Wi-Fi.
          */
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eb3cafa..ac15be6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -162,6 +162,8 @@
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
     <string translatable="false" name="config_tether_apndata"></string>
 
+    <!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
+    <bool translatable="false" name="config_wifi_dual_band_support">false</bool>
 
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 853e46d..d523fa8 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -733,6 +733,38 @@
     }
 
     /**
+     * Set the operational frequency band
+     * @param band One of
+     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
+     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
+     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
+     * @param persist {@code true} if the setting should be remembered.
+     *
+     */
+    public void setFrequencyBand(int band, boolean persist) {
+        enforceChangePermission();
+        if (!isDualBandSupported()) return;
+        Slog.i(TAG, "WifiService trying to set frequency band to " + band +
+                " with persist set to " + persist);
+        mWifiStateMachine.setFrequencyBand(band, persist);
+    }
+
+
+    /**
+     * Get the operational frequency band
+     */
+    public int getFrequencyBand() {
+        enforceAccessPermission();
+        return mWifiStateMachine.getFrequencyBand();
+    }
+
+    public boolean isDualBandSupported() {
+        //TODO: Should move towards adding a driver API that checks at runtime
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_wifi_dual_band_support);
+    }
+
+    /**
      * Return the DHCP-assigned addresses from the last successful DHCP request,
      * if any.
      * @return the DHCP information
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 4bd5286..24001bb 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -60,6 +60,12 @@
 
     void setCountryCode(String country, boolean persist);
 
+    void setFrequencyBand(int band, boolean persist);
+
+    int getFrequencyBand();
+
+    boolean isDualBandSupported();
+
     boolean saveConfiguration();
 
     DhcpInfo getDhcpInfo();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c85a988..8d97ea0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -372,7 +372,26 @@
     
     /** Anything better than or equal to this will show the max bars. */
     private static final int MAX_RSSI = -55;
-    
+
+    /**
+     * Auto settings in the driver. The driver could choose to operate on both
+     * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
+     * @hide
+     */
+    public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
+
+    /**
+     * Operation on 5 GHz alone
+     * @hide
+     */
+    public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
+
+    /**
+     * Operation on 2.4 GHz alone
+     * @hide
+     */
+    public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
+
     IWifiManager mService;
     Handler mHandler;
 
@@ -685,6 +704,51 @@
     }
 
     /**
+     * Set the operational frequency band.
+     * @param band  One of
+     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
+     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
+     *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
+     * @param persist {@code true} if this needs to be remembered
+     * @hide
+     */
+    public void setFrequencyBand(int band, boolean persist) {
+        try {
+            mService.setFrequencyBand(band, persist);
+        } catch (RemoteException e) { }
+    }
+
+    /**
+     * Get the operational frequency band.
+     * @return One of
+     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
+     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
+     *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
+     *     {@code -1} on failure.
+     * @hide
+     */
+    public int getFrequencyBand() {
+        try {
+            return mService.getFrequencyBand();
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
+     * @return {@code true} if supported, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isDualBandSupported() {
+        try {
+            return mService.isDualBandSupported();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Return the DHCP-assigned addresses from the last successful DHCP request,
      * if any.
      * @return the DHCP information
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 93c38cd..95e2df3 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -154,6 +154,8 @@
 
     private AlarmManager mAlarmManager;
     private PendingIntent mScanIntent;
+    /* Tracks current frequency mode */
+    private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
 
     // Channel for sending replies.
     private AsyncChannel mReplyChannel = new AsyncChannel();
@@ -315,6 +317,8 @@
     private static final int CMD_START_WPS_PIN_FROM_AP            = 90;
     /* Start Wi-Fi protected setup pin method configuration with pin obtained from device */
     private static final int CMD_START_WPS_PIN_FROM_DEVICE        = 91;
+    /* Set the frequency band */
+    private static final int CMD_SET_FREQUENCY_BAND               = 92;
 
     /**
      * Interval in milliseconds between polling for connection
@@ -329,13 +333,6 @@
     private static final int SCAN_ACTIVE = 1;
     private static final int SCAN_PASSIVE = 2;
 
-    /* Auto allows 802.11A/B/G operation */
-    private static final int BAND_AUTO = 0;
-    /* 5GHz allows 802.11A operation */
-    private static final int BAND_5G = 1;
-    /* 2.4GHz allows 802.11B/G operation */
-    private static final int BAND_2G = 2;
-
     private static final int SUCCESS = 1;
     private static final int FAILURE = -1;
 
@@ -876,6 +873,27 @@
     }
 
     /**
+     * Set the operational frequency band
+     * @param band
+     * @param persist {@code true} if the setting should be remembered.
+     */
+    public void setFrequencyBand(int band, boolean persist) {
+        if (persist) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.WIFI_FREQUENCY_BAND,
+                    band);
+        }
+        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
+    }
+
+    /**
+     * Returns the operational frequency band
+     */
+    public int getFrequencyBand() {
+        return mFrequencyBand.get();
+    }
+
+    /**
      * Set bluetooth coex mode:
      *
      * @param mode
@@ -995,6 +1013,15 @@
         }
     }
 
+    /**
+     * Set the frequency band from the system setting value, if any.
+     */
+    private void setFrequencyBand() {
+        int band = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO);
+        setFrequencyBand(band, false);
+    }
+
     private void setWifiState(int wifiState) {
         final int previousWifiState = mWifiState.get();
 
@@ -1582,6 +1609,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_REQUEST_CM_WAKELOCK:
                 case CMD_CONNECT_NETWORK:
                 case CMD_SAVE_NETWORK:
@@ -1684,6 +1712,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                     deferMessage(message);
@@ -1812,6 +1841,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                     deferMessage(message);
@@ -1909,6 +1939,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                     deferMessage(message);
@@ -2053,6 +2084,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                 case CMD_START_SCAN:
@@ -2080,6 +2112,8 @@
 
             /* set country code */
             setCountryCode();
+            /* set frequency band of operation */
+            setFrequencyBand();
 
             if (mIsScanMode) {
                 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
@@ -2118,6 +2152,15 @@
                         Log.e(TAG, "Failed to set country code " + country);
                     }
                     break;
+                case CMD_SET_FREQUENCY_BAND:
+                    int band =  message.arg1;
+                    Log.d(TAG, "set frequency band " + band);
+                    if (WifiNative.setBandCommand(band)) {
+                        mFrequencyBand.set(band);
+                    } else {
+                        Log.e(TAG, "Failed to set frequency band " + band);
+                    }
+                    break;
                 case CMD_STOP_DRIVER:
                     mWakeLock.acquire();
                     WifiNative.stopDriverCommand();
@@ -2173,6 +2216,7 @@
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                 case CMD_START_SCAN: