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