summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt6
-rw-r--r--core/java/android/hardware/radio/ITuner.aidl3
-rw-r--r--core/java/android/hardware/radio/RadioManager.java77
-rw-r--r--core/java/android/hardware/radio/RadioTuner.java13
-rw-r--r--core/java/android/hardware/radio/TunerAdapter.java6
-rw-r--r--core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java7
-rw-r--r--services/core/java/com/android/server/broadcastradio/Convert.java59
-rw-r--r--services/core/java/com/android/server/broadcastradio/Tuner.java8
-rw-r--r--services/core/jni/BroadcastRadio/Tuner.cpp6
-rw-r--r--services/core/jni/BroadcastRadio/convert.cpp83
-rw-r--r--services/core/jni/BroadcastRadio/convert.h3
11 files changed, 221 insertions, 50 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 1b292ccb5302..7b416db2831f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -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();
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 7f470ef15b96..ef8f80ce70dd 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -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
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index fcb3d8641717..50a4da2ed656 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -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;
}
}
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index be37cd0e342b..4b4fb1c8ce3c 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -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.
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index c68753788a4d..b62196902570 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -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);
}
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index ee40c48dcb58..29b6fd0e0c2c 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -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
diff --git a/services/core/java/com/android/server/broadcastradio/Convert.java b/services/core/java/com/android/server/broadcastradio/Convert.java
new file mode 100644
index 000000000000..125554fc3025
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/Convert.java
@@ -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;
+ }
+}
diff --git a/services/core/java/com/android/server/broadcastradio/Tuner.java b/services/core/java/com/android/server/broadcastradio/Tuner.java
index b9a1e8167ff2..06a5af5f482e 100644
--- a/services/core/java/com/android/server/broadcastradio/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/Tuner.java
@@ -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");
}
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index aa1925ad365a..85603d5e3608 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -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 },
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index ba1395f73045..3e0bc63c279f 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -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);
@@ -82,6 +83,20 @@ static struct {
struct {
jclass clazz;
+ jmethodID stringMapToNative;
+ } Convert;
+
+ struct {
+ jclass clazz;
+ jmethodID cstor;
+ } HashMap;
+
+ struct {
+ jmethodID put;
+ } Map;
+
+ struct {
+ jclass clazz;
jmethodID cstor;
} ModuleProperties;
@@ -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);
diff --git a/services/core/jni/BroadcastRadio/convert.h b/services/core/jni/BroadcastRadio/convert.h
index 198e594553a3..1fc75f06f38d 100644
--- a/services/core/jni/BroadcastRadio/convert.h
+++ b/services/core/jni/BroadcastRadio/convert.h
@@ -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,