Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "GpsLocationProvider"
     18 
     19 #define LOG_NDEBUG 0
     20 
     21 #include "JNIHelp.h"
     22 #include "jni.h"
     23 #include "hardware/hardware.h"
     24 #include "hardware/gps.h"
     25 #include "hardware_legacy/power.h"
     26 #include "utils/Log.h"
     27 #include "utils/misc.h"
     28 #include "android_runtime/AndroidRuntime.h"
     29 #include "android_runtime/Log.h"
     30 
     31 #include <arpa/inet.h>
     32 #include <string.h>
     33 #include <pthread.h>
     34 #include <linux/in.h>
     35 #include <linux/in6.h>
     36 
     37 static jobject mCallbacksObj = NULL;
     38 
     39 static jmethodID method_reportLocation;
     40 static jmethodID method_reportStatus;
     41 static jmethodID method_reportSvStatus;
     42 static jmethodID method_reportAGpsStatus;
     43 static jmethodID method_reportNmea;
     44 static jmethodID method_setEngineCapabilities;
     45 static jmethodID method_xtraDownloadRequest;
     46 static jmethodID method_reportNiNotification;
     47 static jmethodID method_requestRefLocation;
     48 static jmethodID method_requestSetID;
     49 static jmethodID method_requestUtcTime;
     50 static jmethodID method_reportGeofenceTransition;
     51 static jmethodID method_reportGeofenceStatus;
     52 static jmethodID method_reportGeofenceAddStatus;
     53 static jmethodID method_reportGeofenceRemoveStatus;
     54 static jmethodID method_reportGeofencePauseStatus;
     55 static jmethodID method_reportGeofenceResumeStatus;
     56 static jmethodID method_reportMeasurementData;
     57 static jmethodID method_reportNavigationMessages;
     58 
     59 static const GpsInterface* sGpsInterface = NULL;
     60 static const GpsXtraInterface* sGpsXtraInterface = NULL;
     61 static const AGpsInterface* sAGpsInterface = NULL;
     62 static const GpsNiInterface* sGpsNiInterface = NULL;
     63 static const GpsDebugInterface* sGpsDebugInterface = NULL;
     64 static const AGpsRilInterface* sAGpsRilInterface = NULL;
     65 static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
     66 static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
     67 static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
     68 static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
     69 
     70 // temporary storage for GPS callbacks
     71 static GpsSvStatus  sGpsSvStatus;
     72 static const char* sNmeaString;
     73 static int sNmeaStringLength;
     74 
     75 #define WAKE_LOCK_NAME  "GPS"
     76 
     77 namespace android {
     78 
     79 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     80     if (env->ExceptionCheck()) {
     81         ALOGE("An exception was thrown by callback '%s'.", methodName);
     82         LOGE_EX(env);
     83         env->ExceptionClear();
     84     }
     85 }
     86 
     87 static void location_callback(GpsLocation* location)
     88 {
     89     JNIEnv* env = AndroidRuntime::getJNIEnv();
     90     env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
     91             (jdouble)location->latitude, (jdouble)location->longitude,
     92             (jdouble)location->altitude,
     93             (jfloat)location->speed, (jfloat)location->bearing,
     94             (jfloat)location->accuracy, (jlong)location->timestamp);
     95     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     96 }
     97 
     98 static void status_callback(GpsStatus* status)
     99 {
    100     JNIEnv* env = AndroidRuntime::getJNIEnv();
    101     env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
    102     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    103 }
    104 
    105 static void sv_status_callback(GpsSvStatus* sv_status)
    106 {
    107     JNIEnv* env = AndroidRuntime::getJNIEnv();
    108     memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
    109     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
    110     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    111 }
    112 
    113 static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
    114 {
    115     JNIEnv* env = AndroidRuntime::getJNIEnv();
    116     // The Java code will call back to read these values
    117     // We do this to avoid creating unnecessary String objects
    118     sNmeaString = nmea;
    119     sNmeaStringLength = length;
    120     env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
    121     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    122 }
    123 
    124 static void set_capabilities_callback(uint32_t capabilities)
    125 {
    126     ALOGD("set_capabilities_callback: %du\n", capabilities);
    127     JNIEnv* env = AndroidRuntime::getJNIEnv();
    128     env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
    129     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    130 }
    131 
    132 static void acquire_wakelock_callback()
    133 {
    134     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
    135 }
    136 
    137 static void release_wakelock_callback()
    138 {
    139     release_wake_lock(WAKE_LOCK_NAME);
    140 }
    141 
    142 static void request_utc_time_callback()
    143 {
    144     JNIEnv* env = AndroidRuntime::getJNIEnv();
    145     env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
    146     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    147 }
    148 
    149 static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
    150 {
    151     return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
    152 }
    153 
    154 GpsCallbacks sGpsCallbacks = {
    155     sizeof(GpsCallbacks),
    156     location_callback,
    157     status_callback,
    158     sv_status_callback,
    159     nmea_callback,
    160     set_capabilities_callback,
    161     acquire_wakelock_callback,
    162     release_wakelock_callback,
    163     create_thread_callback,
    164     request_utc_time_callback,
    165 };
    166 
    167 static void xtra_download_request_callback()
    168 {
    169     JNIEnv* env = AndroidRuntime::getJNIEnv();
    170     env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
    171     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    172 }
    173 
    174 GpsXtraCallbacks sGpsXtraCallbacks = {
    175     xtra_download_request_callback,
    176     create_thread_callback,
    177 };
    178 
    179 static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
    180 {
    181     if (INADDR_NONE == ip) {
    182         return NULL;
    183     }
    184 
    185     JNIEnv* env = AndroidRuntime::getJNIEnv();
    186     jbyteArray byteArray = env->NewByteArray(4);
    187     if (byteArray == NULL) {
    188         ALOGE("Unable to allocate byte array for IPv4 address");
    189         return NULL;
    190     }
    191 
    192     jbyte ipv4[4];
    193     if (net_order) {
    194         ALOGV("Converting IPv4 address(net_order) %x", ip);
    195         memcpy(ipv4, &ip, sizeof(ipv4));
    196     } else {
    197         ALOGV("Converting IPv4 address(host_order) %x", ip);
    198         //endianess transparent conversion from int to char[]
    199         ipv4[0] = (jbyte) (ip & 0xFF);
    200         ipv4[1] = (jbyte)((ip>>8) & 0xFF);
    201         ipv4[2] = (jbyte)((ip>>16) & 0xFF);
    202         ipv4[3] = (jbyte) (ip>>24);
    203     }
    204 
    205     env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
    206     return byteArray;
    207 }
    208 
    209 static void agps_status_callback(AGpsStatus* agps_status)
    210 {
    211     JNIEnv* env = AndroidRuntime::getJNIEnv();
    212     jbyteArray byteArray = NULL;
    213     bool isSupported = false;
    214 
    215     size_t status_size = agps_status->size;
    216     if (status_size == sizeof(AGpsStatus_v3)) {
    217       ALOGV("AGpsStatus is V3: %d", status_size);
    218       switch (agps_status->addr.ss_family)
    219       {
    220       case AF_INET:
    221           {
    222             struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
    223             uint32_t *pAddr = (uint32_t*)&(in->sin_addr);
    224             byteArray = convert_to_ipv4(*pAddr, true /* net_order */);
    225             if (byteArray != NULL) {
    226                 isSupported = true;
    227             }
    228             IF_ALOGD() {
    229                 // log the IP for reference in case there is a bogus value pushed by HAL
    230                 char str[INET_ADDRSTRLEN];
    231                 inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN);
    232                 ALOGD("AGPS IP is v4: %s", str);
    233             }
    234           }
    235           break;
    236       case AF_INET6:
    237           {
    238             struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
    239             byteArray = env->NewByteArray(16);
    240             if (byteArray != NULL) {
    241                 env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
    242                 isSupported = true;
    243             } else {
    244                 ALOGE("Unable to allocate byte array for IPv6 address.");
    245             }
    246             IF_ALOGD() {
    247                 // log the IP for reference in case there is a bogus value pushed by HAL
    248                 char str[INET6_ADDRSTRLEN];
    249                 inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN);
    250                 ALOGD("AGPS IP is v6: %s", str);
    251             }
    252           }
    253           break;
    254       default:
    255           ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
    256           break;
    257       }
    258     } else if (status_size >= sizeof(AGpsStatus_v2)) {
    259       ALOGV("AGpsStatus is V2+: %d", status_size);
    260       // for back-compatibility reasons we check in v2 that the data structure size is greater or
    261       // equal to the declared size in gps.h
    262       uint32_t ipaddr = agps_status->ipaddr;
    263       ALOGV("AGPS IP is v4: %x", ipaddr);
    264       byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
    265       if (ipaddr == INADDR_NONE || byteArray != NULL) {
    266           isSupported = true;
    267       }
    268     } else if (status_size >= sizeof(AGpsStatus_v1)) {
    269         ALOGV("AGpsStatus is V1+: %d", status_size);
    270         // because we have to check for >= with regards to v2, we also need to relax the check here
    271         // and only make sure that the size is at least what we expect
    272         isSupported = true;
    273     } else {
    274         ALOGE("Invalid size of AGpsStatus found: %d.", status_size);
    275     }
    276 
    277     if (isSupported) {
    278         jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
    279         ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
    280         env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
    281                             agps_status->status, byteArray);
    282 
    283         checkAndClearExceptionFromCallback(env, __FUNCTION__);
    284     } else {
    285         ALOGD("Skipping calling method_reportAGpsStatus.");
    286     }
    287 
    288     if (byteArray) {
    289         env->DeleteLocalRef(byteArray);
    290     }
    291 }
    292 
    293 AGpsCallbacks sAGpsCallbacks = {
    294     agps_status_callback,
    295     create_thread_callback,
    296 };
    297 
    298 static void gps_ni_notify_callback(GpsNiNotification *notification)
    299 {
    300     ALOGD("gps_ni_notify_callback\n");
    301     JNIEnv* env = AndroidRuntime::getJNIEnv();
    302     jstring requestor_id = env->NewStringUTF(notification->requestor_id);
    303     jstring text = env->NewStringUTF(notification->text);
    304     jstring extras = env->NewStringUTF(notification->extras);
    305 
    306     if (requestor_id && text && extras) {
    307         env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
    308             notification->notification_id, notification->ni_type,
    309             notification->notify_flags, notification->timeout,
    310             notification->default_response, requestor_id, text,
    311             notification->requestor_id_encoding,
    312             notification->text_encoding, extras);
    313     } else {
    314         ALOGE("out of memory in gps_ni_notify_callback\n");
    315     }
    316 
    317     if (requestor_id)
    318         env->DeleteLocalRef(requestor_id);
    319     if (text)
    320         env->DeleteLocalRef(text);
    321     if (extras)
    322         env->DeleteLocalRef(extras);
    323     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    324 }
    325 
    326 GpsNiCallbacks sGpsNiCallbacks = {
    327     gps_ni_notify_callback,
    328     create_thread_callback,
    329 };
    330 
    331 static void agps_request_set_id(uint32_t flags)
    332 {
    333     JNIEnv* env = AndroidRuntime::getJNIEnv();
    334     env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
    335     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    336 }
    337 
    338 static void agps_request_ref_location(uint32_t flags)
    339 {
    340     JNIEnv* env = AndroidRuntime::getJNIEnv();
    341     env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
    342     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    343 }
    344 
    345 AGpsRilCallbacks sAGpsRilCallbacks = {
    346     agps_request_set_id,
    347     agps_request_ref_location,
    348     create_thread_callback,
    349 };
    350 
    351 static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
    352         int32_t transition, GpsUtcTime timestamp)
    353 {
    354     JNIEnv* env = AndroidRuntime::getJNIEnv();
    355 
    356     env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
    357             location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
    358             (jdouble)location->altitude,
    359             (jfloat)location->speed, (jfloat)location->bearing,
    360             (jfloat)location->accuracy, (jlong)location->timestamp,
    361             transition, timestamp);
    362     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    363 };
    364 
    365 static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
    366 {
    367     JNIEnv* env = AndroidRuntime::getJNIEnv();
    368     jint flags = 0;
    369     jdouble latitude = 0;
    370     jdouble longitude = 0;
    371     jdouble altitude = 0;
    372     jfloat speed = 0;
    373     jfloat bearing = 0;
    374     jfloat accuracy = 0;
    375     jlong timestamp = 0;
    376     if (location != NULL) {
    377         flags = location->flags;
    378         latitude = location->latitude;
    379         longitude = location->longitude;
    380         altitude = location->altitude;
    381         speed = location->speed;
    382         bearing = location->bearing;
    383         accuracy = location->accuracy;
    384         timestamp = location->timestamp;
    385     }
    386 
    387     env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
    388             flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
    389     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    390 };
    391 
    392 static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
    393 {
    394     JNIEnv* env = AndroidRuntime::getJNIEnv();
    395     if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
    396         ALOGE("Error in geofence_add_callback: %d\n", status);
    397     }
    398     env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
    399     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    400 };
    401 
    402 static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
    403 {
    404     JNIEnv* env = AndroidRuntime::getJNIEnv();
    405     if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
    406         ALOGE("Error in geofence_remove_callback: %d\n", status);
    407     }
    408     env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
    409     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    410 };
    411 
    412 static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
    413 {
    414     JNIEnv* env = AndroidRuntime::getJNIEnv();
    415     if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
    416         ALOGE("Error in geofence_resume_callback: %d\n", status);
    417     }
    418     env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
    419     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    420 };
    421 
    422 static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
    423 {
    424     JNIEnv* env = AndroidRuntime::getJNIEnv();
    425     if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
    426         ALOGE("Error in geofence_pause_callback: %d\n", status);
    427     }
    428     env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
    429     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    430 };
    431 
    432 GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
    433     gps_geofence_transition_callback,
    434     gps_geofence_status_callback,
    435     gps_geofence_add_callback,
    436     gps_geofence_remove_callback,
    437     gps_geofence_pause_callback,
    438     gps_geofence_resume_callback,
    439     create_thread_callback,
    440 };
    441 
    442 static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
    443     int err;
    444     hw_module_t* module;
    445 
    446     method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
    447     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
    448     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
    449     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
    450     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
    451     method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
    452     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
    453     method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
    454             "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
    455     method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
    456     method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
    457     method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
    458     method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
    459             "(IIDDDFFFJIJ)V");
    460     method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
    461             "(IIDDDFFFJ)V");
    462     method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
    463             "(II)V");
    464     method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
    465             "(II)V");
    466     method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
    467             "(II)V");
    468     method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
    469             "(II)V");
    470     method_reportMeasurementData = env->GetMethodID(
    471             clazz,
    472             "reportMeasurementData",
    473             "(Landroid/location/GpsMeasurementsEvent;)V");
    474     method_reportNavigationMessages = env->GetMethodID(
    475             clazz,
    476             "reportNavigationMessage",
    477             "(Landroid/location/GpsNavigationMessageEvent;)V");
    478 
    479     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    480     if (err == 0) {
    481         hw_device_t* device;
    482         err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
    483         if (err == 0) {
    484             gps_device_t* gps_device = (gps_device_t *)device;
    485             sGpsInterface = gps_device->get_gps_interface(gps_device);
    486         }
    487     }
    488     if (sGpsInterface) {
    489         sGpsXtraInterface =
    490             (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
    491         sAGpsInterface =
    492             (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    493         sGpsNiInterface =
    494             (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
    495         sGpsDebugInterface =
    496             (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
    497         sAGpsRilInterface =
    498             (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
    499         sGpsGeofencingInterface =
    500             (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
    501         sGpsMeasurementInterface =
    502             (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
    503         sGpsNavigationMessageInterface =
    504             (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
    505                     GPS_NAVIGATION_MESSAGE_INTERFACE);
    506         sGnssConfigurationInterface =
    507             (const GnssConfigurationInterface*)sGpsInterface->get_extension(
    508                     GNSS_CONFIGURATION_INTERFACE);
    509     }
    510 }
    511 
    512 static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
    513     if (sGpsInterface != NULL) {
    514         return JNI_TRUE;
    515     } else {
    516         return JNI_FALSE;
    517     }
    518 }
    519 
    520 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
    521 {
    522     // this must be set before calling into the HAL library
    523     if (!mCallbacksObj)
    524         mCallbacksObj = env->NewGlobalRef(obj);
    525 
    526     // fail if the main interface fails to initialize
    527     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
    528         return JNI_FALSE;
    529 
    530     // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
    531     // but continue to allow the rest of the GPS interface to work.
    532     if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
    533         sGpsXtraInterface = NULL;
    534     if (sAGpsInterface)
    535         sAGpsInterface->init(&sAGpsCallbacks);
    536     if (sGpsNiInterface)
    537         sGpsNiInterface->init(&sGpsNiCallbacks);
    538     if (sAGpsRilInterface)
    539         sAGpsRilInterface->init(&sAGpsRilCallbacks);
    540     if (sGpsGeofencingInterface)
    541         sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
    542 
    543     return JNI_TRUE;
    544 }
    545 
    546 static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
    547 {
    548     if (sGpsInterface)
    549         sGpsInterface->cleanup();
    550 }
    551 
    552 static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
    553         jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
    554 {
    555     if (sGpsInterface) {
    556         if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
    557                 preferred_time) == 0) {
    558             return JNI_TRUE;
    559         } else {
    560             return JNI_FALSE;
    561         }
    562     }
    563     else
    564         return JNI_FALSE;
    565 }
    566 
    567 static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
    568 {
    569     if (sGpsInterface) {
    570         if (sGpsInterface->start() == 0) {
    571             return JNI_TRUE;
    572         } else {
    573             return JNI_FALSE;
    574         }
    575     }
    576     else
    577         return JNI_FALSE;
    578 }
    579 
    580 static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
    581 {
    582     if (sGpsInterface) {
    583         if (sGpsInterface->stop() == 0) {
    584             return JNI_TRUE;
    585         } else {
    586             return JNI_FALSE;
    587         }
    588     }
    589     else
    590         return JNI_FALSE;
    591 }
    592 
    593 static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
    594 {
    595     if (sGpsInterface)
    596         sGpsInterface->delete_aiding_data(flags);
    597 }
    598 
    599 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
    600         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
    601         jintArray maskArray)
    602 {
    603     // this should only be called from within a call to reportSvStatus
    604 
    605     jint* prns = env->GetIntArrayElements(prnArray, 0);
    606     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
    607     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
    608     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
    609     jint* mask = env->GetIntArrayElements(maskArray, 0);
    610 
    611     int num_svs = sGpsSvStatus.num_svs;
    612     for (int i = 0; i < num_svs; i++) {
    613         prns[i] = sGpsSvStatus.sv_list[i].prn;
    614         snrs[i] = sGpsSvStatus.sv_list[i].snr;
    615         elev[i] = sGpsSvStatus.sv_list[i].elevation;
    616         azim[i] = sGpsSvStatus.sv_list[i].azimuth;
    617     }
    618     mask[0] = sGpsSvStatus.ephemeris_mask;
    619     mask[1] = sGpsSvStatus.almanac_mask;
    620     mask[2] = sGpsSvStatus.used_in_fix_mask;
    621 
    622     env->ReleaseIntArrayElements(prnArray, prns, 0);
    623     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
    624     env->ReleaseFloatArrayElements(elevArray, elev, 0);
    625     env->ReleaseFloatArrayElements(azumArray, azim, 0);
    626     env->ReleaseIntArrayElements(maskArray, mask, 0);
    627     return (jint) num_svs;
    628 }
    629 
    630 static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env,
    631         jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
    632 {
    633     AGpsRefLocation location;
    634 
    635     if (!sAGpsRilInterface) {
    636         ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
    637         return;
    638     }
    639 
    640     switch(type) {
    641         case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
    642         case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
    643             location.type = type;
    644             location.u.cellID.mcc = mcc;
    645             location.u.cellID.mnc = mnc;
    646             location.u.cellID.lac = lac;
    647             location.u.cellID.cid = cid;
    648             break;
    649         default:
    650             ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
    651             return;
    652             break;
    653     }
    654     sAGpsRilInterface->set_ref_location(&location, sizeof(location));
    655 }
    656 
    657 static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
    658         jobject obj, jbyteArray ni_msg, jint size)
    659 {
    660     size_t sz;
    661 
    662     if (!sAGpsRilInterface) {
    663         ALOGE("no AGPS RIL interface in send_ni_message");
    664         return;
    665     }
    666     if (size < 0)
    667         return;
    668     sz = (size_t)size;
    669     jbyte* b = env->GetByteArrayElements(ni_msg, 0);
    670     sAGpsRilInterface->ni_message((uint8_t *)b,sz);
    671     env->ReleaseByteArrayElements(ni_msg,b,0);
    672 }
    673 
    674 static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
    675         jobject obj, jint type, jstring  setid_string)
    676 {
    677     if (!sAGpsRilInterface) {
    678         ALOGE("no AGPS RIL interface in agps_set_id");
    679         return;
    680     }
    681 
    682     const char *setid = env->GetStringUTFChars(setid_string, NULL);
    683     sAGpsRilInterface->set_set_id(type, setid);
    684     env->ReleaseStringUTFChars(setid_string, setid);
    685 }
    686 
    687 static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
    688                                             jbyteArray nmeaArray, jint buffer_size)
    689 {
    690     // this should only be called from within a call to reportNmea
    691     jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
    692     int length = sNmeaStringLength;
    693     if (length > buffer_size)
    694         length = buffer_size;
    695     memcpy(nmea, sNmeaString, length);
    696     env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
    697     return (jint) length;
    698 }
    699 
    700 static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
    701         jlong time, jlong timeReference, jint uncertainty)
    702 {
    703     if (sGpsInterface)
    704         sGpsInterface->inject_time(time, timeReference, uncertainty);
    705 }
    706 
    707 static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
    708         jdouble latitude, jdouble longitude, jfloat accuracy)
    709 {
    710     if (sGpsInterface)
    711         sGpsInterface->inject_location(latitude, longitude, accuracy);
    712 }
    713 
    714 static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
    715 {
    716     if (sGpsXtraInterface != NULL) {
    717         return JNI_TRUE;
    718     } else {
    719         return JNI_FALSE;
    720     }
    721 }
    722 
    723 static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
    724         jbyteArray data, jint length)
    725 {
    726     if (!sGpsXtraInterface) {
    727         ALOGE("no XTRA interface in inject_xtra_data");
    728         return;
    729     }
    730 
    731     jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
    732     sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
    733     env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
    734 }
    735 
    736 static void android_location_GpsLocationProvider_agps_data_conn_open(
    737         JNIEnv* env, jobject obj, jstring apn, jint apnIpType)
    738 {
    739     if (!sAGpsInterface) {
    740         ALOGE("no AGPS interface in agps_data_conn_open");
    741         return;
    742     }
    743     if (apn == NULL) {
    744         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    745         return;
    746     }
    747 
    748     const char *apnStr = env->GetStringUTFChars(apn, NULL);
    749 
    750     size_t interface_size = sAGpsInterface->size;
    751     if (interface_size == sizeof(AGpsInterface_v2)) {
    752         sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
    753     } else if (interface_size == sizeof(AGpsInterface_v1)) {
    754         sAGpsInterface->data_conn_open(apnStr);
    755     } else {
    756         ALOGE("Invalid size of AGpsInterface found: %d.", interface_size);
    757     }
    758 
    759     env->ReleaseStringUTFChars(apn, apnStr);
    760 }
    761 
    762 static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
    763 {
    764     if (!sAGpsInterface) {
    765         ALOGE("no AGPS interface in agps_data_conn_closed");
    766         return;
    767     }
    768     sAGpsInterface->data_conn_closed();
    769 }
    770 
    771 static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
    772 {
    773     if (!sAGpsInterface) {
    774         ALOGE("no AGPS interface in agps_data_conn_failed");
    775         return;
    776     }
    777     sAGpsInterface->data_conn_failed();
    778 }
    779 
    780 static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
    781         jint type, jstring hostname, jint port)
    782 {
    783     if (!sAGpsInterface) {
    784         ALOGE("no AGPS interface in set_agps_server");
    785         return;
    786     }
    787     const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
    788     sAGpsInterface->set_server(type, c_hostname, port);
    789     env->ReleaseStringUTFChars(hostname, c_hostname);
    790 }
    791 
    792 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
    793       jint notifId, jint response)
    794 {
    795     if (!sGpsNiInterface) {
    796         ALOGE("no NI interface in send_ni_response");
    797         return;
    798     }
    799 
    800     sGpsNiInterface->respond(notifId, response);
    801 }
    802 
    803 static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
    804 {
    805     jstring result = NULL;
    806     if (sGpsDebugInterface) {
    807         const size_t maxLength = 2047;
    808         char buffer[maxLength+1];
    809         size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
    810         if (length > maxLength) length = maxLength;
    811         buffer[length] = 0;
    812         result = env->NewStringUTF(buffer);
    813     }
    814     return result;
    815 }
    816 
    817 static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
    818         jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
    819 {
    820 
    821     if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
    822         if (extraInfo) {
    823             const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
    824             sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
    825             env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
    826         } else {
    827             sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
    828         }
    829 
    830         // update_network_availability callback was not included in original AGpsRilInterface
    831         if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
    832                 && sAGpsRilInterface->update_network_availability) {
    833             const char *c_apn = env->GetStringUTFChars(apn, NULL);
    834             sAGpsRilInterface->update_network_availability(available, c_apn);
    835             env->ReleaseStringUTFChars(apn, c_apn);
    836         }
    837     }
    838 }
    839 
    840 static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* env,
    841           jobject obj) {
    842     if (sGpsGeofencingInterface != NULL) {
    843         return JNI_TRUE;
    844     }
    845     return JNI_FALSE;
    846 }
    847 
    848 static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* env, jobject obj,
    849         jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
    850         jint last_transition, jint monitor_transition, jint notification_responsiveness,
    851         jint unknown_timer) {
    852     if (sGpsGeofencingInterface != NULL) {
    853         sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
    854                 radius, last_transition, monitor_transition, notification_responsiveness,
    855                 unknown_timer);
    856         return JNI_TRUE;
    857     } else {
    858         ALOGE("Geofence interface not available");
    859     }
    860     return JNI_FALSE;
    861 }
    862 
    863 static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* env, jobject obj,
    864         jint geofence_id) {
    865     if (sGpsGeofencingInterface != NULL) {
    866         sGpsGeofencingInterface->remove_geofence_area(geofence_id);
    867         return JNI_TRUE;
    868     } else {
    869         ALOGE("Geofence interface not available");
    870     }
    871     return JNI_FALSE;
    872 }
    873 
    874 static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* env, jobject obj,
    875         jint geofence_id) {
    876     if (sGpsGeofencingInterface != NULL) {
    877         sGpsGeofencingInterface->pause_geofence(geofence_id);
    878         return JNI_TRUE;
    879     } else {
    880         ALOGE("Geofence interface not available");
    881     }
    882     return JNI_FALSE;
    883 }
    884 
    885 static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env, jobject obj,
    886         jint geofence_id, jint monitor_transition) {
    887     if (sGpsGeofencingInterface != NULL) {
    888         sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
    889         return JNI_TRUE;
    890     } else {
    891         ALOGE("Geofence interface not available");
    892     }
    893     return JNI_FALSE;
    894 }
    895 
    896 static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
    897     const char* doubleSignature = "(D)V";
    898     const char* longSignature = "(J)V";
    899 
    900     jclass gpsClockClass = env->FindClass("android/location/GpsClock");
    901     jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
    902 
    903     jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
    904     GpsClockFlags flags = clock->flags;
    905 
    906     if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
    907         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
    908         env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
    909    }
    910 
    911    jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
    912    env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
    913 
    914     jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
    915     env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
    916 
    917     if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
    918         jmethodID setterMethod =
    919                 env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
    920         env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
    921     }
    922 
    923     if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
    924         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
    925         env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
    926     }
    927 
    928     if (flags & GPS_CLOCK_HAS_BIAS) {
    929         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
    930         env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
    931     }
    932 
    933     if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
    934         jmethodID setterMethod =
    935                 env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
    936         env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
    937     }
    938 
    939     if (flags & GPS_CLOCK_HAS_DRIFT) {
    940         jmethodID setterMethod =
    941                 env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
    942         env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
    943     }
    944 
    945     if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
    946         jmethodID setterMethod =
    947                 env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
    948         env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
    949     }
    950 
    951     env->DeleteLocalRef(gpsClockClass);
    952     return gpsClockObject;
    953 }
    954 
    955 static jobject translate_gps_measurement(JNIEnv* env, GpsMeasurement* measurement) {
    956     const char* byteSignature = "(B)V";
    957     const char* shortSignature = "(S)V";
    958     const char* intSignature = "(I)V";
    959     const char* longSignature = "(J)V";
    960     const char* floatSignature = "(F)V";
    961     const char* doubleSignature = "(D)V";
    962 
    963     jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
    964     jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
    965 
    966     jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
    967     GpsMeasurementFlags flags = measurement->flags;
    968 
    969     jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", byteSignature);
    970     env->CallVoidMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
    971 
    972     jmethodID timeOffsetSetterMethod =
    973             env->GetMethodID(gpsMeasurementClass, "setTimeOffsetInNs", doubleSignature);
    974     env->CallVoidMethod(
    975             gpsMeasurementObject,
    976             timeOffsetSetterMethod,
    977             measurement->time_offset_ns);
    978 
    979     jmethodID stateSetterMethod = env->GetMethodID(gpsMeasurementClass, "setState", shortSignature);
    980     env->CallVoidMethod(gpsMeasurementObject, stateSetterMethod, measurement->state);
    981 
    982     jmethodID receivedGpsTowSetterMethod =
    983             env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
    984     env->CallVoidMethod(
    985             gpsMeasurementObject,
    986             receivedGpsTowSetterMethod,
    987             measurement->received_gps_tow_ns);
    988 
    989     jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
    990             gpsMeasurementClass,
    991             "setReceivedGpsTowUncertaintyInNs",
    992             longSignature);
    993     env->CallVoidMethod(
    994             gpsMeasurementObject,
    995             receivedGpsTowUncertaintySetterMethod,
    996             measurement->received_gps_tow_uncertainty_ns);
    997 
    998     jmethodID cn0SetterMethod =
    999             env->GetMethodID(gpsMeasurementClass, "setCn0InDbHz", doubleSignature);
   1000     env->CallVoidMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
   1001 
   1002     jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
   1003             gpsMeasurementClass,
   1004             "setPseudorangeRateInMetersPerSec",
   1005             doubleSignature);
   1006     env->CallVoidMethod(
   1007             gpsMeasurementObject,
   1008             pseudorangeRateSetterMethod,
   1009             measurement->pseudorange_rate_mps);
   1010 
   1011     jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
   1012             gpsMeasurementClass,
   1013             "setPseudorangeRateUncertaintyInMetersPerSec",
   1014             doubleSignature);
   1015     env->CallVoidMethod(
   1016             gpsMeasurementObject,
   1017             pseudorangeRateUncertaintySetterMethod,
   1018             measurement->pseudorange_rate_uncertainty_mps);
   1019 
   1020     jmethodID accumulatedDeltaRangeStateSetterMethod =
   1021             env->GetMethodID(gpsMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
   1022     env->CallVoidMethod(
   1023             gpsMeasurementObject,
   1024             accumulatedDeltaRangeStateSetterMethod,
   1025             measurement->accumulated_delta_range_state);
   1026 
   1027     jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
   1028             gpsMeasurementClass,
   1029             "setAccumulatedDeltaRangeInMeters",
   1030             doubleSignature);
   1031     env->CallVoidMethod(
   1032             gpsMeasurementObject,
   1033             accumulatedDeltaRangeSetterMethod,
   1034             measurement->accumulated_delta_range_m);
   1035 
   1036     jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
   1037             gpsMeasurementClass,
   1038             "setAccumulatedDeltaRangeUncertaintyInMeters",
   1039             doubleSignature);
   1040     env->CallVoidMethod(
   1041             gpsMeasurementObject,
   1042             accumulatedDeltaRangeUncertaintySetterMethod,
   1043             measurement->accumulated_delta_range_uncertainty_m);
   1044 
   1045     if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
   1046         jmethodID setterMethod =
   1047                 env->GetMethodID(gpsMeasurementClass, "setPseudorangeInMeters", doubleSignature);
   1048         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
   1049     }
   1050 
   1051     if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
   1052         jmethodID setterMethod = env->GetMethodID(
   1053                 gpsMeasurementClass,
   1054                 "setPseudorangeUncertaintyInMeters",
   1055                 doubleSignature);
   1056         env->CallVoidMethod(
   1057                 gpsMeasurementObject,
   1058                 setterMethod,
   1059                 measurement->pseudorange_uncertainty_m);
   1060     }
   1061 
   1062     if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
   1063         jmethodID setterMethod =
   1064                 env->GetMethodID(gpsMeasurementClass, "setCodePhaseInChips", doubleSignature);
   1065         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
   1066     }
   1067 
   1068     if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
   1069         jmethodID setterMethod = env->GetMethodID(
   1070                 gpsMeasurementClass,
   1071                 "setCodePhaseUncertaintyInChips",
   1072                 doubleSignature);
   1073         env->CallVoidMethod(
   1074                 gpsMeasurementObject,
   1075                 setterMethod,
   1076                 measurement->code_phase_uncertainty_chips);
   1077     }
   1078 
   1079     if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
   1080         jmethodID setterMethod =
   1081                 env->GetMethodID(gpsMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
   1082         env->CallVoidMethod(
   1083                 gpsMeasurementObject,
   1084                 setterMethod,
   1085                 measurement->carrier_frequency_hz);
   1086     }
   1087 
   1088     if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
   1089         jmethodID setterMethod =
   1090                 env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
   1091         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
   1092     }
   1093 
   1094     if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
   1095         jmethodID setterMethod =
   1096                 env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
   1097         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
   1098     }
   1099 
   1100     if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
   1101         jmethodID setterMethod = env->GetMethodID(
   1102                 gpsMeasurementClass,
   1103                 "setCarrierPhaseUncertainty",
   1104                 doubleSignature);
   1105         env->CallVoidMethod(
   1106                 gpsMeasurementObject,
   1107                 setterMethod,
   1108                 measurement->carrier_phase_uncertainty);
   1109     }
   1110 
   1111     jmethodID lossOfLockSetterMethod =
   1112             env->GetMethodID(gpsMeasurementClass, "setLossOfLock", byteSignature);
   1113     env->CallVoidMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
   1114 
   1115     if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
   1116         jmethodID setterMethod =
   1117                 env->GetMethodID(gpsMeasurementClass, "setBitNumber", intSignature);
   1118         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
   1119     }
   1120 
   1121     if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
   1122         jmethodID setterMethod =
   1123                 env->GetMethodID(gpsMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
   1124         env->CallVoidMethod(
   1125                 gpsMeasurementObject,
   1126                 setterMethod,
   1127                 measurement->time_from_last_bit_ms);
   1128     }
   1129 
   1130     if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
   1131         jmethodID setterMethod =
   1132                 env->GetMethodID(gpsMeasurementClass, "setDopplerShiftInHz", doubleSignature);
   1133         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
   1134     }
   1135 
   1136     if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
   1137         jmethodID setterMethod = env->GetMethodID(
   1138                 gpsMeasurementClass,
   1139                 "setDopplerShiftUncertaintyInHz",
   1140                 doubleSignature);
   1141         env->CallVoidMethod(
   1142                 gpsMeasurementObject,
   1143                 setterMethod,
   1144                 measurement->doppler_shift_uncertainty_hz);
   1145     }
   1146 
   1147     jmethodID multipathIndicatorSetterMethod =
   1148             env->GetMethodID(gpsMeasurementClass, "setMultipathIndicator", byteSignature);
   1149     env->CallVoidMethod(
   1150             gpsMeasurementObject,
   1151             multipathIndicatorSetterMethod,
   1152             measurement->multipath_indicator);
   1153 
   1154     if (flags & GPS_MEASUREMENT_HAS_SNR) {
   1155         jmethodID setterMethod =
   1156                 env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
   1157         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
   1158     }
   1159 
   1160     if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
   1161         jmethodID setterMethod =
   1162                 env->GetMethodID(gpsMeasurementClass, "setElevationInDeg", doubleSignature);
   1163         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
   1164     }
   1165 
   1166     if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
   1167         jmethodID setterMethod =
   1168                 env->GetMethodID(gpsMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
   1169         env->CallVoidMethod(
   1170                 gpsMeasurementObject,
   1171                 setterMethod,
   1172                 measurement->elevation_uncertainty_deg);
   1173     }
   1174 
   1175     if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
   1176         jmethodID setterMethod =
   1177                 env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
   1178         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
   1179     }
   1180 
   1181     if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
   1182         jmethodID setterMethod = env->GetMethodID(
   1183                 gpsMeasurementClass,
   1184                 "setAzimuthUncertaintyInDeg",
   1185                 doubleSignature);
   1186         env->CallVoidMethod(
   1187                 gpsMeasurementObject,
   1188                 setterMethod,
   1189                 measurement->azimuth_uncertainty_deg);
   1190     }
   1191 
   1192     jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
   1193     env->CallVoidMethod(
   1194             gpsMeasurementObject,
   1195             usedInFixSetterMethod,
   1196             (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
   1197 
   1198     return gpsMeasurementObject;
   1199 }
   1200 
   1201 static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
   1202     size_t measurementCount = data->measurement_count;
   1203     if (measurementCount == 0) {
   1204         return NULL;
   1205     }
   1206 
   1207     jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
   1208     jobjectArray gpsMeasurementArray = env->NewObjectArray(
   1209             measurementCount,
   1210             gpsMeasurementClass,
   1211             NULL /* initialElement */);
   1212 
   1213     GpsMeasurement* gpsMeasurements = data->measurements;
   1214     for (uint16_t i = 0; i < measurementCount; ++i) {
   1215         jobject gpsMeasurement = translate_gps_measurement(env, &gpsMeasurements[i]);
   1216         env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
   1217         env->DeleteLocalRef(gpsMeasurement);
   1218     }
   1219 
   1220     env->DeleteLocalRef(gpsMeasurementClass);
   1221     return gpsMeasurementArray;
   1222 }
   1223 
   1224 static void measurement_callback(GpsData* data) {
   1225     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1226     if (data == NULL) {
   1227         ALOGE("Invalid data provided to gps_measurement_callback");
   1228         return;
   1229     }
   1230 
   1231     if (data->size == sizeof(GpsData)) {
   1232         jobject gpsClock = translate_gps_clock(env, &data->clock);
   1233         jobjectArray measurementArray = translate_gps_measurements(env, data);
   1234 
   1235         jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
   1236         jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
   1237                 gpsMeasurementsEventClass,
   1238                 "<init>",
   1239                 "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
   1240 
   1241         jobject gpsMeasurementsEvent = env->NewObject(
   1242                 gpsMeasurementsEventClass,
   1243                 gpsMeasurementsEventCtor,
   1244                 gpsClock,
   1245                 measurementArray);
   1246 
   1247         env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
   1248         checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1249 
   1250         env->DeleteLocalRef(gpsClock);
   1251         env->DeleteLocalRef(measurementArray);
   1252         env->DeleteLocalRef(gpsMeasurementsEventClass);
   1253         env->DeleteLocalRef(gpsMeasurementsEvent);
   1254     } else {
   1255         ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
   1256     }
   1257 }
   1258 
   1259 GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
   1260     sizeof(GpsMeasurementCallbacks),
   1261     measurement_callback,
   1262 };
   1263 
   1264 static jboolean android_location_GpsLocationProvider_is_measurement_supported(
   1265         JNIEnv* env,
   1266         jclass clazz) {
   1267     if (sGpsMeasurementInterface != NULL) {
   1268         return JNI_TRUE;
   1269     }
   1270     return JNI_FALSE;
   1271 }
   1272 
   1273 static jboolean android_location_GpsLocationProvider_start_measurement_collection(
   1274         JNIEnv* env,
   1275         jobject obj) {
   1276     if (sGpsMeasurementInterface == NULL) {
   1277         ALOGE("Measurement interface is not available.");
   1278         return JNI_FALSE;
   1279     }
   1280 
   1281     int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
   1282     if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
   1283         ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
   1284         return JNI_FALSE;
   1285     }
   1286 
   1287     return JNI_TRUE;
   1288 }
   1289 
   1290 static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
   1291         JNIEnv* env,
   1292         jobject obj) {
   1293     if (sGpsMeasurementInterface == NULL) {
   1294         ALOGE("Measurement interface not available");
   1295         return JNI_FALSE;
   1296     }
   1297 
   1298     sGpsMeasurementInterface->close();
   1299     return JNI_TRUE;
   1300 }
   1301 
   1302 static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
   1303     size_t dataLength = message->data_length;
   1304     uint8_t* data = message->data;
   1305     if (dataLength == 0 || data == NULL) {
   1306         ALOGE("Invalid Navigation Message found: data=%p, length=%d", data, dataLength);
   1307         return NULL;
   1308     }
   1309 
   1310     jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
   1311     jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
   1312     jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
   1313 
   1314     jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
   1315     env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
   1316 
   1317     jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
   1318     env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
   1319 
   1320     jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
   1321     env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
   1322 
   1323     jmethodID setSubmessageIdMethod =
   1324             env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
   1325     env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
   1326 
   1327     jbyteArray dataArray = env->NewByteArray(dataLength);
   1328     env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
   1329     jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
   1330     env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
   1331 
   1332     env->DeleteLocalRef(navigationMessageClass);
   1333     env->DeleteLocalRef(dataArray);
   1334     return navigationMessageObject;
   1335 }
   1336 
   1337 static void navigation_message_callback(GpsNavigationMessage* message) {
   1338     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1339     if (message == NULL) {
   1340         ALOGE("Invalid Navigation Message provided to callback");
   1341         return;
   1342     }
   1343 
   1344     if (message->size == sizeof(GpsNavigationMessage)) {
   1345         jobject navigationMessage = translate_gps_navigation_message(env, message);
   1346 
   1347         jclass navigationMessageEventClass =
   1348                 env->FindClass("android/location/GpsNavigationMessageEvent");
   1349         jmethodID navigationMessageEventCtor = env->GetMethodID(
   1350                 navigationMessageEventClass,
   1351                 "<init>",
   1352                 "(Landroid/location/GpsNavigationMessage;)V");
   1353         jobject navigationMessageEvent = env->NewObject(
   1354                 navigationMessageEventClass,
   1355                 navigationMessageEventCtor,
   1356                 navigationMessage);
   1357 
   1358         env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
   1359         checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1360 
   1361         env->DeleteLocalRef(navigationMessage);
   1362         env->DeleteLocalRef(navigationMessageEventClass);
   1363         env->DeleteLocalRef(navigationMessageEvent);
   1364     } else {
   1365         ALOGE("Invalid GpsNavigationMessage size found: %d", message->size);
   1366     }
   1367 }
   1368 
   1369 GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
   1370     sizeof(GpsNavigationMessageCallbacks),
   1371     navigation_message_callback,
   1372 };
   1373 
   1374 static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
   1375         JNIEnv* env,
   1376         jclass clazz) {
   1377     if(sGpsNavigationMessageInterface != NULL) {
   1378         return JNI_TRUE;
   1379     }
   1380     return JNI_FALSE;
   1381 }
   1382 
   1383 static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
   1384         JNIEnv* env,
   1385         jobject obj) {
   1386     if (sGpsNavigationMessageInterface == NULL) {
   1387         ALOGE("Navigation Message interface is not available.");
   1388         return JNI_FALSE;
   1389     }
   1390 
   1391     int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
   1392     if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
   1393         ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
   1394         return JNI_FALSE;
   1395     }
   1396 
   1397     return JNI_TRUE;
   1398 }
   1399 
   1400 static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
   1401         JNIEnv* env,
   1402         jobject obj) {
   1403     if (sGpsNavigationMessageInterface == NULL) {
   1404         ALOGE("Navigation Message interface is not available.");
   1405         return JNI_FALSE;
   1406     }
   1407 
   1408     sGpsNavigationMessageInterface->close();
   1409     return JNI_TRUE;
   1410 }
   1411 
   1412 static void android_location_GpsLocationProvider_configuration_update(JNIEnv* env, jobject obj,
   1413         jstring config_content)
   1414 {
   1415     if (!sGnssConfigurationInterface) {
   1416         ALOGE("no GPS configuration interface in configuraiton_update");
   1417         return;
   1418     }
   1419     const char *data = env->GetStringUTFChars(config_content, NULL);
   1420     ALOGD("GPS configuration:\n %s", data);
   1421     sGnssConfigurationInterface->configuration_update(
   1422             data, env->GetStringUTFLength(config_content));
   1423     env->ReleaseStringUTFChars(config_content, data);
   1424 }
   1425 
   1426 static JNINativeMethod sMethods[] = {
   1427      /* name, signature, funcPtr */
   1428     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
   1429     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
   1430     {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
   1431     {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
   1432     {"native_set_position_mode",
   1433             "(IIIII)Z",
   1434             (void*)android_location_GpsLocationProvider_set_position_mode},
   1435     {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
   1436     {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
   1437     {"native_delete_aiding_data",
   1438             "(I)V",
   1439             (void*)android_location_GpsLocationProvider_delete_aiding_data},
   1440     {"native_read_sv_status",
   1441             "([I[F[F[F[I)I",
   1442             (void*)android_location_GpsLocationProvider_read_sv_status},
   1443     {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
   1444     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
   1445     {"native_inject_location",
   1446             "(DDF)V",
   1447             (void*)android_location_GpsLocationProvider_inject_location},
   1448     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
   1449     {"native_inject_xtra_data",
   1450             "([BI)V",
   1451             (void*)android_location_GpsLocationProvider_inject_xtra_data},
   1452     {"native_agps_data_conn_open",
   1453             "(Ljava/lang/String;I)V",
   1454             (void*)android_location_GpsLocationProvider_agps_data_conn_open},
   1455     {"native_agps_data_conn_closed",
   1456             "()V",
   1457             (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
   1458     {"native_agps_data_conn_failed",
   1459             "()V",
   1460             (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
   1461     {"native_agps_set_id",
   1462             "(ILjava/lang/String;)V",
   1463             (void*)android_location_GpsLocationProvider_agps_set_id},
   1464     {"native_agps_set_ref_location_cellid",
   1465             "(IIIII)V",
   1466             (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
   1467     {"native_set_agps_server",
   1468             "(ILjava/lang/String;I)V",
   1469             (void*)android_location_GpsLocationProvider_set_agps_server},
   1470     {"native_send_ni_response",
   1471             "(II)V",
   1472             (void*)android_location_GpsLocationProvider_send_ni_response},
   1473     {"native_agps_ni_message",
   1474             "([BI)V",
   1475             (void *)android_location_GpsLocationProvider_agps_send_ni_message},
   1476     {"native_get_internal_state",
   1477             "()Ljava/lang/String;",
   1478             (void*)android_location_GpsLocationProvider_get_internal_state},
   1479     {"native_update_network_state",
   1480             "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
   1481             (void*)android_location_GpsLocationProvider_update_network_state },
   1482     {"native_is_geofence_supported",
   1483             "()Z",
   1484             (void*) android_location_GpsLocationProvider_is_geofence_supported},
   1485     {"native_add_geofence",
   1486             "(IDDDIIII)Z",
   1487             (void *)android_location_GpsLocationProvider_add_geofence},
   1488     {"native_remove_geofence",
   1489             "(I)Z",
   1490             (void *)android_location_GpsLocationProvider_remove_geofence},
   1491     {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
   1492     {"native_resume_geofence",
   1493             "(II)Z",
   1494             (void *)android_location_GpsLocationProvider_resume_geofence},
   1495     {"native_is_measurement_supported",
   1496             "()Z",
   1497             (void*) android_location_GpsLocationProvider_is_measurement_supported},
   1498     {"native_start_measurement_collection",
   1499             "()Z",
   1500             (void*) android_location_GpsLocationProvider_start_measurement_collection},
   1501     {"native_stop_measurement_collection",
   1502             "()Z",
   1503             (void*) android_location_GpsLocationProvider_stop_measurement_collection},
   1504     {"native_is_navigation_message_supported",
   1505             "()Z",
   1506             (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
   1507     {"native_start_navigation_message_collection",
   1508             "()Z",
   1509             (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
   1510     {"native_stop_navigation_message_collection",
   1511             "()Z",
   1512             (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
   1513     {"native_configuration_update",
   1514             "(Ljava/lang/String;)V",
   1515             (void*)android_location_GpsLocationProvider_configuration_update},
   1516 };
   1517 
   1518 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
   1519 {
   1520     return jniRegisterNativeMethods(
   1521             env,
   1522             "com/android/server/location/GpsLocationProvider",
   1523             sMethods,
   1524             NELEM(sMethods));
   1525 }
   1526 
   1527 } /* namespace android */
   1528