1 /** 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "BroadcastRadioService.convert.jni" 18 #define LOG_NDEBUG 0 19 20 #include "convert.h" 21 22 #include "regions.h" 23 24 #include <broadcastradio-utils-1x/Utils.h> 25 #include <core_jni_helpers.h> 26 #include <nativehelper/JNIHelp.h> 27 #include <utils/Log.h> 28 29 namespace android { 30 namespace server { 31 namespace BroadcastRadio { 32 namespace convert { 33 34 namespace utils = hardware::broadcastradio::utils; 35 36 using hardware::Return; 37 using hardware::hidl_string; 38 using hardware::hidl_vec; 39 using regions::RegionalBandConfig; 40 41 using V1_0::Band; 42 using V1_0::Deemphasis; 43 using V1_0::Direction; 44 using V1_0::MetadataType; 45 using V1_0::Result; 46 using V1_0::Rds; 47 using V1_1::ProgramIdentifier; 48 using V1_1::ProgramListResult; 49 using V1_1::ProgramSelector; 50 using V1_1::VendorKeyValue; 51 52 // HAL 2.0 flags that have equivalent HAL 1.x fields 53 enum class ProgramInfoFlagsExt { 54 TUNED = 1 << 4, 55 STEREO = 1 << 5, 56 }; 57 58 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config); 59 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region); 60 61 static struct { 62 struct { 63 jfieldID descriptor; 64 } BandConfig; 65 struct { 66 jclass clazz; 67 jmethodID cstor; 68 jfieldID stereo; 69 jfieldID rds; 70 jfieldID ta; 71 jfieldID af; 72 jfieldID ea; 73 } FmBandConfig; 74 struct { 75 jclass clazz; 76 jmethodID cstor; 77 jfieldID stereo; 78 } AmBandConfig; 79 80 struct { 81 jclass clazz; 82 jfieldID region; 83 jfieldID type; 84 jfieldID lowerLimit; 85 jfieldID upperLimit; 86 jfieldID spacing; 87 } BandDescriptor; 88 struct { 89 jclass clazz; 90 jmethodID cstor; 91 } FmBandDescriptor; 92 struct { 93 jclass clazz; 94 jmethodID cstor; 95 } AmBandDescriptor; 96 97 struct { 98 jclass clazz; 99 jmethodID stringMapToNative; 100 } Convert; 101 102 struct { 103 jclass clazz; 104 jmethodID cstor; 105 } HashMap; 106 107 struct { 108 jmethodID get; 109 jmethodID size; 110 } List; 111 112 struct { 113 jmethodID put; 114 } Map; 115 116 struct { 117 jclass clazz; 118 jmethodID cstor; 119 } ModuleProperties; 120 121 struct { 122 jclass clazz; 123 jmethodID cstor; 124 } ProgramInfo; 125 126 struct { 127 jclass clazz; 128 jmethodID cstor; 129 jfieldID programType; 130 jfieldID primaryId; 131 jfieldID secondaryIds; 132 jfieldID vendorIds; 133 134 struct { 135 jclass clazz; 136 jmethodID cstor; 137 jfieldID type; 138 jfieldID value; 139 } Identifier; 140 } ProgramSelector; 141 142 struct { 143 jclass clazz; 144 jmethodID cstor; 145 jmethodID putIntFromNative; 146 jmethodID putStringFromNative; 147 jmethodID putBitmapFromNative; 148 jmethodID putClockFromNative; 149 } RadioMetadata; 150 151 struct { 152 jclass clazz; 153 jmethodID cstor; 154 } RuntimeException; 155 156 struct { 157 jclass clazz; 158 jmethodID cstor; 159 } ParcelableException; 160 161 struct { 162 jclass clazz; 163 } String; 164 } gjni; 165 166 static jstring CastToString(JNIEnv *env, jobject obj) { 167 if (env->IsInstanceOf(obj, gjni.String.clazz)) { 168 return static_cast<jstring>(obj); 169 } else { 170 ALOGE("Cast failed, object is not a string"); 171 return nullptr; 172 } 173 } 174 175 template <> 176 bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult) { 177 return __ThrowIfFailedHidl(env, hidlResult); 178 } 179 180 bool __ThrowIfFailedHidl(JNIEnv *env, const hardware::details::return_status &hidlResult) { 181 if (hidlResult.isOk()) return false; 182 183 ThrowParcelableRuntimeException(env, "HIDL call failed: " + hidlResult.description()); 184 return true; 185 } 186 187 bool __ThrowIfFailed(JNIEnv *env, const Result halResult) { 188 switch (halResult) { 189 case Result::OK: 190 return false; 191 case Result::NOT_INITIALIZED: 192 ThrowParcelableRuntimeException(env, "Result::NOT_INITIALIZED"); 193 return true; 194 case Result::INVALID_ARGUMENTS: 195 jniThrowException(env, "java/lang/IllegalArgumentException", 196 "Result::INVALID_ARGUMENTS"); 197 return true; 198 case Result::INVALID_STATE: 199 jniThrowException(env, "java/lang/IllegalStateException", "Result::INVALID_STATE"); 200 return true; 201 case Result::TIMEOUT: 202 ThrowParcelableRuntimeException(env, "Result::TIMEOUT (unexpected here)"); 203 return true; 204 default: 205 ThrowParcelableRuntimeException(env, "Unknown failure, result: " 206 + std::to_string(static_cast<int32_t>(halResult))); 207 return true; 208 } 209 } 210 211 bool __ThrowIfFailed(JNIEnv *env, const ProgramListResult halResult) { 212 switch (halResult) { 213 case ProgramListResult::NOT_READY: 214 jniThrowException(env, "java/lang/IllegalStateException", "Scan is in progress"); 215 return true; 216 case ProgramListResult::NOT_STARTED: 217 jniThrowException(env, "java/lang/IllegalStateException", "Scan has not been started"); 218 return true; 219 case ProgramListResult::UNAVAILABLE: 220 ThrowParcelableRuntimeException(env, 221 "ProgramListResult::UNAVAILABLE (unexpected here)"); 222 return true; 223 default: 224 return __ThrowIfFailed(env, static_cast<Result>(halResult)); 225 } 226 } 227 228 void ThrowParcelableRuntimeException(JNIEnv *env, const std::string& msg) { 229 auto jMsg = make_javastr(env, msg); 230 auto runtimeExc = make_javaref(env, env->NewObject(gjni.RuntimeException.clazz, 231 gjni.RuntimeException.cstor, jMsg.get())); 232 auto parcelableExc = make_javaref(env, env->NewObject(gjni.ParcelableException.clazz, 233 gjni.ParcelableException.cstor, runtimeExc.get())); 234 235 auto res = env->Throw(static_cast<jthrowable>(parcelableExc.get())); 236 ALOGE_IF(res != JNI_OK, "Couldn't throw parcelable runtime exception"); 237 } 238 239 static JavaRef<jintArray> ArrayFromHal(JNIEnv *env, const hidl_vec<uint32_t>& vec) { 240 auto jArr = make_javaref(env, env->NewIntArray(vec.size())); 241 auto jArrElements = env->GetIntArrayElements(jArr.get(), nullptr); 242 for (size_t i = 0; i < vec.size(); i++) { 243 jArrElements[i] = vec[i]; 244 } 245 env->ReleaseIntArrayElements(jArr.get(), jArrElements, 0); 246 return jArr; 247 } 248 249 static JavaRef<jlongArray> ArrayFromHal(JNIEnv *env, const hidl_vec<uint64_t>& vec) { 250 auto jArr = make_javaref(env, env->NewLongArray(vec.size())); 251 auto jArrElements = env->GetLongArrayElements(jArr.get(), nullptr); 252 for (size_t i = 0; i < vec.size(); i++) { 253 jArrElements[i] = vec[i]; 254 } 255 env->ReleaseLongArrayElements(jArr.get(), jArrElements, 0); 256 return jArr; 257 } 258 259 template <typename T> 260 static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec, 261 jclass jElementClass, std::function<JavaRef<jobject>(JNIEnv*, const T&)> converter) { 262 auto jArr = make_javaref(env, env->NewObjectArray(vec.size(), jElementClass, nullptr)); 263 for (size_t i = 0; i < vec.size(); i++) { 264 auto jElement = converter(env, vec[i]); 265 env->SetObjectArrayElement(jArr.get(), i, jElement.get()); 266 } 267 return jArr; 268 } 269 270 template <typename T> 271 static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec, 272 jclass jElementClass, JavaRef<jobject>(*converter)(JNIEnv*, const T&)) { 273 return ArrayFromHal(env, vec, jElementClass, 274 std::function<JavaRef<jobject>(JNIEnv*, const T&)>(converter)); 275 } 276 277 static std::string StringFromJava(JNIEnv *env, JavaRef<jstring> &jStr) { 278 if (jStr == nullptr) return {}; 279 auto cstr = env->GetStringUTFChars(jStr.get(), nullptr); 280 std::string str(cstr); 281 env->ReleaseStringUTFChars(jStr.get(), cstr); 282 return str; 283 } 284 285 hidl_vec<hidl_string> StringListToHal(JNIEnv *env, jobject jList) { 286 auto len = (jList == nullptr) ? 0 : env->CallIntMethod(jList, gjni.List.size); 287 hidl_vec<hidl_string> list(len); 288 289 for (decltype(len) i = 0; i < len; i++) { 290 auto jString = make_javaref(env, CastToString(env, env->CallObjectMethod( 291 jList, gjni.List.get, i))); 292 list[i] = StringFromJava(env, jString); 293 } 294 295 return list; 296 } 297 298 JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hidl_vec<VendorKeyValue> &info) { 299 ALOGV("%s(%s)", __func__, toString(info).substr(0, 100).c_str()); 300 301 auto jInfo = make_javaref(env, env->NewObject(gjni.HashMap.clazz, gjni.HashMap.cstor)); 302 303 for (auto&& entry : info) { 304 auto jKey = make_javastr(env, entry.key); 305 auto jValue = make_javastr(env, entry.value); 306 env->CallObjectMethod(jInfo.get(), gjni.Map.put, jKey.get(), jValue.get()); 307 } 308 309 return jInfo; 310 } 311 312 hidl_vec<VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo) { 313 ALOGV("%s", __func__); 314 315 auto jInfoArr = make_javaref(env, static_cast<jobjectArray>(env->CallStaticObjectMethod( 316 gjni.Convert.clazz, gjni.Convert.stringMapToNative, jInfo))); 317 if (jInfoArr == nullptr) { 318 ALOGE("Converted array is null"); 319 return {}; 320 } 321 322 auto len = env->GetArrayLength(jInfoArr.get()); 323 hidl_vec<VendorKeyValue> vec; 324 vec.resize(len); 325 326 for (jsize i = 0; i < len; i++) { 327 auto entry = make_javaref(env, static_cast<jobjectArray>( 328 env->GetObjectArrayElement(jInfoArr.get(), i))); 329 auto jKey = make_javaref(env, static_cast<jstring>( 330 env->GetObjectArrayElement(entry.get(), 0))); 331 auto jValue = make_javaref(env, static_cast<jstring>( 332 env->GetObjectArrayElement(entry.get(), 1))); 333 auto key = StringFromJava(env, jKey); 334 auto value = StringFromJava(env, jValue); 335 vec[i] = { key, value }; 336 } 337 338 return vec; 339 } 340 341 static Rds RdsForRegion(bool rds, Region region) { 342 if (!rds) return Rds::NONE; 343 344 switch(region) { 345 case Region::ITU_1: 346 case Region::OIRT: 347 case Region::JAPAN: 348 case Region::KOREA: 349 return Rds::WORLD; 350 case Region::ITU_2: 351 return Rds::US; 352 default: 353 ALOGE("Unexpected region: %d", region); 354 return Rds::NONE; 355 } 356 } 357 358 static Deemphasis DeemphasisForRegion(Region region) { 359 switch(region) { 360 case Region::KOREA: 361 case Region::ITU_2: 362 return Deemphasis::D75; 363 case Region::ITU_1: 364 case Region::OIRT: 365 case Region::JAPAN: 366 return Deemphasis::D50; 367 default: 368 ALOGE("Unexpected region: %d", region); 369 return Deemphasis::D50; 370 } 371 } 372 373 static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &prop10, 374 const V1_1::Properties *prop11, jint moduleId, const std::string& serviceName) { 375 ALOGV("%s", __func__); 376 using namespace std::placeholders; 377 378 auto jServiceName = make_javastr(env, serviceName); 379 auto jImplementor = make_javastr(env, prop10.implementor); 380 auto jProduct = make_javastr(env, prop10.product); 381 auto jVersion = make_javastr(env, prop10.version); 382 auto jSerial = make_javastr(env, prop10.serial); 383 constexpr bool isInitializationRequired = true; 384 bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false; 385 auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr; 386 387 auto regionalBands = regions::mapRegions(prop10.bands); 388 auto jBands = ArrayFromHal<RegionalBandConfig>(env, regionalBands, 389 gjni.BandDescriptor.clazz, BandDescriptorFromHal); 390 auto jSupportedProgramTypes = 391 prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr; 392 auto jSupportedIdentifierTypes = 393 prop11 ? ArrayFromHal(env, prop11->supportedIdentifierTypes) : nullptr; 394 395 return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz, 396 gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId, 397 jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners, 398 prop10.numAudioSources, isInitializationRequired, prop10.supportsCapture, jBands.get(), 399 isBgScanSupported, jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), 400 nullptr, jVendorInfo.get())); 401 } 402 403 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties, 404 jint moduleId, const std::string& serviceName) { 405 return ModulePropertiesFromHal(env, properties, nullptr, moduleId, serviceName); 406 } 407 408 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_1::Properties &properties, 409 jint moduleId, const std::string& serviceName) { 410 return ModulePropertiesFromHal(env, properties.base, &properties, moduleId, serviceName); 411 } 412 413 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config) { 414 return BandDescriptorFromHal(env, config.bandConfig, config.region); 415 } 416 417 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) { 418 ALOGV("%s", __func__); 419 420 jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0; 421 ALOGW_IF(config.spacings.size() > 1, "Multiple spacings - not a regional config"); 422 ALOGW_IF(config.spacings.size() == 0, "No channel spacing specified"); 423 424 if (utils::isFm(config.type)) { 425 auto& fm = config.ext.fm; 426 return make_javaref(env, env->NewObject( 427 gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor, 428 region, config.type, config.lowerLimit, config.upperLimit, spacing, 429 fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea)); 430 } else if (utils::isAm(config.type)) { 431 auto& am = config.ext.am; 432 return make_javaref(env, env->NewObject( 433 gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor, 434 region, config.type, config.lowerLimit, config.upperLimit, spacing, am.stereo)); 435 } else { 436 ALOGE("Unsupported band type: %d", config.type); 437 return nullptr; 438 } 439 } 440 441 JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) { 442 ALOGV("%s", __func__); 443 444 auto descriptor = BandDescriptorFromHal(env, config, region); 445 if (descriptor == nullptr) return nullptr; 446 447 if (utils::isFm(config.type)) { 448 return make_javaref(env, env->NewObject( 449 gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get())); 450 } else if (utils::isAm(config.type)) { 451 return make_javaref(env, env->NewObject( 452 gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get())); 453 } else { 454 ALOGE("Unsupported band type: %d", config.type); 455 return nullptr; 456 } 457 } 458 459 V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region ®ion) { 460 ALOGV("%s", __func__); 461 auto jDescriptor = env->GetObjectField(jConfig, gjni.BandConfig.descriptor); 462 if (jDescriptor == nullptr) { 463 ALOGE("Descriptor is missing"); 464 return {}; 465 } 466 467 region = static_cast<Region>(env->GetIntField(jDescriptor, gjni.BandDescriptor.region)); 468 469 V1_0::BandConfig config = {}; 470 config.type = static_cast<Band>(env->GetIntField(jDescriptor, gjni.BandDescriptor.type)); 471 config.antennaConnected = false; // just don't set it 472 config.lowerLimit = env->GetIntField(jDescriptor, gjni.BandDescriptor.lowerLimit); 473 config.upperLimit = env->GetIntField(jDescriptor, gjni.BandDescriptor.upperLimit); 474 config.spacings = hidl_vec<uint32_t>({ 475 static_cast<uint32_t>(env->GetIntField(jDescriptor, gjni.BandDescriptor.spacing)) 476 }); 477 478 if (env->IsInstanceOf(jConfig, gjni.FmBandConfig.clazz)) { 479 auto& fm = config.ext.fm; 480 fm.deemphasis = DeemphasisForRegion(region); 481 fm.stereo = env->GetBooleanField(jConfig, gjni.FmBandConfig.stereo); 482 fm.rds = RdsForRegion(env->GetBooleanField(jConfig, gjni.FmBandConfig.rds), region); 483 fm.ta = env->GetBooleanField(jConfig, gjni.FmBandConfig.ta); 484 fm.af = env->GetBooleanField(jConfig, gjni.FmBandConfig.af); 485 fm.ea = env->GetBooleanField(jConfig, gjni.FmBandConfig.ea); 486 } else if (env->IsInstanceOf(jConfig, gjni.AmBandConfig.clazz)) { 487 auto& am = config.ext.am; 488 am.stereo = env->GetBooleanField(jConfig, gjni.AmBandConfig.stereo); 489 } else { 490 ALOGE("Unexpected band config type"); 491 return {}; 492 } 493 494 return config; 495 } 496 497 Direction DirectionToHal(bool directionDown) { 498 return directionDown ? Direction::DOWN : Direction::UP; 499 } 500 501 JavaRef<jobject> MetadataFromHal(JNIEnv *env, const hidl_vec<V1_0::MetaData> &metadata) { 502 ALOGV("%s", __func__); 503 if (metadata.size() == 0) return nullptr; 504 505 auto jMetadata = make_javaref(env, env->NewObject( 506 gjni.RadioMetadata.clazz, gjni.RadioMetadata.cstor)); 507 508 for (auto& item : metadata) { 509 jint key = static_cast<jint>(item.key); 510 jint status = 0; 511 switch (item.type) { 512 case MetadataType::INT: 513 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putIntFromNative, 514 key, item.intValue); 515 break; 516 case MetadataType::TEXT: { 517 auto value = make_javastr(env, item.stringValue); 518 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putStringFromNative, 519 key, value.get()); 520 break; 521 } 522 case MetadataType::RAW: { 523 auto len = item.rawValue.size(); 524 if (len == 0) break; 525 auto value = make_javaref(env, env->NewByteArray(len)); 526 if (value == nullptr) { 527 ALOGE("Failed to allocate byte array of len %zu", len); 528 break; 529 } 530 env->SetByteArrayRegion(value.get(), 0, len, 531 reinterpret_cast<const jbyte*>(item.rawValue.data())); 532 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putBitmapFromNative, 533 key, value.get()); 534 break; 535 } 536 case MetadataType::CLOCK: 537 status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putClockFromNative, 538 key, item.clockValue.utcSecondsSinceEpoch, 539 item.clockValue.timezoneOffsetInMinutes); 540 break; 541 default: 542 ALOGW("invalid metadata type %d", item.type); 543 } 544 ALOGE_IF(status != 0, "Failed inserting metadata %d (of type %d)", key, item.type); 545 } 546 547 return jMetadata; 548 } 549 550 static JavaRef<jobject> ProgramIdentifierFromHal(JNIEnv *env, const ProgramIdentifier &id) { 551 ALOGV("%s", __func__); 552 return make_javaref(env, env->NewObject(gjni.ProgramSelector.Identifier.clazz, 553 gjni.ProgramSelector.Identifier.cstor, id.type, id.value)); 554 } 555 556 static JavaRef<jobject> ProgramSelectorFromHal(JNIEnv *env, const ProgramSelector &selector) { 557 ALOGV("%s", __func__); 558 auto jPrimary = ProgramIdentifierFromHal(env, selector.primaryId); 559 auto jSecondary = ArrayFromHal(env, selector.secondaryIds, 560 gjni.ProgramSelector.Identifier.clazz, ProgramIdentifierFromHal); 561 auto jVendor = ArrayFromHal(env, selector.vendorIds); 562 563 return make_javaref(env, env->NewObject(gjni.ProgramSelector.clazz, gjni.ProgramSelector.cstor, 564 selector.programType, jPrimary.get(), jSecondary.get(), jVendor.get())); 565 } 566 567 static ProgramIdentifier ProgramIdentifierToHal(JNIEnv *env, jobject jId) { 568 ALOGV("%s", __func__); 569 570 ProgramIdentifier id = {}; 571 id.type = env->GetIntField(jId, gjni.ProgramSelector.Identifier.type); 572 id.value = env->GetLongField(jId, gjni.ProgramSelector.Identifier.value); 573 return id; 574 } 575 576 ProgramSelector ProgramSelectorToHal(JNIEnv *env, jobject jSelector) { 577 ALOGV("%s", __func__); 578 579 ProgramSelector selector = {}; 580 581 selector.programType = env->GetIntField(jSelector, gjni.ProgramSelector.programType); 582 583 auto jPrimary = env->GetObjectField(jSelector, gjni.ProgramSelector.primaryId); 584 auto jSecondary = reinterpret_cast<jobjectArray>( 585 env->GetObjectField(jSelector, gjni.ProgramSelector.secondaryIds)); 586 auto jVendor = reinterpret_cast<jlongArray>( 587 env->GetObjectField(jSelector, gjni.ProgramSelector.vendorIds)); 588 589 if (jPrimary == nullptr || jSecondary == nullptr || jVendor == nullptr) { 590 ALOGE("ProgramSelector object is incomplete"); 591 return {}; 592 } 593 594 selector.primaryId = ProgramIdentifierToHal(env, jPrimary); 595 auto count = env->GetArrayLength(jSecondary); 596 selector.secondaryIds.resize(count); 597 for (jsize i = 0; i < count; i++) { 598 auto jId = env->GetObjectArrayElement(jSecondary, i); 599 selector.secondaryIds[i] = ProgramIdentifierToHal(env, jId); 600 } 601 602 count = env->GetArrayLength(jVendor); 603 selector.vendorIds.resize(count); 604 auto jVendorElements = env->GetLongArrayElements(jVendor, nullptr); 605 for (jint i = 0; i < count; i++) { 606 selector.vendorIds[i] = jVendorElements[i]; 607 } 608 env->ReleaseLongArrayElements(jVendor, jVendorElements, 0); 609 610 return selector; 611 } 612 613 static JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info10, 614 const V1_1::ProgramInfo *info11, const ProgramSelector &selector) { 615 ALOGV("%s", __func__); 616 617 auto jMetadata = MetadataFromHal(env, info10.metadata); 618 auto jVendorInfo = info11 ? VendorInfoFromHal(env, info11->vendorInfo) : nullptr; 619 auto jSelector = ProgramSelectorFromHal(env, selector); 620 621 jint flags = info11 ? info11->flags : 0; 622 if (info10.tuned) flags |= static_cast<jint>(ProgramInfoFlagsExt::TUNED); 623 if (info10.stereo) flags |= static_cast<jint>(ProgramInfoFlagsExt::STEREO); 624 // info10.digital is dropped, because it has no equivalent in the new APIs 625 626 return make_javaref(env, env->NewObject(gjni.ProgramInfo.clazz, gjni.ProgramInfo.cstor, 627 jSelector.get(), nullptr, nullptr, nullptr, flags, info10.signalStrength, 628 jMetadata.get(), jVendorInfo.get())); 629 } 630 631 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info, V1_0::Band band) { 632 auto selector = utils::make_selector(band, info.channel, info.subChannel); 633 return ProgramInfoFromHal(env, info, nullptr, selector); 634 } 635 636 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info) { 637 return ProgramInfoFromHal(env, info.base, &info, info.selector); 638 } 639 640 } // namespace convert 641 } // namespace BroadcastRadio 642 } // namespace server 643 644 void register_android_server_broadcastradio_convert(JNIEnv *env) { 645 using namespace server::BroadcastRadio::convert; 646 647 auto bandConfigClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$BandConfig"); 648 gjni.BandConfig.descriptor = GetFieldIDOrDie(env, bandConfigClass, 649 "mDescriptor", "Landroid/hardware/radio/RadioManager$BandDescriptor;"); 650 651 auto fmBandConfigClass = FindClassOrDie(env, 652 "android/hardware/radio/RadioManager$FmBandConfig"); 653 gjni.FmBandConfig.clazz = MakeGlobalRefOrDie(env, fmBandConfigClass); 654 gjni.FmBandConfig.cstor = GetMethodIDOrDie(env, fmBandConfigClass, 655 "<init>", "(Landroid/hardware/radio/RadioManager$FmBandDescriptor;)V"); 656 gjni.FmBandConfig.stereo = GetFieldIDOrDie(env, fmBandConfigClass, "mStereo", "Z"); 657 gjni.FmBandConfig.rds = GetFieldIDOrDie(env, fmBandConfigClass, "mRds", "Z"); 658 gjni.FmBandConfig.ta = GetFieldIDOrDie(env, fmBandConfigClass, "mTa", "Z"); 659 gjni.FmBandConfig.af = GetFieldIDOrDie(env, fmBandConfigClass, "mAf", "Z"); 660 gjni.FmBandConfig.ea = GetFieldIDOrDie(env, fmBandConfigClass, "mEa", "Z"); 661 662 auto amBandConfigClass = FindClassOrDie(env, 663 "android/hardware/radio/RadioManager$AmBandConfig"); 664 gjni.AmBandConfig.clazz = MakeGlobalRefOrDie(env, amBandConfigClass); 665 gjni.AmBandConfig.cstor = GetMethodIDOrDie(env, amBandConfigClass, 666 "<init>", "(Landroid/hardware/radio/RadioManager$AmBandDescriptor;)V"); 667 gjni.AmBandConfig.stereo = GetFieldIDOrDie(env, amBandConfigClass, "mStereo", "Z"); 668 669 auto bandDescriptorClass = FindClassOrDie(env, 670 "android/hardware/radio/RadioManager$BandDescriptor"); 671 gjni.BandDescriptor.clazz = MakeGlobalRefOrDie(env, bandDescriptorClass); 672 gjni.BandDescriptor.region = GetFieldIDOrDie(env, bandDescriptorClass, "mRegion", "I"); 673 gjni.BandDescriptor.type = GetFieldIDOrDie(env, bandDescriptorClass, "mType", "I"); 674 gjni.BandDescriptor.lowerLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I"); 675 gjni.BandDescriptor.upperLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I"); 676 gjni.BandDescriptor.spacing = GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I"); 677 678 auto fmBandDescriptorClass = FindClassOrDie(env, 679 "android/hardware/radio/RadioManager$FmBandDescriptor"); 680 gjni.FmBandDescriptor.clazz = MakeGlobalRefOrDie(env, fmBandDescriptorClass); 681 gjni.FmBandDescriptor.cstor = GetMethodIDOrDie(env, fmBandDescriptorClass, 682 "<init>", "(IIIIIZZZZZ)V"); 683 684 auto amBandDescriptorClass = FindClassOrDie(env, 685 "android/hardware/radio/RadioManager$AmBandDescriptor"); 686 gjni.AmBandDescriptor.clazz = MakeGlobalRefOrDie(env, amBandDescriptorClass); 687 gjni.AmBandDescriptor.cstor = GetMethodIDOrDie(env, amBandDescriptorClass, 688 "<init>", "(IIIIIZ)V"); 689 690 auto convertClass = FindClassOrDie(env, "com/android/server/broadcastradio/hal1/Convert"); 691 gjni.Convert.clazz = MakeGlobalRefOrDie(env, convertClass); 692 gjni.Convert.stringMapToNative = GetStaticMethodIDOrDie(env, convertClass, "stringMapToNative", 693 "(Ljava/util/Map;)[[Ljava/lang/String;"); 694 695 auto hashMapClass = FindClassOrDie(env, "java/util/HashMap"); 696 gjni.HashMap.clazz = MakeGlobalRefOrDie(env, hashMapClass); 697 gjni.HashMap.cstor = GetMethodIDOrDie(env, hashMapClass, "<init>", "()V"); 698 699 auto listClass = FindClassOrDie(env, "java/util/List"); 700 gjni.List.get = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;"); 701 gjni.List.size = GetMethodIDOrDie(env, listClass, "size", "()I"); 702 703 auto mapClass = FindClassOrDie(env, "java/util/Map"); 704 gjni.Map.put = GetMethodIDOrDie(env, mapClass, "put", 705 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 706 707 auto modulePropertiesClass = FindClassOrDie(env, 708 "android/hardware/radio/RadioManager$ModuleProperties"); 709 gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass); 710 gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>", 711 "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;" 712 "Ljava/lang/String;IIZZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" 713 "[I[ILjava/util/Map;Ljava/util/Map;)V"); 714 715 auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo"); 716 gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass); 717 gjni.ProgramInfo.cstor = GetMethodIDOrDie(env, programInfoClass, "<init>", "(" 718 "Landroid/hardware/radio/ProgramSelector;" 719 "Landroid/hardware/radio/ProgramSelector$Identifier;" 720 "Landroid/hardware/radio/ProgramSelector$Identifier;" 721 "Ljava/util/Collection;" // relatedContent 722 "II" // flags, signalQuality 723 "Landroid/hardware/radio/RadioMetadata;" 724 "Ljava/util/Map;" // vendorInfo 725 ")V"); 726 727 auto programSelectorClass = FindClassOrDie(env, "android/hardware/radio/ProgramSelector"); 728 gjni.ProgramSelector.clazz = MakeGlobalRefOrDie(env, programSelectorClass); 729 gjni.ProgramSelector.cstor = GetMethodIDOrDie(env, programSelectorClass, "<init>", 730 "(ILandroid/hardware/radio/ProgramSelector$Identifier;" 731 "[Landroid/hardware/radio/ProgramSelector$Identifier;[J)V"); 732 gjni.ProgramSelector.programType = GetFieldIDOrDie(env, programSelectorClass, 733 "mProgramType", "I"); 734 gjni.ProgramSelector.primaryId = GetFieldIDOrDie(env, programSelectorClass, 735 "mPrimaryId", "Landroid/hardware/radio/ProgramSelector$Identifier;"); 736 gjni.ProgramSelector.secondaryIds = GetFieldIDOrDie(env, programSelectorClass, 737 "mSecondaryIds", "[Landroid/hardware/radio/ProgramSelector$Identifier;"); 738 gjni.ProgramSelector.vendorIds = GetFieldIDOrDie(env, programSelectorClass, 739 "mVendorIds", "[J"); 740 741 auto progSelIdClass = FindClassOrDie(env, "android/hardware/radio/ProgramSelector$Identifier"); 742 gjni.ProgramSelector.Identifier.clazz = MakeGlobalRefOrDie(env, progSelIdClass); 743 gjni.ProgramSelector.Identifier.cstor = GetMethodIDOrDie(env, progSelIdClass, 744 "<init>", "(IJ)V"); 745 gjni.ProgramSelector.Identifier.type = GetFieldIDOrDie(env, progSelIdClass, 746 "mType", "I"); 747 gjni.ProgramSelector.Identifier.value = GetFieldIDOrDie(env, progSelIdClass, 748 "mValue", "J"); 749 750 auto radioMetadataClass = FindClassOrDie(env, "android/hardware/radio/RadioMetadata"); 751 gjni.RadioMetadata.clazz = MakeGlobalRefOrDie(env, radioMetadataClass); 752 gjni.RadioMetadata.cstor = GetMethodIDOrDie(env, radioMetadataClass, "<init>", "()V"); 753 gjni.RadioMetadata.putIntFromNative = GetMethodIDOrDie(env, radioMetadataClass, 754 "putIntFromNative", "(II)I"); 755 gjni.RadioMetadata.putStringFromNative = GetMethodIDOrDie(env, radioMetadataClass, 756 "putStringFromNative", "(ILjava/lang/String;)I"); 757 gjni.RadioMetadata.putBitmapFromNative = GetMethodIDOrDie(env, radioMetadataClass, 758 "putBitmapFromNative", "(I[B)I"); 759 gjni.RadioMetadata.putClockFromNative = GetMethodIDOrDie(env, radioMetadataClass, 760 "putClockFromNative", "(IJI)I"); 761 762 auto runtimeExcClass = FindClassOrDie(env, "java/lang/RuntimeException"); 763 gjni.RuntimeException.clazz = MakeGlobalRefOrDie(env, runtimeExcClass); 764 gjni.RuntimeException.cstor = GetMethodIDOrDie(env, runtimeExcClass, "<init>", 765 "(Ljava/lang/String;)V"); 766 767 auto parcelableExcClass = FindClassOrDie(env, "android/os/ParcelableException"); 768 gjni.ParcelableException.clazz = MakeGlobalRefOrDie(env, parcelableExcClass); 769 gjni.ParcelableException.cstor = GetMethodIDOrDie(env, parcelableExcClass, "<init>", 770 "(Ljava/lang/Throwable;)V"); 771 772 auto stringClass = FindClassOrDie(env, "java/lang/String"); 773 gjni.String.clazz = MakeGlobalRefOrDie(env, stringClass); 774 } 775 776 } // namespace android 777