blob: b9dd77af8c8a59401902ff1674069eb352163023 [file] [log] [blame]
Eric Laurent633cb562015-03-05 15:17:20 -08001/*
2**
3** Copyright 2015, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "Radio-JNI"
20#include <utils/Log.h>
21
22#include "jni.h"
23#include "JNIHelp.h"
24#include "core_jni_helpers.h"
25#include <system/radio.h>
26#include <system/radio_metadata.h>
27#include <radio/RadioCallback.h>
28#include <radio/Radio.h>
29#include <utils/RefBase.h>
30#include <utils/Vector.h>
31#include <binder/IMemory.h>
32#include <binder/MemoryDealer.h>
33
34using namespace android;
35
36static jclass gArrayListClass;
37static struct {
38 jmethodID add;
39} gArrayListMethods;
40
41static const char* const kRadioManagerClassPathName = "android/hardware/radio/RadioManager";
42static jclass gRadioManagerClass;
43
44static const char* const kRadioModuleClassPathName = "android/hardware/radio/RadioModule";
45static jclass gRadioModuleClass;
46static struct {
47 jfieldID mNativeContext;
48 jfieldID mId;
49} gModuleFields;
50static jmethodID gPostEventFromNative;
51
52static const char* const kModulePropertiesClassPathName =
53 "android/hardware/radio/RadioManager$ModuleProperties";
54static jclass gModulePropertiesClass;
55static jmethodID gModulePropertiesCstor;
56
57
58static const char* const kRadioBandDescriptorClassPathName =
59 "android/hardware/radio/RadioManager$BandDescriptor";
60static jclass gRadioBandDescriptorClass;
61static struct {
62 jfieldID mRegion;
63 jfieldID mType;
64 jfieldID mLowerLimit;
65 jfieldID mUpperLimit;
66 jfieldID mSpacing;
67} gRadioBandDescriptorFields;
68
69static const char* const kRadioFmBandDescriptorClassPathName =
70 "android/hardware/radio/RadioManager$FmBandDescriptor";
71static jclass gRadioFmBandDescriptorClass;
72static jmethodID gRadioFmBandDescriptorCstor;
73
74static const char* const kRadioAmBandDescriptorClassPathName =
75 "android/hardware/radio/RadioManager$AmBandDescriptor";
76static jclass gRadioAmBandDescriptorClass;
77static jmethodID gRadioAmBandDescriptorCstor;
78
79static const char* const kRadioBandConfigClassPathName =
80 "android/hardware/radio/RadioManager$BandConfig";
81static jclass gRadioBandConfigClass;
82static struct {
83 jfieldID mDescriptor;
84} gRadioBandConfigFields;
85
86
87static const char* const kRadioFmBandConfigClassPathName =
88 "android/hardware/radio/RadioManager$FmBandConfig";
89static jclass gRadioFmBandConfigClass;
90static jmethodID gRadioFmBandConfigCstor;
91static struct {
92 jfieldID mStereo;
93 jfieldID mRds;
94 jfieldID mTa;
95 jfieldID mAf;
96} gRadioFmBandConfigFields;
97
98static const char* const kRadioAmBandConfigClassPathName =
99 "android/hardware/radio/RadioManager$AmBandConfig";
100static jclass gRadioAmBandConfigClass;
101static jmethodID gRadioAmBandConfigCstor;
102static struct {
103 jfieldID mStereo;
104} gRadioAmBandConfigFields;
105
106
107static const char* const kRadioProgramInfoClassPathName =
108 "android/hardware/radio/RadioManager$ProgramInfo";
109static jclass gRadioProgramInfoClass;
110static jmethodID gRadioProgramInfoCstor;
111
112static const char* const kRadioMetadataClassPathName =
113 "android/hardware/radio/RadioMetadata";
114static jclass gRadioMetadataClass;
115static jmethodID gRadioMetadataCstor;
116static struct {
117 jmethodID putIntFromNative;
118 jmethodID putStringFromNative;
119 jmethodID putBitmapFromNative;
120} gRadioMetadataMethods;
121
122static Mutex gLock;
123
124enum {
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
138static 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
145static 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
159static 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
193static 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
227static 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
292static 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
320static 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
364static jint
365android_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
451class JNIRadioCallback: public RadioCallback
452{
453public:
454 JNIRadioCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
455 ~JNIRadioCallback();
456
457 virtual void onEvent(struct radio_event *event);
458
459private:
460 jclass mClass; // Reference to Radio class
461 jobject mObject; // Weak ref to Radio Java object to call on
462};
463
464JNIRadioCallback::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
481JNIRadioCallback::~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
492void 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
541static void
542android_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
570static void
571android_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
582static void
583android_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
593static jint
594android_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
617static jint
618android_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
645static jint
646android_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
657static jboolean
658android_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
673static jint
674android_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
685static jint
686android_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
697static jint
698android_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
709static jint
710android_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
721static jint
722android_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
748exit:
749 if (jInfo != NULL) {
750 env->DeleteLocalRef(jInfo);
751 }
752 radio_metadata_deallocate(nInfo.metadata);
753 return jStatus;
754}
755
756static jboolean
757android_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
776static jboolean
777android_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
795static JNINativeMethod gMethods[] = {
796 {"listModules",
797 "(Ljava/util/List;)I",
798 (void *)android_hardware_Radio_listModules},
799};
800
801static 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
846int 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}