Merge "introduce WifiConnectionstatistics" into lmp-dev
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 292f1e8..71b6bee 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -24,6 +24,8 @@
 import android.net.wifi.ScanSettings;
 import android.net.wifi.WifiChannel;
 import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConnectionStatistics;
+
 import android.net.DhcpInfo;
 
 
@@ -146,5 +148,7 @@
     int getAllowScansWithTraffic();
 
     void setAllowScansWithTraffic(int enabled);
+
+    WifiConnectionStatistics getConnectionStatistics();
 }
 
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 4a4b9ff..73de099 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -28,13 +28,19 @@
  * but does not currently report them to external clients.
  */
 public class ScanResult implements Parcelable {
-    /** The network name. */
+    /**
+     * The network name.
+     */
     public String SSID;
 
-    /** Ascii encoded SSID. This will replace SSID when we deprecate it. @hide */
+    /**
+     * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
+     */
     public WifiSsid wifiSsid;
 
-    /** The address of the access point. */
+    /**
+     * The address of the access point.
+     */
     public String BSSID;
     /**
      * Describes the authentication, key management, and encryption schemes
@@ -63,6 +69,27 @@
      */
     public long seen;
 
+    /**
+     * @hide
+     * Update RSSI of the scan result
+     * @param previousRSSI
+     * @param previousSeen
+     * @param maxAge
+     */
+    public void averageRssi(int previousRssi, long previousSeen, int maxAge) {
+
+        if (seen == 0) {
+            seen = System.currentTimeMillis();
+        }
+        long age = seen - previousSeen;
+
+        if (previousSeen > 0 && age > 0 && age < maxAge/2) {
+            // Average the RSSI with previously seen instances of this scan result
+            double alpha = 0.5 - (double) age / (double) maxAge;
+            level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha);
+        }
+    }
+
     /** @hide */
     public static final int ENABLED                                          = 0;
     /** @hide */
@@ -79,6 +106,25 @@
     public int status;
 
     /**
+     * Status: indicating the scan result is not a result
+     * that is part of user's saved configurations
+     * @hide
+     */
+    public boolean untrusted;
+
+    /**
+     * Number of time we connected to it
+     * @hide
+     */
+    public int numConnection;
+
+    /**
+     * Number of time autojoin used it
+     * @hide
+     */
+    public int numUsage;
+
+    /**
      * The approximate distance to the AP in centimeter, if available.  Else
      * {@link UNSPECIFIED}.
      * {@hide}
@@ -105,18 +151,32 @@
     public final static int UNSPECIFIED = -1;
     /**
      * @hide
-     * TODO: makes real freq boundaries
      */
     public boolean is24GHz() {
-        return frequency > 2400 && frequency < 2500;
+        return ScanResult.is24GHz(frequency);
     }
 
     /**
      * @hide
      * TODO: makes real freq boundaries
      */
