blob: c8718281b139e45f4475b7c1cc5bae70e0399a46 [file] [log] [blame]
destradaa1af4b022013-07-12 15:43:36 -07001/*
2 * Copyright (C) 2013 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/license/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 "FuseLocationProvider"
18#define LOG_NDEBUG 0
19
20#define WAKE_LOCK_NAME "FLP"
21#define LOCATION_CLASS_NAME "android/location/Location"
22
23#include "jni.h"
24#include "JNIHelp.h"
25#include "android_runtime/AndroidRuntime.h"
26#include "hardware/fused_location.h"
27#include "hardware_legacy/power.h"
28
29static jobject sCallbacksObj = NULL;
30static JNIEnv *sCallbackEnv = NULL;
31static hw_device_t* sHardwareDevice = NULL;
32
33static jmethodID sOnLocationReport = NULL;
34static jmethodID sOnDataReport = NULL;
35static jmethodID sOnGeofenceTransition = NULL;
36static jmethodID sOnGeofenceMonitorStatus = NULL;
37static jmethodID sOnGeofenceAdd = NULL;
38static jmethodID sOnGeofenceRemove = NULL;
39static jmethodID sOnGeofencePause = NULL;
40static jmethodID sOnGeofenceResume = NULL;
41
42static const FlpLocationInterface* sFlpInterface = NULL;
43static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
44static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
45static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
46
47namespace android {
48
49static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
50 if(!env->ExceptionCheck()) {
51 return;
52 }
53
54 ALOGE("An exception was thrown by '%s'.", methodName);
55 LOGE_EX(env);
56 env->ExceptionClear();
57}
58
59static inline void ThrowOnError(
60 JNIEnv* env,
61 int resultCode,
62 const char* methodName) {
63 if(resultCode == FLP_RESULT_SUCCESS) {
64 return;
65 }
66
67 ALOGE("Error %d in '%s'", resultCode, methodName);
68 jclass exceptionClass = env->FindClass("java/lang/RuntimeException");
69 env->ThrowNew(exceptionClass, methodName);
70}
71
72static bool IsValidCallbackThread() {
73 JNIEnv* env = AndroidRuntime::getJNIEnv();
74
75 if(sCallbackEnv == NULL || sCallbackEnv != env) {
76 ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv);
77 return false;
78 }
79
80 return true;
81}
82
83static int SetThreadEvent(ThreadEvent event) {
84 JavaVM* javaVm = AndroidRuntime::getJavaVM();
85
86 switch(event) {
87 case ASSOCIATE_JVM:
88 {
89 if(sCallbackEnv != NULL) {
90 ALOGE(
91 "Attempted to associate callback in '%s'. Callback already associated.",
92 __FUNCTION__
93 );
94 return FLP_RESULT_ERROR;
95 }
96
97 JavaVMAttachArgs args = {
98 JNI_VERSION_1_6,
99 "FLP Service Callback Thread",
100 /* group */ NULL
101 };
102
103 jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
104 if (attachResult != 0) {
105 ALOGE("Callback thread attachment error: %d", attachResult);
106 return FLP_RESULT_ERROR;
107 }
108
109 ALOGV("Callback thread attached: %p", sCallbackEnv);
110 break;
111 }
112 case DISASSOCIATE_JVM:
113 {
114 if (!IsValidCallbackThread()) {
115 ALOGE(
116 "Attempted to dissasociate an unnownk callback thread : '%s'.",
117 __FUNCTION__
118 );
119 return FLP_RESULT_ERROR;
120 }
121
122 if (javaVm->DetachCurrentThread() != 0) {
123 return FLP_RESULT_ERROR;
124 }
125
126 sCallbackEnv = NULL;
127 break;
128 }
129 default:
130 ALOGE("Invalid ThreadEvent request %d", event);
131 return FLP_RESULT_ERROR;
132 }
133
134 return FLP_RESULT_SUCCESS;
135}
136
137/*
138 * Initializes the FlpHardwareProvider class from the native side by opening
139 * the HW module and obtaining the proper interfaces.
140 */
141static void ClassInit(JNIEnv* env, jclass clazz) {
142 // get references to the Java provider methods
143 sOnLocationReport = env->GetMethodID(
144 clazz,
145 "onLocationReport",
146 "([Landroid/location/Location;)V");
147 sOnDataReport = env->GetMethodID(
148 clazz,
149 "onDataReport",
150 "(Ljava/lang/String;)V"
151 );
152 sOnGeofenceTransition = env->GetMethodID(
153 clazz,
154 "onGeofenceTransition",
155 "(ILandroid/location/Location;IJI)V"
156 );
157 sOnGeofenceMonitorStatus = env->GetMethodID(
158 clazz,
159 "onGeofenceMonitorStatus",
160 "(IILandroid/location/Location;)V"
161 );
162 sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
163 sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
164 sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
165 sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
166}
167
168/*
169 * Helper function to unwrap a java object back into a FlpLocation structure.
170 */
171static void TranslateFromObject(
172 JNIEnv* env,
173 jobject locationObject,
174 FlpLocation& location) {
175 location.size = sizeof(FlpLocation);
176 location.flags = 0;
177
178 jclass locationClass = env->GetObjectClass(locationObject);
179
180 jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
181 location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
182 jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
183 location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
184 jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
185 location.timestamp = env->CallLongMethod(locationObject, getTime);
186 location.flags |= FLP_LOCATION_HAS_LAT_LONG;
187
188 jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
189 if (env->CallBooleanMethod(locationObject, hasAltitude)) {
190 jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
191 location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
192 location.flags |= FLP_LOCATION_HAS_ALTITUDE;
193 }
194
195 jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
196 if (env->CallBooleanMethod(locationObject, hasSpeed)) {
197 jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
198 location.speed = env->CallFloatMethod(locationObject, getSpeed);
199 location.flags |= FLP_LOCATION_HAS_SPEED;
200 }
201
202 jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
203 if (env->CallBooleanMethod(locationObject, hasBearing)) {
204 jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
205 location.bearing = env->CallFloatMethod(locationObject, getBearing);
206 location.flags |= FLP_LOCATION_HAS_BEARING;
207 }
208
209 jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
210 if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
211 jmethodID getAccuracy = env->GetMethodID(
212 locationClass,
213 "getAccuracy",
214 "()F"
215 );
216 location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
217 location.flags |= FLP_LOCATION_HAS_ACCURACY;
218 }
219
220 // TODO: wire sources_used if Location class exposes them
221}
222
223/*
224 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
225 */
226static void TranslateFromObject(
227 JNIEnv* env,
228 jobject batchOptionsObject,
229 FlpBatchOptions& batchOptions) {
230 jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
231
232 jmethodID getMaxPower = env->GetMethodID(
233 batchOptionsClass,
234 "getMaxPowerAllocationInMW",
235 "()D"
236 );
237 batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
238 batchOptionsObject,
239 getMaxPower
240 );
241
242 jmethodID getPeriod = env->GetMethodID(
243 batchOptionsClass,
244 "getPeriodInNS",
245 "()J"
246 );
247 batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
248
249 jmethodID getSourcesToUse = env->GetMethodID(
250 batchOptionsClass,
251 "getSourcesToUse",
252 "()I"
253 );
254 batchOptions.sources_to_use = env->CallIntMethod(
255 batchOptionsObject,
256 getSourcesToUse
257 );
258
259 jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
260 batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
261}
262
263/*
destradaa06828092013-08-12 18:50:30 -0700264 * Helper function to unwrap Geofence structures from the Java Runtime calls.
265 */
266static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
267 JNIEnv* env,
268 jobject geofenceRequestObject,
269 Geofence& geofence) {
270 jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
271
272 jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
273 geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
274
275 jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
276 // this works because GeofenceHardwareRequest.java and fused_location.h have
277 // the same notion of geofence types
278 GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
279 if(type != TYPE_CIRCLE) {
280 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
281 }
282 geofence.data->type = type;
283 GeofenceCircle& circle = geofence.data->geofence.circle;
284
285 jmethodID getLatitude = env->GetMethodID(
286 geofenceRequestClass,
287 "getLatitude",
288 "()D");
289 circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
290
291 jmethodID getLongitude = env->GetMethodID(
292 geofenceRequestClass,
293 "getLongitude",
294 "()D");
295 circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
296
297 jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
298 circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
299
300 GeofenceOptions* options = geofence.options;
301 jmethodID getMonitorTransitions = env->GetMethodID(
302 geofenceRequestClass,
303 "getMonitorTransitions",
304 "()I");
305 options->monitor_transitions = env->CallIntMethod(
306 geofenceRequestObject,
307 getMonitorTransitions);
308
309 jmethodID getUnknownTimer = env->GetMethodID(
310 geofenceRequestClass,
311 "getUnknownTimer",
312 "()I");
313 options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
314
315 jmethodID getNotificationResponsiveness = env->GetMethodID(
316 geofenceRequestClass,
317 "getNotificationResponsiveness",
318 "()D");
319 options->notification_responsivenes_ms = env->CallIntMethod(
320 geofenceRequestObject,
321 getNotificationResponsiveness);
322
323 jmethodID getLastTransition = env->GetMethodID(
324 geofenceRequestClass,
325 "getLastTransition",
326 "()I");
327 options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
328
329 // TODO: set data.sources_to_use when available
330}
331
332/*
destradaa1af4b022013-07-12 15:43:36 -0700333 * Helper function to transform FlpLocation into a java object.
334 */
335static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
336 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
337 jmethodID locationCtor = sCallbackEnv->GetMethodID(
338 locationClass,
339 "<init>",
340 "(Ljava/lang/String;)V"
341 );
342
343 // the provider is set in the upper JVM layer
344 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
345 jint flags = location->flags;
346
347 // set the valid information in the object
348 if (flags & FLP_LOCATION_HAS_LAT_LONG) {
349 jmethodID setLatitude = sCallbackEnv->GetMethodID(
350 locationClass,
351 "setLatitude",
352 "(D)V"
353 );
354 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
355
356 jmethodID setLongitude = sCallbackEnv->GetMethodID(
357 locationClass,
358 "setLongitude",
359 "(D)V"
360 );
361 sCallbackEnv->CallVoidMethod(
362 locationObject,
363 setLongitude,
364 location->longitude
365 );
366
367 jmethodID setTime = sCallbackEnv->GetMethodID(
368 locationClass,
369 "setTime",
370 "(J)V"
371 );
372 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
373 }
374
375 if (flags & FLP_LOCATION_HAS_ALTITUDE) {
376 jmethodID setAltitude = sCallbackEnv->GetMethodID(
377 locationClass,
378 "setAltitude",
379 "(D)V"
380 );
381 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
382 }
383
384 if (flags & FLP_LOCATION_HAS_SPEED) {
385 jmethodID setSpeed = sCallbackEnv->GetMethodID(
386 locationClass,
387 "setSpeed",
388 "(F)V"
389 );
390 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
391 }
392
393 if (flags & FLP_LOCATION_HAS_BEARING) {
394 jmethodID setBearing = sCallbackEnv->GetMethodID(
395 locationClass,
396 "setBearing",
397 "(F)V"
398 );
399 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
400 }
401
402 if (flags & FLP_LOCATION_HAS_ACCURACY) {
403 jmethodID setAccuracy = sCallbackEnv->GetMethodID(
404 locationClass,
405 "setAccuracy",
406 "(F)V"
407 );
408 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
409 }
410
411 // TODO: wire FlpLocation::sources_used when needed
412}
413
414/*
415 * Helper function to serialize FlpLocation structures.
416 */
417static void TranslateToObjectArray(
418 int32_t locationsCount,
419 FlpLocation** locations,
420 jobjectArray& locationsArray) {
421 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
422 locationsArray = sCallbackEnv->NewObjectArray(
423 locationsCount,
424 locationClass,
425 /* initialElement */ NULL
426 );
427
428 for (int i = 0; i < locationsCount; ++i) {
429 jobject locationObject = NULL;
430 TranslateToObject(locations[i], locationObject);
431 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
432 sCallbackEnv->DeleteLocalRef(locationObject);
433 }
434}
435
436static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
437 if(!IsValidCallbackThread()) {
438 return;
439 }
440
441 if(locationsCount == 0 || locations == NULL) {
442 ALOGE(
443 "Invalid LocationCallback. Count: %d, Locations: %p",
444 locationsCount,
445 locations
446 );
447 return;
448 }
449
450 jobjectArray locationsArray = NULL;
451 TranslateToObjectArray(locationsCount, locations, locationsArray);
452
453 sCallbackEnv->CallVoidMethod(
454 sCallbacksObj,
455 sOnLocationReport,
456 locationsArray
457 );
458 CheckExceptions(sCallbackEnv, __FUNCTION__);
459}
460
461static void AcquireWakelock() {
462 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
463}
464
465static void ReleaseWakelock() {
466 release_wake_lock(WAKE_LOCK_NAME);
467}
468
469FlpCallbacks sFlpCallbacks = {
470 sizeof(FlpCallbacks),
471 LocationCallback,
472 AcquireWakelock,
473 ReleaseWakelock,
474 SetThreadEvent
475};
476
477static void ReportData(char* data, int length) {
478 jstring stringData = NULL;
479
480 if(length != 0 && data != NULL) {
481 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
482 } else {
483 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
484 return;
485 }
486
487 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
488 CheckExceptions(sCallbackEnv, __FUNCTION__);
489}
490
491FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
492 sizeof(FlpDiagnosticCallbacks),
493 SetThreadEvent,
494 ReportData
495};
496
497static void GeofenceTransitionCallback(
498 int32_t geofenceId,
499 FlpLocation* location,
500 int32_t transition,
501 FlpUtcTime timestamp,
502 uint32_t sourcesUsed
503 ) {
504 if(!IsValidCallbackThread()) {
505 return;
506 }
507
508 if(location == NULL) {
509 ALOGE("GeofenceTransition received with invalid location: %p", location);
510 return;
511 }
512
513 jobject locationObject = NULL;
514 TranslateToObject(location, locationObject);
515
516 sCallbackEnv->CallVoidMethod(
517 sCallbacksObj,
518 sOnGeofenceTransition,
519 geofenceId,
520 locationObject,
521 transition,
522 timestamp,
523 sourcesUsed
524 );
525 CheckExceptions(sCallbackEnv, __FUNCTION__);
526}
527
528static void GeofenceMonitorStatusCallback(
529 int32_t status,
530 uint32_t source,
531 FlpLocation* lastLocation) {
532 if(!IsValidCallbackThread()) {
533 return;
534 }
535
536 jobject locationObject = NULL;
537 if(lastLocation != NULL) {
538 TranslateToObject(lastLocation, locationObject);
539 }
540
541 sCallbackEnv->CallVoidMethod(
542 sCallbacksObj,
543 sOnGeofenceMonitorStatus,
544 status,
545 source,
546 locationObject
547 );
548 CheckExceptions(sCallbackEnv, __FUNCTION__);
549}
550
551static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
552 if(!IsValidCallbackThread()) {
553 return;
554 }
555
556 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
557 CheckExceptions(sCallbackEnv, __FUNCTION__);
558}
559
560static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
561 if(!IsValidCallbackThread()) {
562 return;
563 }
564
565 sCallbackEnv->CallVoidMethod(
566 sCallbacksObj,
567 sOnGeofenceRemove,
568 geofenceId,
569 result
570 );
571 CheckExceptions(sCallbackEnv, __FUNCTION__);
572}
573
574static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
575 if(!IsValidCallbackThread()) {
576 return;
577 }
578
579 sCallbackEnv->CallVoidMethod(
580 sCallbacksObj,
581 sOnGeofencePause,
582 geofenceId,
583 result
584 );
585 CheckExceptions(sCallbackEnv, __FUNCTION__);
586}
587
588static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
589 if(!IsValidCallbackThread()) {
590 return;
591 }
592
593 sCallbackEnv->CallVoidMethod(
594 sCallbacksObj,
595 sOnGeofenceResume,
596 geofenceId,
597 result
598 );
599 CheckExceptions(sCallbackEnv, __FUNCTION__);
600}
601
602FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
603 sizeof(FlpGeofenceCallbacks),
604 GeofenceTransitionCallback,
605 GeofenceMonitorStatusCallback,
606 GeofenceAddCallback,
607 GeofenceRemoveCallback,
608 GeofencePauseCallback,
609 GeofenceResumeCallback,
610 SetThreadEvent
611};
612
613/*
614 * Initializes the Fused Location Provider in the native side. It ensures that
615 * the Flp interfaces are initialized properly.
616 */
617static void Init(JNIEnv* env, jobject obj) {
618 if(sHardwareDevice != NULL) {
619 ALOGD("Hardware Device already opened.");
620 return;
621 }
622
623 const hw_module_t* module = NULL;
624 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
625 if(err != 0) {
626 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
627 return;
628 }
629
630 err = module->methods->open(
destradaa06828092013-08-12 18:50:30 -0700631 module,
destradaa1af4b022013-07-12 15:43:36 -0700632 FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
633 if(err != 0) {
634 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
635 return;
636 }
637
638 sFlpInterface = NULL;
639 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
640 sFlpInterface = flp_device->get_flp_interface(flp_device);
641
642 if(sFlpInterface != NULL) {
643 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
644 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
645 );
646
647 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
648 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
649 );
650
651 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
652 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
653 );
654 }
655
656 if(sCallbacksObj == NULL) {
657 sCallbacksObj = env->NewGlobalRef(obj);
658 }
659
660 // initialize the Flp interfaces
661 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
662 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
663 }
664
665 if(sFlpDiagnosticInterface != NULL) {
666 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
667 }
668
669 if(sFlpGeofencingInterface != NULL) {
670 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
671 }
672
673 // TODO: inject any device context if when needed
674}
675
676static jboolean IsSupported(JNIEnv* env, jclass clazz) {
677 return sFlpInterface != NULL;
678}
679
680static jint GetBatchSize(JNIEnv* env, jobject object) {
681 if(sFlpInterface == NULL) {
682 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
683 }
684
685 return sFlpInterface->get_batch_size();
686}
687
688static void StartBatching(
689 JNIEnv* env,
690 jobject object,
691 jint id,
692 jobject optionsObject) {
693 if(sFlpInterface == NULL || optionsObject == NULL) {
694 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
695 }
696
697 FlpBatchOptions options;
698 TranslateFromObject(env, optionsObject, options);
699 int result = sFlpInterface->start_batching(id, &options);
700 ThrowOnError(env, result, __FUNCTION__);
701}
702
703static void UpdateBatchingOptions(
704 JNIEnv* env,
705 jobject object,
706 jint id,
707 jobject optionsObject) {
708 if(sFlpInterface == NULL || optionsObject == NULL) {
709 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
710 }
711
712 FlpBatchOptions options;
713 TranslateFromObject(env, optionsObject, options);
714 int result = sFlpInterface->update_batching_options(id, &options);
715 ThrowOnError(env, result, __FUNCTION__);
716}
717
718static void StopBatching(JNIEnv* env, jobject object, jint id) {
719 if(sFlpInterface == NULL) {
720 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
721 }
722
723 sFlpInterface->stop_batching(id);
724}
725
726static void Cleanup(JNIEnv* env, jobject object) {
727 if(sFlpInterface == NULL) {
728 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
729 }
730
731 sFlpInterface->cleanup();
732
733 if(sCallbacksObj != NULL) {
734 env->DeleteGlobalRef(sCallbacksObj);
735 sCallbacksObj = NULL;
736 }
737
738 sFlpInterface = NULL;
739 sFlpDiagnosticInterface = NULL;
740 sFlpDeviceContextInterface = NULL;
741 sFlpGeofencingInterface = NULL;
742
743 if(sHardwareDevice != NULL) {
744 sHardwareDevice->close(sHardwareDevice);
745 sHardwareDevice = NULL;
746 }
747}
748
749static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
750 if(sFlpInterface == NULL) {
751 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
752 }
753
754 sFlpInterface->get_batched_location(lastNLocations);
755}
756
757static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
758 if(locationObject == NULL) {
759 ALOGE("Invalid location for injection: %p", locationObject);
760 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
761 }
762
763 if(sFlpInterface == NULL) {
764 // there is no listener, bail
765 return;
766 }
767
768 FlpLocation location;
769 TranslateFromObject(env, locationObject, location);
770 int result = sFlpInterface->inject_location(&location);
771 if (result != FLP_RESULT_ERROR) {
772 // do not throw but log, this operation should be fire and forget
773 ALOGE("Error %d in '%s'", result, __FUNCTION__);
774 }
775}
776
777static jboolean IsDiagnosticSupported() {
778 return sFlpDiagnosticInterface != NULL;
779}
780
781static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
782 if(stringData == NULL) {
783 ALOGE("Invalid diagnostic data for injection: %p", stringData);
784 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
785 }
786
787 if(sFlpDiagnosticInterface == NULL) {
788 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
789 }
790
791 int length = env->GetStringLength(stringData);
792 const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
793 if(data == NULL) {
794 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
795 }
796
797 int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
798 ThrowOnError(env, result, __FUNCTION__);
799}
800
801static jboolean IsDeviceContextSupported() {
802 return sFlpDeviceContextInterface != NULL;
803}
804
805static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
806 if(sFlpDeviceContextInterface == NULL) {
807 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
808 }
809
810 int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
811 ThrowOnError(env, result, __FUNCTION__);
812}
813
814static jboolean IsGeofencingSupported() {
815 return sFlpGeofencingInterface != NULL;
816}
817
818static void AddGeofences(
819 JNIEnv* env,
820 jobject object,
destradaa06828092013-08-12 18:50:30 -0700821 jobjectArray geofenceRequestsArray) {
822 if(geofenceRequestsArray == NULL) {
823 ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
destradaa1af4b022013-07-12 15:43:36 -0700824 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
825 }
826
827 if (sFlpGeofencingInterface == NULL) {
828 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
829 }
830
destradaa06828092013-08-12 18:50:30 -0700831 jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray);
832 if(geofenceRequestsCount == 0) {
833 return;
834 }
835
836 Geofence* geofences = new Geofence[geofenceRequestsCount];
destradaa1af4b022013-07-12 15:43:36 -0700837 if (geofences == NULL) {
838 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
839 }
840
destradaa06828092013-08-12 18:50:30 -0700841 for (int i = 0; i < geofenceRequestsCount; ++i) {
842 geofences[i].data = new GeofenceData();
843 geofences[i].options = new GeofenceOptions();
844 jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
destradaa1af4b022013-07-12 15:43:36 -0700845
destradaa06828092013-08-12 18:50:30 -0700846 TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
destradaa1af4b022013-07-12 15:43:36 -0700847 }
848
destradaa06828092013-08-12 18:50:30 -0700849 sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
850 if (geofences != NULL) {
851 for(int i = 0; i < geofenceRequestsCount; ++i) {
852 delete geofences[i].data;
853 delete geofences[i].options;
854 }
855 delete[] geofences;
856 }
destradaa1af4b022013-07-12 15:43:36 -0700857}
858
859static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
860 if(sFlpGeofencingInterface == NULL) {
861 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
862 }
863
864 sFlpGeofencingInterface->pause_geofence(geofenceId);
865}
866
867static void ResumeGeofence(
868 JNIEnv* env,
869 jobject object,
870 jint geofenceId,
871 jint monitorTransitions) {
872 if(sFlpGeofencingInterface == NULL) {
873 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
874 }
875
876 sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
877}
878
879static void ModifyGeofenceOption(
880 JNIEnv* env,
881 jobject object,
882 jint geofenceId,
883 jint lastTransition,
884 jint monitorTransitions,
885 jint notificationResponsiveness,
886 jint unknownTimer,
887 jint sourcesToUse) {
888 if(sFlpGeofencingInterface == NULL) {
889 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
890 }
891
892 GeofenceOptions options = {
893 lastTransition,
894 monitorTransitions,
895 notificationResponsiveness,
896 unknownTimer,
897 (uint32_t)sourcesToUse
898 };
899
900 sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
901}
902
903static void RemoveGeofences(
904 JNIEnv* env,
905 jobject object,
906 jintArray geofenceIdsArray) {
907 if(sFlpGeofencingInterface == NULL) {
908 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
909 }
910
911 jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
912 jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
913 if(geofenceIds == NULL) {
914 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
915 }
916
917 sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
918}
919
920static JNINativeMethod sMethods[] = {
921 //{"name", "signature", functionPointer }
922 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
923 {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
924 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
925 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
926 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
destradaa06828092013-08-12 18:50:30 -0700927 {"nativeStartBatching",
928 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -0700929 reinterpret_cast<void*>(StartBatching)},
destradaa06828092013-08-12 18:50:30 -0700930 {"nativeUpdateBatchingOptions",
931 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -0700932 reinterpret_cast<void*>(UpdateBatchingOptions)},
933 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
destradaa06828092013-08-12 18:50:30 -0700934 {"nativeRequestBatchedLocation",
935 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700936 reinterpret_cast<void*>(GetBatchedLocation)},
destradaa06828092013-08-12 18:50:30 -0700937 {"nativeInjectLocation",
938 "(Landroid/location/Location;)V",
destradaa1af4b022013-07-12 15:43:36 -0700939 reinterpret_cast<void*>(InjectLocation)},
destradaa06828092013-08-12 18:50:30 -0700940 {"nativeIsDiagnosticSupported",
941 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700942 reinterpret_cast<void*>(IsDiagnosticSupported)},
destradaa06828092013-08-12 18:50:30 -0700943 {"nativeInjectDiagnosticData",
944 "(Ljava/lang/String;)V",
destradaa1af4b022013-07-12 15:43:36 -0700945 reinterpret_cast<void*>(InjectDiagnosticData)},
destradaa06828092013-08-12 18:50:30 -0700946 {"nativeIsDeviceContextSupported",
947 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700948 reinterpret_cast<void*>(IsDeviceContextSupported)},
destradaa06828092013-08-12 18:50:30 -0700949 {"nativeInjectDeviceContext",
950 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700951 reinterpret_cast<void*>(InjectDeviceContext)},
destradaa06828092013-08-12 18:50:30 -0700952 {"nativeIsGeofencingSupported",
953 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700954 reinterpret_cast<void*>(IsGeofencingSupported)},
destradaa06828092013-08-12 18:50:30 -0700955 {"nativeAddGeofences",
956 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V",
destradaa1af4b022013-07-12 15:43:36 -0700957 reinterpret_cast<void*>(AddGeofences)},
958 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
959 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
destradaa06828092013-08-12 18:50:30 -0700960 {"nativeModifyGeofenceOption",
961 "(IIIIII)V",
destradaa1af4b022013-07-12 15:43:36 -0700962 reinterpret_cast<void*>(ModifyGeofenceOption)},
963 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
964};
965
966/*
967 * Registration method invoked on JNI Load.
968 */
969int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
970 return jniRegisterNativeMethods(
971 env,
972 "com/android/server/location/FlpHardwareProvider",
973 sMethods,
974 NELEM(sMethods)
975 );
976}
977
978} /* name-space Android */