diff options
author | Eric Laurent <elaurent@google.com> | 2015-03-05 15:17:20 -0800 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2015-03-13 15:32:59 -0700 |
commit | 633cb563f36001d6973b69291086cbdfe50612c5 (patch) | |
tree | 10a6624151d0d7f17926516d8235cd6c1805ea59 | |
parent | aa357ebe7a1416cce9752babbe221c83975a81ce (diff) | |
download | frameworks_base-633cb563f36001d6973b69291086cbdfe50612c5.zip frameworks_base-633cb563f36001d6973b69291086cbdfe50612c5.tar.gz frameworks_base-633cb563f36001d6973b69291086cbdfe50612c5.tar.bz2 |
broadcast radio JNI.
Initial implementation of broadcast radio JNI.
Change-Id: Ia01f567292295928fbf6d9c23de362867dc15314
-rw-r--r-- | core/jni/Android.mk | 5 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_hardware_Radio.cpp | 936 |
3 files changed, 942 insertions, 1 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 30a7e68..84568e4 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -140,6 +140,7 @@ LOCAL_SRC_FILES:= \ android_hardware_camera2_legacy_LegacyCameraDevice.cpp \ android_hardware_camera2_legacy_PerfMeasurement.cpp \ android_hardware_camera2_DngCreator.cpp \ + android_hardware_Radio.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ android_hardware_SoundTrigger.cpp \ @@ -236,10 +237,12 @@ LOCAL_SHARED_LIBRARIES := \ libpdfium \ libimg_utils \ libnetd_client \ + libradio \ libsoundtrigger \ libminikin \ libprocessgroup \ - libnativebridge + libnativebridge \ + libradio_metadata LOCAL_SHARED_LIBRARIES += \ libhwui \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index ad52e3f..441af15 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -81,6 +81,7 @@ extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env); extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env); extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); +extern int register_android_hardware_Radio(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); extern int register_android_hardware_SoundTrigger(JNIEnv *env); @@ -1254,6 +1255,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement), REG_JNI(register_android_hardware_camera2_DngCreator), + REG_JNI(register_android_hardware_Radio), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_SoundTrigger), diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp new file mode 100644 index 0000000..b9dd77a --- /dev/null +++ b/core/jni/android_hardware_Radio.cpp @@ -0,0 +1,936 @@ +/* +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Radio-JNI" +#include <utils/Log.h> + +#include "jni.h" +#include "JNIHelp.h" +#include "core_jni_helpers.h" +#include <system/radio.h> +#include <system/radio_metadata.h> +#include <radio/RadioCallback.h> +#include <radio/Radio.h> +#include <utils/RefBase.h> +#include <utils/Vector.h> +#include <binder/IMemory.h> +#include <binder/MemoryDealer.h> + +using namespace android; + +static jclass gArrayListClass; +static struct { + jmethodID add; +} gArrayListMethods; + +static const char* const kRadioManagerClassPathName = "android/hardware/radio/RadioManager"; +static jclass gRadioManagerClass; + +static const char* const kRadioModuleClassPathName = "android/hardware/radio/RadioModule"; +static jclass gRadioModuleClass; +static struct { + jfieldID mNativeContext; + jfieldID mId; +} gModuleFields; +static jmethodID gPostEventFromNative; + +static const char* const kModulePropertiesClassPathName = + "android/hardware/radio/RadioManager$ModuleProperties"; +static jclass gModulePropertiesClass; +static jmethodID gModulePropertiesCstor; + + +static const char* const kRadioBandDescriptorClassPathName = + "android/hardware/radio/RadioManager$BandDescriptor"; +static jclass gRadioBandDescriptorClass; +static struct { + jfieldID mRegion; + jfieldID mType; + jfieldID mLowerLimit; + jfieldID mUpperLimit; + jfieldID mSpacing; +} gRadioBandDescriptorFields; + +static const char* const kRadioFmBandDescriptorClassPathName = + "android/hardware/radio/RadioManager$FmBandDescriptor"; +static jclass gRadioFmBandDescriptorClass; +static jmethodID gRadioFmBandDescriptorCstor; + +static const char* const kRadioAmBandDescriptorClassPathName = + "android/hardware/radio/RadioManager$AmBandDescriptor"; +static jclass gRadioAmBandDescriptorClass; +static jmethodID gRadioAmBandDescriptorCstor; + +static const char* const kRadioBandConfigClassPathName = + "android/hardware/radio/RadioManager$BandConfig"; +static jclass gRadioBandConfigClass; +static struct { + jfieldID mDescriptor; +} gRadioBandConfigFields; + + +static const char* const kRadioFmBandConfigClassPathName = + "android/hardware/radio/RadioManager$FmBandConfig"; +static jclass gRadioFmBandConfigClass; +static jmethodID gRadioFmBandConfigCstor; +static struct { + jfieldID mStereo; + jfieldID mRds; + jfieldID mTa; + jfieldID mAf; +} gRadioFmBandConfigFields; + +static const char* const kRadioAmBandConfigClassPathName = + "android/hardware/radio/RadioManager$AmBandConfig"; +static jclass gRadioAmBandConfigClass; +static jmethodID gRadioAmBandConfigCstor; +static struct { + jfieldID mStereo; +} gRadioAmBandConfigFields; + + +static const char* const kRadioProgramInfoClassPathName = + "android/hardware/radio/RadioManager$ProgramInfo"; +static jclass gRadioProgramInfoClass; +static jmethodID gRadioProgramInfoCstor; + +static const char* const kRadioMetadataClassPathName = + "android/hardware/radio/RadioMetadata"; +static jclass gRadioMetadataClass; +static jmethodID gRadioMetadataCstor; +static struct { + jmethodID putIntFromNative; + jmethodID putStringFromNative; + jmethodID putBitmapFromNative; +} gRadioMetadataMethods; + +static Mutex gLock; + +enum { + RADIO_STATUS_OK = 0, + RADIO_STATUS_ERROR = INT_MIN, + RADIO_PERMISSION_DENIED = -1, + RADIO_STATUS_NO_INIT = -19, + RADIO_STATUS_BAD_VALUE = -22, + RADIO_STATUS_DEAD_OBJECT = -32, + RADIO_STATUS_INVALID_OPERATION = -38, + RADIO_STATUS_TIMED_OUT = -110, +}; + + +// ---------------------------------------------------------------------------- + +static sp<Radio> getRadio(JNIEnv* env, jobject thiz) +{ + Mutex::Autolock l(gLock); + Radio* const radio = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext); + return sp<Radio>(radio); +} + +static sp<Radio> setRadio(JNIEnv* env, jobject thiz, const sp<Radio>& module) +{ + Mutex::Autolock l(gLock); + sp<Radio> old = (Radio*)env->GetLongField(thiz, gModuleFields.mNativeContext); + if (module.get()) { + module->incStrong((void*)setRadio); + } + if (old != 0) { + old->decStrong((void*)setRadio); + } + env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get()); + return old; +} + +static jint convertBandDescriptorFromNative(JNIEnv *env, + jobject *jBandDescriptor, + const radio_band_config_t *nBandconfig) +{ + ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region); + + if (nBandconfig->band.type == RADIO_BAND_FM || + nBandconfig->band.type == RADIO_BAND_FM_HD) { + *jBandDescriptor = env->NewObject(gRadioFmBandDescriptorClass, gRadioFmBandDescriptorCstor, + nBandconfig->region, nBandconfig->band.type, + nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, + nBandconfig->band.spacings[0], + nBandconfig->band.fm.stereo, + nBandconfig->band.fm.rds != RADIO_RDS_NONE, + nBandconfig->band.fm.ta, + nBandconfig->band.fm.af); + } else if (nBandconfig->band.type == RADIO_BAND_AM) { + *jBandDescriptor = env->NewObject(gRadioAmBandDescriptorClass, gRadioAmBandDescriptorCstor, + nBandconfig->region, nBandconfig->band.type, + nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, + nBandconfig->band.spacings[0], + nBandconfig->band.am.stereo); + } else { + ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type); + return (jint)RADIO_STATUS_BAD_VALUE; + } + + if (*jBandDescriptor == NULL) { + return (jint)RADIO_STATUS_NO_INIT; + } + + return (jint)RADIO_STATUS_OK; +} + +static jint convertBandConfigFromNative(JNIEnv *env, + jobject *jBandConfig, + const radio_band_config_t *nBandconfig) +{ + ALOGV("%s type %d region %d", __FUNCTION__, nBandconfig->band.type, nBandconfig->region); + + if (nBandconfig->band.type == RADIO_BAND_FM || + nBandconfig->band.type == RADIO_BAND_FM_HD) { + *jBandConfig = env->NewObject(gRadioFmBandConfigClass, gRadioFmBandConfigCstor, + nBandconfig->region, nBandconfig->band.type, + nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, + nBandconfig->band.spacings[0], + nBandconfig->band.fm.stereo, + nBandconfig->band.fm.rds != RADIO_RDS_NONE, + nBandconfig->band.fm.ta, + nBandconfig->band.fm.af); + } else if (nBandconfig->band.type == RADIO_BAND_AM) { + *jBandConfig = env->NewObject(gRadioAmBandConfigClass, gRadioAmBandConfigCstor, + nBandconfig->region, nBandconfig->band.type, + nBandconfig->band.lower_limit, nBandconfig->band.upper_limit, + nBandconfig->band.spacings[0], + nBandconfig->band.am.stereo); + } else { + ALOGE("%s unknown band type %d", __FUNCTION__, nBandconfig->band.type); + return (jint)RADIO_STATUS_BAD_VALUE; + } + + if (*jBandConfig == NULL) { + return (jint)RADIO_STATUS_NO_INIT; + } + + return (jint)RADIO_STATUS_OK; +} + +static jint convertMetadataFromNative(JNIEnv *env, + jobject *jMetadata, + const radio_metadata_t *nMetadata) +{ + ALOGV("%s", __FUNCTION__); + int count = radio_metadata_get_count(nMetadata); + if (count <= 0) { + return (jint)count; + } + *jMetadata = env->NewObject(gRadioMetadataClass, gRadioMetadataCstor); + + jint jCount = 0; + jint jStatus = 0; + for (unsigned int i = 0; i < (unsigned int)count; i++) { + radio_metadata_key_t key; + radio_metadata_type_t type; + void *value; + unsigned int size; + if (radio_metadata_get_at_index(nMetadata, i , &key, &type, &value, &size) != 0) { + continue; + } + switch (type) { + case RADIO_METADATA_TYPE_INT: { + ALOGV("%s RADIO_METADATA_TYPE_INT %d", __FUNCTION__, key); + jStatus = env->CallIntMethod(*jMetadata, + gRadioMetadataMethods.putIntFromNative, + key, *(jint *)value); + if (jStatus == 0) { + jCount++; + } + } break; + case RADIO_METADATA_TYPE_TEXT: { + ALOGV("%s RADIO_METADATA_TYPE_TEXT %d", __FUNCTION__, key); + jstring jText = env->NewStringUTF((char *)value); + jStatus = env->CallIntMethod(*jMetadata, + gRadioMetadataMethods.putStringFromNative, + key, jText); + if (jStatus == 0) { + jCount++; + } + env->DeleteLocalRef(jText); + } break; + case RADIO_METADATA_TYPE_RAW: { + ALOGV("%s RADIO_METADATA_TYPE_RAW %d size %u", __FUNCTION__, key, size); + if (size == 0) { + break; + } + jbyteArray jData = env->NewByteArray(size); + if (jData == NULL) { + break; + } + env->SetByteArrayRegion(jData, 0, size, (jbyte *)value); + jStatus = env->CallIntMethod(*jMetadata, + gRadioMetadataMethods.putBitmapFromNative, + key, jData); + if (jStatus == 0) { + jCount++; + } + env->DeleteLocalRef(jData); + } break; + } + } + return jCount; +} + +static jint convertProgramInfoFromNative(JNIEnv *env, + jobject *jProgramInfo, + const radio_program_info_t *nProgramInfo) +{ + ALOGV("%s", __FUNCTION__); + int jStatus; + jobject jMetadata = NULL; + if (nProgramInfo->metadata != NULL) { + ALOGV("%s metadata %p", __FUNCTION__, nProgramInfo->metadata); + jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata); + if (jStatus < 0) { + return jStatus; + } + } + + ALOGV("%s channel %d tuned %d", __FUNCTION__, nProgramInfo->channel, nProgramInfo->tuned); + + *jProgramInfo = env->NewObject(gRadioProgramInfoClass, gRadioProgramInfoCstor, + nProgramInfo->channel, nProgramInfo->sub_channel, + nProgramInfo->tuned, nProgramInfo->stereo, + nProgramInfo->digital, nProgramInfo->signal_strength, + jMetadata); + + env->DeleteLocalRef(jMetadata); + return (jint)RADIO_STATUS_OK; +} + + +static jint convertBandConfigToNative(JNIEnv *env, + radio_band_config_t *nBandconfig, + jobject jBandConfig) +{ + ALOGV("%s", __FUNCTION__); + + jobject jDescriptor = env->GetObjectField(jBandConfig, gRadioBandConfigFields.mDescriptor); + + if (jDescriptor == NULL) { + return (jint)RADIO_STATUS_NO_INIT; + } + + nBandconfig->region = + (radio_region_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mRegion); + nBandconfig->band.type = + (radio_band_t)env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mType); + nBandconfig->band.lower_limit = + env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mLowerLimit); + nBandconfig->band.upper_limit = + env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mUpperLimit); + nBandconfig->band.num_spacings = 1; + nBandconfig->band.spacings[0] = + env->GetIntField(jDescriptor, gRadioBandDescriptorFields.mSpacing); + + if (env->IsInstanceOf(jBandConfig, gRadioFmBandConfigClass)) { + nBandconfig->band.fm.deemphasis = radio_demephasis_for_region(nBandconfig->region); + nBandconfig->band.fm.stereo = + env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mStereo); + nBandconfig->band.fm.rds = + radio_rds_for_region(env->GetBooleanField(jBandConfig, + gRadioFmBandConfigFields.mRds), + nBandconfig->region); + nBandconfig->band.fm.ta = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mTa); + nBandconfig->band.fm.af = env->GetBooleanField(jBandConfig, gRadioFmBandConfigFields.mAf); + } else if (env->IsInstanceOf(jBandConfig, gRadioAmBandConfigClass)) { + nBandconfig->band.am.stereo = + env->GetBooleanField(jBandConfig, gRadioAmBandConfigFields.mStereo); + } else { + return (jint)RADIO_STATUS_BAD_VALUE; + } + + return (jint)RADIO_STATUS_OK; +} + +static jint +android_hardware_Radio_listModules(JNIEnv *env, jobject clazz, + jobject jModules) +{ + ALOGV("%s", __FUNCTION__); + + if (jModules == NULL) { + ALOGE("listModules NULL ArrayList"); + return RADIO_STATUS_BAD_VALUE; + } + if (!env->IsInstanceOf(jModules, gArrayListClass)) { + ALOGE("listModules not an arraylist"); + return RADIO_STATUS_BAD_VALUE; + } + + unsigned int numModules = 0; + radio_properties_t *nModules = NULL; + + status_t status = Radio::listModules(nModules, &numModules); + if (status != NO_ERROR || numModules == 0) { + return (jint)status; + } + + nModules = (radio_properties_t *)calloc(numModules, sizeof(radio_properties_t)); + + status = Radio::listModules(nModules, &numModules); + ALOGV("%s Radio::listModules status %d numModules %d", __FUNCTION__, status, numModules); + + if (status != NO_ERROR) { + numModules = 0; + } + + for (size_t i = 0; i < numModules; i++) { + if (nModules[i].num_bands == 0) { + continue; + } + ALOGV("%s module %zu id %d implementor %s product %s", + __FUNCTION__, i, nModules[i].handle, nModules[i].implementor, + nModules[i].product); + + + jobjectArray jBands = env->NewObjectArray(nModules[i].num_bands, + gRadioBandDescriptorClass, NULL); + + for (size_t j = 0; j < nModules[i].num_bands; j++) { + jobject jBandDescriptor; + int jStatus = + convertBandDescriptorFromNative(env, &jBandDescriptor, &nModules[i].bands[j]); + if (jStatus != RADIO_STATUS_OK) { + continue; + } + env->SetObjectArrayElement(jBands, j, jBandDescriptor); + env->DeleteLocalRef(jBandDescriptor); + } + + if (env->GetArrayLength(jBands) == 0) { + continue; + } + jstring jImplementor = env->NewStringUTF(nModules[i].implementor); + jstring jProduct = env->NewStringUTF(nModules[i].product); + jstring jVersion = env->NewStringUTF(nModules[i].version); + jstring jSerial = env->NewStringUTF(nModules[i].serial); + jobject jModule = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor, + nModules[i].handle, nModules[i].class_id, + jImplementor, jProduct, jVersion, jSerial, + nModules[i].num_tuners, + nModules[i].num_audio_sources, + nModules[i].supports_capture, + jBands); + + env->DeleteLocalRef(jImplementor); + env->DeleteLocalRef(jProduct); + env->DeleteLocalRef(jVersion); + env->DeleteLocalRef(jSerial); + env->DeleteLocalRef(jBands); + if (jModule == NULL) { + continue; + } + env->CallBooleanMethod(jModules, gArrayListMethods.add, jModule); + } + + free(nModules); + return (jint) status; +} + +// ---------------------------------------------------------------------------- + +class JNIRadioCallback: public RadioCallback +{ +public: + JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz); + ~JNIRadioCallback(); + + virtual void onEvent(struct radio_event *event); + +private: + jclass mClass; // Reference to Radio class + jobject mObject; // Weak ref to Radio Java object to call on +}; + +JNIRadioCallback::JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz) +{ + + // Hold onto the RadioModule class for use in calling the static method + // that posts events to the application thread. + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + ALOGE("Can't find class %s", kRadioModuleClassPathName); + return; + } + mClass = (jclass)env->NewGlobalRef(clazz); + + // We use a weak reference so the RadioModule object can be garbage collected. + // The reference is only used as a proxy for callbacks. + mObject = env->NewGlobalRef(weak_thiz); +} + +JNIRadioCallback::~JNIRadioCallback() +{ + // remove global references + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + return; + } + env->DeleteGlobalRef(mObject); + env->DeleteGlobalRef(mClass); +} + +void JNIRadioCallback::onEvent(struct radio_event *event) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + return; + } + + ALOGV("%s", __FUNCTION__); + + jobject jObj = NULL; + jint jArg2 = 0; + jint jStatus = RADIO_STATUS_OK; + switch (event->type) { + case RADIO_EVENT_CONFIG: + jStatus = convertBandConfigFromNative(env, &jObj, &event->config); + break; + case RADIO_EVENT_TUNED: + case RADIO_EVENT_AF_SWITCH: + ALOGV("%s RADIO_EVENT_TUNED channel %d", __FUNCTION__, event->info.channel); + jStatus = convertProgramInfoFromNative(env, &jObj, &event->info); + break; + case RADIO_EVENT_METADATA: + jStatus = convertMetadataFromNative(env, &jObj, event->metadata); + if (jStatus >= 0) { + jStatus = RADIO_STATUS_OK; + } + break; + case RADIO_EVENT_ANTENNA: + case RADIO_EVENT_TA: + case RADIO_EVENT_CONTROL: + jArg2 = event->on ? 1 : 0; + break; + } + + if (jStatus != RADIO_STATUS_OK) { + return; + } + env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, + event->type, event->status, jArg2, jObj); + + env->DeleteLocalRef(jObj); + if (env->ExceptionCheck()) { + ALOGW("An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} + +// ---------------------------------------------------------------------------- + +static void +android_hardware_Radio_setup(JNIEnv *env, jobject thiz, + jobject weak_this, jobject jConfig, jboolean withAudio) +{ + ALOGV("%s", __FUNCTION__); + + setRadio(env, thiz, 0); + + sp<JNIRadioCallback> callback = new JNIRadioCallback(env, thiz, weak_this); + + radio_handle_t handle = (radio_handle_t)env->GetIntField(thiz, gModuleFields.mId); + + struct radio_band_config nConfig; + struct radio_band_config *configPtr = NULL; + if (jConfig != NULL) { + jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig); + if (jStatus != RADIO_STATUS_OK) { + return; + } + configPtr = &nConfig; + } + sp<Radio> module = Radio::attach(handle, configPtr, (bool)withAudio, callback); + if (module == 0) { + return; + } + + setRadio(env, thiz, module); +} + +static void +android_hardware_Radio_close(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = setRadio(env, thiz, 0); + ALOGV("detach module %p", module.get()); + if (module != 0) { + ALOGV("detach module->detach()"); + module->detach(); + } +} + +static void +android_hardware_Radio_finalize(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module != 0) { + ALOGW("Radio finalized without being detached"); + } + android_hardware_Radio_close(env, thiz); +} + +static jint +android_hardware_Radio_setConfiguration(JNIEnv *env, jobject thiz, jobject jConfig) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + + if (!env->IsInstanceOf(jConfig, gRadioFmBandConfigClass) && + !env->IsInstanceOf(jConfig, gRadioAmBandConfigClass)) { + return RADIO_STATUS_BAD_VALUE; + } + + struct radio_band_config nConfig; + jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig); + if (jStatus != RADIO_STATUS_OK) { + return jStatus; + } + + status_t status = module->setConfiguration(&nConfig); + return (jint)status; +} + +static jint +android_hardware_Radio_getConfiguration(JNIEnv *env, jobject thiz, jobjectArray jConfigs) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + if (env->GetArrayLength(jConfigs) != 1) { + return (jint)RADIO_STATUS_BAD_VALUE; + } + + struct radio_band_config nConfig; + + status_t status = module->getConfiguration(&nConfig); + if (status != NO_ERROR) { + return (jint)status; + } + jobject jConfig; + int jStatus = convertBandConfigFromNative(env, &jConfig, &nConfig); + if (jStatus != RADIO_STATUS_OK) { + return jStatus; + } + env->SetObjectArrayElement(jConfigs, 0, jConfig); + env->DeleteLocalRef(jConfig); + return RADIO_STATUS_OK; +} + +static jint +android_hardware_Radio_setMute(JNIEnv *env, jobject thiz, jboolean mute) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + status_t status = module->setMute((bool)mute); + return (jint)status; +} + +static jboolean +android_hardware_Radio_getMute(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return true; + } + bool mute = true; + status_t status = module->getMute(&mute); + if (status != NO_ERROR) { + return true; + } + return (jboolean)mute; +} + +static jint +android_hardware_Radio_step(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + status_t status = module->step((radio_direction_t)direction, (bool)skipSubChannel); + return (jint)status; +} + +static jint +android_hardware_Radio_scan(JNIEnv *env, jobject thiz, jint direction, jboolean skipSubChannel) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + status_t status = module->scan((radio_direction_t)direction, (bool)skipSubChannel); + return (jint)status; +} + +static jint +android_hardware_Radio_tune(JNIEnv *env, jobject thiz, jint channel, jint subChannel) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + status_t status = module->tune((unsigned int)channel, (unsigned int)subChannel); + return (jint)status; +} + +static jint +android_hardware_Radio_cancel(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + status_t status = module->cancel(); + return (jint)status; +} + +static jint +android_hardware_Radio_getProgramInformation(JNIEnv *env, jobject thiz, jobjectArray jInfos) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return RADIO_STATUS_NO_INIT; + } + if (env->GetArrayLength(jInfos) != 1) { + return (jint)RADIO_STATUS_BAD_VALUE; + } + + struct radio_program_info nInfo; + radio_metadata_allocate(&nInfo.metadata, 0, 0); + jobject jInfo = NULL; + int jStatus; + + jStatus = (int)module->getProgramInformation(&nInfo); + if (jStatus != RADIO_STATUS_OK) { + goto exit; + } + jStatus = convertProgramInfoFromNative(env, &jInfo, &nInfo); + if (jStatus != RADIO_STATUS_OK) { + goto exit; + } + env->SetObjectArrayElement(jInfos, 0, jInfo); + +exit: + if (jInfo != NULL) { + env->DeleteLocalRef(jInfo); + } + radio_metadata_deallocate(nInfo.metadata); + return jStatus; +} + +static jboolean +android_hardware_Radio_isAntennaConnected(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return false; + } + + struct radio_band_config nConfig; + + status_t status = module->getConfiguration(&nConfig); + if (status != NO_ERROR) { + return false; + } + + return (jboolean)nConfig.band.antenna_connected; +} + + +static jboolean +android_hardware_Radio_hasControl(JNIEnv *env, jobject thiz) +{ + ALOGV("%s", __FUNCTION__); + sp<Radio> module = getRadio(env, thiz); + if (module == NULL) { + return false; + } + + bool hasControl; + status_t status = module->hasControl(&hasControl); + if (status != NO_ERROR) { + return false; + } + + return (jboolean)hasControl; +} + + +static JNINativeMethod gMethods[] = { + {"listModules", + "(Ljava/util/List;)I", + (void *)android_hardware_Radio_listModules}, +}; + +static JNINativeMethod gModuleMethods[] = { + {"native_setup", + "(Ljava/lang/Object;Landroid/hardware/radio/RadioManager$BandConfig;Z)V", + (void *)android_hardware_Radio_setup}, + {"native_finalize", + "()V", + (void *)android_hardware_Radio_finalize}, + {"close", + "()V", + (void *)android_hardware_Radio_close}, + {"setConfiguration", + "(Landroid/hardware/radio/RadioManager$BandConfig;)I", + (void *)android_hardware_Radio_setConfiguration}, + {"getConfiguration", + "([Landroid/hardware/radio/RadioManager$BandConfig;)I", + (void *)android_hardware_Radio_getConfiguration}, + {"setMute", + "(Z)I", + (void *)android_hardware_Radio_setMute}, + {"getMute", + "()Z", + (void *)android_hardware_Radio_getMute}, + {"step", + "(IZ)I", + (void *)android_hardware_Radio_step}, + {"scan", + "(IZ)I", + (void *)android_hardware_Radio_scan}, + {"tune", + "(II)I", + (void *)android_hardware_Radio_tune}, + {"cancel", + "()I", + (void *)android_hardware_Radio_cancel}, + {"getProgramInformation", + "([Landroid/hardware/radio/RadioManager$ProgramInfo;)I", + (void *)android_hardware_Radio_getProgramInformation}, + {"isAntennaConnected", + "()Z", + (void *)android_hardware_Radio_isAntennaConnected}, + {"hasControl", + "()Z", + (void *)android_hardware_Radio_hasControl}, +}; + +int register_android_hardware_Radio(JNIEnv *env) +{ + jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); + gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); + gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); + + jclass lClass = FindClassOrDie(env, kRadioManagerClassPathName); + gRadioManagerClass = MakeGlobalRefOrDie(env, lClass); + + jclass moduleClass = FindClassOrDie(env, kRadioModuleClassPathName); + gRadioModuleClass = MakeGlobalRefOrDie(env, moduleClass); + gPostEventFromNative = GetStaticMethodIDOrDie(env, moduleClass, "postEventFromNative", + "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + gModuleFields.mNativeContext = GetFieldIDOrDie(env, moduleClass, "mNativeContext", "J"); + gModuleFields.mId = GetFieldIDOrDie(env, moduleClass, "mId", "I"); + + jclass modulePropertiesClass = FindClassOrDie(env, kModulePropertiesClassPathName); + gModulePropertiesClass = MakeGlobalRefOrDie(env, modulePropertiesClass); + gModulePropertiesCstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>", + "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;)V"); + + jclass bandDescriptorClass = FindClassOrDie(env, kRadioBandDescriptorClassPathName); + gRadioBandDescriptorClass = MakeGlobalRefOrDie(env, bandDescriptorClass); + gRadioBandDescriptorFields.mRegion = GetFieldIDOrDie(env, bandDescriptorClass, "mRegion", "I"); + gRadioBandDescriptorFields.mType = GetFieldIDOrDie(env, bandDescriptorClass, "mType", "I"); + gRadioBandDescriptorFields.mLowerLimit = + GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I"); + gRadioBandDescriptorFields.mUpperLimit = + GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I"); + gRadioBandDescriptorFields.mSpacing = + GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I"); + + jclass fmBandDescriptorClass = FindClassOrDie(env, kRadioFmBandDescriptorClassPathName); + gRadioFmBandDescriptorClass = MakeGlobalRefOrDie(env, fmBandDescriptorClass); + gRadioFmBandDescriptorCstor = GetMethodIDOrDie(env, fmBandDescriptorClass, "<init>", + "(IIIIIZZZZ)V"); + + jclass amBandDescriptorClass = FindClassOrDie(env, kRadioAmBandDescriptorClassPathName); + gRadioAmBandDescriptorClass = MakeGlobalRefOrDie(env, amBandDescriptorClass); + gRadioAmBandDescriptorCstor = GetMethodIDOrDie(env, amBandDescriptorClass, "<init>", + "(IIIIIZ)V"); + + jclass bandConfigClass = FindClassOrDie(env, kRadioBandConfigClassPathName); + gRadioBandConfigClass = MakeGlobalRefOrDie(env, bandConfigClass); + gRadioBandConfigFields.mDescriptor = + GetFieldIDOrDie(env, bandConfigClass, "mDescriptor", + "Landroid/hardware/radio/RadioManager$BandDescriptor;"); + + jclass fmBandConfigClass = FindClassOrDie(env, kRadioFmBandConfigClassPathName); + gRadioFmBandConfigClass = MakeGlobalRefOrDie(env, fmBandConfigClass); + gRadioFmBandConfigCstor = GetMethodIDOrDie(env, fmBandConfigClass, "<init>", + "(IIIIIZZZZ)V"); + gRadioFmBandConfigFields.mStereo = GetFieldIDOrDie(env, fmBandConfigClass, "mStereo", "Z"); + gRadioFmBandConfigFields.mRds = GetFieldIDOrDie(env, fmBandConfigClass, "mRds", "Z"); + gRadioFmBandConfigFields.mTa = GetFieldIDOrDie(env, fmBandConfigClass, "mTa", "Z"); + gRadioFmBandConfigFields.mAf = GetFieldIDOrDie(env, fmBandConfigClass, "mAf", "Z"); + + + jclass amBandConfigClass = FindClassOrDie(env, kRadioAmBandConfigClassPathName); + gRadioAmBandConfigClass = MakeGlobalRefOrDie(env, amBandConfigClass); + gRadioAmBandConfigCstor = GetMethodIDOrDie(env, amBandConfigClass, "<init>", + "(IIIIIZ)V"); + gRadioAmBandConfigFields.mStereo = GetFieldIDOrDie(env, amBandConfigClass, "mStereo", "Z"); + + jclass programInfoClass = FindClassOrDie(env, kRadioProgramInfoClassPathName); + gRadioProgramInfoClass = MakeGlobalRefOrDie(env, programInfoClass); + gRadioProgramInfoCstor = GetMethodIDOrDie(env, programInfoClass, "<init>", + "(IIZZZILandroid/hardware/radio/RadioMetadata;)V"); + + jclass metadataClass = FindClassOrDie(env, kRadioMetadataClassPathName); + gRadioMetadataClass = MakeGlobalRefOrDie(env, metadataClass); + gRadioMetadataCstor = GetMethodIDOrDie(env, metadataClass, "<init>", "()V"); + gRadioMetadataMethods.putIntFromNative = GetMethodIDOrDie(env, metadataClass, + "putIntFromNative", + "(II)I"); + gRadioMetadataMethods.putStringFromNative = GetMethodIDOrDie(env, metadataClass, + "putStringFromNative", + "(ILjava/lang/String;)I"); + gRadioMetadataMethods.putBitmapFromNative = GetMethodIDOrDie(env, metadataClass, + "putBitmapFromNative", + "(I[B)I"); + + + RegisterMethodsOrDie(env, kRadioManagerClassPathName, gMethods, NELEM(gMethods)); + + int ret = RegisterMethodsOrDie(env, kRadioModuleClassPathName, gModuleMethods, NELEM(gModuleMethods)); + + ALOGI("%s DONE", __FUNCTION__); + + return ret; +} |