From 54587ced033aca263d05e784a038cc717a1d2f3c Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Sun, 16 Jul 2017 15:15:40 -0700 Subject: [PATCH] Make it possible to check if a given program/identifier type is supported. Test: instrumentalization Bug: b/63702941 Change-Id: I436b62fa4cda8458a92a15a75543bedd43e65dcd --- api/system-current.txt | 2 + .../android/hardware/radio/RadioManager.java | 44 +++++++++++ .../jni/com_android_server_radio_convert.cpp | 76 +++++++++++++------ 3 files changed, 97 insertions(+), 25 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 28e4c485425d7..5c9f98629f69f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -17383,6 +17383,8 @@ package android.hardware.radio { method public java.lang.String getVersion(); method public boolean isBackgroundScanningSupported(); method public boolean isCaptureSupported(); + method public boolean isProgramIdentifierSupported(int); + method public boolean isProgramTypeSupported(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 3a0306e8e35a7..6a59be039dca4 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -34,6 +34,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * The RadioManager class allows to control a broadcast radio tuner present on the device. @@ -132,11 +134,15 @@ public class RadioManager { private final boolean mIsCaptureSupported; private final BandDescriptor[] mBands; private final boolean mIsBgScanSupported; + private final Set mSupportedProgramTypes; + private final Set mSupportedIdentifierTypes; private final String mVendorExension; 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 vendorExension) { mId = id; mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName; @@ -150,9 +156,18 @@ public class RadioManager { mIsCaptureSupported = isCaptureSupported; mBands = bands; mIsBgScanSupported = isBgScanSupported; + mSupportedProgramTypes = arrayToSet(supportedProgramTypes); + mSupportedIdentifierTypes = arrayToSet(supportedIdentifierTypes); mVendorExension = vendorExension; } + private static Set arrayToSet(int[] arr) { + return Arrays.stream(arr).boxed().collect(Collectors.toSet()); + } + + private static int[] setToArray(Set set) { + return set.stream().mapToInt(Integer::intValue).toArray(); + } /** Unique module identifier provided by the native service. * For use with {@link #openTuner(int, BandConfig, boolean, Callback, Handler)}. @@ -244,6 +259,31 @@ public class RadioManager { return mIsBgScanSupported; } + /** + * Checks, if a given program type is supported by this tuner. + * + * If a program type is supported by radio module, it means it can tune + * to ProgramSelector of a given type. + * + * @return {@code true} if a given program type is supported. + */ + public boolean isProgramTypeSupported(@ProgramSelector.ProgramType int type) { + return mSupportedProgramTypes.contains(type); + } + + /** + * Checks, if a given program identifier is supported by this tuner. + * + * If an identifier is supported by radio module, it means it can use it for + * tuning to ProgramSelector with either primary or secondary Identifier of + * a given type. + * + * @return {@code true} if a given program type is supported. + */ + public boolean isProgramIdentifierSupported(@ProgramSelector.IdentifierType int type) { + return mSupportedIdentifierTypes.contains(type); + } + /** * Opaque vendor-specific string, passed from HAL without changes. * Format of this string can vary across vendors. @@ -283,6 +323,8 @@ public class RadioManager { mBands[i] = (BandDescriptor) tmp[i]; } mIsBgScanSupported = in.readInt() == 1; + mSupportedProgramTypes = arrayToSet(in.createIntArray()); + mSupportedIdentifierTypes = arrayToSet(in.createIntArray()); mVendorExension = in.readString(); } @@ -311,6 +353,8 @@ public class RadioManager { dest.writeInt(mIsCaptureSupported ? 1 : 0); dest.writeParcelableArray(mBands, flags); dest.writeInt(mIsBgScanSupported ? 1 : 0); + dest.writeIntArray(setToArray(mSupportedProgramTypes)); + dest.writeIntArray(setToArray(mSupportedIdentifierTypes)); dest.writeString(mVendorExension); } diff --git a/services/core/jni/com_android_server_radio_convert.cpp b/services/core/jni/com_android_server_radio_convert.cpp index af000bdbfc858..6cad7f8adc558 100644 --- a/services/core/jni/com_android_server_radio_convert.cpp +++ b/services/core/jni/com_android_server_radio_convert.cpp @@ -185,6 +185,44 @@ void ThrowParcelableRuntimeException(JNIEnv *env, const std::string& msg) { ALOGE_IF(res != JNI_OK, "Couldn't throw parcelable runtime exception"); } +static JavaRef ArrayFromHal(JNIEnv *env, const hidl_vec& vec) { + auto jArr = make_javaref(env, env->NewIntArray(vec.size())); + auto jArrElements = env->GetIntArrayElements(jArr.get(), nullptr); + for (size_t i = 0; i < vec.size(); i++) { + jArrElements[i] = vec[i]; + } + env->ReleaseIntArrayElements(jArr.get(), jArrElements, 0); + return jArr; +} + +static JavaRef ArrayFromHal(JNIEnv *env, const hidl_vec& vec) { + auto jArr = make_javaref(env, env->NewLongArray(vec.size())); + auto jArrElements = env->GetLongArrayElements(jArr.get(), nullptr); + for (size_t i = 0; i < vec.size(); i++) { + jArrElements[i] = vec[i]; + } + env->ReleaseLongArrayElements(jArr.get(), jArrElements, 0); + return jArr; +} + +template +static JavaRef ArrayFromHal(JNIEnv *env, const hidl_vec& vec, + jclass jElementClass, std::function(JNIEnv*, const T&)> converter) { + auto jArr = make_javaref(env, env->NewObjectArray(vec.size(), jElementClass, nullptr)); + for (size_t i = 0; i < vec.size(); i++) { + auto jElement = converter(env, vec[i]); + env->SetObjectArrayElement(jArr.get(), i, jElement.get()); + } + return jArr; +} + +template +static JavaRef ArrayFromHal(JNIEnv *env, const hidl_vec& vec, + jclass jElementClass, JavaRef(*converter)(JNIEnv*, const T&)) { + return ArrayFromHal(env, vec, jElementClass, + std::function(JNIEnv*, const T&)>(converter)); +} + static Rds RdsForRegion(bool rds, Region region) { if (!rds) return Rds::NONE; @@ -220,6 +258,7 @@ static Deemphasis DeemphasisForRegion(Region region) { static JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &prop10, const V1_1::Properties *prop11, jint moduleId, const std::string& serviceName) { ALOGV("ModulePropertiesFromHal()"); + using namespace std::placeholders; auto jServiceName = make_javastr(env, serviceName); auto jImplementor = make_javastr(env, prop10.implementor); @@ -228,21 +267,19 @@ static JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert auto jSerial = make_javastr(env, prop10.serial); bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false; auto jVendorExtension = prop11 ? make_javastr(env, prop11->vendorExension) : nullptr; - - auto jBands = make_javaref(env, env->NewObjectArray(prop10.bands.size(), - gjni.BandDescriptor.clazz, nullptr)); - int i = 0; - for (auto &&band : prop10.bands) { - // ITU_1 is the default region just because its index is 0. - auto jBand = BandDescriptorFromHal(env, band, Region::ITU_1); - env->SetObjectArrayElement(jBands.get(), i++, jBand.get()); - } + // ITU_1 is the default region just because its index is 0. + auto jBands = ArrayFromHal(env, prop10.bands, gjni.BandDescriptor.clazz, + std::bind(BandDescriptorFromHal, _1, _2, Region::ITU_1)); + auto jSupportedProgramTypes = + prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr; + auto jSupportedIdentifierTypes = + prop11 ? ArrayFromHal(env, prop11->supportedIdentifierTypes) : nullptr; return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz, gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId, jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners, prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported, - jVendorExtension.get())); + jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), jVendorExtension.get())); } JavaRef ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties, @@ -411,20 +448,9 @@ static JavaRef ProgramIdentifierFromHal(JNIEnv *env, const ProgramIdent static JavaRef ProgramSelectorFromHal(JNIEnv *env, const ProgramSelector &selector) { ALOGV("ProgramSelectorFromHal()"); auto jPrimary = ProgramIdentifierFromHal(env, selector.primaryId); - - auto jSecondary = make_javaref(env, env->NewObjectArray(selector.secondaryIds.size(), - gjni.ProgramSelector.Identifier.clazz, nullptr)); - for (size_t i = 0; i < selector.secondaryIds.size(); i++) { - auto jId = ProgramIdentifierFromHal(env, selector.secondaryIds[i]); - env->SetObjectArrayElement(jSecondary.get(), i, jId.get()); - } - - auto jVendor = make_javaref(env, env->NewLongArray(selector.vendorIds.size())); - auto jVendorElements = env->GetLongArrayElements(jVendor.get(), nullptr); - for (size_t i = 0; i < selector.vendorIds.size(); i++) { - jVendorElements[i] = selector.vendorIds[i]; - } - env->ReleaseLongArrayElements(jVendor.get(), jVendorElements, 0); + auto jSecondary = ArrayFromHal(env, selector.secondaryIds, + gjni.ProgramSelector.Identifier.clazz, ProgramIdentifierFromHal); + auto jVendor = ArrayFromHal(env, selector.vendorIds); return make_javaref(env, env->NewObject(gjni.ProgramSelector.clazz, gjni.ProgramSelector.cstor, selector.programType, jPrimary.get(), jSecondary.get(), jVendor.get())); @@ -554,7 +580,7 @@ void register_android_server_radio_convert(JNIEnv *env) { gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" - "Ljava/lang/String;)V"); + "[I[ILjava/lang/String;)V"); auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo"); gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);