Home | History | Annotate | Download | only in jni
      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