gps: Network initiated SUPL

Initial contribution from Qualcomm.

Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index 90a0487..c329602 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -16,16 +16,18 @@
 
 #define LOG_TAG "GpsLocationProvider"
 
+//#define LOG_NDDEBUG 0
+
 #include "JNIHelp.h"
 #include "jni.h"
 #include "hardware_legacy/gps.h"
+#include "hardware_legacy/gps_ni.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
 
 #include <string.h>
 #include <pthread.h>
 
-
 static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
 static jmethodID method_reportLocation;
@@ -34,16 +36,19 @@
 static jmethodID method_reportAGpsStatus;
 static jmethodID method_reportNmea;
 static jmethodID method_xtraDownloadRequest;
+static jmethodID method_reportNiNotification;
 
 static const GpsInterface* sGpsInterface = NULL;
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
 static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsNiInterface* sGpsNiInterface = NULL;
 
 // data written to by GPS callbacks
 static GpsLocation  sGpsLocation;
 static GpsStatus    sGpsStatus;
 static GpsSvStatus  sGpsSvStatus;
 static AGpsStatus   sAGpsStatus;
+static GpsNiNotification  sGpsNiNotification;
 
 // buffer for NMEA data
 #define NMEA_SENTENCE_LENGTH    100
@@ -62,6 +67,7 @@
 static GpsSvStatus  sGpsSvStatusCopy;
 static AGpsStatus   sAGpsStatusCopy;
 static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
+static GpsNiNotification  sGpsNiNotificationCopy;
 
 enum CallbackType {
     kLocation = 1,
@@ -71,6 +77,7 @@
     kXtraDownloadRequest = 16,
     kDisableRequest = 32,
     kNmeaAvailable = 64,
+    kNiNotification = 128,
 }; 
 static int sPendingCallbacks;
 
@@ -160,6 +167,20 @@
     pthread_mutex_unlock(&sEventMutex);
 }
 
+static void
+gps_ni_notify_callback(GpsNiNotification *notification)
+{
+   LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id);
+
+   pthread_mutex_lock(&sEventMutex);
+
+   sPendingCallbacks |= kNiNotification;
+   memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification));
+
+   pthread_cond_signal(&sEventCond);
+   pthread_mutex_unlock(&sEventMutex);
+}
+
 GpsXtraCallbacks sGpsXtraCallbacks = {
     download_request_callback,
 };
@@ -168,6 +189,10 @@
     agps_status_callback,
 };
 
+GpsNiCallbacks sGpsNiCallbacks = {
+    gps_ni_notify_callback,
+};
+
 static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
@@ -175,6 +200,7 @@
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
 }
 
 static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
@@ -194,6 +220,12 @@
         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
     if (sAGpsInterface)
         sAGpsInterface->init(&sAGpsCallbacks);
+
+    if (!sGpsNiInterface)
+       sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+    if (sGpsNiInterface)
+       sGpsNiInterface->init(&sGpsNiCallbacks);
+
     return true;
 }
 
@@ -210,7 +242,7 @@
     sGpsInterface->cleanup();
 }
 
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode, 
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
         jboolean singleFix, jint fixFrequency)
 {
     int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
@@ -235,7 +267,7 @@
 {
     pthread_mutex_lock(&sEventMutex);
     pthread_cond_wait(&sEventCond, &sEventMutex);
-    
+
     // copy and clear the callback flags
     int pendingCallbacks = sPendingCallbacks;
     sPendingCallbacks = 0;
@@ -254,18 +286,20 @@
         memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
     if (pendingCallbacks & kNmeaAvailable)
         memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
+    if (pendingCallbacks & kNiNotification)
+        memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
     pthread_mutex_unlock(&sEventMutex);   
 
-    if (pendingCallbacks & kLocation) { 
+    if (pendingCallbacks & kLocation) {
         env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
                 (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
-                (jdouble)sGpsLocationCopy.altitude, 
-                (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing, 
+                (jdouble)sGpsLocationCopy.altitude,
+                (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
                 (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
     }
     if (pendingCallbacks & kStatus) {
         env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
-    }  
+    }
     if (pendingCallbacks & kSvStatus) {
         env->CallVoidMethod(obj, method_reportSvStatus);
     }
@@ -277,16 +311,34 @@
             env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
         }
     }
-    if (pendingCallbacks & kXtraDownloadRequest) {    
+    if (pendingCallbacks & kXtraDownloadRequest) {
         env->CallVoidMethod(obj, method_xtraDownloadRequest);
     }
     if (pendingCallbacks & kDisableRequest) {
         // don't need to do anything - we are just poking so wait_for_event will return.
     }
+    if (pendingCallbacks & kNiNotification) {
+       LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
+       jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
+       jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
+       jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
+       env->CallVoidMethod(obj, method_reportNiNotification,
+             sGpsNiNotificationCopy.notification_id,
+             sGpsNiNotificationCopy.ni_type,
+             sGpsNiNotificationCopy.notify_flags,
+             sGpsNiNotificationCopy.timeout,
+             sGpsNiNotificationCopy.default_response,
+             reqId,
+             text,
+             sGpsNiNotificationCopy.requestor_id_encoding,
+             sGpsNiNotificationCopy.text_encoding,
+             extras
+       );
+    }
 }
 
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj, 
-        jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray, 
+static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
+        jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
         jintArray maskArray)
 {
     // this should only be called from within a call to reportStatus, so we don't need to lock here
@@ -358,7 +410,7 @@
     return (sGpsXtraInterface != NULL);
 }
 
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, 
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
         jbyteArray data, jint length)
 {
     jbyte* bytes = env->GetByteArrayElements(data, 0);
@@ -415,6 +467,16 @@
     }
 }
 
+static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
+      jint notifId, jint response)
+{
+   if (!sGpsNiInterface)
+      sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+   if (sGpsNiInterface) {
+      sGpsNiInterface->respond(notifId, response);
+   }
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -436,6 +498,7 @@
     {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
     {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
     {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+    {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
 };
 
 int register_android_location_GpsLocationProvider(JNIEnv* env)