1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the license at 7 * 8 * http://www.apache.org/license/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the license. 15 */ 16 17 #define LOG_TAG "FlpHardwareProvider" 18 #define LOG_NDEBUG 0 19 20 #define WAKE_LOCK_NAME "FLP" 21 #define LOCATION_CLASS_NAME "android/location/Location" 22 23 #include "jni.h" 24 #include "JNIHelp.h" 25 #include "android_runtime/AndroidRuntime.h" 26 #include "android_runtime/Log.h" 27 #include "hardware/fused_location.h" 28 #include "hardware_legacy/power.h" 29 30 static jobject sCallbacksObj = NULL; 31 static JNIEnv *sCallbackEnv = NULL; 32 static hw_device_t* sHardwareDevice = NULL; 33 34 static jmethodID sOnLocationReport = NULL; 35 static jmethodID sOnDataReport = NULL; 36 static jmethodID sOnGeofenceTransition = NULL; 37 static jmethodID sOnGeofenceMonitorStatus = NULL; 38 static jmethodID sOnGeofenceAdd = NULL; 39 static jmethodID sOnGeofenceRemove = NULL; 40 static jmethodID sOnGeofencePause = NULL; 41 static jmethodID sOnGeofenceResume = NULL; 42 43 static const FlpLocationInterface* sFlpInterface = NULL; 44 static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL; 45 static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL; 46 static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL; 47 48 namespace android { 49 50 static 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 60 static 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); 69 env->FatalError(methodName); 70 } 71 72 static 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 83 static 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 */ 141 static 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 */ 171 static void TranslateFromObject( 172 JNIEnv* env, 173 jobject locationObject, 174 FlpLocation& location) { 175 location.size = sizeof(FlpLocation); 176 location.flags = 0; 177 178 jclass locationClass = env->GetObjectClass(locationObject); 179 180 jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D"); 181 location.latitude = env->CallDoubleMethod(locationObject, getLatitude); 182 jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D"); 183 location.longitude = env->CallDoubleMethod(locationObject, getLongitude); 184 jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J"); 185 location.timestamp = env->CallLongMethod(locationObject, getTime); 186 location.flags |= FLP_LOCATION_HAS_LAT_LONG; 187 188 jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z"); 189 if (env->CallBooleanMethod(locationObject, hasAltitude)) { 190 jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D"); 191 location.altitude = env->CallDoubleMethod(locationObject, getAltitude); 192 location.flags |= FLP_LOCATION_HAS_ALTITUDE; 193 } 194 195 jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z"); 196 if (env->CallBooleanMethod(locationObject, hasSpeed)) { 197 jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F"); 198 location.speed = env->CallFloatMethod(locationObject, getSpeed); 199 location.flags |= FLP_LOCATION_HAS_SPEED; 200 } 201 202 jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z"); 203 if (env->CallBooleanMethod(locationObject, hasBearing)) { 204 jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F"); 205 location.bearing = env->CallFloatMethod(locationObject, getBearing); 206 location.flags |= FLP_LOCATION_HAS_BEARING; 207 } 208 209 jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z"); 210 if (env->CallBooleanMethod(locationObject, hasAccuracy)) { 211 jmethodID getAccuracy = env->GetMethodID( 212 locationClass, 213 "getAccuracy", 214 "()F" 215 ); 216 location.accuracy = env->CallFloatMethod(locationObject, getAccuracy); 217 location.flags |= FLP_LOCATION_HAS_ACCURACY; 218 } 219 220 // TODO: wire sources_used if Location class exposes them 221 222 env->DeleteLocalRef(locationClass); 223 } 224 225 /* 226 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls. 227 */ 228 static 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); 263 264 env->DeleteLocalRef(batchOptionsClass); 265 } 266 267 /* 268 * Helper function to unwrap Geofence structures from the Java Runtime calls. 269 */ 270 static 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 "()I"); 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 334 335 env->DeleteLocalRef(geofenceRequestClass); 336 } 337 338 /* 339 * Helper function to transform FlpLocation into a java object. 340 */ 341 static 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 418 419 sCallbackEnv->DeleteLocalRef(locationClass); 420 } 421 422 /* 423 * Helper function to serialize FlpLocation structures. 424 */ 425 static 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 } 442 443 sCallbackEnv->DeleteLocalRef(locationClass); 444 } 445 446 static 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__); 469 470 if(locationsArray != NULL) { 471 sCallbackEnv->DeleteLocalRef(locationsArray); 472 } 473 } 474 475 static void AcquireWakelock() { 476 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); 477 } 478 479 static void ReleaseWakelock() { 480 release_wake_lock(WAKE_LOCK_NAME); 481 } 482 483 FlpCallbacks sFlpCallbacks = { 484 sizeof(FlpCallbacks), 485 LocationCallback, 486 AcquireWakelock, 487 ReleaseWakelock, 488 SetThreadEvent 489 }; 490 491 static 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 505 FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = { 506 sizeof(FlpDiagnosticCallbacks), 507 SetThreadEvent, 508 ReportData 509 }; 510 511 static 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__); 540 541 if(locationObject != NULL) { 542 sCallbackEnv->DeleteLocalRef(locationObject); 543 } 544 } 545 546 static 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__); 567 568 if(locationObject != NULL) { 569 sCallbackEnv->DeleteLocalRef(locationObject); 570 } 571 } 572 573 static 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 582 static 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 596 static 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 610 static 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 624 FlpGeofenceCallbacks 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 */ 639 static 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( 653 module, 654 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 698 static jboolean IsSupported(JNIEnv* env, jclass clazz) { 699 return sFlpInterface != NULL; 700 } 701 702 static 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 710 static 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 725 static 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 740 static 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 748 static 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 771 static 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 779 static 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); 793 if (result != FLP_RESULT_SUCCESS) { 794 // do not throw but log, this operation should be fire and forget 795 ALOGE("Error %d in '%s'", result, __FUNCTION__); 796 } 797 } 798 799 static jboolean IsDiagnosticSupported() { 800 return sFlpDiagnosticInterface != NULL; 801 } 802 803 static 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 823 static jboolean IsDeviceContextSupported() { 824 return sFlpDeviceContextInterface != NULL; 825 } 826 827 static 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 836 static jboolean IsGeofencingSupported() { 837 return sFlpGeofencingInterface != NULL; 838 } 839 840 static void AddGeofences( 841 JNIEnv* env, 842 jobject object, 843 jobjectArray geofenceRequestsArray) { 844 if(geofenceRequestsArray == NULL) { 845 ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray); 846 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 847 } 848 849 if (sFlpGeofencingInterface == NULL) { 850 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 851 } 852 853 jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray); 854 if(geofenceRequestsCount == 0) { 855 return; 856 } 857 858 Geofence* geofences = new Geofence[geofenceRequestsCount]; 859 if (geofences == NULL) { 860 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__); 861 } 862 863 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); 867 868 TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]); 869 env->DeleteLocalRef(geofenceObject); 870 } 871 872 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 } 880 } 881 882 static 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 890 static 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 902 static 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 926 static 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 env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/); 942 } 943 944 static JNINativeMethod sMethods[] = { 945 //{"name", "signature", functionPointer } 946 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, 947 {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, 948 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, 949 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, 950 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, 951 {"nativeStartBatching", 952 "(ILandroid/location/FusedBatchOptions;)V", 953 reinterpret_cast<void*>(StartBatching)}, 954 {"nativeUpdateBatchingOptions", 955 "(ILandroid/location/FusedBatchOptions;)V", 956 reinterpret_cast<void*>(UpdateBatchingOptions)}, 957 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, 958 {"nativeRequestBatchedLocation", 959 "(I)V", 960 reinterpret_cast<void*>(GetBatchedLocation)}, 961 {"nativeInjectLocation", 962 "(Landroid/location/Location;)V", 963 reinterpret_cast<void*>(InjectLocation)}, 964 {"nativeIsDiagnosticSupported", 965 "()Z", 966 reinterpret_cast<void*>(IsDiagnosticSupported)}, 967 {"nativeInjectDiagnosticData", 968 "(Ljava/lang/String;)V", 969 reinterpret_cast<void*>(InjectDiagnosticData)}, 970 {"nativeIsDeviceContextSupported", 971 "()Z", 972 reinterpret_cast<void*>(IsDeviceContextSupported)}, 973 {"nativeInjectDeviceContext", 974 "(I)V", 975 reinterpret_cast<void*>(InjectDeviceContext)}, 976 {"nativeIsGeofencingSupported", 977 "()Z", 978 reinterpret_cast<void*>(IsGeofencingSupported)}, 979 {"nativeAddGeofences", 980 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V", 981 reinterpret_cast<void*>(AddGeofences)}, 982 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, 983 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, 984 {"nativeModifyGeofenceOption", 985 "(IIIIII)V", 986 reinterpret_cast<void*>(ModifyGeofenceOption)}, 987 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} 988 }; 989 990 /* 991 * Registration method invoked on JNI Load. 992 */ 993 int register_android_server_location_FlpHardwareProvider(JNIEnv* env) { 994 return jniRegisterNativeMethods( 995 env, 996 "com/android/server/location/FlpHardwareProvider", 997 sMethods, 998 NELEM(sMethods) 999 ); 1000 } 1001 1002 } /* name-space Android */ 1003