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