blob: c2fccc1e70112725a71ca874042f1cb9b4d3583d [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) {
destradaa5ce66d82014-05-28 18:24:08 -0700142 sFlpInterface = NULL;
143
destradaa1af4b022013-07-12 15:43:36 -0700144 // get references to the Java provider methods
145 sOnLocationReport = env->GetMethodID(
146 clazz,
147 "onLocationReport",
148 "([Landroid/location/Location;)V");
149 sOnDataReport = env->GetMethodID(
150 clazz,
151 "onDataReport",
152 "(Ljava/lang/String;)V"
153 );
154 sOnGeofenceTransition = env->GetMethodID(
155 clazz,
156 "onGeofenceTransition",
157 "(ILandroid/location/Location;IJI)V"
158 );
159 sOnGeofenceMonitorStatus = env->GetMethodID(
160 clazz,
161 "onGeofenceMonitorStatus",
162 "(IILandroid/location/Location;)V"
163 );
164 sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
165 sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
166 sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
167 sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
destradaa5ce66d82014-05-28 18:24:08 -0700168
169 // open the hardware module
170 const hw_module_t* module = NULL;
171 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
172 if (err != 0) {
173 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
174 return;
175 }
176
177 err = module->methods->open(
178 module,
179 FUSED_LOCATION_HARDWARE_MODULE_ID,
180 &sHardwareDevice);
181 if (err != 0) {
182 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
183 return;
184 }
185
186 // acquire the interfaces pointers
187 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
188 sFlpInterface = flp_device->get_flp_interface(flp_device);
189
190 if (sFlpInterface != NULL) {
191 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
192 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE));
193
194 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
195 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE));
196
197 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
198 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE));
199 }
destradaa1af4b022013-07-12 15:43:36 -0700200}
201
202/*
203 * Helper function to unwrap a java object back into a FlpLocation structure.
204 */
205static void TranslateFromObject(
206 JNIEnv* env,
207 jobject locationObject,
208 FlpLocation& location) {
209 location.size = sizeof(FlpLocation);
210 location.flags = 0;
211
212 jclass locationClass = env->GetObjectClass(locationObject);
213
214 jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
215 location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
216 jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
217 location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
218 jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
219 location.timestamp = env->CallLongMethod(locationObject, getTime);
220 location.flags |= FLP_LOCATION_HAS_LAT_LONG;
221
222 jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
223 if (env->CallBooleanMethod(locationObject, hasAltitude)) {
224 jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
225 location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
226 location.flags |= FLP_LOCATION_HAS_ALTITUDE;
227 }
228
229 jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
230 if (env->CallBooleanMethod(locationObject, hasSpeed)) {
231 jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
232 location.speed = env->CallFloatMethod(locationObject, getSpeed);
233 location.flags |= FLP_LOCATION_HAS_SPEED;
234 }
235
236 jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
237 if (env->CallBooleanMethod(locationObject, hasBearing)) {
238 jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
239 location.bearing = env->CallFloatMethod(locationObject, getBearing);
240 location.flags |= FLP_LOCATION_HAS_BEARING;
241 }
242
243 jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
244 if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
245 jmethodID getAccuracy = env->GetMethodID(
246 locationClass,
247 "getAccuracy",
248 "()F"
249 );
250 location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
251 location.flags |= FLP_LOCATION_HAS_ACCURACY;
252 }
253
254 // TODO: wire sources_used if Location class exposes them
destradaab75cb3a2013-08-23 17:26:16 -0700255
256 env->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700257}
258
259/*
260 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
261 */
262static void TranslateFromObject(
263 JNIEnv* env,
264 jobject batchOptionsObject,
265 FlpBatchOptions& batchOptions) {
266 jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
267
268 jmethodID getMaxPower = env->GetMethodID(
269 batchOptionsClass,
270 "getMaxPowerAllocationInMW",
271 "()D"
272 );
273 batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
274 batchOptionsObject,
275 getMaxPower
276 );
277
278 jmethodID getPeriod = env->GetMethodID(
279 batchOptionsClass,
280 "getPeriodInNS",
281 "()J"
282 );
283 batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
284
285 jmethodID getSourcesToUse = env->GetMethodID(
286 batchOptionsClass,
287 "getSourcesToUse",
288 "()I"
289 );
290 batchOptions.sources_to_use = env->CallIntMethod(
291 batchOptionsObject,
292 getSourcesToUse
293 );
294
295 jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
296 batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
destradaab75cb3a2013-08-23 17:26:16 -0700297
298 env->DeleteLocalRef(batchOptionsClass);
destradaa1af4b022013-07-12 15:43:36 -0700299}
300
301/*
destradaa0682809a2013-08-12 18:50:30 -0700302 * Helper function to unwrap Geofence structures from the Java Runtime calls.
303 */
304static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
305 JNIEnv* env,
306 jobject geofenceRequestObject,
307 Geofence& geofence) {
308 jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
309
310 jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
311 geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
312
313 jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
314 // this works because GeofenceHardwareRequest.java and fused_location.h have
315 // the same notion of geofence types
316 GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
317 if(type != TYPE_CIRCLE) {
318 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
319 }
320 geofence.data->type = type;
321 GeofenceCircle& circle = geofence.data->geofence.circle;
322
323 jmethodID getLatitude = env->GetMethodID(
324 geofenceRequestClass,
325 "getLatitude",
326 "()D");
327 circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
328
329 jmethodID getLongitude = env->GetMethodID(
330 geofenceRequestClass,
331 "getLongitude",
332 "()D");
333 circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
334
335 jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
336 circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
337
338 GeofenceOptions* options = geofence.options;
339 jmethodID getMonitorTransitions = env->GetMethodID(
340 geofenceRequestClass,
341 "getMonitorTransitions",
342 "()I");
343 options->monitor_transitions = env->CallIntMethod(
344 geofenceRequestObject,
345 getMonitorTransitions);
346
347 jmethodID getUnknownTimer = env->GetMethodID(
348 geofenceRequestClass,
349 "getUnknownTimer",
350 "()I");
351 options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
352
353 jmethodID getNotificationResponsiveness = env->GetMethodID(
354 geofenceRequestClass,
355 "getNotificationResponsiveness",
destradaa839904e2013-09-11 12:42:51 -0700356 "()I");
destradaa0682809a2013-08-12 18:50:30 -0700357 options->notification_responsivenes_ms = env->CallIntMethod(
358 geofenceRequestObject,
359 getNotificationResponsiveness);
360
361 jmethodID getLastTransition = env->GetMethodID(
362 geofenceRequestClass,
363 "getLastTransition",
364 "()I");
365 options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
366
367 // TODO: set data.sources_to_use when available
destradaab75cb3a2013-08-23 17:26:16 -0700368
369 env->DeleteLocalRef(geofenceRequestClass);
destradaa0682809a2013-08-12 18:50:30 -0700370}
371
372/*
destradaa1af4b022013-07-12 15:43:36 -0700373 * Helper function to transform FlpLocation into a java object.
374 */
375static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
376 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
377 jmethodID locationCtor = sCallbackEnv->GetMethodID(
378 locationClass,
379 "<init>",
380 "(Ljava/lang/String;)V"
381 );
382
383 // the provider is set in the upper JVM layer
384 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
385 jint flags = location->flags;
386
387 // set the valid information in the object
388 if (flags & FLP_LOCATION_HAS_LAT_LONG) {
389 jmethodID setLatitude = sCallbackEnv->GetMethodID(
390 locationClass,
391 "setLatitude",
392 "(D)V"
393 );
394 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
395
396 jmethodID setLongitude = sCallbackEnv->GetMethodID(
397 locationClass,
398 "setLongitude",
399 "(D)V"
400 );
401 sCallbackEnv->CallVoidMethod(
402 locationObject,
403 setLongitude,
404 location->longitude
405 );
406
407 jmethodID setTime = sCallbackEnv->GetMethodID(
408 locationClass,
409 "setTime",
410 "(J)V"
411 );
412 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
413 }
414
415 if (flags & FLP_LOCATION_HAS_ALTITUDE) {
416 jmethodID setAltitude = sCallbackEnv->GetMethodID(
417 locationClass,
418 "setAltitude",
419 "(D)V"
420 );
421 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
422 }
423
424 if (flags & FLP_LOCATION_HAS_SPEED) {
425 jmethodID setSpeed = sCallbackEnv->GetMethodID(
426 locationClass,
427 "setSpeed",
428 "(F)V"
429 );
430 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
431 }
432
433 if (flags & FLP_LOCATION_HAS_BEARING) {
434 jmethodID setBearing = sCallbackEnv->GetMethodID(
435 locationClass,
436 "setBearing",
437 "(F)V"
438 );
439 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
440 }
441
442 if (flags & FLP_LOCATION_HAS_ACCURACY) {
443 jmethodID setAccuracy = sCallbackEnv->GetMethodID(
444 locationClass,
445 "setAccuracy",
446 "(F)V"
447 );
448 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
449 }
450
451 // TODO: wire FlpLocation::sources_used when needed
destradaab75cb3a2013-08-23 17:26:16 -0700452
453 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700454}
455
456/*
457 * Helper function to serialize FlpLocation structures.
458 */
459static void TranslateToObjectArray(
460 int32_t locationsCount,
461 FlpLocation** locations,
462 jobjectArray& locationsArray) {
463 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
464 locationsArray = sCallbackEnv->NewObjectArray(
465 locationsCount,
466 locationClass,
467 /* initialElement */ NULL
468 );
469
470 for (int i = 0; i < locationsCount; ++i) {
471 jobject locationObject = NULL;
472 TranslateToObject(locations[i], locationObject);
473 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
474 sCallbackEnv->DeleteLocalRef(locationObject);
475 }
destradaab75cb3a2013-08-23 17:26:16 -0700476
477 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700478}
479
480static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
481 if(!IsValidCallbackThread()) {
482 return;
483 }
484
485 if(locationsCount == 0 || locations == NULL) {
486 ALOGE(
487 "Invalid LocationCallback. Count: %d, Locations: %p",
488 locationsCount,
489 locations
490 );
491 return;
492 }
493
494 jobjectArray locationsArray = NULL;
495 TranslateToObjectArray(locationsCount, locations, locationsArray);
496
497 sCallbackEnv->CallVoidMethod(
498 sCallbacksObj,
499 sOnLocationReport,
500 locationsArray
501 );
502 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700503
504 if(locationsArray != NULL) {
505 sCallbackEnv->DeleteLocalRef(locationsArray);
506 }
destradaa1af4b022013-07-12 15:43:36 -0700507}
508
509static void AcquireWakelock() {
510 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
511}
512
513static void ReleaseWakelock() {
514 release_wake_lock(WAKE_LOCK_NAME);
515}
516
517FlpCallbacks sFlpCallbacks = {
518 sizeof(FlpCallbacks),
519 LocationCallback,
520 AcquireWakelock,
521 ReleaseWakelock,
522 SetThreadEvent
523};
524
525static void ReportData(char* data, int length) {
526 jstring stringData = NULL;
527
528 if(length != 0 && data != NULL) {
529 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
530 } else {
531 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
532 return;
533 }
534
535 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
536 CheckExceptions(sCallbackEnv, __FUNCTION__);
537}
538
539FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
540 sizeof(FlpDiagnosticCallbacks),
541 SetThreadEvent,
542 ReportData
543};
544
545static void GeofenceTransitionCallback(
546 int32_t geofenceId,
547 FlpLocation* location,
548 int32_t transition,
549 FlpUtcTime timestamp,
550 uint32_t sourcesUsed
551 ) {
552 if(!IsValidCallbackThread()) {
553 return;
554 }
555
556 if(location == NULL) {
557 ALOGE("GeofenceTransition received with invalid location: %p", location);
558 return;
559 }
560
561 jobject locationObject = NULL;
562 TranslateToObject(location, locationObject);
563
564 sCallbackEnv->CallVoidMethod(
565 sCallbacksObj,
566 sOnGeofenceTransition,
567 geofenceId,
568 locationObject,
569 transition,
570 timestamp,
571 sourcesUsed
572 );
573 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700574
575 if(locationObject != NULL) {
576 sCallbackEnv->DeleteLocalRef(locationObject);
577 }
destradaa1af4b022013-07-12 15:43:36 -0700578}
579
580static void GeofenceMonitorStatusCallback(
581 int32_t status,
582 uint32_t source,
583 FlpLocation* lastLocation) {
584 if(!IsValidCallbackThread()) {
585 return;
586 }
587
588 jobject locationObject = NULL;
589 if(lastLocation != NULL) {
590 TranslateToObject(lastLocation, locationObject);
591 }
592
593 sCallbackEnv->CallVoidMethod(
594 sCallbacksObj,
595 sOnGeofenceMonitorStatus,
596 status,
597 source,
598 locationObject
599 );
600 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700601
602 if(locationObject != NULL) {
603 sCallbackEnv->DeleteLocalRef(locationObject);
604 }
destradaa1af4b022013-07-12 15:43:36 -0700605}
606
607static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
608 if(!IsValidCallbackThread()) {
609 return;
610 }
611
612 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
613 CheckExceptions(sCallbackEnv, __FUNCTION__);
614}
615
616static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
617 if(!IsValidCallbackThread()) {
618 return;
619 }
620
621 sCallbackEnv->CallVoidMethod(
622 sCallbacksObj,
623 sOnGeofenceRemove,
624 geofenceId,
625 result
626 );
627 CheckExceptions(sCallbackEnv, __FUNCTION__);
628}
629
630static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
631 if(!IsValidCallbackThread()) {
632 return;
633 }
634
635 sCallbackEnv->CallVoidMethod(
636 sCallbacksObj,
637 sOnGeofencePause,
638 geofenceId,
639 result
640 );
641 CheckExceptions(sCallbackEnv, __FUNCTION__);
642}
643
644static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
645 if(!IsValidCallbackThread()) {
646 return;
647 }
648
649 sCallbackEnv->CallVoidMethod(
650 sCallbacksObj,
651 sOnGeofenceResume,
652 geofenceId,
653 result
654 );
655 CheckExceptions(sCallbackEnv, __FUNCTION__);
656}
657
658FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
659 sizeof(FlpGeofenceCallbacks),
660 GeofenceTransitionCallback,
661 GeofenceMonitorStatusCallback,
662 GeofenceAddCallback,
663 GeofenceRemoveCallback,
664 GeofencePauseCallback,
665 GeofenceResumeCallback,
666 SetThreadEvent
667};
668
669/*
670 * Initializes the Fused Location Provider in the native side. It ensures that
671 * the Flp interfaces are initialized properly.
672 */
673static void Init(JNIEnv* env, jobject obj) {
destradaa1af4b022013-07-12 15:43:36 -0700674 if(sCallbacksObj == NULL) {
675 sCallbacksObj = env->NewGlobalRef(obj);
676 }
677
678 // initialize the Flp interfaces
679 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
680 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
681 }
682
683 if(sFlpDiagnosticInterface != NULL) {
684 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
685 }
686
687 if(sFlpGeofencingInterface != NULL) {
688 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
689 }
690
691 // TODO: inject any device context if when needed
692}
693
694static jboolean IsSupported(JNIEnv* env, jclass clazz) {
destradaa5ce66d82014-05-28 18:24:08 -0700695 if (sFlpInterface == NULL) {
696 return JNI_FALSE;
697 }
698 return JNI_TRUE;
destradaa1af4b022013-07-12 15:43:36 -0700699}
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,
destradaa0682809a2013-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
destradaa0682809a2013-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
destradaa0682809a2013-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
destradaa0682809a2013-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
destradaa0682809a2013-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);
destradaa7f02eb22013-09-20 13:08:41 -0700940 env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
destradaa1af4b022013-07-12 15:43:36 -0700941}
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)},
destradaa0682809a2013-08-12 18:50:30 -0700950 {"nativeStartBatching",
951 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -0700952 reinterpret_cast<void*>(StartBatching)},
destradaa0682809a2013-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)},
destradaa0682809a2013-08-12 18:50:30 -0700957 {"nativeRequestBatchedLocation",
958 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700959 reinterpret_cast<void*>(GetBatchedLocation)},
destradaa0682809a2013-08-12 18:50:30 -0700960 {"nativeInjectLocation",
961 "(Landroid/location/Location;)V",
destradaa1af4b022013-07-12 15:43:36 -0700962 reinterpret_cast<void*>(InjectLocation)},
destradaa0682809a2013-08-12 18:50:30 -0700963 {"nativeIsDiagnosticSupported",
964 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700965 reinterpret_cast<void*>(IsDiagnosticSupported)},
destradaa0682809a2013-08-12 18:50:30 -0700966 {"nativeInjectDiagnosticData",
967 "(Ljava/lang/String;)V",
destradaa1af4b022013-07-12 15:43:36 -0700968 reinterpret_cast<void*>(InjectDiagnosticData)},
destradaa0682809a2013-08-12 18:50:30 -0700969 {"nativeIsDeviceContextSupported",
970 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700971 reinterpret_cast<void*>(IsDeviceContextSupported)},
destradaa0682809a2013-08-12 18:50:30 -0700972 {"nativeInjectDeviceContext",
973 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -0700974 reinterpret_cast<void*>(InjectDeviceContext)},
destradaa0682809a2013-08-12 18:50:30 -0700975 {"nativeIsGeofencingSupported",
976 "()Z",
destradaa1af4b022013-07-12 15:43:36 -0700977 reinterpret_cast<void*>(IsGeofencingSupported)},
destradaa0682809a2013-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)},
destradaa0682809a2013-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 */