com_android_server_location_GpsLocationProvider.cpp revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
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 <string.h>
32#include <pthread.h>
33
34static jobject mCallbacksObj = NULL;
35
36static jmethodID method_reportLocation;
37static jmethodID method_reportStatus;
38static jmethodID method_reportSvStatus;
39static jmethodID method_reportAGpsStatus;
40static jmethodID method_reportNmea;
41static jmethodID method_setEngineCapabilities;
42static jmethodID method_xtraDownloadRequest;
43static jmethodID method_reportNiNotification;
44static jmethodID method_requestRefLocation;
45static jmethodID method_requestSetID;
46static jmethodID method_requestUtcTime;
47static jmethodID method_reportGeofenceTransition;
48static jmethodID method_reportGeofenceStatus;
49static jmethodID method_reportGeofenceAddStatus;
50static jmethodID method_reportGeofenceRemoveStatus;
51static jmethodID method_reportGeofencePauseStatus;
52static jmethodID method_reportGeofenceResumeStatus;
53
54static const GpsInterface* sGpsInterface = NULL;
55static const GpsXtraInterface* sGpsXtraInterface = NULL;
56static const AGpsInterface* sAGpsInterface = NULL;
57static const GpsNiInterface* sGpsNiInterface = NULL;
58static const GpsDebugInterface* sGpsDebugInterface = NULL;
59static const AGpsRilInterface* sAGpsRilInterface = NULL;
60static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
61
62// temporary storage for GPS callbacks
63static GpsSvStatus  sGpsSvStatus;
64static const char* sNmeaString;
65static int sNmeaStringLength;
66
67#define WAKE_LOCK_NAME  "GPS"
68
69namespace android {
70
71static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
72    if (env->ExceptionCheck()) {
73        ALOGE("An exception was thrown by callback '%s'.", methodName);
74        LOGE_EX(env);
75        env->ExceptionClear();
76    }
77}
78
79static void location_callback(GpsLocation* location)
80{
81    JNIEnv* env = AndroidRuntime::getJNIEnv();
82    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
83            (jdouble)location->latitude, (jdouble)location->longitude,
84            (jdouble)location->altitude,
85            (jfloat)location->speed, (jfloat)location->bearing,
86            (jfloat)location->accuracy, (jlong)location->timestamp);
87    checkAndClearExceptionFromCallback(env, __FUNCTION__);
88}
89
90static void status_callback(GpsStatus* status)
91{
92    JNIEnv* env = AndroidRuntime::getJNIEnv();
93    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
94    checkAndClearExceptionFromCallback(env, __FUNCTION__);
95}
96
97static void sv_status_callback(GpsSvStatus* sv_status)
98{
99    JNIEnv* env = AndroidRuntime::getJNIEnv();
100    memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
101    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
102    checkAndClearExceptionFromCallback(env, __FUNCTION__);
103}
104
105static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
106{
107    JNIEnv* env = AndroidRuntime::getJNIEnv();
108    // The Java code will call back to read these values
109    // We do this to avoid creating unnecessary String objects
110    sNmeaString = nmea;
111    sNmeaStringLength = length;
112    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
113    checkAndClearExceptionFromCallback(env, __FUNCTION__);
114}
115
116static void set_capabilities_callback(uint32_t capabilities)
117{
118    ALOGD("set_capabilities_callback: %du\n", capabilities);
119    JNIEnv* env = AndroidRuntime::getJNIEnv();
120    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
121    checkAndClearExceptionFromCallback(env, __FUNCTION__);
122}
123
124static void acquire_wakelock_callback()
125{
126    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
127}
128
129static void release_wakelock_callback()
130{
131    release_wake_lock(WAKE_LOCK_NAME);
132}
133
134static void request_utc_time_callback()
135{
136    JNIEnv* env = AndroidRuntime::getJNIEnv();
137    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
138    checkAndClearExceptionFromCallback(env, __FUNCTION__);
139}
140
141static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
142{
143    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
144}
145
146GpsCallbacks sGpsCallbacks = {
147    sizeof(GpsCallbacks),
148    location_callback,
149    status_callback,
150    sv_status_callback,
151    nmea_callback,
152    set_capabilities_callback,
153    acquire_wakelock_callback,
154    release_wakelock_callback,
155    create_thread_callback,
156    request_utc_time_callback,
157};
158
159static void xtra_download_request_callback()
160{
161    JNIEnv* env = AndroidRuntime::getJNIEnv();
162    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
163    checkAndClearExceptionFromCallback(env, __FUNCTION__);
164}
165
166GpsXtraCallbacks sGpsXtraCallbacks = {
167    xtra_download_request_callback,
168    create_thread_callback,
169};
170
171static void agps_status_callback(AGpsStatus* agps_status)
172{
173    JNIEnv* env = AndroidRuntime::getJNIEnv();
174
175    uint32_t ipaddr;
176    // ipaddr field was not included in original AGpsStatus
177    if (agps_status->size >= sizeof(AGpsStatus))
178        ipaddr = agps_status->ipaddr;
179    else
180        ipaddr = 0xFFFFFFFF;
181    env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
182                        agps_status->type, agps_status->status, ipaddr);
183    checkAndClearExceptionFromCallback(env, __FUNCTION__);
184}
185
186AGpsCallbacks sAGpsCallbacks = {
187    agps_status_callback,
188    create_thread_callback,
189};
190
191static void gps_ni_notify_callback(GpsNiNotification *notification)
192{
193    ALOGD("gps_ni_notify_callback\n");
194    JNIEnv* env = AndroidRuntime::getJNIEnv();
195    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
196    jstring text = env->NewStringUTF(notification->text);
197    jstring extras = env->NewStringUTF(notification->extras);
198
199    if (requestor_id && text && extras) {
200        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
201            notification->notification_id, notification->ni_type,
202            notification->notify_flags, notification->timeout,
203            notification->default_response, requestor_id, text,
204            notification->requestor_id_encoding,
205            notification->text_encoding, extras);
206    } else {
207        ALOGE("out of memory in gps_ni_notify_callback\n");
208    }
209
210    if (requestor_id)
211        env->DeleteLocalRef(requestor_id);
212    if (text)
213        env->DeleteLocalRef(text);
214    if (extras)
215        env->DeleteLocalRef(extras);
216    checkAndClearExceptionFromCallback(env, __FUNCTION__);
217}
218
219GpsNiCallbacks sGpsNiCallbacks = {
220    gps_ni_notify_callback,
221    create_thread_callback,
222};
223
224static void agps_request_set_id(uint32_t flags)
225{
226    JNIEnv* env = AndroidRuntime::getJNIEnv();
227    env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
228    checkAndClearExceptionFromCallback(env, __FUNCTION__);
229}
230
231static void agps_request_ref_location(uint32_t flags)
232{
233    JNIEnv* env = AndroidRuntime::getJNIEnv();
234    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
235    checkAndClearExceptionFromCallback(env, __FUNCTION__);
236}
237
238AGpsRilCallbacks sAGpsRilCallbacks = {
239    agps_request_set_id,
240    agps_request_ref_location,
241    create_thread_callback,
242};
243
244static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
245        int32_t transition, GpsUtcTime timestamp)
246{
247    JNIEnv* env = AndroidRuntime::getJNIEnv();
248
249    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
250            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
251            (jdouble)location->altitude,
252            (jfloat)location->speed, (jfloat)location->bearing,
253            (jfloat)location->accuracy, (jlong)location->timestamp,
254            transition, timestamp);
255    checkAndClearExceptionFromCallback(env, __FUNCTION__);
256};
257
258static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
259{
260    JNIEnv* env = AndroidRuntime::getJNIEnv();
261    jint flags = 0;
262    jdouble latitude = 0;
263    jdouble longitude = 0;
264    jdouble altitude = 0;
265    jfloat speed = 0;
266    jfloat bearing = 0;
267    jfloat accuracy = 0;
268    jlong timestamp = 0;
269    if (location != NULL) {
270        flags = location->flags;
271        latitude = location->latitude;
272        longitude = location->longitude;
273        altitude = location->altitude;
274        speed = location->speed;
275        bearing = location->bearing;
276        accuracy = location->accuracy;
277        timestamp = location->timestamp;
278    }
279
280    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
281            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
282    checkAndClearExceptionFromCallback(env, __FUNCTION__);
283};
284
285static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
286{
287    JNIEnv* env = AndroidRuntime::getJNIEnv();
288    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
289        ALOGE("Error in geofence_add_callback: %d\n", status);
290    }
291    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
292    checkAndClearExceptionFromCallback(env, __FUNCTION__);
293};
294
295static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
296{
297    JNIEnv* env = AndroidRuntime::getJNIEnv();
298    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
299        ALOGE("Error in geofence_remove_callback: %d\n", status);
300    }
301    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
302    checkAndClearExceptionFromCallback(env, __FUNCTION__);
303};
304
305static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
306{
307    JNIEnv* env = AndroidRuntime::getJNIEnv();
308    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
309        ALOGE("Error in geofence_resume_callback: %d\n", status);
310    }
311    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
312    checkAndClearExceptionFromCallback(env, __FUNCTION__);
313};
314
315static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
316{
317    JNIEnv* env = AndroidRuntime::getJNIEnv();
318    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
319        ALOGE("Error in geofence_pause_callback: %d\n", status);
320    }
321    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
322    checkAndClearExceptionFromCallback(env, __FUNCTION__);
323};
324
325GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
326    gps_geofence_transition_callback,
327    gps_geofence_status_callback,
328    gps_geofence_add_callback,
329    gps_geofence_remove_callback,
330    gps_geofence_pause_callback,
331    gps_geofence_resume_callback,
332    create_thread_callback,
333};
334
335static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
336    int err;
337    hw_module_t* module;
338
339    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
340    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
341    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
342    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
343    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
344    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
345    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
346    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
347            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
348    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
349    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
350    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
351    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
352            "(IIDDDFFFJIJ)V");
353    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
354            "(IIDDDFFFJ)V");
355    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
356            "(II)V");
357    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
358            "(II)V");
359    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
360            "(II)V");
361    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
362            "(II)V");
363
364    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
365    if (err == 0) {
366        hw_device_t* device;
367        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
368        if (err == 0) {
369            gps_device_t* gps_device = (gps_device_t *)device;
370            sGpsInterface = gps_device->get_gps_interface(gps_device);
371        }
372    }
373    if (sGpsInterface) {
374        sGpsXtraInterface =
375            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
376        sAGpsInterface =
377            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
378        sGpsNiInterface =
379            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
380        sGpsDebugInterface =
381            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
382        sAGpsRilInterface =
383            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
384        sGpsGeofencingInterface =
385            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
386    }
387}
388
389static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
390    return (sGpsInterface != NULL);
391}
392
393static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
394{
395    // this must be set before calling into the HAL library
396    if (!mCallbacksObj)
397        mCallbacksObj = env->NewGlobalRef(obj);
398
399    // fail if the main interface fails to initialize
400    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
401        return false;
402
403    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
404    // but continue to allow the rest of the GPS interface to work.
405    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
406        sGpsXtraInterface = NULL;
407    if (sAGpsInterface)
408        sAGpsInterface->init(&sAGpsCallbacks);
409    if (sGpsNiInterface)
410        sGpsNiInterface->init(&sGpsNiCallbacks);
411    if (sAGpsRilInterface)
412        sAGpsRilInterface->init(&sAGpsRilCallbacks);
413    if (sGpsGeofencingInterface)
414        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
415
416    return true;
417}
418
419static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
420{
421    if (sGpsInterface)
422        sGpsInterface->cleanup();
423}
424
425static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
426        jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
427{
428    if (sGpsInterface)
429        return (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
430                preferred_time) == 0);
431    else
432        return false;
433}
434
435static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
436{
437    if (sGpsInterface)
438        return (sGpsInterface->start() == 0);
439    else
440        return false;
441}
442
443static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
444{
445    if (sGpsInterface)
446        return (sGpsInterface->stop() == 0);
447    else
448        return false;
449}
450
451static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
452{
453    if (sGpsInterface)
454        sGpsInterface->delete_aiding_data(flags);
455}
456
457static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
458        jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
459        jintArray maskArray)
460{
461    // this should only be called from within a call to reportSvStatus
462
463    jint* prns = env->GetIntArrayElements(prnArray, 0);
464    jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
465    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
466    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
467    jint* mask = env->GetIntArrayElements(maskArray, 0);
468
469    int num_svs = sGpsSvStatus.num_svs;
470    for (int i = 0; i < num_svs; i++) {
471        prns[i] = sGpsSvStatus.sv_list[i].prn;
472        snrs[i] = sGpsSvStatus.sv_list[i].snr;
473        elev[i] = sGpsSvStatus.sv_list[i].elevation;
474        azim[i] = sGpsSvStatus.sv_list[i].azimuth;
475    }
476    mask[0] = sGpsSvStatus.ephemeris_mask;
477    mask[1] = sGpsSvStatus.almanac_mask;
478    mask[2] = sGpsSvStatus.used_in_fix_mask;
479
480    env->ReleaseIntArrayElements(prnArray, prns, 0);
481    env->ReleaseFloatArrayElements(snrArray, snrs, 0);
482    env->ReleaseFloatArrayElements(elevArray, elev, 0);
483    env->ReleaseFloatArrayElements(azumArray, azim, 0);
484    env->ReleaseIntArrayElements(maskArray, mask, 0);
485    return num_svs;
486}
487
488static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env,
489        jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
490{
491    AGpsRefLocation location;
492
493    if (!sAGpsRilInterface) {
494        ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
495        return;
496    }
497
498    switch(type) {
499        case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
500        case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
501            location.type = type;
502            location.u.cellID.mcc = mcc;
503            location.u.cellID.mnc = mnc;
504            location.u.cellID.lac = lac;
505            location.u.cellID.cid = cid;
506            break;
507        default:
508            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
509            return;
510            break;
511    }
512    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
513}
514
515static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
516        jobject obj, jbyteArray ni_msg, jint size)
517{
518    size_t sz;
519
520    if (!sAGpsRilInterface) {
521        ALOGE("no AGPS RIL interface in send_ni_message");
522        return;
523    }
524    if (size < 0)
525        return;
526    sz = (size_t)size;
527    jbyte* b = env->GetByteArrayElements(ni_msg, 0);
528    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
529    env->ReleaseByteArrayElements(ni_msg,b,0);
530}
531
532static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
533        jobject obj, jint type, jstring  setid_string)
534{
535    if (!sAGpsRilInterface) {
536        ALOGE("no AGPS RIL interface in agps_set_id");
537        return;
538    }
539
540    const char *setid = env->GetStringUTFChars(setid_string, NULL);
541    sAGpsRilInterface->set_set_id(type, setid);
542    env->ReleaseStringUTFChars(setid_string, setid);
543}
544
545static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
546                                            jbyteArray nmeaArray, jint buffer_size)
547{
548    // this should only be called from within a call to reportNmea
549    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
550    int length = sNmeaStringLength;
551    if (length > buffer_size)
552        length = buffer_size;
553    memcpy(nmea, sNmeaString, length);
554    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
555    return length;
556}
557
558static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
559        jlong time, jlong timeReference, jint uncertainty)
560{
561    if (sGpsInterface)
562        sGpsInterface->inject_time(time, timeReference, uncertainty);
563}
564
565static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
566        jdouble latitude, jdouble longitude, jfloat accuracy)
567{
568    if (sGpsInterface)
569        sGpsInterface->inject_location(latitude, longitude, accuracy);
570}
571
572static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
573{
574    return (sGpsXtraInterface != NULL);
575}
576
577static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
578        jbyteArray data, jint length)
579{
580    if (!sGpsXtraInterface) {
581        ALOGE("no XTRA interface in inject_xtra_data");
582        return;
583    }
584
585    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
586    sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
587    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
588}
589
590static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
591{
592    if (!sAGpsInterface) {
593        ALOGE("no AGPS interface in agps_data_conn_open");
594        return;
595    }
596    if (apn == NULL) {
597        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
598        return;
599    }
600    const char *apnStr = env->GetStringUTFChars(apn, NULL);
601    sAGpsInterface->data_conn_open(apnStr);
602    env->ReleaseStringUTFChars(apn, apnStr);
603}
604
605static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
606{
607    if (!sAGpsInterface) {
608        ALOGE("no AGPS interface in agps_data_conn_closed");
609        return;
610    }
611    sAGpsInterface->data_conn_closed();
612}
613
614static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
615{
616    if (!sAGpsInterface) {
617        ALOGE("no AGPS interface in agps_data_conn_failed");
618        return;
619    }
620    sAGpsInterface->data_conn_failed();
621}
622
623static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
624        jint type, jstring hostname, jint port)
625{
626    if (!sAGpsInterface) {
627        ALOGE("no AGPS interface in set_agps_server");
628        return;
629    }
630    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
631    sAGpsInterface->set_server(type, c_hostname, port);
632    env->ReleaseStringUTFChars(hostname, c_hostname);
633}
634
635static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
636      jint notifId, jint response)
637{
638    if (!sGpsNiInterface) {
639        ALOGE("no NI interface in send_ni_response");
640        return;
641    }
642
643    sGpsNiInterface->respond(notifId, response);
644}
645
646static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
647{
648    jstring result = NULL;
649    if (sGpsDebugInterface) {
650        const size_t maxLength = 2047;
651        char buffer[maxLength+1];
652        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
653        if (length > maxLength) length = maxLength;
654        buffer[length] = 0;
655        result = env->NewStringUTF(buffer);
656    }
657    return result;
658}
659
660static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
661        jboolean connected, int type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
662{
663
664    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
665        if (extraInfo) {
666            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
667            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
668            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
669        } else {
670            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
671        }
672
673        // update_network_availability callback was not included in original AGpsRilInterface
674        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
675                && sAGpsRilInterface->update_network_availability) {
676            const char *c_apn = env->GetStringUTFChars(apn, NULL);
677            sAGpsRilInterface->update_network_availability(available, c_apn);
678            env->ReleaseStringUTFChars(apn, c_apn);
679        }
680    }
681}
682
683static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* env,
684          jobject obj) {
685    if (sGpsGeofencingInterface != NULL) {
686        return JNI_TRUE;
687    }
688    return JNI_FALSE;
689}
690
691static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* env, jobject obj,
692        jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
693        jint last_transition, jint monitor_transition, jint notification_responsiveness,
694        jint unknown_timer) {
695    if (sGpsGeofencingInterface != NULL) {
696        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
697                radius, last_transition, monitor_transition, notification_responsiveness,
698                unknown_timer);
699        return JNI_TRUE;
700    } else {
701        ALOGE("Geofence interface not available");
702    }
703    return JNI_FALSE;
704}
705
706static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* env, jobject obj,
707        jint geofence_id) {
708    if (sGpsGeofencingInterface != NULL) {
709        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
710        return JNI_TRUE;
711    } else {
712        ALOGE("Geofence interface not available");
713    }
714    return JNI_FALSE;
715}
716
717static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* env, jobject obj,
718        jint geofence_id) {
719    if (sGpsGeofencingInterface != NULL) {
720        sGpsGeofencingInterface->pause_geofence(geofence_id);
721        return JNI_TRUE;
722    } else {
723        ALOGE("Geofence interface not available");
724    }
725    return JNI_FALSE;
726}
727
728static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env, jobject obj,
729        jint geofence_id, jint monitor_transition) {
730    if (sGpsGeofencingInterface != NULL) {
731        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
732        return JNI_TRUE;
733    } else {
734        ALOGE("Geofence interface not available");
735    }
736    return JNI_FALSE;
737}
738
739static JNINativeMethod sMethods[] = {
740     /* name, signature, funcPtr */
741    {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
742    {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
743    {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
744    {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
745    {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
746    {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
747    {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
748    {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
749    {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
750    {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
751    {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
752    {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
753    {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
754    {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
755    {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
756    {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
757    {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
758    {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
759    {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
760    {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
761    {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
762    {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
763    {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
764    {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
765    {"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
766    {"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
767    {"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
768    {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
769    {"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
770};
771
772int register_android_server_location_GpsLocationProvider(JNIEnv* env)
773{
774    return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
775}
776
777} /* namespace android */
778