1 /* 2 ** 3 ** Copyright 2015, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 //#define LOG_NDEBUG 0 19 #define LOG_TAG "Radio-JNI" 20 #include <utils/Log.h> 21 22 #include "jni.h" 23 #include "JNIHelp.h" 24 #include "core_jni_helpers.h" 25 #include <system/radio.h> 26 #include <system/radio_metadata.h> 27 #include <radio/RadioCallback.h> 28 #include <radio/Radio.h> 29 #include <utils/RefBase.h> 30 #include <utils/Vector.h> 31 #include <binder/IMemory.h> 32 #include <binder/MemoryDealer.h> 33 34 using namespace android; 35 36 static jclass gArrayListClass; 37 static struct { 38 jmethodID add; 39 } gArrayListMethods; 40 41 static const char* const kRadioManagerClassPathName = "android/hardware/radio/RadioManager"; 42 static jclass gRadioManagerClass; 43 44 static const char* const kRadioModuleClassPathName = "android/hardware/radio/RadioModule"; 45 static jclass gRadioModuleClass; 46 static struct { 47 jfieldID mNativeContext; 48 jfieldID mId; 49 } gModuleFields; 50 static jmethodID gPostEventFromNative; 51 52 static const char* const kModulePropertiesClassPathName = 53 "android/hardware/radio/RadioManager$ModuleProperties"; 54 static jclass gModulePropertiesClass; 55 static jmethodID gModulePropertiesCstor; 56 57 58 static const char* const kRadioBandDescriptorClassPathName = 59 "android/hardware/radio/RadioManager$BandDescriptor"; 60 static jclass gRadioBandDescriptorClass; 61 static struct { 62 jfieldID mRegion; 63 jfieldID mType; 64 jfieldID mLowerLimit; 65 jfieldID mUpperLimit; 66 jfieldID mSpacing; 67 } gRadioBandDescriptorFields; 68 69 static const char* const kRadioFmBandDescriptorClassPathName = 70 "android/hardware/radio/RadioManager$FmBandDescriptor"; 71 static jclass gRadioFmBandDescriptorClass; 72 static jmethodID gRadioFmBandDescriptorCstor; 73 74 static const char* const kRadioAmBandDescriptorClassPathName = 75 "android/hardware/radio/RadioManager$AmBandDescriptor"; 76 static jclass gRadioAmBandDescriptorClass; 77 static jmethodID gRadioAmBandDescriptorCstor; 78 79 static const char* const kRadioBandConfigClassPathName = 80 "android/hardware/radio/RadioManager$BandConfig"; 81 static jclass gRadioBandConfigClass; 82 static struct { 83 jfieldID mDescriptor; 84 } gRadioBandConfigFields; 85 86 87 static const char* const kRadioFmBandConfigClassPathName = 88 "android/hardware/radio/RadioManager$FmBandConfig"; 89 static jclass gRadioFmBandConfigClass; 90 static jmethodID gRadioFmBandConfigCstor; 91 static struct { 92 jfieldID mStereo; 93 jfieldID mRds; 94 jfieldID mTa; 95 jfieldID mAf; 96 } gRadioFmBandConfigFields; 97 98 static const char* const kRadioAmBandConfigClassPathName = 99 "android/hardware/radio/RadioManager$AmBandConfig"; 100 static jclass gRadioAmBandConfigClass; 101 static jmethodID gRadioAmBandConfigCstor; 102 static struct { 103 jfieldID mStereo; 104 } gRadioAmBandConfigFields; 105 106 107 static const char* const kRadioProgramInfoClassPathName = 108 "android/hardware/radio/RadioManager$ProgramInfo"; 109 static jclass gRadioProgramInfoClass; 110 static jmethodID gRadioProgramInfoCstor; 111 112 static const char* const kRadioMetadataClassPathName = 113 "android/hardware/radio/RadioMetadata"; 114 static jclass gRadioMetadataClass; 115 static jmethodID gRadioMetadataCstor; 116 static struct { 117 jmethodID putIntFromNative; 118 jmethodID putStringFromNative; 119 jmethodID putBitmapFromNative; 120 } gRadioMetadataMethods; 121 122 static Mutex gLock; 123 124 enum { 125 RADIO_STATUS_OK = 0, 126 RADIO_STATUS_ERROR = INT_MIN, 127 RADIO_PERMISSION_DENIED = -1, 128 RADIO_STATUS_NO_INIT = -19, 129 RADIO_STATUS_BAD_VALUE = -22, 130 RADIO_STATUS_DEAD_OBJECT = -32, 131 RADIO_STATUS_INVALID_OPERATION = -38, 132 RADIO_STATUS_TIMED_OUT = -110, 133 }; 134 135 136 // ---------------------------------------------------------------------------- 137 138 static sp<Radio> getRadio(JNIEnv* env, jobject thiz) 139 { 140 Mutex::Autolock l(gLock); 141 Radio* const radio = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext); 142 return sp<Radio>(radio); 143 } 144 145 static sp<Radio> setRadio(JNIEnv* env, jobject thiz, const sp<Radio>& module) 146 { 147 Mutex::Autolock l(gLock); 148 sp<Radio> old = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext); 149 if (module.get()) { 150 module->incStrong((void*)setRadio); 151 } 152 if (old != 0) { 153 old->decStrong((void*)setRadio); 154 } 155 env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get()); 156 return old; 157 } 158 159 static jint convertBandDescriptorFromNative(JNIEnv *env, 160 jobject *jBandDescriptor, 161 const radio_band_config_t *nBandconfig) 162 { 163 ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region); 164 165 if (nBandconfig->band.type == RADIO_BAND_FM || 166 nBandconfig->band.type == RADIO_BAND_FM_HD) { 167 *jBandDescriptor = env->NewObject(gRadioFmBandDescriptorClass, gRadioFmBandDescriptorCstor, 168 nBandconfig->region, nBandconfig->band.type, 169 nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, 170 nBandconfig->band.spacings[0], 171 nBandconfig->band.fm.stereo, 172 nBandconfig->band.fm.rds != RADIO_RDS_NONE, 173 nBandconfig->band.fm.ta, 174 nBandconfig->band.fm.af); 175 } else if (nBandconfig->band.type == RADIO_BAND_AM) { 176 *jBandDescriptor = env->NewObject(gRadioAmBandDescriptorClass, gRadioAmBandDescriptorCstor, 177 nBandconfig->region, nBandconfig->band.type, 178 nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, 179 nBandconfig->band.spacings[0], 180 nBandconfig->band.am.stereo); 181 } else { 182 ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type); 183 return (jint)RADIO_STATUS_BAD_VALUE; 184 } 185 186 if (*jBandDescriptor == NULL) { 187 return (jint)RADIO_STATUS_NO_INIT; 188 } 189 190 return (jint)RADIO_STATUS_OK; 191 } 192 193 static jint convertBandConfigFromNative(JNIEnv *env, 194 jobject *jBandConfig, 195 const radio_band_config_t *nBandconfig) 196 { 197 ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region); 198 199 if (nBandconfig->band.type == RADIO_BAND_FM || 200 nBandconfig->band.type == RADIO_BAND_FM_HD) { 201 *jBandConfig = env->NewObject(gRadioFmBandConfigClass, gRadioFmBandConfigCstor, 202 nBandconfig->region, nBandconfig->band.type, 203 nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, 204 nBandconfig->band.spacings[0], 205 nBandconfig->band.fm.stereo, 206 nBandconfig->band.fm.rds != RADIO_RDS_NONE, 207 nBandconfig->band.fm.ta, 208 nBandconfig->band.fm.af); 209 } else if (nBandconfig->band.type == RADIO_BAND_AM) { 210 *jBandConfig = env->NewObject(gRadioAmBandConfigClass, gRadioAmBandConfigCstor, 211 nBandconfig->region, nBandconfig->band.type, 212 nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, 213 nBandconfig->band.spacings[0], 214 nBandconfig->band.am.stereo); 215 } else { 216 ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type); 217 return (jint)RADIO_STATUS_BAD_VALUE; 218 } 219 220 if (*jBandConfig == NULL) { 221 return (jint)RADIO_STATUS_NO_INIT; 222 } 223 224 return (jint)RADIO_STATUS_OK; 225 } 226 227 static jint convertMetadataFromNative(JNIEnv *env, 228 jobject *jMetadata, 229 const radio_metadata_t *nMetadata) 230 { 231 ALOGV("%s", __FUNCTION__); 232 int count = radio_metadata_get_count(nMetadata); 233 if (count <= 0) { 234 return (jint)count; 235 } 236 *jMetadata = env->NewObject(gRadioMetadataClass, gRadioMetadataCstor); 237 238 jint jCount = 0; 239 jint jStatus = 0; 240 for (unsigned int i = 0; i < (unsigned int)count; i++) { 241 radio_metadata_key_t key; 242 radio_metadata_type_t type; 243 void *value; 244 unsigned int size; 245 if (radio_metadata_get_at_index(nMetadata, i , &key, &type, &value, &size) != 0) { 246 continue; 247 } 248 switch (type) { 249 case RADIO_METADATA_TYPE_INT: { 250 ALOGV("%s RADIO_METADATA_TYPE_INT %d", __FUNCTION__, key); 251 jStatus = env->CallIntMethod(*jMetadata, 252 gRadioMetadataMethods.putIntFromNative, 253 key, *(jint *)value); 254 if (jStatus == 0) { 255 jCount++; 256 } 257 } break; 258 case RADIO_METADATA_TYPE_TEXT: { 259 ALOGV("%s RADIO_METADATA_TYPE_TEXT %d", __FUNCTION__, key); 260 jstring jText = env->NewStringUTF((char *)value); 261 jStatus = env->CallIntMethod(*jMetadata, 262 gRadioMetadataMethods.putStringFromNative, 263 key, jText); 264 if (jStatus == 0) { 265 jCount++; 266 } 267 env->DeleteLocalRef(jText); 268 } break; 269 case RADIO_METADATA_TYPE_RAW: { 270 ALOGV("%s RADIO_METADATA_TYPE_RAW %d size %u", __FUNCTION__, key, size); 271 if (size == 0) { 272 break; 273 } 274 jbyteArray jData = env->NewByteArray(size); 275 if (jData == NULL) { 276 break; 277 } 278 env->SetByteArrayRegion(jData, 0, size, (jbyte *)value); 279 jStatus = env->CallIntMethod(*jMetadata, 280 gRadioMetadataMethods.putBitmapFromNative, 281 key, jData); 282 if (jStatus == 0) { 283 jCount++; 284 } 285 env->DeleteLocalRef(jData); 286 } break; 287 } 288 } 289 return jCount; 290 } 291 292 static jint convertProgramInfoFromNative(JNIEnv *env, 293 jobject *jProgramInfo, 294 const radio_program_info_t *nProgramInfo) 295 { 296 ALOGV("%s", __FUNCTION__); 297 int jStatus; 298 jobject jMetadata = NULL; 299 if (nProgramInfo->metadata != NULL) { 300 ALOGV("%s metadata %p", __FUNCTION__, nProgramInfo->metadata); 301 jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata); 302 if (jStatus < 0) { 303 return jStatus; 304 } 305 } 306 307 ALOGV("%s channel %d tuned %d", __FUNCTION__, nProgramInfo->channel, nProgramInfo->tuned); 308 309 *jProgramInfo = env->NewObject(gRadioProgramInfoClass, gRadioProgramInfoCstor, 310 nProgramInfo->channel, nProgramInfo->sub_channel, 311 nProgramInfo->tuned, nProgramInfo->stereo, 312 nProgramInfo->digital, nProgramInfo->signal_strength, 313 jMetadata); 314 315 env->DeleteLocalRef(jMetadata); 316 return (jint)RADIO_STATUS_OK; 317 } 318 319 320 static jint convertBandConfigToNative(JNIEnv *env, 321 radio_band_config_t *nBandconfig, 322 jobject jBandConfig) 323 { 324 ALOGV("%s", __FUNCTION__); 325 326 jobject jDescriptor = env->GetObjectField(jBandConfig, gRadioBandConfigFields.mDescriptor); 327 328 if (jDescriptor == NULL) { 329 return (jint)RADIO_STATUS_NO_INIT; 330 } 331 332 nBandconfig->region = 333 (radio_region_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mRegion); 334 nBandconfig->band.type = 335 (radio_band_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mType); 336 nBandconfig->band.lower_limit = 337 env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mLowerLimit); 338 nBandconfig->band.upper_limit = 339 env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mUpperLimit); 340 nBandconfig->band.num_spacings = 1; 341 nBandconfig->band.spacings[0] = 342 env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mSpacing); 343 344 if (env->IsInstanceOf(jBandConfig, gRadioFmBandConfigClass)) { 345 nBandconfig->band.fm.deemphasis = radio_demephasis_for_region(nBandconfig->region); 346 nBandconfig->band.fm.stereo = 347 env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mStereo); 348 nBandconfig->band.fm.rds = 349 radio_rds_for_region(env->GetBooleanField(jBandConfig, 350 gRadioFmBandConfigFields.mRds), 351 nBandconfig->region); 352 nBandconfig->band.fm.ta = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mTa); 353 nBandconfig->band.fm.af = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mAf); 354 } else if (env->IsInstanceOf(jBandConfig, gRadioAmBandConfigClass)) { 355 nBandconfig->band.am.stereo = 356 env->GetBooleanField(jBandConfig, gRadioAmBandConfigFields.mStereo); 357 } else { 358 return (jint)RADIO_STATUS_BAD_VALUE; 359 } 360 361 return (jint)RADIO_STATUS_OK; 362 } 363 364 static jint 365 android_hardware_Radio_listModules(JNIEnv *env, jobject clazz, 366 jobject jModules) 367 { 368 ALOGV("%s", __FUNCTION__); 369 370 if (jModules == NULL) { 371 ALOGE("listModules NULL ArrayList"); 372 return RADIO_STATUS_BAD_VALUE; 373 } 374 if (!env->IsInstanceOf(jModules, gArrayListClass)) { 375 ALOGE("listModules not an arraylist"); 376 return RADIO_STATUS_BAD_VALUE; 377 } 378 379 unsigned int numModules = 0; 380 radio_properties_t *nModules = NULL; 381 382 status_t status = Radio::listModules(nModules, &numModules); 383 if (status != NO_ERROR || numModules == 0) { 384 return (jint)status; 385 } 386 387 nModules = (radio_properties_t *)calloc(numModules, sizeof(radio_properties_t)); 388 389 status = Radio::listModules(nModules, &numModules); 390 ALOGV("%s Radio::listModules status %d numModules %d", __FUNCTION__, status, numModules); 391 392 if (status != NO_ERROR) { 393 numModules = 0; 394 } 395 396 for (size_t i = 0; i < numModules; i++) { 397 if (nModules[i].num_bands == 0) { 398 continue; 399 } 400 ALOGV("%s module %zu id %d implementor %s product %s", 401 __FUNCTION__, i, nModules[i].handle, nModules[i].implementor, 402 nModules[i].product); 403 404 405 jobjectArray jBands = env->NewObjectArray(nModules[i].num_bands, 406 gRadioBandDescriptorClass, NULL); 407 408 for (size_t j = 0; j < nModules[i].num_bands; j++) { 409 jobject jBandDescriptor; 410 int jStatus = 411 convertBandDescriptorFromNative(env, &jBandDescriptor, &nModules[i].bands[j]); 412 if (jStatus != RADIO_STATUS_OK) { 413 continue; 414 } 415 env->SetObjectArrayElement(jBands, j, jBandDescriptor); 416 env->DeleteLocalRef(jBandDescriptor); 417 } 418 419 if (env->GetArrayLength(jBands) == 0) { 420 continue; 421 } 422 jstring jImplementor = env->NewStringUTF(nModules[i].implementor); 423 jstring jProduct = env->NewStringUTF(nModules[i].product); 424 jstring jVersion = env->NewStringUTF(nModules[i].version); 425 jstring jSerial = env->NewStringUTF(nModules[i].serial); 426 jobject jModule = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor, 427 nModules[i].handle, nModules[i].class_id, 428 jImplementor, jProduct, jVersion, jSerial, 429 nModules[i].num_tuners, 430 nModules[i].num_audio_sources, 431 nModules[i].supports_capture, 432 jBands); 433 434 env->DeleteLocalRef(jImplementor); 435 env->DeleteLocalRef(jProduct); 436 env->DeleteLocalRef(jVersion); 437 env->DeleteLocalRef(jSerial); 438 env->DeleteLocalRef(jBands); 439 if (jModule == NULL) { 440 continue; 441 } 442 env->CallBooleanMethod(jModules, gArrayListMethods.add, jModule); 443 } 444 445 free(nModules); 446 return (jint) status; 447 } 448 449 // ---------------------------------------------------------------------------- 450 451 class JNIRadioCallback: public RadioCallback 452 { 453 public: 454 JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz); 455 ~JNIRadioCallback(); 456 457 virtual void onEvent(struct radio_event *event); 458 459 private: 460 jclass mClass; // Reference to Radio class 461 jobject mObject; // Weak ref to Radio Java object to call on 462 }; 463 464 JNIRadioCallback::JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz) 465 { 466 467 // Hold onto the RadioModule class for use in calling the static method 468 // that posts events to the application thread. 469 jclass clazz = env->GetObjectClass(thiz); 470 if (clazz == NULL) { 471 ALOGE("Can't find class %s", kRadioModuleClassPathName); 472 return; 473 } 474 mClass = (jclass)env->NewGlobalRef(clazz); 475 476 // We use a weak reference so the RadioModule object can be garbage collected. 477 // The reference is only used as a proxy for callbacks. 478 mObject = env->NewGlobalRef(weak_thiz); 479 } 480 481 JNIRadioCallback::~JNIRadioCallback() 482 { 483 // remove global references 484 JNIEnv *env = AndroidRuntime::getJNIEnv(); 485 if (env == NULL) { 486 return; 487 } 488 env->DeleteGlobalRef(mObject); 489 env->DeleteGlobalRef(mClass); 490 } 491 492 void JNIRadioCallback::onEvent(struct radio_event *event) 493 { 494 JNIEnv *env = AndroidRuntime::getJNIEnv(); 495 if (env == NULL) { 496 return; 497 } 498 499 ALOGV("%s", __FUNCTION__); 500 501 jobject jObj = NULL; 502 jint jArg2 = 0; 503 jint jStatus = RADIO_STATUS_OK; 504 switch (event->type) { 505 case RADIO_EVENT_CONFIG: 506 jStatus = convertBandConfigFromNative(env, &jObj, &event->config); 507 break; 508 case RADIO_EVENT_TUNED: 509 case RADIO_EVENT_AF_SWITCH: 510 ALOGV("%s RADIO_EVENT_TUNED channel %d", __FUNCTION__, event->info.channel); 511 jStatus = convertProgramInfoFromNative(env, &jObj, &event->info); 512 break; 513 case RADIO_EVENT_METADATA: 514 jStatus = convertMetadataFromNative(env, &jObj, event->metadata); 515 if (jStatus >= 0) { 516 jStatus = RADIO_STATUS_OK; 517 } 518 break; 519 case RADIO_EVENT_ANTENNA: 520 case RADIO_EVENT_TA: 521 case RADIO_EVENT_CONTROL: 522 jArg2 = event->on ? 1 : 0; 523 break; 524 } 525 526 if (jStatus != RADIO_STATUS_OK) { 527 return; 528 } 529 env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, 530 event->type, event->status, jArg2, jObj); 531 532 env->DeleteLocalRef(jObj); 533 if (env->ExceptionCheck()) { 534 ALOGW("An exception occurred while notifying an event."); 535 env->ExceptionClear(); 536 } 537 } 538 539 // ---------------------------------------------------------------------------- 540 541 static void 542 android_hardware_Radio_setup(JNIEnv *env, jobject thiz, 543 jobject weak_this, jobject jConfig, jboolean withAudio) 544 { 545 ALOGV("%s", __FUNCTION__); 546 547 setRadio(env, thiz, 0); 548 549 sp<JNIRadioCallback> callback = new JNIRadioCallback(env, thiz, weak_this); 550 551 radio_handle_t handle = (radio_handle_t)env->GetIntField(thiz, gModuleFields.mId); 552 553 struct radio_band_config nConfig; 554 struct radio_band_config *configPtr = NULL; 555 if (jConfig != NULL) { 556 jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig); 557 if (jStatus != RADIO_STATUS_OK) { 558 return; 559 } 560 configPtr = &nConfig; 561 } 562 sp<Radio> module = Radio::attach(handle, configPtr, (bool)withAudio, callback); 563 if (module == 0) { 564 return; 565 } 566 567 setRadio(env, thiz, module); 568 } 569 570 static void 571 android_hardware_Radio_close(JNIEnv *env, jobject thiz) 572 { 573 ALOGV("%s", __FUNCTION__); 574 sp<Radio> module = setRadio(env, thiz, 0); 575 ALOGV("detach module %p", module.get()); 576 if (module != 0) { 577 ALOGV("detach module->detach()"); 578 module->detach(); 579 } 580 } 581 582 static void 583 android_hardware_Radio_finalize(JNIEnv *env, jobject thiz) 584 { 585 ALOGV("%s", __FUNCTION__); 586 sp<Radio> module = getRadio(env, thiz); 587 if (module != 0) { 588 ALOGW("Radio finalized without being detached"); 589 } 590 android_hardware_Radio_close(env, thiz); 591 } 592 593 static jint 594 android_hardware_Radio_setConfiguration(JNIEnv *env, jobject thiz, jobject jConfig) 595 { 596 ALOGV("%s", __FUNCTION__); 597 sp<Radio> module = getRadio(env, thiz); 598 if (module == NULL) { 599 return RADIO_STATUS_NO_INIT; 600 } 601 602 if (!env->IsInstanceOf(jConfig, gRadioFmBandConfigClass) && 603 !env->IsInstanceOf(jConfig, gRadioAmBandConfigClass)) { 604 return RADIO_STATUS_BAD_VALUE; 605 } 606 607 struct radio_band_config nConfig; 608 jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig); 609 if (jStatus != RADIO_STATUS_OK) { 610 return jStatus; 611 } 612 613 status_t status = module->setConfiguration(&nConfig); 614 return (jint)status; 615 } 616 617 static jint 618 android_hardware_Radio_getConfiguration(JNIEnv *env, jobject thiz, jobjectArray jConfigs) 619 { 620 ALOGV("%s", __FUNCTION__); 621 sp<Radio> module = getRadio(env, thiz); 622 if (module == NULL) { 623 return RADIO_STATUS_NO_INIT; 624 } 625 if (env->GetArrayLength(jConfigs) != 1) { 626 return (jint)RADIO_STATUS_BAD_VALUE; 627 } 628 629 struct radio_band_config nConfig; 630 631 status_t status = module->getConfiguration(&nConfig); 632 if (status != NO_ERROR) { 633 return (jint)status; 634 } 635 jobject jConfig; 636 int jStatus = convertBandConfigFromNative(env, &jConfig, &nConfig); 637 if (jStatus != RADIO_STATUS_OK) { 638 return jStatus; 639 } 640 env->SetObjectArrayElement(jConfigs, 0, jConfig); 641 env->DeleteLocalRef(jConfig); 642 return RADIO_STATUS_OK; 643 } 644 645 static jint 646 android_hardware_Radio_setMute(JNIEnv *env, jobject thiz, jboolean mute) 647 { 648 ALOGV("%s", __FUNCTION__); 649 sp<Radio> module = getRadio(env, thiz); 650 if (module == NULL) { 651 return RADIO_STATUS_NO_INIT; 652 } 653 status_t status = module->setMute((bool)mute); 654 return (jint)status; 655 } 656 657 static jboolean 658 android_hardware_Radio_getMute(JNIEnv *env, jobject thiz) 659 { 660 ALOGV("%s", __FUNCTION__); 661 sp<Radio> module = getRadio(env, thiz); 662 if (module == NULL) { 663 return true; 664 } 665 bool mute = true; 666 status_t status = module->getMute(&mute); 667 if (status != NO_ERROR) { 668 return true; 669 } 670 return (jboolean)mute; 671 } 672 673 static jint 674 android_hardware_Radio_step(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel) 675 { 676 ALOGV("%s", __FUNCTION__); 677 sp<Radio> module = getRadio(env, thiz); 678 if (module == NULL) { 679 return RADIO_STATUS_NO_INIT; 680 } 681 status_t status = module->step((radio_direction_t)direction, (bool)skipSubChannel); 682 return (jint)status; 683 } 684 685 static jint 686 android_hardware_Radio_scan(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel) 687 { 688 ALOGV("%s", __FUNCTION__); 689 sp<Radio> module = getRadio(env, thiz); 690 if (module == NULL) { 691 return RADIO_STATUS_NO_INIT; 692 } 693 status_t status = module->scan((radio_direction_t)direction, (bool)skipSubChannel); 694 return (jint)status; 695 } 696 697 static jint 698 android_hardware_Radio_tune(JNIEnv *env, jobject thiz, jint channel, jint subChannel) 699 { 700 ALOGV("%s", __FUNCTION__); 701 sp<Radio> module = getRadio(env, thiz); 702 if (module == NULL) { 703 return RADIO_STATUS_NO_INIT; 704 } 705 status_t status = module->tune((unsigned int)channel, (unsigned int)subChannel); 706 return (jint)status; 707 } 708 709 static jint 710 android_hardware_Radio_cancel(JNIEnv *env, jobject thiz) 711 { 712 ALOGV("%s", __FUNCTION__); 713 sp<Radio> module = getRadio(env, thiz); 714 if (module == NULL) { 715 return RADIO_STATUS_NO_INIT; 716 } 717 status_t status = module->cancel(); 718 return (jint)status; 719 } 720 721 static jint 722 android_hardware_Radio_getProgramInformation(JNIEnv *env, jobject thiz, jobjectArray jInfos) 723 { 724 ALOGV("%s", __FUNCTION__); 725 sp<Radio> module = getRadio(env, thiz); 726 if (module == NULL) { 727 return RADIO_STATUS_NO_INIT; 728 } 729 if (env->GetArrayLength(jInfos) != 1) { 730 return (jint)RADIO_STATUS_BAD_VALUE; 731 } 732 733 struct radio_program_info nInfo; 734 radio_metadata_allocate(&nInfo.metadata, 0, 0); 735 jobject jInfo = NULL; 736 int jStatus; 737 738 jStatus = (int)module->getProgramInformation(&nInfo); 739 if (jStatus != RADIO_STATUS_OK) { 740 goto exit; 741 } 742 jStatus = convertProgramInfoFromNative(env, &jInfo, &nInfo); 743 if (jStatus != RADIO_STATUS_OK) { 744 goto exit; 745 } 746 env->SetObjectArrayElement(jInfos, 0, jInfo); 747 748 exit: 749 if (jInfo != NULL) { 750 env->DeleteLocalRef(jInfo); 751 } 752 radio_metadata_deallocate(nInfo.metadata); 753 return jStatus; 754 } 755 756 static jboolean 757 android_hardware_Radio_isAntennaConnected(JNIEnv *env, jobject thiz) 758 { 759 ALOGV("%s", __FUNCTION__); 760 sp<Radio> module = getRadio(env, thiz); 761 if (module == NULL) { 762 return false; 763 } 764 765 struct radio_band_config nConfig; 766 767 status_t status = module->getConfiguration(&nConfig); 768 if (status != NO_ERROR) { 769 return false; 770 } 771 772 return (jboolean)nConfig.band.antenna_connected; 773 } 774 775 776 static jboolean 777 android_hardware_Radio_hasControl(JNIEnv *env, jobject thiz) 778 { 779 ALOGV("%s", __FUNCTION__); 780 sp<Radio> module = getRadio(env, thiz); 781 if (module == NULL) { 782 return false; 783 } 784 785 bool hasControl; 786 status_t status = module->hasControl(&hasControl); 787 if (status != NO_ERROR) { 788 return false; 789 } 790 791 return (jboolean)hasControl; 792 } 793 794 795 static JNINativeMethod gMethods[] = { 796 {"listModules", 797 "(Ljava/util/List;)I", 798 (void *)android_hardware_Radio_listModules}, 799 }; 800 801 static JNINativeMethod gModuleMethods[] = { 802 {"native_setup", 803 "(Ljava/lang/Object;Landroid/hardware/radio/RadioManager$BandConfig;Z)V", 804 (void *)android_hardware_Radio_setup}, 805 {"native_finalize", 806 "()V", 807 (void *)android_hardware_Radio_finalize}, 808 {"close", 809 "()V", 810 (void *)android_hardware_Radio_close}, 811 {"setConfiguration", 812 "(Landroid/hardware/radio/RadioManager$BandConfig;)I", 813 (void *)android_hardware_Radio_setConfiguration}, 814 {"getConfiguration", 815 "([Landroid/hardware/radio/RadioManager$BandConfig;)I", 816 (void *)android_hardware_Radio_getConfiguration}, 817 {"setMute", 818 "(Z)I", 819 (void *)android_hardware_Radio_setMute}, 820 {"getMute", 821 "()Z", 822 (void *)android_hardware_Radio_getMute}, 823 {"step", 824 "(IZ)I", 825 (void *)android_hardware_Radio_step}, 826 {"scan", 827 "(IZ)I", 828 (void *)android_hardware_Radio_scan}, 829 {"tune", 830 "(II)I", 831 (void *)android_hardware_Radio_tune}, 832 {"cancel", 833 "()I", 834 (void *)android_hardware_Radio_cancel}, 835 {"getProgramInformation", 836 "([Landroid/hardware/radio/RadioManager$ProgramInfo;)I", 837 (void *)android_hardware_Radio_getProgramInformation}, 838 {"isAntennaConnected", 839 "()Z", 840 (void *)android_hardware_Radio_isAntennaConnected}, 841 {"hasControl", 842 "()Z", 843 (void *)android_hardware_Radio_hasControl}, 844 }; 845 846 int register_android_hardware_Radio(JNIEnv *env) 847 { 848 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); 849 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); 850 gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); 851 852 jclass lClass = FindClassOrDie(env, kRadioManagerClassPathName); 853 gRadioManagerClass = MakeGlobalRefOrDie(env, lClass); 854 855 jclass moduleClass = FindClassOrDie(env, kRadioModuleClassPathName); 856 gRadioModuleClass = MakeGlobalRefOrDie(env, moduleClass); 857 gPostEventFromNative = GetStaticMethodIDOrDie(env, moduleClass, "postEventFromNative", 858 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 859 gModuleFields.mNativeContext = GetFieldIDOrDie(env, moduleClass, "mNativeContext", "J"); 860 gModuleFields.mId = GetFieldIDOrDie(env, moduleClass, "mId", "I"); 861 862 jclass modulePropertiesClass = FindClassOrDie(env, kModulePropertiesClassPathName); 863 gModulePropertiesClass = MakeGlobalRefOrDie(env, modulePropertiesClass); 864 gModulePropertiesCstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>", 865 "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;)V"); 866 867 jclass bandDescriptorClass = FindClassOrDie(env, kRadioBandDescriptorClassPathName); 868 gRadioBandDescriptorClass = MakeGlobalRefOrDie(env, bandDescriptorClass); 869 gRadioBandDescriptorFields.mRegion = GetFieldIDOrDie(env, bandDescriptorClass, "mRegion", "I"); 870 gRadioBandDescriptorFields.mType = GetFieldIDOrDie(env, bandDescriptorClass, "mType", "I"); 871 gRadioBandDescriptorFields.mLowerLimit = 872 GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I"); 873 gRadioBandDescriptorFields.mUpperLimit = 874 GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I"); 875 gRadioBandDescriptorFields.mSpacing = 876 GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I"); 877 878 jclass fmBandDescriptorClass = FindClassOrDie(env, kRadioFmBandDescriptorClassPathName); 879 gRadioFmBandDescriptorClass = MakeGlobalRefOrDie(env, fmBandDescriptorClass); 880 gRadioFmBandDescriptorCstor = GetMethodIDOrDie(env, fmBandDescriptorClass, "<init>", 881 "(IIIIIZZZZ)V"); 882 883 jclass amBandDescriptorClass = FindClassOrDie(env, kRadioAmBandDescriptorClassPathName); 884 gRadioAmBandDescriptorClass = MakeGlobalRefOrDie(env, amBandDescriptorClass); 885 gRadioAmBandDescriptorCstor = GetMethodIDOrDie(env, amBandDescriptorClass, "<init>", 886 "(IIIIIZ)V"); 887 888 jclass bandConfigClass = FindClassOrDie(env, kRadioBandConfigClassPathName); 889 gRadioBandConfigClass = MakeGlobalRefOrDie(env, bandConfigClass); 890 gRadioBandConfigFields.mDescriptor = 891 GetFieldIDOrDie(env, bandConfigClass, "mDescriptor", 892 "Landroid/hardware/radio/RadioManager$BandDescriptor;"); 893 894 jclass fmBandConfigClass = FindClassOrDie(env, kRadioFmBandConfigClassPathName); 895 gRadioFmBandConfigClass = MakeGlobalRefOrDie(env, fmBandConfigClass); 896 gRadioFmBandConfigCstor = GetMethodIDOrDie(env, fmBandConfigClass, "<init>", 897 "(IIIIIZZZZ)V"); 898 gRadioFmBandConfigFields.mStereo = GetFieldIDOrDie(env, fmBandConfigClass, "mStereo", "Z"); 899 gRadioFmBandConfigFields.mRds = GetFieldIDOrDie(env, fmBandConfigClass, "mRds", "Z"); 900 gRadioFmBandConfigFields.mTa = GetFieldIDOrDie(env, fmBandConfigClass, "mTa", "Z"); 901 gRadioFmBandConfigFields.mAf = GetFieldIDOrDie(env, fmBandConfigClass, "mAf", "Z"); 902 903 904 jclass amBandConfigClass = FindClassOrDie(env, kRadioAmBandConfigClassPathName); 905 gRadioAmBandConfigClass = MakeGlobalRefOrDie(env, amBandConfigClass); 906 gRadioAmBandConfigCstor = GetMethodIDOrDie(env, amBandConfigClass, "<init>", 907 "(IIIIIZ)V"); 908 gRadioAmBandConfigFields.mStereo = GetFieldIDOrDie(env, amBandConfigClass, "mStereo", "Z"); 909 910 jclass programInfoClass = FindClassOrDie(env, kRadioProgramInfoClassPathName); 911 gRadioProgramInfoClass = MakeGlobalRefOrDie(env, programInfoClass); 912 gRadioProgramInfoCstor = GetMethodIDOrDie(env, programInfoClass, "<init>", 913 "(IIZZZILandroid/hardware/radio/RadioMetadata;)V"); 914 915 jclass metadataClass = FindClassOrDie(env, kRadioMetadataClassPathName); 916 gRadioMetadataClass = MakeGlobalRefOrDie(env, metadataClass); 917 gRadioMetadataCstor = GetMethodIDOrDie(env, metadataClass, "<init>", "()V"); 918 gRadioMetadataMethods.putIntFromNative = GetMethodIDOrDie(env, metadataClass, 919 "putIntFromNative", 920 "(II)I"); 921 gRadioMetadataMethods.putStringFromNative = GetMethodIDOrDie(env, metadataClass, 922 "putStringFromNative", 923 "(ILjava/lang/String;)I"); 924 gRadioMetadataMethods.putBitmapFromNative = GetMethodIDOrDie(env, metadataClass, 925 "putBitmapFromNative", 926 "(I[B)I"); 927 928 929 RegisterMethodsOrDie(env, kRadioManagerClassPathName, gMethods, NELEM(gMethods)); 930 931 int ret = RegisterMethodsOrDie(env, kRadioModuleClassPathName, gModuleMethods, NELEM(gModuleMethods)); 932 933 ALOGI("%s DONE", __FUNCTION__); 934 935 return ret; 936 } 937