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