+    public static boolean is24GHz(int freq) {
+        return freq > 2400 && freq < 2500;
+    }
+
+    /**
+     * @hide
+     */
     public boolean is5GHz() {
-        return frequency > 4900 && frequency < 5900;
+        return ScanResult.is24GHz(frequency);
+    }
+
+    /**
+     * @hide
+     * TODO: makes real freq boundaries
+     */
+    public static boolean is5GHz(int freq) {
+        return freq > 4900 && freq < 5900;
     }
 
     /** information element from beacon
@@ -175,6 +235,9 @@
             seen = source.seen;
             passpoint = source.passpoint;
             status = source.status;
+            untrusted = source.untrusted;
+            numConnection = source.numConnection;
+            numUsage = source.numUsage;
         }
     }
 
@@ -237,6 +300,9 @@
         dest.writeInt(distanceSdCm);
         dest.writeLong(seen);
         dest.writeInt(status);
+        dest.writeInt(untrusted ? 1 : 0);
+        dest.writeInt(numConnection);
+        dest.writeInt(numUsage);
         if (passpoint != null) {
             dest.writeInt(1);
             passpoint.writeToParcel(dest, flags);
@@ -275,6 +341,9 @@
                 );
                 sr.seen = in.readLong();
                 sr.status = in.readInt();
+                sr.untrusted = in.readInt() != 0;
+                sr.numConnection = in.readInt();
+                sr.numUsage = in.readInt();
                 if (in.readInt() == 1) {
                     sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in);
                 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 94e9a5d..dd30ac7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -669,6 +669,14 @@
 
     /**
      * @hide
+     * Number of time we associated to this configuration.
+     */
+    @SystemApi
+    public int numAssociation;
+
+
+    /**
+     * @hide
      * Connect choices
      *
      * remember the keys identifying the known WifiConfiguration over which this configuration
@@ -1188,6 +1196,7 @@
             numConnectionFailures = source.numConnectionFailures;
             numScorerOverride = source.numScorerOverride;
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
+            numAssociation = source.numAssociation;
         }
     }
 
@@ -1239,6 +1248,7 @@
         dest.writeInt(numConnectionFailures);
         dest.writeInt(numScorerOverride);
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
+        dest.writeInt(numAssociation);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1286,6 +1296,7 @@
                 config.numConnectionFailures = in.readInt();
                 config.numScorerOverride = in.readInt();
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
+                config.numAssociation = in.readInt();
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl b/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl
new file mode 100644
index 0000000..601face
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, 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 android.net.wifi;
+
+parcelable WifiConnectionStatistics;
diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.java b/wifi/java/android/net/wifi/WifiConnectionStatistics.java
new file mode 100644
index 0000000..8e79a17
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiConnectionStatistics.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 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 android.net.wifi;
+
+import android.annotation.SystemApi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.HashMap;
+
+/**
+ * Wifi Connection Statistics: gather various stats regarding WiFi connections,
+ * connection requests, auto-join
+ * and WiFi usage.
+ * @hide
+ */
+@SystemApi
+public class WifiConnectionStatistics implements Parcelable {
+    private static final String TAG = "WifiConnnectionStatistics";
+
+    /**
+     *  history of past connection to untrusted SSID
+     *  Key = SSID
+     *  Value = num connection
+     */
+    public HashMap<String, WifiNetworkConnectionStatistics> untrustedNetworkHistory;
+
+    // Number of time we polled the chip and were on 5GHz
+    public int num5GhzConnected;
+
+    // Number of time we polled the chip and were on 2.4GHz
+    public int num24GhzConnected;
+
+    public WifiConnectionStatistics() {
+        untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>();
+    }
+
+    public void incrementOrAddUntrusted(String SSID, int connection, int usage) {
+        WifiNetworkConnectionStatistics stats;
+        if (TextUtils.isEmpty(SSID))
+            return;
+        if (untrustedNetworkHistory.containsKey(SSID)) {
+            stats = untrustedNetworkHistory.get(SSID);
+            if (stats != null){
+                stats.numConnection = connection + stats.numConnection;
+                stats.numUsage = usage + stats.numUsage;
+            }
+        } else {
+            stats = new WifiNetworkConnectionStatistics(connection, usage);
+        }
+        if (stats != null) {
+            untrustedNetworkHistory.put(SSID, stats);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("Connected on: 2.4Ghz=").append(num24GhzConnected);
+        sbuf.append(" 5Ghz=").append(num5GhzConnected).append("\n");
+
+        for (String Key : untrustedNetworkHistory.keySet()) {
+            WifiNetworkConnectionStatistics stats = untrustedNetworkHistory.get(Key);
+            if (stats != null) {
+                sbuf.append(Key).append(" ").append(stats.toString()).append("\n");
+            }
+        }
+        return sbuf.toString();
+    }
+
+    /** copy constructor*/
+    public WifiConnectionStatistics(WifiConnectionStatistics source) {
+        untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>();
+        if (source != null) {
+            untrustedNetworkHistory.putAll(source.untrustedNetworkHistory);
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(num24GhzConnected);
+        dest.writeInt(num5GhzConnected);
+        dest.writeInt(untrustedNetworkHistory.size());
+        for (String Key : untrustedNetworkHistory.keySet()) {
+            WifiNetworkConnectionStatistics num = untrustedNetworkHistory.get(Key);
+            dest.writeString(Key);
+            dest.writeInt(num.numConnection);
+            dest.writeInt(num.numUsage);
+
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<WifiConnectionStatistics> CREATOR =
+        new Creator<WifiConnectionStatistics>() {
+            public WifiConnectionStatistics createFromParcel(Parcel in) {
+                WifiConnectionStatistics stats = new WifiConnectionStatistics();
+                stats.num24GhzConnected = in.readInt();
+                stats.num5GhzConnected = in.readInt();
+                int n = in.readInt();
+                while (n-- > 0) {
+                    String Key = in.readString();
+                    int numConnection = in.readInt();
+                    int numUsage = in.readInt();
+                    WifiNetworkConnectionStatistics st =
+                            new WifiNetworkConnectionStatistics(numConnection, numUsage);
+                    stats.untrustedNetworkHistory.put(Key, st);
+                }
+                return stats;
+            }
+
+            public WifiConnectionStatistics[] newArray(int size) {
+                return new WifiConnectionStatistics[size];
+            }
+        };
+}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index e46f916..e808136 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -371,7 +371,7 @@
      * TODO: makes real freq boundaries
      */
     public boolean is24GHz() {
-        return mFrequency < 4000;
+        return ScanResult.is24GHz(mFrequency);
     }
 
     /**
@@ -379,7 +379,7 @@
      * TODO: makes real freq boundaries
      */
     public boolean is5GHz() {
-        return mFrequency > 4000;
+        return ScanResult.is5GHz(mFrequency);
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 8945e52..dfed174 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -639,6 +639,16 @@
         }
     }
 
+    /** @hide */
+    @SystemApi
+    public WifiConnectionStatistics getConnectionStatistics() {
+        try {
+            return mService.getConnectionStatistics();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
     /**
      * Add a new network description to the set of configured networks.
      * The {@code networkId} field of the supplied configuration object
diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl
new file mode 100644
index 0000000..5f497e2
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, 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 android.net.wifi;
+
+parcelable WifiNetworkConnectionStatistics;
diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
new file mode 100644
index 0000000..c7d62e5
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 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 android.net.wifi;
+
+import android.annotation.SystemApi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+
+/**
+ * Connection Statistics For a WiFi Network.
+ * @hide
+ */
+@SystemApi
+public class WifiNetworkConnectionStatistics implements Parcelable {
+    private static final String TAG = "WifiNetworkConnnectionStatistics";
+
+    public int numConnection;
+    public int numUsage;
+
+    public WifiNetworkConnectionStatistics(int connection, int usage) {
+        numConnection = connection;
+        numUsage = usage;
+    }
+
+    public WifiNetworkConnectionStatistics() { }
+
+
+    @Override
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("c=").append(numConnection);
+        sbuf.append(" u=").append(numUsage);
+        return sbuf.toString();
+    }
+
+
+    /** copy constructor*/
+    public WifiNetworkConnectionStatistics(WifiNetworkConnectionStatistics source) {
+        numConnection = source.numConnection;
+        numUsage = source.numUsage;
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(numConnection);
+        dest.writeInt(numUsage);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<WifiNetworkConnectionStatistics> CREATOR =
+        new Creator<WifiNetworkConnectionStatistics>() {
+            public WifiNetworkConnectionStatistics createFromParcel(Parcel in) {
+                int numConnection = in.readInt();
+                int numUsage = in.readInt();
+                WifiNetworkConnectionStatistics stats =
+                        new WifiNetworkConnectionStatistics(numConnection, numUsage);
+                return stats;
+            }
+
+            public WifiNetworkConnectionStatistics[] newArray(int size) {
+                return new WifiNetworkConnectionStatistics[size];
+            }
+        };
+}