Merge "Pass vendor-specific info as map." into oc-mr1-dev

This commit is contained in:
Tomasz Wasilczyk
2017-08-04 21:12:21 +00:00
committed by Android (Google) Code Review
11 changed files with 221 additions and 50 deletions

View File

@@ -17392,7 +17392,7 @@ package android.hardware.radio {
method public java.lang.String getProduct();
method public java.lang.String getSerial();
method public java.lang.String getServiceName();
method public java.lang.String getVendorInfo();
method public java.util.Map<java.lang.String, java.lang.String> getVendorInfo();
method public java.lang.String getVersion();
method public boolean isBackgroundScanningSupported();
method public boolean isCaptureSupported();
@@ -17409,7 +17409,7 @@ package android.hardware.radio {
method public android.hardware.radio.ProgramSelector getSelector();
method public int getSignalStrength();
method public deprecated int getSubChannel();
method public java.lang.String getVendorInfo();
method public java.util.Map<java.lang.String, java.lang.String> getVendorInfo();
method public boolean isDigital();
method public boolean isLive();
method public boolean isMuted();
@@ -17473,7 +17473,7 @@ package android.hardware.radio {
method public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
method public abstract boolean getMute();
method public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
method public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.lang.String);
method public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
method public abstract boolean hasControl();
method public abstract boolean isAnalogForced();
method public abstract boolean isAntennaConnected();

View File

@@ -74,12 +74,13 @@ interface ITuner {
boolean startBackgroundScan();
/**
* @param vendorFilter Vendor-specific filter, must be Map<String, String>
* @returns the list, or null if scan is in progress
* @throws IllegalArgumentException if invalid arguments are passed
* @throws IllegalStateException if the scan has not been started, client may
* call startBackgroundScan to fix this.
*/
List<RadioManager.ProgramInfo> getProgramList(String filter);
List<RadioManager.ProgramInfo> getProgramList(in Map vendorFilter);
/**
* @throws IllegalStateException if the switch is not supported at current

View File

@@ -35,7 +35,9 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -117,6 +119,25 @@ public class RadioManager {
* @see BandDescriptor */
public static final int REGION_KOREA = 4;
private static void writeStringMap(@NonNull Parcel dest, @NonNull Map<String, String> map) {
dest.writeInt(map.size());
for (Map.Entry<String, String> entry : map.entrySet()) {
dest.writeString(entry.getKey());
dest.writeString(entry.getValue());
}
}
private static @NonNull Map<String, String> readStringMap(@NonNull Parcel in) {
int size = in.readInt();
Map<String, String> map = new HashMap<>();
while (size-- > 0) {
String key = in.readString();
String value = in.readString();
map.put(key, value);
}
return map;
}
/*****************************************************************************
* Lists properties, options and radio bands supported by a given broadcast radio module.
* Each module has a unique ID used to address it when calling RadioManager APIs.
@@ -138,14 +159,14 @@ public class RadioManager {
private final boolean mIsBgScanSupported;
private final Set<Integer> mSupportedProgramTypes;
private final Set<Integer> mSupportedIdentifierTypes;
private final String mVendorInfo;
@NonNull private final Map<String, String> mVendorInfo;
ModuleProperties(int id, String serviceName, int classId, String implementor,
String product, String version, String serial, int numTuners, int numAudioSources,
boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
@ProgramSelector.ProgramType int[] supportedProgramTypes,
@ProgramSelector.IdentifierType int[] supportedIdentifierTypes,
String vendorInfo) {
Map<String, String> vendorInfo) {
mId = id;
mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
mClassId = classId;
@@ -160,7 +181,7 @@ public class RadioManager {
mIsBgScanSupported = isBgScanSupported;
mSupportedProgramTypes = arrayToSet(supportedProgramTypes);
mSupportedIdentifierTypes = arrayToSet(supportedIdentifierTypes);
mVendorInfo = vendorInfo;
mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
}
private static Set<Integer> arrayToSet(int[] arr) {
@@ -287,17 +308,17 @@ public class RadioManager {
}
/**
* Opaque vendor-specific string, passed from HAL without changes.
* Format of this string can vary across vendors.
* A map of vendor-specific opaque strings, passed from HAL without changes.
* Format of these strings can vary across vendors.
*
* It may be used for extra features, that's not supported by a platform,
* for example: "preset-slots=6;ultra-hd-capable=false".
* for example: preset-slots=6; ultra-hd-capable=false.
*
* Client application MUST verify vendor/product name from the
* ModuleProperties class before doing any interpretation of this value.
* Keys must be prefixed with unique vendor Java-style namespace,
* eg. 'com.somecompany.parameter1'.
*/
public @NonNull String getVendorInfo() {
return mVendorInfo == null ? "" : mVendorInfo;
public @NonNull Map<String, String> getVendorInfo() {
return mVendorInfo;
}
/** List of descriptors for all bands supported by this module.
@@ -327,7 +348,7 @@ public class RadioManager {
mIsBgScanSupported = in.readInt() == 1;
mSupportedProgramTypes = arrayToSet(in.createIntArray());
mSupportedIdentifierTypes = arrayToSet(in.createIntArray());
mVendorInfo = in.readString();
mVendorInfo = readStringMap(in);
}
public static final Parcelable.Creator<ModuleProperties> CREATOR
@@ -357,7 +378,7 @@ public class RadioManager {
dest.writeInt(mIsBgScanSupported ? 1 : 0);
dest.writeIntArray(setToArray(mSupportedProgramTypes));
dest.writeIntArray(setToArray(mSupportedIdentifierTypes));
dest.writeString(mVendorInfo);
writeStringMap(dest, mVendorInfo);
}
@Override
@@ -394,7 +415,7 @@ public class RadioManager {
result = prime * result + (mIsCaptureSupported ? 1 : 0);
result = prime * result + Arrays.hashCode(mBands);
result = prime * result + (mIsBgScanSupported ? 1 : 0);
result = prime * result + ((mVendorInfo == null) ? 0 : mVendorInfo.hashCode());
result = prime * result + mVendorInfo.hashCode();
return result;
}
@@ -440,7 +461,7 @@ public class RadioManager {
return false;
if (mIsBgScanSupported != other.isBackgroundScanningSupported())
return false;
if (!TextUtils.equals(mVendorInfo, other.mVendorInfo)) return false;
if (!mVendorInfo.equals(other.mVendorInfo)) return false;
return true;
}
}
@@ -1324,11 +1345,11 @@ public class RadioManager {
private final int mFlags;
private final int mSignalStrength;
private final RadioMetadata mMetadata;
private final String mVendorInfo;
@NonNull private final Map<String, String> mVendorInfo;
ProgramInfo(@NonNull ProgramSelector selector, boolean tuned, boolean stereo,
boolean digital, int signalStrength, RadioMetadata metadata, int flags,
String vendorInfo) {
Map<String, String> vendorInfo) {
mSelector = selector;
mTuned = tuned;
mStereo = stereo;
@@ -1336,7 +1357,7 @@ public class RadioManager {
mFlags = flags;
mSignalStrength = signalStrength;
mMetadata = metadata;
mVendorInfo = vendorInfo;
mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
}
/**
@@ -1447,17 +1468,17 @@ public class RadioManager {
}
/**
* Opaque vendor-specific string, passed from HAL without changes.
* Format of this string can vary across vendors.
* A map of vendor-specific opaque strings, passed from HAL without changes.
* Format of these strings can vary across vendors.
*
* It may be used for extra features, that's not supported by a platform,
* for example: "paid-service=true;bitrate=320kbps".
* for example: paid-service=true; bitrate=320kbps.
*
* Client application MUST verify vendor/product name from the
* ModuleProperties class before doing any interpretation of this value.
* Keys must be prefixed with unique vendor Java-style namespace,
* eg. 'com.somecompany.parameter1'.
*/
public @NonNull String getVendorInfo() {
return mVendorInfo == null ? "" : mVendorInfo;
public @NonNull Map<String, String> getVendorInfo() {
return mVendorInfo;
}
private ProgramInfo(Parcel in) {
@@ -1472,7 +1493,7 @@ public class RadioManager {
mMetadata = null;
}
mFlags = in.readInt();
mVendorInfo = in.readString();
mVendorInfo = readStringMap(in);
}
public static final Parcelable.Creator<ProgramInfo> CREATOR
@@ -1500,7 +1521,7 @@ public class RadioManager {
mMetadata.writeToParcel(dest, flags);
}
dest.writeInt(mFlags);
dest.writeString(mVendorInfo);
writeStringMap(dest, mVendorInfo);
}
@Override
@@ -1528,7 +1549,7 @@ public class RadioManager {
result = prime * result + mFlags;
result = prime * result + mSignalStrength;
result = prime * result + ((mMetadata == null) ? 0 : mMetadata.hashCode());
result = prime * result + ((mVendorInfo == null) ? 0 : mVendorInfo.hashCode());
result = prime * result + mVendorInfo.hashCode();
return result;
}
@@ -1555,7 +1576,7 @@ public class RadioManager {
return false;
} else if (!mMetadata.equals(other.getMetadata()))
return false;
if (!TextUtils.equals(mVendorInfo, other.mVendorInfo)) return false;
if (!mVendorInfo.equals(other.mVendorInfo)) return false;
return true;
}
}

View File

@@ -23,6 +23,7 @@ import android.graphics.Bitmap;
import android.os.Handler;
import java.util.List;
import java.util.Map;
/**
* RadioTuner interface provides methods to control a radio tuner on the device: selecting and
@@ -270,16 +271,18 @@ public abstract class RadioTuner {
/**
* Get the list of discovered radio stations.
*
* To get the full list, set filter to null or empty string. Otherwise, client application
* must verify vendor product/name before setting this parameter to anything else.
* To get the full list, set filter to null or empty map.
* Keys must be prefixed with unique vendor Java-style namespace,
* eg. 'com.somecompany.parameter1'.
*
* @param filter vendor-specific selector for radio stations.
* @param vendorFilter vendor-specific selector for radio stations.
* @return a list of radio stations.
* @throws IllegalStateException if the scan is in progress or has not been started,
* startBackgroundScan() call may fix it.
* @throws IllegalArgumentException if the filter argument is not valid.
* @throws IllegalArgumentException if the vendorFilter argument is not valid.
*/
public abstract @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
public abstract @NonNull List<RadioManager.ProgramInfo>
getProgramList(@Nullable Map<String, String> vendorFilter);
/**
* Checks, if the analog playback is forced, see setAnalogForced.

View File

@@ -23,6 +23,7 @@ import android.os.RemoteException;
import android.util.Log;
import java.util.List;
import java.util.Map;
/**
* Implements the RadioTuner interface by forwarding calls to radio service.
@@ -222,9 +223,10 @@ class TunerAdapter extends RadioTuner {
}
@Override
public @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter) {
public @NonNull List<RadioManager.ProgramInfo>
getProgramList(@Nullable Map<String, String> vendorFilter) {
try {
return mTuner.getProgramList(filter);
return mTuner.getProgramList(vendorFilter);
} catch (RemoteException e) {
throw new RuntimeException("service died", e);
}

View File

@@ -28,7 +28,9 @@ import android.util.Log;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
@@ -291,6 +293,7 @@ public class RadioTunerTest {
assertEquals(RadioManager.STATUS_OK, ret);
assertNotNull(info[0]);
assertEquals(channel, info[0].getChannel());
Log.d(TAG, "PI: " + info[0].toString());
}
@Test
@@ -344,7 +347,9 @@ public class RadioTunerTest {
openTuner();
try {
List<RadioManager.ProgramInfo> list = mRadioTuner.getProgramList(null);
Map<String, String> filter = new HashMap<>();
filter.put("com.google.dummy", "dummy");
List<RadioManager.ProgramInfo> list = mRadioTuner.getProgramList(filter);
assertNotNull(list);
} catch (IllegalStateException e) {
// the list may or may not be ready at this point

View File

@@ -0,0 +1,59 @@
/**
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.broadcastradio;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
import java.util.Map;
import java.util.Set;
class Convert {
private static final String TAG = "BroadcastRadioService.Convert";
/**
* Converts string map to an array that's easily accessible by native code.
*
* Calling this java method once is more efficient than converting map object on the native
* side, which requires several separate java calls for each element.
*
* @param map map to convert.
* @returns array (sized the same as map) of two-element string arrays
* (first element is the key, second is value).
*/
static @NonNull String[][] stringMapToNative(@Nullable Map<String, String> map) {
if (map == null) {
Slog.v(TAG, "map is null, returning zero-elements array");
return new String[0][0];
}
Set<Map.Entry<String, String>> entries = map.entrySet();
int len = entries.size();
String[][] arr = new String[len][2];
int i = 0;
for (Map.Entry<String, String> entry : entries) {
arr[i][0] = entry.getKey();
arr[i][1] = entry.getValue();
i++;
}
Slog.v(TAG, "converted " + i + " element(s)");
return arr;
}
}

View File

@@ -28,6 +28,7 @@ import android.os.RemoteException;
import android.util.Slog;
import java.util.List;
import java.util.Map;
class Tuner extends ITuner.Stub {
private static final String TAG = "BroadcastRadioService.Tuner";
@@ -86,7 +87,7 @@ class Tuner extends ITuner.Stub {
private native RadioManager.ProgramInfo nativeGetProgramInformation(long nativeContext);
private native boolean nativeStartBackgroundScan(long nativeContext);
private native List<RadioManager.ProgramInfo> nativeGetProgramList(long nativeContext,
String filter);
Map<String, String> vendorFilter);
private native byte[] nativeGetImage(long nativeContext, int id);
@@ -242,10 +243,11 @@ class Tuner extends ITuner.Stub {
}
@Override
public List<RadioManager.ProgramInfo> getProgramList(String filter) {
public List<RadioManager.ProgramInfo> getProgramList(Map vendorFilter) {
Map<String, String> sFilter = vendorFilter;
synchronized (mLock) {
checkNotClosedLocked();
List<RadioManager.ProgramInfo> list = nativeGetProgramList(mNativeContext, filter);
List<RadioManager.ProgramInfo> list = nativeGetProgramList(mNativeContext, sFilter);
if (list == null) {
throw new IllegalStateException("Program list is not ready");
}

View File

@@ -374,7 +374,7 @@ static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeCont
return !convert::ThrowIfFailed(env, halResult);
}
static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContext, jstring jFilter) {
static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContext, jobject jVendorFilter) {
ALOGV("%s", __func__);
auto halTuner = getHalTuner11(nativeContext);
if (halTuner == nullptr) {
@@ -384,7 +384,7 @@ static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContex
JavaRef<jobject> jList;
ProgramListResult halResult = ProgramListResult::NOT_INITIALIZED;
auto filter = env->GetStringUTFChars(jFilter, nullptr);
auto filter = convert::VendorInfoToHal(env, jVendorFilter);
auto hidlResult = halTuner->getProgramList(filter,
[&](ProgramListResult result, const hidl_vec<V1_1::ProgramInfo>& programList) {
halResult = result;
@@ -505,7 +505,7 @@ static const JNINativeMethod gTunerMethods[] = {
{ "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
(void*)nativeGetProgramInformation },
{ "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
{ "nativeGetProgramList", "(JLjava/lang/String;)Ljava/util/List;",
{ "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;",
(void*)nativeGetProgramList },
{ "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
{ "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },

View File

@@ -41,6 +41,7 @@ using V1_0::Rds;
using V1_1::ProgramIdentifier;
using V1_1::ProgramListResult;
using V1_1::ProgramSelector;
using V1_1::VendorKeyValue;
static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
@@ -80,6 +81,20 @@ static struct {
jmethodID cstor;
} AmBandDescriptor;
struct {
jclass clazz;
jmethodID stringMapToNative;
} Convert;
struct {
jclass clazz;
jmethodID cstor;
} HashMap;
struct {
jmethodID put;
} Map;
struct {
jclass clazz;
jmethodID cstor;
@@ -228,6 +243,53 @@ static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec,
std::function<JavaRef<jobject>(JNIEnv*, const T&)>(converter));
}
static std::string StringFromJava(JNIEnv *env, JavaRef<jstring> &jStr) {
auto cstr = (jStr == nullptr) ? nullptr : env->GetStringUTFChars(jStr.get(), nullptr);
std::string str(cstr);
env->ReleaseStringUTFChars(jStr.get(), cstr);
return str;
}
JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hidl_vec<VendorKeyValue> &info) {
ALOGV("%s(%s)", __func__, toString(info).substr(0, 100).c_str());
auto jInfo = make_javaref(env, env->NewObject(gjni.HashMap.clazz, gjni.HashMap.cstor));
for (auto&& entry : info) {
auto jKey = make_javastr(env, entry.key);
auto jValue = make_javastr(env, entry.value);
env->CallObjectMethod(jInfo.get(), gjni.Map.put, jKey.get(), jValue.get());
}
return jInfo;
}
hidl_vec<VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo) {
ALOGV("%s", __func__);
auto jInfoArr = make_javaref(env, static_cast<jobjectArray>(env->CallStaticObjectMethod(
gjni.Convert.clazz, gjni.Convert.stringMapToNative, jInfo)));
LOG_FATAL_IF(jInfoArr == nullptr, "Converted array is null");
auto len = env->GetArrayLength(jInfoArr.get());
hidl_vec<VendorKeyValue> vec;
vec.resize(len);
for (jsize i = 0; i < len; i++) {
auto entry = make_javaref(env, static_cast<jobjectArray>(
env->GetObjectArrayElement(jInfoArr.get(), i)));
auto jKey = make_javaref(env, static_cast<jstring>(
env->GetObjectArrayElement(entry.get(), 0)));
auto jValue = make_javaref(env, static_cast<jstring>(
env->GetObjectArrayElement(entry.get(), 1)));
auto key = StringFromJava(env, jKey);
auto value = StringFromJava(env, jValue);
vec[i] = { key, value };
}
return vec;
}
static Rds RdsForRegion(bool rds, Region region) {
if (!rds) return Rds::NONE;
@@ -271,7 +333,7 @@ static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert
auto jVersion = make_javastr(env, prop10.version);
auto jSerial = make_javastr(env, prop10.serial);
bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
auto jVendorInfo = prop11 ? make_javastr(env, prop11->vendorInfo) : nullptr;
auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
// ITU_1 is the default region just because its index is 0.
auto jBands = ArrayFromHal<V1_0::BandConfig>(env, prop10.bands, gjni.BandDescriptor.clazz,
std::bind(BandDescriptorFromHal, _1, _2, Region::ITU_1));
@@ -512,7 +574,7 @@ static JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo
ALOGV("%s", __func__);
auto jMetadata = MetadataFromHal(env, info10.metadata);
auto jVendorInfo = info11 ? make_javastr(env, info11->vendorInfo) : nullptr;
auto jVendorInfo = info11 ? VendorInfoFromHal(env, info11->vendorInfo) : nullptr;
auto jSelector = ProgramSelectorFromHal(env, selector);
return make_javaref(env, env->NewObject(gjni.ProgramInfo.clazz, gjni.ProgramInfo.cstor,
@@ -579,19 +641,32 @@ void register_android_server_broadcastradio_convert(JNIEnv *env) {
gjni.AmBandDescriptor.cstor = GetMethodIDOrDie(env, amBandDescriptorClass,
"<init>", "(IIIIIZ)V");
auto convertClass = FindClassOrDie(env, "com/android/server/broadcastradio/Convert");
gjni.Convert.clazz = MakeGlobalRefOrDie(env, convertClass);
gjni.Convert.stringMapToNative = GetStaticMethodIDOrDie(env, convertClass, "stringMapToNative",
"(Ljava/util/Map;)[[Ljava/lang/String;");
auto hashMapClass = FindClassOrDie(env, "java/util/HashMap");
gjni.HashMap.clazz = MakeGlobalRefOrDie(env, hashMapClass);
gjni.HashMap.cstor = GetMethodIDOrDie(env, hashMapClass, "<init>", "()V");
auto mapClass = FindClassOrDie(env, "java/util/Map");
gjni.Map.put = GetMethodIDOrDie(env, mapClass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
auto modulePropertiesClass = FindClassOrDie(env,
"android/hardware/radio/RadioManager$ModuleProperties");
gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass);
gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
"(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
"[I[ILjava/lang/String;)V");
"[I[ILjava/util/Map;)V");
auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);
gjni.ProgramInfo.cstor = GetMethodIDOrDie(env, programInfoClass, "<init>",
"(Landroid/hardware/radio/ProgramSelector;ZZZILandroid/hardware/radio/RadioMetadata;I"
"Ljava/lang/String;)V");
"Ljava/util/Map;)V");
auto programSelectorClass = FindClassOrDie(env, "android/hardware/radio/ProgramSelector");
gjni.ProgramSelector.clazz = MakeGlobalRefOrDie(env, programSelectorClass);

View File

@@ -35,6 +35,9 @@ namespace convert {
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hardware::hidl_vec<V1_1::VendorKeyValue> &info);
hardware::hidl_vec<V1_1::VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo);
JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties,
jint moduleId, const std::string& serviceName);
JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_1::Properties &properties,