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