blob: f5d7f8be4c36ccade14d4791abc64477a42045dd [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
destradaa264705a2013-08-21 12:55:32 -070017#define LOG_TAG "FlpHardwareProvider"
destradaa1af4b022013-07-12 15:43:36 -070018#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"
Ruben Brunk87eac992013-09-09 17:44:59 -070026#include "android_runtime/Log.h"
destradaa1af4b022013-07-12 15:43:36 -070027#include "hardware/fused_location.h"
28#include "hardware_legacy/power.h"
29
30static jobject sCallbacksObj = NULL;
31static JNIEnv *sCallbackEnv = NULL;
32static hw_device_t* sHardwareDevice = NULL;
33
34static jmethodID sOnLocationReport = NULL;
35static jmethodID sOnDataReport = NULL;
36static jmethodID sOnGeofenceTransition = NULL;
37static jmethodID sOnGeofenceMonitorStatus = NULL;
38static jmethodID sOnGeofenceAdd = NULL;
39static jmethodID sOnGeofenceRemove = NULL;
40static jmethodID sOnGeofencePause = NULL;
41static jmethodID sOnGeofenceResume = NULL;
42
43static const FlpLocationInterface* sFlpInterface = NULL;
44static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
45static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
46static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
47
48namespace android {
49
50static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
51 if(!env->ExceptionCheck()) {
52 return;
53 }
54
55 ALOGE("An exception was thrown by '%s'.", methodName);
56 LOGE_EX(env);
57 env->ExceptionClear();
58}
59
60static inline void ThrowOnError(
61 JNIEnv* env,
62 int resultCode,
63 const char* methodName) {
64 if(resultCode == FLP_RESULT_SUCCESS) {
65 return;
66 }
67
68 ALOGE("Error %d in '%s'", resultCode, methodName);
destradaa264705a2013-08-21 12:55:32 -070069 env->FatalError(methodName);
destradaa1af4b022013-07-12 15:43:36 -070070}
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
destradaab75cb3a2013-08-23 17:26:16 -0700221
222 env->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700223}
224
225/*
226 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
227 */
228static void TranslateFromObject(
229 JNIEnv* env,
230 jobject batchOptionsObject,
231 FlpBatchOptions& batchOptions) {
232 jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
233
234 jmethodID getMaxPower = env->GetMethodID(
235 batchOptionsClass,
236 "getMaxPowerAllocationInMW",
237 "()D"
238 );
239 batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
240 batchOptionsObject,
241 getMaxPower
242 );
243
244 jmethodID getPeriod = env->GetMethodID(
245 batchOptionsClass,
246 "getPeriodInNS",
247 "()J"
248 );
249 batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
250
251 jmethodID getSourcesToUse = env->GetMethodID(
252 batchOptionsClass,
253 "getSourcesToUse",
254 "()I"
255 );
256 batchOptions.sources_to_use = env->CallIntMethod(
257 batchOptionsObject,
258 getSourcesToUse
259 );
260
261 jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
262 batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
destradaab75cb3a2013-08-23 17:26:16 -0700263
264 env->DeleteLocalRef(batchOptionsClass);
destradaa1af4b022013-07-12 15:43:36 -0700265}
266
267/*
destradaa06828092013-08-12 18:50:30 -0700268 * Helper function to unwrap Geofence structures from the Java Runtime calls.
269 */
270static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
271 JNIEnv* env,
272 jobject geofenceRequestObject,
273 Geofence& geofence) {
274 jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
275
276 jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
277 geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
278
279 jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
280 // this works because GeofenceHardwareRequest.java and fused_location.h have
281 // the same notion of geofence types
282 GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
283 if(type != TYPE_CIRCLE) {
284 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
285 }
286 geofence.data->type = type;
287 GeofenceCircle& circle = geofence.data->geofence.circle;
288
289 jmethodID getLatitude = env->GetMethodID(
290 geofenceRequestClass,
291 "getLatitude",
292 "()D");
293 circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
294
295 jmethodID getLongitude = env->GetMethodID(
296 geofenceRequestClass,
297 "getLongitude",
298 "()D");
299 circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
300
301 jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
302 circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
303
304 GeofenceOptions* options = geofence.options;
305 jmethodID getMonitorTransitions = env->GetMethodID(
306 geofenceRequestClass,
307 "getMonitorTransitions",
308 "()I");
309 options->monitor_transitions = env->CallIntMethod(
310 geofenceRequestObject,
311 getMonitorTransitions);
312
313 jmethodID getUnknownTimer = env->GetMethodID(
314 geofenceRequestClass,
315 "getUnknownTimer",
316 "()I");
317 options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
318
319 jmethodID getNotificationResponsiveness = env->GetMethodID(
320 geofenceRequestClass,
321 "getNotificationResponsiveness",
322 "()D");
323 options->notification_responsivenes_ms = env->CallIntMethod(
324 geofenceRequestObject,
325 getNotificationResponsiveness);
326
327 jmethodID getLastTransition = env->GetMethodID(
328 geofenceRequestClass,
329 "getLastTransition",
330 "()I");
331 options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
332
333 // TODO: set data.sources_to_use when available
destradaab75cb3a2013-08-23 17:26:16 -0700334
335 env->DeleteLocalRef(geofenceRequestClass);
destradaa06828092013-08-12 18:50:30 -0700336}
337
338/*
destradaa1af4b022013-07-12 15:43:36 -0700339 * Helper function to transform FlpLocation into a java object.
340 */
341static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
342 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
343 jmethodID locationCtor = sCallbackEnv->GetMethodID(
344 locationClass,
345 "<init>",
346 "(Ljava/lang/String;)V"
347 );
348
349 // the provider is set in the upper JVM layer
350 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
351 jint flags = location->flags;
352
353 // set the valid information in the object
354 if (flags & FLP_LOCATION_HAS_LAT_LONG) {
355 jmethodID setLatitude = sCallbackEnv->GetMethodID(
356 locationClass,
357 "setLatitude",
358 "(D)V"
359 );
360 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
361
362 jmethodID setLongitude = sCallbackEnv->GetMethodID(
363 locationClass,
364 "setLongitude",
365 "(D)V"
366 );
367 sCallbackEnv->CallVoidMethod(
368 locationObject,
369 setLongitude,
370 location->longitude
371 );
372
373 jmethodID setTime = sCallbackEnv->GetMethodID(
374 locationClass,
375 "setTime",
376 "(J)V"
377 );
378 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
379 }
380
381 if (flags & FLP_LOCATION_HAS_ALTITUDE) {
382 jmethodID setAltitude = sCallbackEnv->GetMethodID(
383 locationClass,
384 "setAltitude",
385 "(D)V"
386 );
387 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
388 }
389
390 if (flags & FLP_LOCATION_HAS_SPEED) {
391 jmethodID setSpeed = sCallbackEnv->GetMethodID(
392 locationClass,
393 "setSpeed",
394 "(F)V"
395 );
396 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
397 }
398
399 if (flags & FLP_LOCATION_HAS_BEARING) {
400 jmethodID setBearing = sCallbackEnv->GetMethodID(
401 locationClass,
402 "setBearing",
403 "(F)V"
404 );
405 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
406 }
407
408 if (flags & FLP_LOCATION_HAS_ACCURACY) {
409 jmethodID setAccuracy = sCallbackEnv->GetMethodID(
410 locationClass,
411 "setAccuracy",
412 "(F)V"
413 );
414 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
415 }
416
417 // TODO: wire FlpLocation::sources_used when needed
destradaab75cb3a2013-08-23 17:26:16 -0700418
419 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700420}
421
422/*
423 * Helper function to serialize FlpLocation structures.
424 */
425static void TranslateToObjectArray(
426 int32_t locationsCount,
427 FlpLocation** locations,
428 jobjectArray& locationsArray) {
429 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
430 locationsArray = sCallbackEnv->NewObjectArray(
431 locationsCount,
432 locationClass,
433 /* initialElement */ NULL
434 );
435
436 for (int i = 0; i < locationsCount; ++i) {
437 jobject locationObject = NULL;
438 TranslateToObject(locations[i], locationObject);
439 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
440 sCallbackEnv->DeleteLocalRef(locationObject);
441 }
destradaab75cb3a2013-08-23 17:26:16 -0700442
443 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700444}
445
446static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
447 if(!IsValidCallbackThread()) {
448 return;
449 }
450
451 if(locationsCount == 0 || locations == NULL) {
452 ALOGE(
453 "Invalid LocationCallback. Count: %d, Locations: %p",
454 locationsCount,
455 locations
456 );
457 return;
458 }
459
460 jobjectArray locationsArray = NULL;
461 TranslateToObjectArray(locationsCount, locations, locationsArray);
462
463 sCallbackEnv->CallVoidMethod(
464 sCallbacksObj,
465 sOnLocationReport,
466 locationsArray
467 );
468 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700469
470 if(locationsArray != NULL) {
471 sCallbackEnv->DeleteLocalRef(locationsArray);
472 }
destradaa1af4b022013-07-12 15:43:36 -0700473}
474
475static void AcquireWakelock() {
476 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
477}
478
479static void ReleaseWakelock() {
480 release_wake_lock(WAKE_LOCK_NAME);
481}
482
483FlpCallbacks sFlpCallbacks = {
484 sizeof(FlpCallbacks),
485 LocationCallback,
486 AcquireWakelock,
487 ReleaseWakelock,
488 SetThreadEvent
489};
490
491static void ReportData(char* data, int length) {
492 jstring stringData = NULL;
493
494 if(length != 0 && data != NULL) {
495 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
496 } else {
497 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
498 return;
499 }
500
501 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
502 CheckExceptions(sCallbackEnv, __FUNCTION__);
503}
504
505FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
506 sizeof(FlpDiagnosticCallbacks),
507 SetThreadEvent,
508 ReportData
509};
510
511static void GeofenceTransitionCallback(
512 int32_t geofenceId,
513 FlpLocation* location,
514 int32_t transition,
515 FlpUtcTime timestamp,
516 uint32_t sourcesUsed
517 ) {
518 if(!IsValidCallbackThread()) {
519 return;
520 }
521
522 if(location == NULL) {
523 ALOGE("GeofenceTransition received with invalid location: %p", location);
524 return;
525 }
526
527 jobject locationObject = NULL;
528 TranslateToObject(location, locationObject);
529
530 sCallbackEnv->CallVoidMethod(
531 sCallbacksObj,
532 sOnGeofenceTransition,
533 geofenceId,
534 locationObject,
535 transition,
536 timestamp,
537 sourcesUsed
538 );
539 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700540
541 if(locationObject != NULL) {
542 sCallbackEnv->DeleteLocalRef(locationObject);
543 }
destradaa1af4b022013-07-12 15:43:36 -0700544}
545
546static void GeofenceMonitorStatusCallback(
547 int32_t status,
548 uint32_t source,
549 FlpLocation* lastLocation) {
550 if(!IsValidCallbackThread()) {
551 return;
552 }
553
554 jobject locationObject = NULL;
555 if(lastLocation != NULL) {
556 TranslateToObject(lastLocation, locationObject);
557 }
558
559 sCallbackEnv->CallVoidMethod(
560 sCallbacksObj,
561 sOnGeofenceMonitorStatus,
562 status,
563 source,
564 locationObject
565 );
566 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700567
568 if(locationObject != NULL) {
569 sCallbackEnv->DeleteLocalRef(locationObject);
570 }
destradaa1af4b022013-07-12 15:43:36 -0700571}
572
573static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
574 if(!IsValidCallbackThread()) {
575 return;
576 }
577
578 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
579 CheckExceptions(sCallbackEnv, __FUNCTION__);
580}
581
582static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
583 if(!IsValidCallbackThread()) {
584 return;
585 }
586
587 sCallbackEnv->CallVoidMethod(
588 sCallbacksObj,
589 sOnGeofenceRemove,
590 geofenceId,
591 result
592 );
593 CheckExceptions(sCallbackEnv, __FUNCTION__);
594}
595
596static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
597 if(!IsValidCallbackThread()) {
598 return;
599 }
600
601 sCallbackEnv->CallVoidMethod(
602 sCallbacksObj,
603 sOnGeofencePause,
604 geofenceId,
605 result
606 );
607 CheckExceptions(sCallbackEnv, __FUNCTION__);
608}
609
610static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
611 if(!IsValidCallbackThread()) {
612 return;
613 }
614
615 sCallbackEnv->CallVoidMethod(
616 sCallbacksObj,
617 sOnGeofenceResume,
618 geofenceId,
619 result
620 );
621 CheckExceptions(sCallbackEnv, __FUNCTION__);
622}
623
624FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
625 sizeof(FlpGeofenceCallbacks),
626 GeofenceTransitionCallback,
627 GeofenceMonitorStatusCallback,
628 GeofenceAddCallback,
629 GeofenceRemoveCallback,
630 GeofencePauseCallback,
631 GeofenceResumeCallback,
632 SetThreadEvent
633};
634
635/*
636 * Initializes the Fused Location Provider in the native side. It ensures that
637 * the Flp interfaces are initialized properly.
638 */
639static void Init(JNIEnv* env, jobject obj) {
640 if(sHardwareDevice != NULL) {
641 ALOGD("Hardware Device already opened.");
642 return;
643 }
644
645 const hw_module_t* module = NULL;
646 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
647 if(err != 0) {
648 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
649 return;
650 }
651
652 err = module->methods->open(
destradaa06828092013-08-12 18:50:30 -0700653 module,
destradaa1af4b022013-07-12 15:43:36 -0700654 FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
655 if(err != 0) {
656 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
657 return;
658 }
659
660 sFlpInterface = NULL;
661 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
662 sFlpInterface = flp_device->get_flp_interface(flp_device);
663
664 if(sFlpInterface != NULL) {
665 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
666 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
667 );
668
669 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
670 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
671 );
672
673 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
674 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
675 );
676 }
677
678 if(sCallbacksObj == NULL) {
679 sCallbacksObj = env->NewGlobalRef(obj);
680 }
681
682 // initialize the Flp interfaces
683 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
684 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
685 }
686
687 if(sFlpDiagnosticInterface != NULL) {
688 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
689 }
690
691 if(sFlpGeofencingInterface != NULL) {
692 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
693 }
694
695 // TODO: inject any device context if when needed
696}
697
698static jboolean IsSupported(JNIEnv* env, jclass clazz) {
699 return sFlpInterface != NULL;
700}
701
702static jint GetBatchSize(JNIEnv* env, jobject object) {
703 if(sFlpInterface == NULL) {
704 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
705 }
706
707 return sFlpInterface->get_batch_size();
708}
709
710static void StartBatching(
711 JNIEnv* env,
712 jobject object,
713 jint id,
714 jobject optionsObject) {
715 if(sFlpInterface == NULL || optionsObject == NULL) {
716 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
717 }
718
719 FlpBatchOptions options;
720 TranslateFromObject(env, optionsObject, options);
721 int result = sFlpInterface->start_batching(id, &options);
722 ThrowOnError(env, result, __FUNCTION__);
723}
724
725static void UpdateBatchingOptions(
726 JNIEnv* env,
727 jobject object,
728 jint id,
729 jobject optionsObject) {
730 if(sFlpInterface == NULL || optionsObject == NULL) {
731 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
732 }
733
734 FlpBatchOptions options;
735 TranslateFromObject(env, optionsObject, options);
736 int result = sFlpInterface->update_batching_options(id, &options);
737 ThrowOnError(env, result, __FUNCTION__);
738}
739
740static void StopBatching(JNIEnv* env, jobject object, jint id) {
741 if(sFlpInterface == NULL) {
742 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
743 }
744
745 sFlpInterface->stop_batching(id);
746}
747
748static void Cleanup(JNIEnv* env, jobject object) {
749 if(sFlpInterface == NULL) {
750 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
751 }
752
753 sFlpInterface->cleanup();
754
755 if(sCallbacksObj != NULL) {
756 env->DeleteGlobalRef(sCallbacksObj);
757 sCallbacksObj = NULL;
758 }
759
760 sFlpInterface = NULL;
761 sFlpDiagnosticInterface = NULL;
762 sFlpDeviceContextInterface = NULL;
763 sFlpGeofencingInterface = NULL;
764
765 if(sHardwareDevice != NULL) {
766 sHardwareDevice->close(sHardwareDevice);
767 sHardwareDevice = NULL;
768 }
769}
770
771static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
772 if(sFlpInterface == NULL) {
773 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
774 }
775
776 sFlpInterface->get_batched_location(lastNLocations);
777}
778
779static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
780 if(locationObject == NULL) {
781 ALOGE("Invalid location for injection: %p", locationObject);
782 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
783 }
784
785 if(sFlpInterface == NULL) {
786 // there is no listener, bail
787 return;
788 }
789
790 FlpLocation location;
791 TranslateFromObject(env, locationObject, location);
792 int result = sFlpInterface->inject_location(&location);
destradaa264705a2013-08-21 12:55:32 -0700793 if (result != FLP_RESULT_SUCCESS) {
destradaa1af4b022013-07-12 15:43:36 -0700794 // do not throw but log, this operation should be fire and forget
795 ALOGE("Error %d in '%s'", result, __FUNCTION__);
796 }
797}
798
799static jboolean IsDiagnosticSupported() {
800 return sFlpDiagnosticInterface != NULL;
801}
802
803static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
804 if(stringData == NULL) {
805 ALOGE("Invalid diagnostic data for injection: %p", stringData);
806 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
807 }
808
809 if(sFlpDiagnosticInterface == NULL) {
810 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
811 }
812
813 int length = env->GetStringLength(stringData);
814 const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
815 if(data == NULL) {
816 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
817 }
818
819 int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
820 ThrowOnError(env, result, __FUNCTION__);
821}
822
823static jboolean IsDeviceContextSupported() {
824 return sFlpDeviceContextInterface != NULL;
825}
826
827static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
828 if(sFlpDeviceContextInterface == NULL) {
829 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
830 }
831
832 int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
833 ThrowOnError(env, result, __FUNCTION__);
834}
835
836static jboolean IsGeofencingSupported() {
837 return sFlpGeofencingInterface != NULL;
838}
839
840static void AddGeofences(
841 JNIEnv* env,
842 jobject object,
destradaa06828092013-08-12 18:50:30 -0700843 jobjectArray geofenceRequestsArray) {
844 if(geofenceRequestsArray == NULL) {
845 ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
destradaa1af4b022013-07-12 15:43:36 -0700846 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
847 }
848
849 if (sFlpGeofencingInterface == NULL) {
850 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
851 }
852
destradaa06828092013-08-12 18:50:30 -0700853 jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray);
854 if(geofenceRequestsCount == 0) {
855 return;
856 }
857
858 Geofence* geofences = new Geofence[geofenceRequestsCount];
destradaa1af4b022013-07-12 15:43:36 -0700859 if (geofences == NULL) {
860 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
861 }
862
destradaa06828092013-08-12 18:50:30 -0700863 for (int i = 0; i < geofenceRequestsCount; ++i) {
864 geofences[i].data = new GeofenceData();
865 geofences[i].options = new GeofenceOptions();
866 jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
destradaa1af4b022013-07-12 15:43:36 -0700867
destradaa06828092013-08-12 18:50:30 -0700868 TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
destradaab75cb3a2013-08-23 17:26:16 -0700869 env->DeleteLocalRef(geofenceObject);
destradaa1af4b022013-07-12 15:43:36 -0700870 }
871
destradaa06828092013-08-12 18:50:30 -0700872 sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
873 if (geofences != NULL) {
874 for(int i = 0; i < geofenceRequestsCount; ++i) {
875 delete geofences[i].data;
876 delete geofences[i].options;
877 }
878 delete[] geofences;
879 }
destradaa1af4b022013-07-12 15:43:36 -0700880}
881
882static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
883 if(sFlpGeofencingInterface == NULL) {
884 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
885 }
886
887 sFlpGeofencingInterface->pause_geofence(geofenceId);
888}
889
890static void ResumeGeofence(
891 JNIEnv* env,
892 jobject object,
893 jint geofenceId,
894 jint monitorTransitions) {
895 if(sFlpGeofencingInterface == NULL) {
896 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
897 }
898
899 sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
900}
901
902static void ModifyGeofenceOption(
903 JNIEnv* env,
904 jobject object,
905 jint geofenceId,
906 jint lastTransition,
907 jint monitorTransitions,
908 jint notificationResponsiveness,
909 jint unknownTimer,
910 jint sourcesToUse) {
911 if(sFlpGeofencingInterface == NULL) {
912 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
913 }
914
915 GeofenceOptions options = {
916 lastTransition,
917 monitorTransitions,
918 notificationResponsiveness,
919 unknownTimer,
920 (uint32_t)sourcesToUse
921 };
922
923 sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
924}
925
926static void RemoveGeofences(
927 JNIEnv* env,
928 jobject object,
929 jintArray geofenceIdsArray) {
930 if(sFlpGeofencingInterface == NULL) {
931 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
932 }
933
934 jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
935 jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
936 if(geofenceIds == NULL) {
937 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
938 }
939
940 sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
941}
942
943static JNINativeMethod sMethods[] = {
944 //{"name", "signature", functionPointer }
945 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
946 {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
947 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
948 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
949 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
destradaa06828092013-08-12 18:50:30 -0700950 {"nativeStartBatching",
951 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -0700952 reinterpret_cast<void*>(StartBatching)},
destradaa06828092013-08-12 18:50:30 -0700953 {"nativeUpdateBatchingOptions",
954 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -0700955 reinterpret_cast<void*>(UpdateBatchingOptions)},
956 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
destradaa06828092013-08-12 18:50:30 -0700957 {"nativeRequestBatchedLocation",
958 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700959 reinterpret_cast<void*>(GetBatchedLocation)},
destradaa06828092013-08-12 18:50:30 -0700960 {"nativeInjectLocation",
961 "(Landroid/location/Location;)V",
destradaa1af4b022013-07-12 15:43:36 -0700962 reinterpret_cast<void*>(InjectLocation)},
destradaa06828092013-08-12 18:50:30 -0700963 {"nativeIsDiagnosticSupported",
964 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700965 reinterpret_cast<void*>(IsDiagnosticSupported)},
destradaa06828092013-08-12 18:50:30 -0700966 {"nativeInjectDiagnosticData",
967 "(Ljava/lang/String;)V",
destradaa1af4b022013-07-12 15:43:36 -0700968 reinterpret_cast<void*>(InjectDiagnosticData)},
destradaa06828092013-08-12 18:50:30 -0700969 {"nativeIsDeviceContextSupported",
970 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700971 reinterpret_cast<void*>(IsDeviceContextSupported)},
destradaa06828092013-08-12 18:50:30 -0700972 {"nativeInjectDeviceContext",
973 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700974 reinterpret_cast<void*>(InjectDeviceContext)},
destradaa06828092013-08-12 18:50:30 -0700975 {"nativeIsGeofencingSupported",
976 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700977 reinterpret_cast<void*>(IsGeofencingSupported)},
destradaa06828092013-08-12 18:50:30 -0700978 {"nativeAddGeofences",
979 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V",
destradaa1af4b022013-07-12 15:43:36 -0700980 reinterpret_cast<void*>(AddGeofences)},
981 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
982 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
destradaa06828092013-08-12 18:50:30 -0700983 {"nativeModifyGeofenceOption",
984 "(IIIIII)V",
destradaa1af4b022013-07-12 15:43:36 -0700985 reinterpret_cast<void*>(ModifyGeofenceOption)},
986 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
987};
988
989/*
990 * Registration method invoked on JNI Load.
991 */
992int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
993 return jniRegisterNativeMethods(
994 env,
995 "com/android/server/location/FlpHardwareProvider",
996 sMethods,
997 NELEM(sMethods)
998 );
999}
1000
1001} /* name-space Android */