blob: 48b86db94cdd21968aef03423fc8428ad91e265a [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/*
264 * Helper function to transform FlpLocation into a java object.
265 */
266static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
267 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
268 jmethodID locationCtor = sCallbackEnv->GetMethodID(
269 locationClass,
270 "<init>",
271 "(Ljava/lang/String;)V"
272 );
273
274 // the provider is set in the upper JVM layer
275 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
276 jint flags = location->flags;
277
278 // set the valid information in the object
279 if (flags & FLP_LOCATION_HAS_LAT_LONG) {
280 jmethodID setLatitude = sCallbackEnv->GetMethodID(
281 locationClass,
282 "setLatitude",
283 "(D)V"
284 );
285 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
286
287 jmethodID setLongitude = sCallbackEnv->GetMethodID(
288 locationClass,
289 "setLongitude",
290 "(D)V"
291 );
292 sCallbackEnv->CallVoidMethod(
293 locationObject,
294 setLongitude,
295 location->longitude
296 );
297
298 jmethodID setTime = sCallbackEnv->GetMethodID(
299 locationClass,
300 "setTime",
301 "(J)V"
302 );
303 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
304 }
305
306 if (flags & FLP_LOCATION_HAS_ALTITUDE) {
307 jmethodID setAltitude = sCallbackEnv->GetMethodID(
308 locationClass,
309 "setAltitude",
310 "(D)V"
311 );
312 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
313 }
314
315 if (flags & FLP_LOCATION_HAS_SPEED) {
316 jmethodID setSpeed = sCallbackEnv->GetMethodID(
317 locationClass,
318 "setSpeed",
319 "(F)V"
320 );
321 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
322 }
323
324 if (flags & FLP_LOCATION_HAS_BEARING) {
325 jmethodID setBearing = sCallbackEnv->GetMethodID(
326 locationClass,
327 "setBearing",
328 "(F)V"
329 );
330 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
331 }
332
333 if (flags & FLP_LOCATION_HAS_ACCURACY) {
334 jmethodID setAccuracy = sCallbackEnv->GetMethodID(
335 locationClass,
336 "setAccuracy",
337 "(F)V"
338 );
339 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
340 }
341
342 // TODO: wire FlpLocation::sources_used when needed
343}
344
345/*
346 * Helper function to serialize FlpLocation structures.
347 */
348static void TranslateToObjectArray(
349 int32_t locationsCount,
350 FlpLocation** locations,
351 jobjectArray& locationsArray) {
352 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
353 locationsArray = sCallbackEnv->NewObjectArray(
354 locationsCount,
355 locationClass,
356 /* initialElement */ NULL
357 );
358
359 for (int i = 0; i < locationsCount; ++i) {
360 jobject locationObject = NULL;
361 TranslateToObject(locations[i], locationObject);
362 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
363 sCallbackEnv->DeleteLocalRef(locationObject);
364 }
365}
366
367static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
368 if(!IsValidCallbackThread()) {
369 return;
370 }
371
372 if(locationsCount == 0 || locations == NULL) {
373 ALOGE(
374 "Invalid LocationCallback. Count: %d, Locations: %p",
375 locationsCount,
376 locations
377 );
378 return;
379 }
380
381 jobjectArray locationsArray = NULL;
382 TranslateToObjectArray(locationsCount, locations, locationsArray);
383
384 sCallbackEnv->CallVoidMethod(
385 sCallbacksObj,
386 sOnLocationReport,
387 locationsArray
388 );
389 CheckExceptions(sCallbackEnv, __FUNCTION__);
390}
391
392static void AcquireWakelock() {
393 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
394}
395
396static void ReleaseWakelock() {
397 release_wake_lock(WAKE_LOCK_NAME);
398}
399
400FlpCallbacks sFlpCallbacks = {
401 sizeof(FlpCallbacks),
402 LocationCallback,
403 AcquireWakelock,
404 ReleaseWakelock,
405 SetThreadEvent
406};
407
408static void ReportData(char* data, int length) {
409 jstring stringData = NULL;
410
411 if(length != 0 && data != NULL) {
412 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
413 } else {
414 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
415 return;
416 }
417
418 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
419 CheckExceptions(sCallbackEnv, __FUNCTION__);
420}
421
422FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
423 sizeof(FlpDiagnosticCallbacks),
424 SetThreadEvent,
425 ReportData
426};
427
428static void GeofenceTransitionCallback(
429 int32_t geofenceId,
430 FlpLocation* location,
431 int32_t transition,
432 FlpUtcTime timestamp,
433 uint32_t sourcesUsed
434 ) {
435 if(!IsValidCallbackThread()) {
436 return;
437 }
438
439 if(location == NULL) {
440 ALOGE("GeofenceTransition received with invalid location: %p", location);
441 return;
442 }
443
444 jobject locationObject = NULL;
445 TranslateToObject(location, locationObject);
446
447 sCallbackEnv->CallVoidMethod(
448 sCallbacksObj,
449 sOnGeofenceTransition,
450 geofenceId,
451 locationObject,
452 transition,
453 timestamp,
454 sourcesUsed
455 );
456 CheckExceptions(sCallbackEnv, __FUNCTION__);
457}
458
459static void GeofenceMonitorStatusCallback(
460 int32_t status,
461 uint32_t source,
462 FlpLocation* lastLocation) {
463 if(!IsValidCallbackThread()) {
464 return;
465 }
466
467 jobject locationObject = NULL;
468 if(lastLocation != NULL) {
469 TranslateToObject(lastLocation, locationObject);
470 }
471
472 sCallbackEnv->CallVoidMethod(
473 sCallbacksObj,
474 sOnGeofenceMonitorStatus,
475 status,
476 source,
477 locationObject
478 );
479 CheckExceptions(sCallbackEnv, __FUNCTION__);
480}
481
482static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
483 if(!IsValidCallbackThread()) {
484 return;
485 }
486
487 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
488 CheckExceptions(sCallbackEnv, __FUNCTION__);
489}
490
491static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
492 if(!IsValidCallbackThread()) {
493 return;
494 }
495
496 sCallbackEnv->CallVoidMethod(
497 sCallbacksObj,
498 sOnGeofenceRemove,
499 geofenceId,
500 result
501 );
502 CheckExceptions(sCallbackEnv, __FUNCTION__);
503}
504
505static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
506 if(!IsValidCallbackThread()) {
507 return;
508 }
509
510 sCallbackEnv->CallVoidMethod(
511 sCallbacksObj,
512 sOnGeofencePause,
513 geofenceId,
514 result
515 );
516 CheckExceptions(sCallbackEnv, __FUNCTION__);
517}
518
519static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
520 if(!IsValidCallbackThread()) {
521 return;
522 }
523
524 sCallbackEnv->CallVoidMethod(
525 sCallbacksObj,
526 sOnGeofenceResume,
527 geofenceId,
528 result
529 );
530 CheckExceptions(sCallbackEnv, __FUNCTION__);
531}
532
533FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
534 sizeof(FlpGeofenceCallbacks),
535 GeofenceTransitionCallback,
536 GeofenceMonitorStatusCallback,
537 GeofenceAddCallback,
538 GeofenceRemoveCallback,
539 GeofencePauseCallback,
540 GeofenceResumeCallback,
541 SetThreadEvent
542};
543
544/*
545 * Initializes the Fused Location Provider in the native side. It ensures that
546 * the Flp interfaces are initialized properly.
547 */
548static void Init(JNIEnv* env, jobject obj) {
549 if(sHardwareDevice != NULL) {
550 ALOGD("Hardware Device already opened.");
551 return;
552 }
553
554 const hw_module_t* module = NULL;
555 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
556 if(err != 0) {
557 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
558 return;
559 }
560
561 err = module->methods->open(
562 module,
563 FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
564 if(err != 0) {
565 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
566 return;
567 }
568
569 sFlpInterface = NULL;
570 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
571 sFlpInterface = flp_device->get_flp_interface(flp_device);
572
573 if(sFlpInterface != NULL) {
574 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
575 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
576 );
577
578 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
579 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
580 );
581
582 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
583 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
584 );
585 }
586
587 if(sCallbacksObj == NULL) {
588 sCallbacksObj = env->NewGlobalRef(obj);
589 }
590
591 // initialize the Flp interfaces
592 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
593 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
594 }
595
596 if(sFlpDiagnosticInterface != NULL) {
597 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
598 }
599
600 if(sFlpGeofencingInterface != NULL) {
601 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
602 }
603
604 // TODO: inject any device context if when needed
605}
606
607static jboolean IsSupported(JNIEnv* env, jclass clazz) {
608 return sFlpInterface != NULL;
609}
610
611static jint GetBatchSize(JNIEnv* env, jobject object) {
612 if(sFlpInterface == NULL) {
613 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
614 }
615
616 return sFlpInterface->get_batch_size();
617}
618
619static void StartBatching(
620 JNIEnv* env,
621 jobject object,
622 jint id,
623 jobject optionsObject) {
624 if(sFlpInterface == NULL || optionsObject == NULL) {
625 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
626 }
627
628 FlpBatchOptions options;
629 TranslateFromObject(env, optionsObject, options);
630 int result = sFlpInterface->start_batching(id, &options);
631 ThrowOnError(env, result, __FUNCTION__);
632}
633
634static void UpdateBatchingOptions(
635 JNIEnv* env,
636 jobject object,
637 jint id,
638 jobject optionsObject) {
639 if(sFlpInterface == NULL || optionsObject == NULL) {
640 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
641 }
642
643 FlpBatchOptions options;
644 TranslateFromObject(env, optionsObject, options);
645 int result = sFlpInterface->update_batching_options(id, &options);
646 ThrowOnError(env, result, __FUNCTION__);
647}
648
649static void StopBatching(JNIEnv* env, jobject object, jint id) {
650 if(sFlpInterface == NULL) {
651 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
652 }
653
654 sFlpInterface->stop_batching(id);
655}
656
657static void Cleanup(JNIEnv* env, jobject object) {
658 if(sFlpInterface == NULL) {
659 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
660 }
661
662 sFlpInterface->cleanup();
663
664 if(sCallbacksObj != NULL) {
665 env->DeleteGlobalRef(sCallbacksObj);
666 sCallbacksObj = NULL;
667 }
668
669 sFlpInterface = NULL;
670 sFlpDiagnosticInterface = NULL;
671 sFlpDeviceContextInterface = NULL;
672 sFlpGeofencingInterface = NULL;
673
674 if(sHardwareDevice != NULL) {
675 sHardwareDevice->close(sHardwareDevice);
676 sHardwareDevice = NULL;
677 }
678}
679
680static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
681 if(sFlpInterface == NULL) {
682 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
683 }
684
685 sFlpInterface->get_batched_location(lastNLocations);
686}
687
688static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
689 if(locationObject == NULL) {
690 ALOGE("Invalid location for injection: %p", locationObject);
691 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
692 }
693
694 if(sFlpInterface == NULL) {
695 // there is no listener, bail
696 return;
697 }
698
699 FlpLocation location;
700 TranslateFromObject(env, locationObject, location);
701 int result = sFlpInterface->inject_location(&location);
702 if (result != FLP_RESULT_ERROR) {
703 // do not throw but log, this operation should be fire and forget
704 ALOGE("Error %d in '%s'", result, __FUNCTION__);
705 }
706}
707
708static jboolean IsDiagnosticSupported() {
709 return sFlpDiagnosticInterface != NULL;
710}
711
712static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
713 if(stringData == NULL) {
714 ALOGE("Invalid diagnostic data for injection: %p", stringData);
715 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
716 }
717
718 if(sFlpDiagnosticInterface == NULL) {
719 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
720 }
721
722 int length = env->GetStringLength(stringData);
723 const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
724 if(data == NULL) {
725 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
726 }
727
728 int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
729 ThrowOnError(env, result, __FUNCTION__);
730}
731
732static jboolean IsDeviceContextSupported() {
733 return sFlpDeviceContextInterface != NULL;
734}
735
736static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
737 if(sFlpDeviceContextInterface == NULL) {
738 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
739 }
740
741 int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
742 ThrowOnError(env, result, __FUNCTION__);
743}
744
745static jboolean IsGeofencingSupported() {
746 return sFlpGeofencingInterface != NULL;
747}
748
749static void AddGeofences(
750 JNIEnv* env,
751 jobject object,
752 jintArray geofenceIdsArray,
753 jobjectArray geofencesArray) {
754 if(geofencesArray == NULL) {
755 ALOGE("Invalid Geofences to add: %p", geofencesArray);
756 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
757 }
758
759 if (sFlpGeofencingInterface == NULL) {
760 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
761 }
762
763 jint geofencesCount = env->GetArrayLength(geofenceIdsArray);
764 Geofence* geofences = new Geofence[geofencesCount];
765 if (geofences == NULL) {
766 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
767 }
768
769 jint* ids = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
770 for (int i = 0; i < geofencesCount; ++i) {
771 geofences[i].geofence_id = ids[i];
772
773 // TODO: fill in the GeofenceData
774
775 // TODO: fill in the GeofenceOptions
776 }
777
778 sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences);
779 if (geofences != NULL) delete[] geofences;
780}
781
782static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
783 if(sFlpGeofencingInterface == NULL) {
784 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
785 }
786
787 sFlpGeofencingInterface->pause_geofence(geofenceId);
788}
789
790static void ResumeGeofence(
791 JNIEnv* env,
792 jobject object,
793 jint geofenceId,
794 jint monitorTransitions) {
795 if(sFlpGeofencingInterface == NULL) {
796 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
797 }
798
799 sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
800}
801
802static void ModifyGeofenceOption(
803 JNIEnv* env,
804 jobject object,
805 jint geofenceId,
806 jint lastTransition,
807 jint monitorTransitions,
808 jint notificationResponsiveness,
809 jint unknownTimer,
810 jint sourcesToUse) {
811 if(sFlpGeofencingInterface == NULL) {
812 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
813 }
814
815 GeofenceOptions options = {
816 lastTransition,
817 monitorTransitions,
818 notificationResponsiveness,
819 unknownTimer,
820 (uint32_t)sourcesToUse
821 };
822
823 sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
824}
825
826static void RemoveGeofences(
827 JNIEnv* env,
828 jobject object,
829 jintArray geofenceIdsArray) {
830 if(sFlpGeofencingInterface == NULL) {
831 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
832 }
833
834 jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
835 jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
836 if(geofenceIds == NULL) {
837 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
838 }
839
840 sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
841}
842
843static JNINativeMethod sMethods[] = {
844 //{"name", "signature", functionPointer }
845 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
846 {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
847 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
848 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
849 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
850 {"nativeStartBatching",
851 "(ILandroid/location/FusedBatchOptions;)V",
852 reinterpret_cast<void*>(StartBatching)},
853 {"nativeUpdateBatchingOptions",
854 "(ILandroid/location/FusedBatchOptions;)V",
855 reinterpret_cast<void*>(UpdateBatchingOptions)},
856 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
857 {"nativeRequestBatchedLocation",
858 "(I)V",
859 reinterpret_cast<void*>(GetBatchedLocation)},
860 {"nativeInjectLocation",
861 "(Landroid/location/Location;)V",
862 reinterpret_cast<void*>(InjectLocation)},
863 {"nativeIsDiagnosticSupported",
864 "()Z",
865 reinterpret_cast<void*>(IsDiagnosticSupported)},
866 {"nativeInjectDiagnosticData",
867 "(Ljava/lang/String;)V",
868 reinterpret_cast<void*>(InjectDiagnosticData)},
869 {"nativeIsDeviceContextSupported",
870 "()Z",
871 reinterpret_cast<void*>(IsDeviceContextSupported)},
872 {"nativeInjectDeviceContext",
873 "(I)V",
874 reinterpret_cast<void*>(InjectDeviceContext)},
875 {"nativeIsGeofencingSupported",
876 "()Z",
877 reinterpret_cast<void*>(IsGeofencingSupported)},
878 {"nativeAddGeofences",
879 "([I[Landroid/location/Geofence;)V",
880 reinterpret_cast<void*>(AddGeofences)},
881 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
882 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
883 {"nativeModifyGeofenceOption",
884 "(IIIIII)V",
885 reinterpret_cast<void*>(ModifyGeofenceOption)},
886 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
887};
888
889/*
890 * Registration method invoked on JNI Load.
891 */
892int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
893 return jniRegisterNativeMethods(
894 env,
895 "com/android/server/location/FlpHardwareProvider",
896 sMethods,
897 NELEM(sMethods)
898 );
899}
900
901} /* name-space Android */