Introduce onLost event on bssid hotlist

Change-Id: I84c3174398fea9a1456fb007586c2c559dd3fe4d
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 864976c..b1f9ed0 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -1389,7 +1389,8 @@
     }
 
     public static interface HotlistEventHandler {
-        void onHotlistApFound (ScanResult[]result);
+        void onHotlistApFound (ScanResult[] result);
+        void onHotlistApLost  (ScanResult[] result);
     }
 
     private static int sHotlistCmdId = 0;
@@ -1434,7 +1435,18 @@
                 sHotlistEventHandler.onHotlistApFound(results);
             } else {
                 /* this can happen because of race conditions */
-                Log.d(TAG, "Ignoring hotlist AP found change");
+                Log.d(TAG, "Ignoring hotlist AP found event");
+            }
+        }
+    }
+
+    synchronized public static void onHotlistApLost(int id, ScanResult[] results) {
+        synchronized (mLock) {
+            if (sHotlistCmdId != 0) {
+                sHotlistEventHandler.onHotlistApLost(results);
+            } else {
+                /* this can happen because of race conditions */
+                Log.d(TAG, "Ignoring hotlist AP lost event");
             }
         }
     }
diff --git a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
index 6dacfb4..729382b 100644
--- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
@@ -269,6 +269,12 @@
         }
 
         @Override
+        public void onHotlistApLost(ScanResult[] results) {
+            if (DBG) Log.d(TAG, "HotlistApLost event received");
+            sendMessage(CMD_HOTLIST_AP_LOST, 0, 0, results);
+        }
+
+        @Override
         public void onChangesFound(ScanResult[] results) {
             if (DBG) Log.d(TAG, "onWifiChangesFound event received");
             sendMessage(CMD_WIFI_CHANGE_DETECTED, 0, 0, results);
@@ -401,7 +407,16 @@
                             if (DBG) Log.d(TAG, "Found " + results.length + " results");
                             Collection<ClientInfo> clients = mClients.values();
                             for (ClientInfo ci2 : clients) {
-                                ci2.reportHotlistResults(results);
+                                ci2.reportHotlistResults(WifiScanner.CMD_AP_FOUND, results);
+                            }
+                        }
+                        break;
+                    case CMD_HOTLIST_AP_LOST: {
+                            ScanResult[] results = (ScanResult[])msg.obj;
+                            if (DBG) Log.d(TAG, "Lost " + results.length + " results");
+                            Collection<ClientInfo> clients = mClients.values();
+                            for (ClientInfo ci2 : clients) {
+                                ci2.reportHotlistResults(WifiScanner.CMD_AP_LOST, results);
                             }
                         }
                         break;
@@ -614,7 +629,7 @@
             return mHotlistSettings.values();
         }
 
-        void reportHotlistResults(ScanResult[] results) {
+        void reportHotlistResults(int what, ScanResult[] results) {
             Iterator<Map.Entry<Integer, WifiScanner.HotlistSettings>> it =
                     mHotlistSettings.entrySet().iterator();
             while (it.hasNext()) {
@@ -650,7 +665,7 @@
                 WifiScanner.ParcelableScanResults parcelableScanResults =
                         new WifiScanner.ParcelableScanResults(results2);
 
-                mChannel.sendMessage(WifiScanner.CMD_AP_FOUND, 0, handler, parcelableScanResults);
+                mChannel.sendMessage(what, 0, handler, parcelableScanResults);
             }
         }
 
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 2bd4229..6156e79 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -599,6 +599,57 @@
         id, scanResults);
 }
 
+static void onHotlistApLost(wifi_request_id id,
+        unsigned num_results, wifi_scan_result *results) {
+
+    JNIEnv *env = NULL;
+    mVM->AttachCurrentThread(&env, NULL);
+
+    ALOGD("onHotlistApLost called, vm = %p, obj = %p, env = %p, num_results = %d",
+            mVM, mCls, env, num_results);
+
+    jclass clsScanResult = (env)->FindClass("android/net/wifi/ScanResult");
+    if (clsScanResult == NULL) {
+        ALOGE("Error in accessing class");
+        return;
+    }
+
+    jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
+    if (scanResults == NULL) {
+        ALOGE("Error in allocating array");
+        return;
+    }
+
+    for (unsigned i = 0; i < num_results; i++) {
+
+        jobject scanResult = createObject(env, "android/net/wifi/ScanResult");
+        if (scanResult == NULL) {
+            ALOGE("Error in creating scan result");
+            return;
+        }
+
+        setStringField(env, scanResult, "SSID", results[i].ssid);
+
+        char bssid[32];
+        sprintf(bssid, "%02x:%02x:%02x:%02x:%02x:%02x", results[i].bssid[0], results[i].bssid[1],
+            results[i].bssid[2], results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
+
+        setStringField(env, scanResult, "BSSID", bssid);
+
+        setIntField(env, scanResult, "level", results[i].rssi);
+        setIntField(env, scanResult, "frequency", results[i].channel);
+        setLongField(env, scanResult, "timestamp", results[i].ts);
+
+        env->SetObjectArrayElement(scanResults, i, scanResult);
+
+        ALOGD("Lost AP %32s %s", results[i].ssid, bssid);
+    }
+
+    reportEvent(env, mCls, "onHotlistApLost", "(I[Landroid/net/wifi/ScanResult;)V",
+        id, scanResults);
+}
+
+
 static jboolean android_net_wifi_setHotlist(
         JNIEnv *env, jclass cls, jint iface, jint id, jobject ap)  {
 
@@ -608,6 +659,8 @@
     wifi_bssid_hotlist_params params;
     memset(&params, 0, sizeof(params));
 
+    params.lost_ap_sample_size = getIntField(env, ap, "apLostThreshold");
+
     jobjectArray array = (jobjectArray) getObjectField(env, ap,
             "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;");
     params.num_ap = env->GetArrayLength(array);
@@ -651,6 +704,7 @@
     memset(&handler, 0, sizeof(handler));
 
     handler.on_hotlist_ap_found = &onHotlistApFound;
+    handler.on_hotlist_ap_lost  = &onHotlistApLost;
     return wifi_set_bssid_hotlist(id, handle, params, handler) == WIFI_SUCCESS;
 }