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