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: %zd", 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 ipAddr = *(uint32_t*)&(in->sin_addr);
    224             byteArray = convert_to_ipv4(ipAddr, true /* net_order */);
    225             if (ipAddr == INADDR_NONE || 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+: %zd", 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+: %zd", 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: %zd.", 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(
    513         JNIEnv* /* env */, jclass /* clazz */)
    514 {
    515     return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
    516 }
    517 
    518 static jboolean android_location_GpsLocationProvider_is_agps_ril_supported(
    519         JNIEnv* /* env */, jclass /* clazz */)
    520 {
    521     return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
    522 }
    523 
    524 static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
    525         JNIEnv* /* env */, jclass /* jclazz */)
    526 {
    527     return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
    528 }
    529 
    530 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
    531 {
    532     // this must be set before calling into the HAL library
    533     if (!mCallbacksObj)
    534         mCallbacksObj = env->NewGlobalRef(obj);
    535 
    536     // fail if the main interface fails to initialize
    537     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
    538         return JNI_FALSE;
    539 
    540     // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
    541     // but continue to allow the rest of the GPS interface to work.
    542     if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
    543         sGpsXtraInterface = NULL;
    544     if (sAGpsInterface)
    545         sAGpsInterface->init(&sAGpsCallbacks);
    546     if (sGpsNiInterface)
    547         sGpsNiInterface->init(&sGpsNiCallbacks);
    548     if (sAGpsRilInterface)
    549         sAGpsRilInterface->init(&sAGpsRilCallbacks);
    550     if (sGpsGeofencingInterface)
    551         sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
    552 
    553     return JNI_TRUE;
    554 }
    555 
    556 static void android_location_GpsLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
    557 {
    558     if (sGpsInterface)
    559         sGpsInterface->cleanup();
    560 }
    561 
    562 static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* /* env */,
    563         jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
    564         jint preferred_time)
    565 {
    566     if (sGpsInterface) {
    567         if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
    568                 preferred_time) == 0) {
    569             return JNI_TRUE;
    570         } else {
    571             return JNI_FALSE;
    572         }
    573     }
    574     else
    575         return JNI_FALSE;
    576 }
    577 
    578 static jboolean android_location_GpsLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
    579 {
    580     if (sGpsInterface) {
    581         if (sGpsInterface->start() == 0) {
    582             return JNI_TRUE;
    583         } else {
    584             return JNI_FALSE;
    585         }
    586     }
    587     else
    588         return JNI_FALSE;
    589 }
    590 
    591 static jboolean android_location_GpsLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
    592 {
    593     if (sGpsInterface) {
    594         if (sGpsInterface->stop() == 0) {
    595             return JNI_TRUE;
    596         } else {
    597             return JNI_FALSE;
    598         }
    599     }
    600     else
    601         return JNI_FALSE;
    602 }
    603 
    604 static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* /* env */,
    605                                                                     jobject /* obj */,
    606                                                                     jint flags)
    607 {
    608     if (sGpsInterface)
    609         sGpsInterface->delete_aiding_data(flags);
    610 }
    611 
    612 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
    613         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
    614         jintArray maskArray)
    615 {
    616     // this should only be called from within a call to reportSvStatus
    617 
    618     jint* prns = env->GetIntArrayElements(prnArray, 0);
    619     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
    620     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
    621     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
    622     jint* mask = env->GetIntArrayElements(maskArray, 0);
    623 
    624     int num_svs = sGpsSvStatus.num_svs;
    625     for (int i = 0; i < num_svs; i++) {
    626         prns[i] = sGpsSvStatus.sv_list[i].prn;
    627         snrs[i] = sGpsSvStatus.sv_list[i].snr;
    628         elev[i] = sGpsSvStatus.sv_list[i].elevation;
    629         azim[i] = sGpsSvStatus.sv_list[i].azimuth;
    630     }
    631     mask[0] = sGpsSvStatus.ephemeris_mask;
    632     mask[1] = sGpsSvStatus.almanac_mask;
    633     mask[2] = sGpsSvStatus.used_in_fix_mask;
    634 
    635     env->ReleaseIntArrayElements(prnArray, prns, 0);
    636     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
    637     env->ReleaseFloatArrayElements(elevArray, elev, 0);
    638     env->ReleaseFloatArrayElements(azumArray, azim, 0);
    639     env->ReleaseIntArrayElements(maskArray, mask, 0);
    640     return (jint) num_svs;
    641 }
    642 
    643 static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
    644         JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
    645 {
    646     AGpsRefLocation location;
    647 
    648     if (!sAGpsRilInterface) {
    649         ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
    650         return;
    651     }
    652 
    653     switch(type) {
    654         case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
    655         case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
    656             location.type = type;
    657             location.u.cellID.mcc = mcc;
    658             location.u.cellID.mnc = mnc;
    659             location.u.cellID.lac = lac;
    660             location.u.cellID.cid = cid;
    661             break;
    662         default:
    663             ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
    664             return;
    665             break;
    666     }
    667     sAGpsRilInterface->set_ref_location(&location, sizeof(location));
    668 }
    669 
    670 static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
    671         jobject /* obj */, jbyteArray ni_msg, jint size)
    672 {
    673     size_t sz;
    674 
    675     if (!sAGpsRilInterface) {
    676         ALOGE("no AGPS RIL interface in send_ni_message");
    677         return;
    678     }
    679     if (size < 0)
    680         return;
    681     sz = (size_t)size;
    682     jbyte* b = env->GetByteArrayElements(ni_msg, 0);
    683     sAGpsRilInterface->ni_message((uint8_t *)b,sz);
    684     env->ReleaseByteArrayElements(ni_msg,b,0);
    685 }
    686 
    687 static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
    688                                                              jint type, jstring  setid_string)
    689 {
    690     if (!sAGpsRilInterface) {
    691         ALOGE("no AGPS RIL interface in agps_set_id");
    692         return;
    693     }
    694 
    695     const char *setid = env->GetStringUTFChars(setid_string, NULL);
    696     sAGpsRilInterface->set_set_id(type, setid);
    697     env->ReleaseStringUTFChars(setid_string, setid);
    698 }
    699 
    700 static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
    701                                             jbyteArray nmeaArray, jint buffer_size)
    702 {
    703     // this should only be called from within a call to reportNmea
    704     jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
    705     int length = sNmeaStringLength;
    706     if (length > buffer_size)
    707         length = buffer_size;
    708     memcpy(nmea, sNmeaString, length);
    709     env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
    710     return (jint) length;
    711 }
    712 
    713 static void android_location_GpsLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
    714         jlong time, jlong timeReference, jint uncertainty)
    715 {
    716     if (sGpsInterface)
    717         sGpsInterface->inject_time(time, timeReference, uncertainty);
    718 }
    719 
    720 static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
    721         jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
    722 {
    723     if (sGpsInterface)
    724         sGpsInterface->inject_location(latitude, longitude, accuracy);
    725 }
    726 
    727 static jboolean android_location_GpsLocationProvider_supports_xtra(
    728         JNIEnv* /* env */, jobject /* obj */)
    729 {
    730     return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
    731 }
    732 
    733 static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
    734         jbyteArray data, jint length)
    735 {
    736     if (!sGpsXtraInterface) {
    737         ALOGE("no XTRA interface in inject_xtra_data");
    738         return;
    739     }
    740 
    741     jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
    742     sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
    743     env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
    744 }
    745 
    746 static void android_location_GpsLocationProvider_agps_data_conn_open(
    747         JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
    748 {
    749     if (!sAGpsInterface) {
    750         ALOGE("no AGPS interface in agps_data_conn_open");
    751         return;
    752     }
    753     if (apn == NULL) {
    754         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    755         return;
    756     }
    757 
    758     const char *apnStr = env->GetStringUTFChars(apn, NULL);
    759 
    760     size_t interface_size = sAGpsInterface->size;
    761     if (interface_size == sizeof(AGpsInterface_v2)) {
    762         sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
    763     } else if (interface_size == sizeof(AGpsInterface_v1)) {
    764         sAGpsInterface->data_conn_open(apnStr);
    765     } else {
    766         ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
    767     }
    768 
    769     env->ReleaseStringUTFChars(apn, apnStr);
    770 }
    771 
    772 static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
    773                                                                        jobject /* obj */)
    774 {
    775     if (!sAGpsInterface) {
    776         ALOGE("no AGPS interface in agps_data_conn_closed");
    777         return;
    778     }
    779     sAGpsInterface->data_conn_closed();
    780 }
    781 
    782 static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
    783                                                                        jobject /* obj */)
    784 {
    785     if (!sAGpsInterface) {
    786         ALOGE("no AGPS interface in agps_data_conn_failed");
    787         return;
    788     }
    789     sAGpsInterface->data_conn_failed();
    790 }
    791 
    792 static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
    793         jint type, jstring hostname, jint port)
    794 {
    795     if (!sAGpsInterface) {
    796         ALOGE("no AGPS interface in set_agps_server");
    797         return;
    798     }
    799     const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
    800     sAGpsInterface->set_server(type, c_hostname, port);
    801     env->ReleaseStringUTFChars(hostname, c_hostname);
    802 }
    803 
    804 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* /* env */,
    805       jobject /* obj */, jint notifId, jint response)
    806 {
    807     if (!sGpsNiInterface) {
    808         ALOGE("no NI interface in send_ni_response");
    809         return;
    810     }
    811 
    812     sGpsNiInterface->respond(notifId, response);
    813 }
    814 
    815 static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env,
    816                                                                        jobject /* obj */) {
    817     jstring result = NULL;
    818     if (sGpsDebugInterface) {
    819         const size_t maxLength = 2047;
    820         char buffer[maxLength+1];
    821         size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
    822         if (length > maxLength) length = maxLength;
    823         buffer[length] = 0;
    824         result = env->NewStringUTF(buffer);
    825     }
    826     return result;
    827 }
    828 
    829 static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
    830         jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
    831 {
    832 
    833     if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
    834         if (extraInfo) {
    835             const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
    836             sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
    837             env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
    838         } else {
    839             sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
    840         }
    841 
    842         // update_network_availability callback was not included in original AGpsRilInterface
    843         if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
    844                 && sAGpsRilInterface->update_network_availability) {
    845             const char *c_apn = env->GetStringUTFChars(apn, NULL);
    846             sAGpsRilInterface->update_network_availability(available, c_apn);
    847             env->ReleaseStringUTFChars(apn, c_apn);
    848         }
    849     }
    850 }
    851 
    852 static jboolean android_location_GpsLocationProvider_is_geofence_supported(
    853         JNIEnv* /* env */, jobject /* obj */)
    854 {
    855     return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
    856 }
    857 
    858 static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* /* env */,
    859         jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
    860         jint last_transition, jint monitor_transition, jint notification_responsiveness,
    861         jint unknown_timer) {
    862     if (sGpsGeofencingInterface != NULL) {
    863         sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
    864                 radius, last_transition, monitor_transition, notification_responsiveness,
    865                 unknown_timer);
    866         return JNI_TRUE;
    867     } else {
    868         ALOGE("Geofence interface not available");
    869     }
    870     return JNI_FALSE;
    871 }
    872 
    873 static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* /* env */,
    874         jobject /* obj */, jint geofence_id) {
    875     if (sGpsGeofencingInterface != NULL) {
    876         sGpsGeofencingInterface->remove_geofence_area(geofence_id);
    877         return JNI_TRUE;
    878     } else {
    879         ALOGE("Geofence interface not available");
    880     }
    881     return JNI_FALSE;
    882 }
    883 
    884 static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* /* env */,
    885         jobject /* obj */, jint geofence_id) {
    886     if (sGpsGeofencingInterface != NULL) {
    887         sGpsGeofencingInterface->pause_geofence(geofence_id);
    888         return JNI_TRUE;
    889     } else {
    890         ALOGE("Geofence interface not available");
    891     }
    892     return JNI_FALSE;
    893 }
    894 
    895 static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* /* env */,
    896         jobject /* obj */, jint geofence_id, jint monitor_transition) {
    897     if (sGpsGeofencingInterface != NULL) {
    898         sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
    899         return JNI_TRUE;
    900     } else {
    901         ALOGE("Geofence interface not available");
    902     }
    903     return JNI_FALSE;
    904 }
    905 
    906 static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
    907     const char* doubleSignature = "(D)V";
    908     const char* longSignature = "(J)V";
    909 
    910     jclass gpsClockClass = env->FindClass("android/location/GpsClock");
    911     jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
    912 
    913     jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
    914     GpsClockFlags flags = clock->flags;
    915 
    916     if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
    917         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
    918         env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
    919    }
    920 
    921    jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
    922    env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
    923 
    924     jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
    925     env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
    926 
    927     if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
    928         jmethodID setterMethod =
    929                 env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
    930         env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
    931     }
    932 
    933     if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
    934         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
    935         env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
    936     }
    937 
    938     if (flags & GPS_CLOCK_HAS_BIAS) {
    939         jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
    940         env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
    941     }
    942 
    943     if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
    944         jmethodID setterMethod =
    945                 env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
    946         env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
    947     }
    948 
    949     if (flags & GPS_CLOCK_HAS_DRIFT) {
    950         jmethodID setterMethod =
    951                 env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
    952         env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
    953     }
    954 
    955     if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
    956         jmethodID setterMethod =
    957                 env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
    958         env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
    959     }
    960 
    961     env->DeleteLocalRef(gpsClockClass);
    962     return gpsClockObject;
    963 }
    964 
    965 static jobject translate_gps_measurement(JNIEnv* env, GpsMeasurement* measurement) {
    966     const char* byteSignature = "(B)V";
    967     const char* shortSignature = "(S)V";
    968     const char* intSignature = "(I)V";
    969     const char* longSignature = "(J)V";
    970     const char* floatSignature = "(F)V";
    971     const char* doubleSignature = "(D)V";
    972 
    973     jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
    974     jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
    975 
    976     jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
    977     GpsMeasurementFlags flags = measurement->flags;
    978 
    979     jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", byteSignature);
    980     env->CallVoidMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
    981 
    982     jmethodID timeOffsetSetterMethod =
    983             env->GetMethodID(gpsMeasurementClass, "setTimeOffsetInNs", doubleSignature);
    984     env->CallVoidMethod(
    985             gpsMeasurementObject,
    986             timeOffsetSetterMethod,
    987             measurement->time_offset_ns);
    988 
    989     jmethodID stateSetterMethod = env->GetMethodID(gpsMeasurementClass, "setState", shortSignature);
    990     env->CallVoidMethod(gpsMeasurementObject, stateSetterMethod, measurement->state);
    991 
    992     jmethodID receivedGpsTowSetterMethod =
    993             env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
    994     env->CallVoidMethod(
    995             gpsMeasurementObject,
    996             receivedGpsTowSetterMethod,
    997             measurement->received_gps_tow_ns);
    998 
    999     jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
   1000             gpsMeasurementClass,
   1001             "setReceivedGpsTowUncertaintyInNs",
   1002             longSignature);
   1003     env->CallVoidMethod(
   1004             gpsMeasurementObject,
   1005             receivedGpsTowUncertaintySetterMethod,
   1006             measurement->received_gps_tow_uncertainty_ns);
   1007 
   1008     jmethodID cn0SetterMethod =
   1009             env->GetMethodID(gpsMeasurementClass, "setCn0InDbHz", doubleSignature);
   1010     env->CallVoidMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
   1011 
   1012     jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
   1013             gpsMeasurementClass,
   1014             "setPseudorangeRateInMetersPerSec",
   1015             doubleSignature);
   1016     env->CallVoidMethod(
   1017             gpsMeasurementObject,
   1018             pseudorangeRateSetterMethod,
   1019             measurement->pseudorange_rate_mps);
   1020 
   1021     jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
   1022             gpsMeasurementClass,
   1023             "setPseudorangeRateUncertaintyInMetersPerSec",
   1024             doubleSignature);
   1025     env->CallVoidMethod(
   1026             gpsMeasurementObject,
   1027             pseudorangeRateUncertaintySetterMethod,
   1028             measurement->pseudorange_rate_uncertainty_mps);
   1029 
   1030     jmethodID accumulatedDeltaRangeStateSetterMethod =
   1031             env->GetMethodID(gpsMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
   1032     env->CallVoidMethod(
   1033             gpsMeasurementObject,
   1034             accumulatedDeltaRangeStateSetterMethod,
   1035             measurement->accumulated_delta_range_state);
   1036 
   1037     jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
   1038             gpsMeasurementClass,
   1039             "setAccumulatedDeltaRangeInMeters",
   1040             doubleSignature);
   1041     env->CallVoidMethod(
   1042             gpsMeasurementObject,
   1043             accumulatedDeltaRangeSetterMethod,
   1044             measurement->accumulated_delta_range_m);
   1045 
   1046     jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
   1047             gpsMeasurementClass,
   1048             "setAccumulatedDeltaRangeUncertaintyInMeters",
   1049             doubleSignature);
   1050     env->CallVoidMethod(
   1051             gpsMeasurementObject,
   1052             accumulatedDeltaRangeUncertaintySetterMethod,
   1053             measurement->accumulated_delta_range_uncertainty_m);
   1054 
   1055     if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
   1056         jmethodID setterMethod =
   1057                 env->GetMethodID(gpsMeasurementClass, "setPseudorangeInMeters", doubleSignature);
   1058         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
   1059     }
   1060 
   1061     if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
   1062         jmethodID setterMethod = env->GetMethodID(
   1063                 gpsMeasurementClass,
   1064                 "setPseudorangeUncertaintyInMeters",
   1065                 doubleSignature);
   1066         env->CallVoidMethod(
   1067                 gpsMeasurementObject,
   1068                 setterMethod,
   1069                 measurement->pseudorange_uncertainty_m);
   1070     }
   1071 
   1072     if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
   1073         jmethodID setterMethod =
   1074                 env->GetMethodID(gpsMeasurementClass, "setCodePhaseInChips", doubleSignature);
   1075         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
   1076     }
   1077 
   1078     if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
   1079         jmethodID setterMethod = env->GetMethodID(
   1080                 gpsMeasurementClass,
   1081                 "setCodePhaseUncertaintyInChips",
   1082                 doubleSignature);
   1083         env->CallVoidMethod(
   1084                 gpsMeasurementObject,
   1085                 setterMethod,
   1086                 measurement->code_phase_uncertainty_chips);
   1087     }
   1088 
   1089     if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
   1090         jmethodID setterMethod =
   1091                 env->GetMethodID(gpsMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
   1092         env->CallVoidMethod(
   1093                 gpsMeasurementObject,
   1094                 setterMethod,
   1095                 measurement->carrier_frequency_hz);
   1096     }
   1097 
   1098     if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
   1099         jmethodID setterMethod =
   1100                 env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
   1101         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
   1102     }
   1103 
   1104     if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
   1105         jmethodID setterMethod =
   1106                 env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
   1107         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
   1108     }
   1109 
   1110     if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
   1111         jmethodID setterMethod = env->GetMethodID(
   1112                 gpsMeasurementClass,
   1113                 "setCarrierPhaseUncertainty",
   1114                 doubleSignature);
   1115         env->CallVoidMethod(
   1116                 gpsMeasurementObject,
   1117                 setterMethod,
   1118                 measurement->carrier_phase_uncertainty);
   1119     }
   1120 
   1121     jmethodID lossOfLockSetterMethod =
   1122             env->GetMethodID(gpsMeasurementClass, "setLossOfLock", byteSignature);
   1123     env->CallVoidMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
   1124 
   1125     if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
   1126         jmethodID setterMethod =
   1127                 env->GetMethodID(gpsMeasurementClass, "setBitNumber", intSignature);
   1128         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
   1129     }
   1130 
   1131     if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
   1132         jmethodID setterMethod =
   1133                 env->GetMethodID(gpsMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
   1134         env->CallVoidMethod(
   1135                 gpsMeasurementObject,
   1136                 setterMethod,
   1137                 measurement->time_from_last_bit_ms);
   1138     }
   1139 
   1140     if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
   1141         jmethodID setterMethod =
   1142                 env->GetMethodID(gpsMeasurementClass, "setDopplerShiftInHz", doubleSignature);
   1143         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
   1144     }
   1145 
   1146     if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
   1147         jmethodID setterMethod = env->GetMethodID(
   1148                 gpsMeasurementClass,
   1149                 "setDopplerShiftUncertaintyInHz",
   1150                 doubleSignature);
   1151         env->CallVoidMethod(
   1152                 gpsMeasurementObject,
   1153                 setterMethod,
   1154                 measurement->doppler_shift_uncertainty_hz);
   1155     }
   1156 
   1157     jmethodID multipathIndicatorSetterMethod =
   1158             env->GetMethodID(gpsMeasurementClass, "setMultipathIndicator", byteSignature);
   1159     env->CallVoidMethod(
   1160             gpsMeasurementObject,
   1161             multipathIndicatorSetterMethod,
   1162             measurement->multipath_indicator);
   1163 
   1164     if (flags & GPS_MEASUREMENT_HAS_SNR) {
   1165         jmethodID setterMethod =
   1166                 env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
   1167         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
   1168     }
   1169 
   1170     if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
   1171         jmethodID setterMethod =
   1172                 env->GetMethodID(gpsMeasurementClass, "setElevationInDeg", doubleSignature);
   1173         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
   1174     }
   1175 
   1176     if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
   1177         jmethodID setterMethod =
   1178                 env->GetMethodID(gpsMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
   1179         env->CallVoidMethod(
   1180                 gpsMeasurementObject,
   1181                 setterMethod,
   1182                 measurement->elevation_uncertainty_deg);
   1183     }
   1184 
   1185     if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
   1186         jmethodID setterMethod =
   1187                 env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
   1188         env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
   1189     }
   1190 
   1191     if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
   1192         jmethodID setterMethod = env->GetMethodID(
   1193                 gpsMeasurementClass,
   1194                 "setAzimuthUncertaintyInDeg",
   1195                 doubleSignature);
   1196         env->CallVoidMethod(
   1197                 gpsMeasurementObject,
   1198                 setterMethod,
   1199                 measurement->azimuth_uncertainty_deg);
   1200     }
   1201 
   1202     jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
   1203     env->CallVoidMethod(
   1204             gpsMeasurementObject,
   1205             usedInFixSetterMethod,
   1206             (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
   1207 
   1208     env->DeleteLocalRef(gpsMeasurementClass);
   1209     return gpsMeasurementObject;
   1210 }
   1211 
   1212 static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
   1213     size_t measurementCount = data->measurement_count;
   1214     if (measurementCount == 0) {
   1215         return NULL;
   1216     }
   1217 
   1218     jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
   1219     jobjectArray gpsMeasurementArray = env->NewObjectArray(
   1220             measurementCount,
   1221             gpsMeasurementClass,
   1222             NULL /* initialElement */);
   1223 
   1224     GpsMeasurement* gpsMeasurements = data->measurements;
   1225     for (uint16_t i = 0; i < measurementCount; ++i) {
   1226         jobject gpsMeasurement = translate_gps_measurement(env, &gpsMeasurements[i]);
   1227         env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
   1228         env->DeleteLocalRef(gpsMeasurement);
   1229     }
   1230 
   1231     env->DeleteLocalRef(gpsMeasurementClass);
   1232     return gpsMeasurementArray;
   1233 }
   1234 
   1235 static void measurement_callback(GpsData* data) {
   1236     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1237     if (data == NULL) {
   1238         ALOGE("Invalid data provided to gps_measurement_callback");
   1239         return;
   1240     }
   1241 
   1242     if (data->size == sizeof(GpsData)) {
   1243         jobject gpsClock = translate_gps_clock(env, &data->clock);
   1244         jobjectArray measurementArray = translate_gps_measurements(env, data);
   1245 
   1246         jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
   1247         jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
   1248                 gpsMeasurementsEventClass,
   1249                 "<init>",
   1250                 "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
   1251 
   1252         jobject gpsMeasurementsEvent = env->NewObject(
   1253                 gpsMeasurementsEventClass,
   1254                 gpsMeasurementsEventCtor,
   1255                 gpsClock,
   1256                 measurementArray);
   1257 
   1258         env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
   1259         checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1260 
   1261         env->DeleteLocalRef(gpsClock);
   1262         env->DeleteLocalRef(measurementArray);
   1263         env->DeleteLocalRef(gpsMeasurementsEventClass);
   1264         env->DeleteLocalRef(gpsMeasurementsEvent);
   1265     } else {
   1266         ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
   1267     }
   1268 }
   1269 
   1270 GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
   1271     sizeof(GpsMeasurementCallbacks),
   1272     measurement_callback,
   1273 };
   1274 
   1275 static jboolean android_location_GpsLocationProvider_is_measurement_supported(
   1276         JNIEnv* env,
   1277         jclass clazz) {
   1278     if (sGpsMeasurementInterface != NULL) {
   1279         return JNI_TRUE;
   1280     }
   1281     return JNI_FALSE;
   1282 }
   1283 
   1284 static jboolean android_location_GpsLocationProvider_start_measurement_collection(
   1285         JNIEnv* env,
   1286         jobject obj) {
   1287     if (sGpsMeasurementInterface == NULL) {
   1288         ALOGE("Measurement interface is not available.");
   1289         return JNI_FALSE;
   1290     }
   1291 
   1292     int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
   1293     if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
   1294         ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
   1295         return JNI_FALSE;
   1296     }
   1297 
   1298     return JNI_TRUE;
   1299 }
   1300 
   1301 static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
   1302         JNIEnv* env,
   1303         jobject obj) {
   1304     if (sGpsMeasurementInterface == NULL) {
   1305         ALOGE("Measurement interface not available");
   1306         return JNI_FALSE;
   1307     }
   1308 
   1309     sGpsMeasurementInterface->close();
   1310     return JNI_TRUE;
   1311 }
   1312 
   1313 static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
   1314     size_t dataLength = message->data_length;
   1315     uint8_t* data = message->data;
   1316     if (dataLength == 0 || data == NULL) {
   1317         ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
   1318         return NULL;
   1319     }
   1320 
   1321     jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
   1322     jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
   1323     jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
   1324 
   1325     jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
   1326     env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
   1327 
   1328     jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
   1329     env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
   1330 
   1331     jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
   1332     env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
   1333 
   1334     jmethodID setSubmessageIdMethod =
   1335             env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
   1336     env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
   1337 
   1338     jbyteArray dataArray = env->NewByteArray(dataLength);
   1339     env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
   1340     jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
   1341     env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
   1342 
   1343     env->DeleteLocalRef(navigationMessageClass);
   1344     env->DeleteLocalRef(dataArray);
   1345     return navigationMessageObject;
   1346 }
   1347 
   1348 static void navigation_message_callback(GpsNavigationMessage* message) {
   1349     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1350     if (message == NULL) {
   1351         ALOGE("Invalid Navigation Message provided to callback");
   1352         return;
   1353     }
   1354 
   1355     if (message->size == sizeof(GpsNavigationMessage)) {
   1356         jobject navigationMessage = translate_gps_navigation_message(env, message);
   1357 
   1358         jclass navigationMessageEventClass =
   1359                 env->FindClass("android/location/GpsNavigationMessageEvent");
   1360         jmethodID navigationMessageEventCtor = env->GetMethodID(
   1361                 navigationMessageEventClass,
   1362                 "<init>",
   1363                 "(Landroid/location/GpsNavigationMessage;)V");
   1364         jobject navigationMessageEvent = env->NewObject(
   1365                 navigationMessageEventClass,
   1366                 navigationMessageEventCtor,
   1367                 navigationMessage);
   1368 
   1369         env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
   1370         checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1371 
   1372         env->DeleteLocalRef(navigationMessage);
   1373         env->DeleteLocalRef(navigationMessageEventClass);
   1374         env->DeleteLocalRef(navigationMessageEvent);
   1375     } else {
   1376         ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
   1377     }
   1378 }
   1379 
   1380 GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
   1381     sizeof(GpsNavigationMessageCallbacks),
   1382     navigation_message_callback,
   1383 };
   1384 
   1385 static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
   1386         JNIEnv* env,
   1387         jclass clazz) {
   1388     if(sGpsNavigationMessageInterface != NULL) {
   1389         return JNI_TRUE;
   1390     }
   1391     return JNI_FALSE;
   1392 }
   1393 
   1394 static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
   1395         JNIEnv* env,
   1396         jobject obj) {
   1397     if (sGpsNavigationMessageInterface == NULL) {
   1398         ALOGE("Navigation Message interface is not available.");
   1399         return JNI_FALSE;
   1400     }
   1401 
   1402     int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
   1403     if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
   1404         ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
   1405         return JNI_FALSE;
   1406     }
   1407 
   1408     return JNI_TRUE;
   1409 }
   1410 
   1411 static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
   1412         JNIEnv* env,
   1413         jobject obj) {
   1414     if (sGpsNavigationMessageInterface == NULL) {
   1415         ALOGE("Navigation Message interface is not available.");
   1416         return JNI_FALSE;
   1417     }
   1418 
   1419     sGpsNavigationMessageInterface->close();
   1420     return JNI_TRUE;
   1421 }
   1422 
   1423 static void android_location_GpsLocationProvider_configuration_update(JNIEnv* env, jobject obj,
   1424         jstring config_content)
   1425 {
   1426     if (!sGnssConfigurationInterface) {
   1427         ALOGE("no GPS configuration interface in configuraiton_update");
   1428         return;
   1429     }
   1430     const char *data = env->GetStringUTFChars(config_content, NULL);
   1431     ALOGD("GPS configuration:\n %s", data);
   1432     sGnssConfigurationInterface->configuration_update(
   1433             data, env->GetStringUTFLength(config_content));
   1434     env->ReleaseStringUTFChars(config_content, data);
   1435 }
   1436 
   1437 static JNINativeMethod sMethods[] = {
   1438      /* name, signature, funcPtr */
   1439     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
   1440     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
   1441     {"native_is_agps_ril_supported", "()Z",
   1442             (void*)android_location_GpsLocationProvider_is_agps_ril_supported},
   1443     {"native_is_gnss_configuration_supported", "()Z",
   1444             (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
   1445     {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
   1446     {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
   1447     {"native_set_position_mode",
   1448             "(IIIII)Z",
   1449             (void*)android_location_GpsLocationProvider_set_position_mode},
   1450     {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
   1451     {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
   1452     {"native_delete_aiding_data",
   1453             "(I)V",
   1454             (void*)android_location_GpsLocationProvider_delete_aiding_data},
   1455     {"native_read_sv_status",
   1456             "([I[F[F[F[I)I",
   1457             (void*)android_location_GpsLocationProvider_read_sv_status},
   1458     {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
   1459     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
   1460     {"native_inject_location",
   1461             "(DDF)V",
   1462             (void*)android_location_GpsLocationProvider_inject_location},
   1463     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
   1464     {"native_inject_xtra_data",
   1465             "([BI)V",
   1466             (void*)android_location_GpsLocationProvider_inject_xtra_data},
   1467     {"native_agps_data_conn_open",
   1468             "(Ljava/lang/String;I)V",
   1469             (void*)android_location_GpsLocationProvider_agps_data_conn_open},
   1470     {"native_agps_data_conn_closed",
   1471             "()V",
   1472             (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
   1473     {"native_agps_data_conn_failed",
   1474             "()V",
   1475             (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
   1476     {"native_agps_set_id",
   1477             "(ILjava/lang/String;)V",
   1478             (void*)android_location_GpsLocationProvider_agps_set_id},
   1479     {"native_agps_set_ref_location_cellid",
   1480             "(IIIII)V",
   1481             (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
   1482     {"native_set_agps_server",
   1483             "(ILjava/lang/String;I)V",
   1484             (void*)android_location_GpsLocationProvider_set_agps_server},
   1485     {"native_send_ni_response",
   1486             "(II)V",
   1487             (void*)android_location_GpsLocationProvider_send_ni_response},
   1488     {"native_agps_ni_message",
   1489             "([BI)V",
   1490             (void *)android_location_GpsLocationProvider_agps_send_ni_message},
   1491     {"native_get_internal_state",
   1492             "()Ljava/lang/String;",
   1493             (void*)android_location_GpsLocationProvider_get_internal_state},
   1494     {"native_update_network_state",
   1495             "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
   1496             (void*)android_location_GpsLocationProvider_update_network_state },
   1497     {"native_is_geofence_supported",
   1498             "()Z",
   1499             (void*) android_location_GpsLocationProvider_is_geofence_supported},
   1500     {"native_add_geofence",
   1501             "(IDDDIIII)Z",
   1502             (void *)android_location_GpsLocationProvider_add_geofence},
   1503     {"native_remove_geofence",
   1504             "(I)Z",
   1505             (void *)android_location_GpsLocationProvider_remove_geofence},
   1506     {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
   1507     {"native_resume_geofence",
   1508             "(II)Z",
   1509             (void *)android_location_GpsLocationProvider_resume_geofence},
   1510     {"native_is_measurement_supported",
   1511             "()Z",
   1512             (void*) android_location_GpsLocationProvider_is_measurement_supported},
   1513     {"native_start_measurement_collection",
   1514             "()Z",
   1515             (void*) android_location_GpsLocationProvider_start_measurement_collection},
   1516     {"native_stop_measurement_collection",
   1517             "()Z",
   1518             (void*) android_location_GpsLocationProvider_stop_measurement_collection},
   1519     {"native_is_navigation_message_supported",
   1520             "()Z",
   1521             (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
   1522     {"native_start_navigation_message_collection",
   1523             "()Z",
   1524             (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
   1525     {"native_stop_navigation_message_collection",
   1526             "()Z",
   1527             (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
   1528     {"native_configuration_update",
   1529             "(Ljava/lang/String;)V",
   1530             (void*)android_location_GpsLocationProvider_configuration_update},
   1531 };
   1532 
   1533 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
   1534 {
   1535     return jniRegisterNativeMethods(
   1536             env,
   1537             "com/android/server/location/GpsLocationProvider",
   1538             sMethods,
   1539             NELEM(sMethods));
   1540 }
   1541 
   1542 } /* namespace android */
   1543