OSDN Git Service

disables hardware acceleration if debug.egl.hw=0
[android-x86/frameworks-base.git] / services / jni / com_android_server_location_GpsLocationProvider.cpp
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
34 static jobject mCallbacksObj = NULL;
35
36 static jmethodID method_reportLocation;
37 static jmethodID method_reportStatus;
38 static jmethodID method_reportSvStatus;
39 static jmethodID method_reportAGpsStatus;
40 static jmethodID method_reportNmea;
41 static jmethodID method_setEngineCapabilities;
42 static jmethodID method_xtraDownloadRequest;
43 static jmethodID method_reportNiNotification;
44 static jmethodID method_requestRefLocation;
45 static jmethodID method_requestSetID;
46 static jmethodID method_requestUtcTime;
47 static jmethodID method_reportGeofenceTransition;
48 static jmethodID method_reportGeofenceStatus;
49 static jmethodID method_reportGeofenceAddStatus;
50 static jmethodID method_reportGeofenceRemoveStatus;
51 static jmethodID method_reportGeofencePauseStatus;
52 static jmethodID method_reportGeofenceResumeStatus;
53
54 static const GpsInterface* sGpsInterface = NULL;
55 static const GpsXtraInterface* sGpsXtraInterface = NULL;
56 static const AGpsInterface* sAGpsInterface = NULL;
57 static const GpsNiInterface* sGpsNiInterface = NULL;
58 static const GpsDebugInterface* sGpsDebugInterface = NULL;
59 static const AGpsRilInterface* sAGpsRilInterface = NULL;
60 static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
61
62 // temporary storage for GPS callbacks
63 static GpsSvStatus  sGpsSvStatus;
64 static const char* sNmeaString;
65 static int sNmeaStringLength;
66
67 #define WAKE_LOCK_NAME  "GPS"
68
69 namespace android {
70
71 static 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
79 static 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
90 static 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
97 static 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
105 static 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
116 static 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
124 static void acquire_wakelock_callback()
125 {
126     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
127 }
128
129 static void release_wakelock_callback()
130 {
131     release_wake_lock(WAKE_LOCK_NAME);
132 }
133
134 static void request_utc_time_callback()
135 {
136     JNIEnv* env = AndroidRuntime::getJNIEnv();
137     env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
138     checkAndClearExceptionFromCallback(env, __FUNCTION__);
139 }
140
141 static 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
146 GpsCallbacks 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
159 static void xtra_download_request_callback()
160 {
161     JNIEnv* env = AndroidRuntime::getJNIEnv();
162     env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
163     checkAndClearExceptionFromCallback(env, __FUNCTION__);
164 }
165
166 GpsXtraCallbacks sGpsXtraCallbacks = {
167     xtra_download_request_callback,
168     create_thread_callback,
169 };
170
171 static 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
186 AGpsCallbacks sAGpsCallbacks = {
187     agps_status_callback,
188     create_thread_callback,
189 };
190
191 static 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
219 GpsNiCallbacks sGpsNiCallbacks = {
220     gps_ni_notify_callback,
221     create_thread_callback,
222 };
223
224 static 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
231 static 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
238 AGpsRilCallbacks sAGpsRilCallbacks = {
239     agps_request_set_id,
240     agps_request_ref_location,
241     create_thread_callback,
242 };
243
244 static 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
258 static 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
285 static 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
295 static 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
305 static 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
315 static 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
325 GpsGeofenceCallbacks 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
335 static 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
389 static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
390     return (sGpsInterface != NULL);
391 }
392
393 static 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
419 static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
420 {
421     if (sGpsInterface)
422         sGpsInterface->cleanup();
423 }
424
425 static 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
435 static 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
443 static 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
451 static 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
457 static 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
488 static 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
515 static 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
532 static 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
545 static 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
558 static 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
565 static 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
572 static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
573 {
574     return (sGpsXtraInterface != NULL);
575 }
576
577 static 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
590 static 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
605 static 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
614 static 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
623 static 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
635 static 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
646 static 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
660 static 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
683 static 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
691 static 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
706 static 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
717 static 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
728 static 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
739 static 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
772 int 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 */