blob: 004b0e3ea07ebf68499755b0177f97dd80661a33 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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#include "JNIHelp.h"
20#include "jni.h"
21#include "hardware_legacy/gps.h"
22#include "utils/Log.h"
23#include "utils/misc.h"
24
25#include <string.h>
26#include <pthread.h>
27
28
29static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
30static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
31static jmethodID method_reportLocation;
32static jmethodID method_reportStatus;
33static jmethodID method_reportSvStatus;
Mike Lockwoode3635c92009-05-11 08:38:02 -040034static jmethodID method_reportAGpsStatus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035static jmethodID method_xtraDownloadRequest;
36
37static const GpsInterface* sGpsInterface = NULL;
38static const GpsXtraInterface* sGpsXtraInterface = NULL;
Mike Lockwoode3635c92009-05-11 08:38:02 -040039static const AGpsInterface* sAGpsInterface = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41// data written to by GPS callbacks
42static GpsLocation sGpsLocation;
43static GpsStatus sGpsStatus;
44static GpsSvStatus sGpsSvStatus;
Mike Lockwoode3635c92009-05-11 08:38:02 -040045static AGpsStatus sAGpsStatus;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
48// and android_location_GpsLocationProvider_read_status
49static GpsLocation sGpsLocationCopy;
50static GpsStatus sGpsStatusCopy;
51static GpsSvStatus sGpsSvStatusCopy;
Mike Lockwoode3635c92009-05-11 08:38:02 -040052static AGpsStatus sAGpsStatusCopy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54enum CallbackType {
55 kLocation = 1,
56 kStatus = 2,
57 kSvStatus = 4,
Mike Lockwoode3635c92009-05-11 08:38:02 -040058 kAGpsStatus = 8,
Mike Lockwood58bda982009-04-14 16:25:07 -040059 kXtraDownloadRequest = 16,
60 kDisableRequest = 32,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061};
62static int sPendingCallbacks;
63
64namespace android {
65
66static void location_callback(GpsLocation* location)
67{
68 pthread_mutex_lock(&sEventMutex);
69
70 sPendingCallbacks |= kLocation;
71 memcpy(&sGpsLocation, location, sizeof(sGpsLocation));
72
73 pthread_cond_signal(&sEventCond);
74 pthread_mutex_unlock(&sEventMutex);
75}
76
77static void status_callback(GpsStatus* status)
78{
79 pthread_mutex_lock(&sEventMutex);
80
81 sPendingCallbacks |= kStatus;
82 memcpy(&sGpsStatus, status, sizeof(sGpsStatus));
83
84 pthread_cond_signal(&sEventCond);
85 pthread_mutex_unlock(&sEventMutex);
86}
87
88static void sv_status_callback(GpsSvStatus* sv_status)
89{
90 pthread_mutex_lock(&sEventMutex);
91
92 sPendingCallbacks |= kSvStatus;
93 memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus));
94
95 pthread_cond_signal(&sEventCond);
96 pthread_mutex_unlock(&sEventMutex);
97}
98
Mike Lockwoode3635c92009-05-11 08:38:02 -040099static void agps_status_callback(AGpsStatus* agps_status)
Mike Lockwood58bda982009-04-14 16:25:07 -0400100{
101 pthread_mutex_lock(&sEventMutex);
102
Mike Lockwoode3635c92009-05-11 08:38:02 -0400103 sPendingCallbacks |= kAGpsStatus;
104 memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus));
Mike Lockwood58bda982009-04-14 16:25:07 -0400105
106 pthread_cond_signal(&sEventCond);
107 pthread_mutex_unlock(&sEventMutex);
108}
109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110GpsCallbacks sGpsCallbacks = {
111 location_callback,
112 status_callback,
113 sv_status_callback,
114};
115
116static void
117download_request_callback()
118{
119 pthread_mutex_lock(&sEventMutex);
120 sPendingCallbacks |= kXtraDownloadRequest;
121 pthread_cond_signal(&sEventCond);
122 pthread_mutex_unlock(&sEventMutex);
123}
124
125GpsXtraCallbacks sGpsXtraCallbacks = {
126 download_request_callback,
127};
128
Mike Lockwoode3635c92009-05-11 08:38:02 -0400129AGpsCallbacks sAGpsCallbacks = {
130 agps_status_callback,
Mike Lockwood58bda982009-04-14 16:25:07 -0400131};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
133static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
134 method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
135 method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
136 method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
Mike Lockwoode3635c92009-05-11 08:38:02 -0400137 method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
139}
140
141static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
142 if (!sGpsInterface)
143 sGpsInterface = gps_get_interface();
144 return (sGpsInterface != NULL);
145}
146
147static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
148{
149 if (!sGpsInterface)
150 sGpsInterface = gps_get_interface();
Mike Lockwood58bda982009-04-14 16:25:07 -0400151 if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
152 return false;
153
Mike Lockwoode3635c92009-05-11 08:38:02 -0400154 if (!sAGpsInterface)
155 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
156 if (sAGpsInterface)
157 sAGpsInterface->init(&sAGpsCallbacks);
Mike Lockwoodc21a08f2009-04-30 15:16:39 -0400158 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159}
160
161static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
162{
163 pthread_mutex_lock(&sEventMutex);
164 sPendingCallbacks |= kDisableRequest;
165 pthread_cond_signal(&sEventCond);
166 pthread_mutex_unlock(&sEventMutex);
167}
168
169static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
170{
171 sGpsInterface->cleanup();
172}
173
The Android Open Source Project10592532009-03-18 17:39:46 -0700174static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
175 jboolean singleFix, jint fixFrequency)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176{
The Android Open Source Project10592532009-03-18 17:39:46 -0700177 int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 if (result) {
179 return result;
180 }
181
182 return (sGpsInterface->start() == 0);
183}
184
185static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
186{
187 return (sGpsInterface->stop() == 0);
188}
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
191{
192 sGpsInterface->delete_aiding_data(flags);
193}
194
195static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
196{
197 pthread_mutex_lock(&sEventMutex);
198 pthread_cond_wait(&sEventCond, &sEventMutex);
199
200 // copy and clear the callback flags
201 int pendingCallbacks = sPendingCallbacks;
202 sPendingCallbacks = 0;
203
204 // copy everything and unlock the mutex before calling into Java code to avoid the possibility
205 // of timeouts in the GPS engine.
206 memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
207 memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
208 memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
Mike Lockwoode3635c92009-05-11 08:38:02 -0400209 memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 pthread_mutex_unlock(&sEventMutex);
211
212 if (pendingCallbacks & kLocation) {
213 env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
214 (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
215 (jdouble)sGpsLocationCopy.altitude,
216 (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
217 (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
218 }
219 if (pendingCallbacks & kStatus) {
220 env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
221 }
222 if (pendingCallbacks & kSvStatus) {
223 env->CallVoidMethod(obj, method_reportSvStatus);
224 }
Mike Lockwoode3635c92009-05-11 08:38:02 -0400225 if (pendingCallbacks & kAGpsStatus) {
226 env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
Mike Lockwood58bda982009-04-14 16:25:07 -0400227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 if (pendingCallbacks & kXtraDownloadRequest) {
229 env->CallVoidMethod(obj, method_xtraDownloadRequest);
230 }
231 if (pendingCallbacks & kDisableRequest) {
232 // don't need to do anything - we are just poking so wait_for_event will return.
233 }
234}
235
236static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
237 jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
238 jintArray maskArray)
239{
240 // this should only be called from within a call to reportStatus, so we don't need to lock here
241
242 jint* prns = env->GetIntArrayElements(prnArray, 0);
243 jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
244 jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
245 jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
246 jint* mask = env->GetIntArrayElements(maskArray, 0);
247
248 int num_svs = sGpsSvStatusCopy.num_svs;
249 for (int i = 0; i < num_svs; i++) {
250 prns[i] = sGpsSvStatusCopy.sv_list[i].prn;
251 snrs[i] = sGpsSvStatusCopy.sv_list[i].snr;
252 elev[i] = sGpsSvStatusCopy.sv_list[i].elevation;
253 azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth;
254 }
255 mask[0] = sGpsSvStatusCopy.ephemeris_mask;
256 mask[1] = sGpsSvStatusCopy.almanac_mask;
257 mask[2] = sGpsSvStatusCopy.used_in_fix_mask;
258
259 env->ReleaseIntArrayElements(prnArray, prns, 0);
260 env->ReleaseFloatArrayElements(snrArray, snrs, 0);
261 env->ReleaseFloatArrayElements(elevArray, elev, 0);
262 env->ReleaseFloatArrayElements(azumArray, azim, 0);
263 env->ReleaseIntArrayElements(maskArray, mask, 0);
264 return num_svs;
265}
266
267static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
268 jlong timeReference, jint uncertainty)
269{
270 sGpsInterface->inject_time(time, timeReference, uncertainty);
271}
272
273static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
274{
275 if (!sGpsXtraInterface) {
276 sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
277 if (sGpsXtraInterface) {
278 int result = sGpsXtraInterface->init(&sGpsXtraCallbacks);
279 if (result) {
280 sGpsXtraInterface = NULL;
281 }
282 }
283 }
284
285 return (sGpsXtraInterface != NULL);
286}
287
288static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
289 jbyteArray data, jint length)
290{
291 jbyte* bytes = env->GetByteArrayElements(data, 0);
292 sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
293 env->ReleaseByteArrayElements(data, bytes, 0);
294}
295
Mike Lockwoode3635c92009-05-11 08:38:02 -0400296static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
The Android Open Source Project10592532009-03-18 17:39:46 -0700297{
Mike Lockwoode3635c92009-05-11 08:38:02 -0400298 if (!sAGpsInterface) {
299 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
The Android Open Source Project10592532009-03-18 17:39:46 -0700300 }
Mike Lockwoode3635c92009-05-11 08:38:02 -0400301 if (sAGpsInterface) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700302 if (apn == NULL) {
303 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
304 return;
305 }
306 const char *apnStr = env->GetStringUTFChars(apn, NULL);
Mike Lockwoode3635c92009-05-11 08:38:02 -0400307 sAGpsInterface->data_conn_open(apnStr);
The Android Open Source Project10592532009-03-18 17:39:46 -0700308 env->ReleaseStringUTFChars(apn, apnStr);
309 }
310}
311
Mike Lockwoode3635c92009-05-11 08:38:02 -0400312static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
Mike Lockwood58bda982009-04-14 16:25:07 -0400313{
Mike Lockwoode3635c92009-05-11 08:38:02 -0400314 if (!sAGpsInterface) {
315 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
Mike Lockwood58bda982009-04-14 16:25:07 -0400316 }
Mike Lockwoode3635c92009-05-11 08:38:02 -0400317 if (sAGpsInterface) {
318 sAGpsInterface->data_conn_closed();
Mike Lockwood58bda982009-04-14 16:25:07 -0400319 }
320}
321
Mike Lockwoode3635c92009-05-11 08:38:02 -0400322static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
Mike Lockwood58bda982009-04-14 16:25:07 -0400323{
Mike Lockwoode3635c92009-05-11 08:38:02 -0400324 if (!sAGpsInterface) {
325 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
Mike Lockwood58bda982009-04-14 16:25:07 -0400326 }
Mike Lockwoode3635c92009-05-11 08:38:02 -0400327 if (sAGpsInterface) {
328 sAGpsInterface->data_conn_failed();
Mike Lockwood58bda982009-04-14 16:25:07 -0400329 }
330}
331
Mike Lockwoode3635c92009-05-11 08:38:02 -0400332static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
333 jint type, jint addr, jint port)
Mike Lockwood58bda982009-04-14 16:25:07 -0400334{
Mike Lockwoode3635c92009-05-11 08:38:02 -0400335 if (!sAGpsInterface) {
336 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
Mike Lockwood58bda982009-04-14 16:25:07 -0400337 }
Mike Lockwoode3635c92009-05-11 08:38:02 -0400338 if (sAGpsInterface) {
339 sAGpsInterface->set_server(type, addr, port);
Mike Lockwood58bda982009-04-14 16:25:07 -0400340 }
341}
342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343static JNINativeMethod sMethods[] = {
344 /* name, signature, funcPtr */
345 {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
Mike Lockwoode3635c92009-05-11 08:38:02 -0400346 {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
347 {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
348 {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
349 {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
350 {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start},
351 {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
352 {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
353 {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
354 {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
355 {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
356 {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
357 {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
358 {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
359 {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
360 {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
361 {"native_set_agps_server", "(III)V", (void*)android_location_GpsLocationProvider_set_agps_server},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362};
363
364int register_android_location_GpsLocationProvider(JNIEnv* env)
365{
366 return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods));
367}
368
369} /* namespace android */