Merge "Add automotive-general-tests tag to the test"
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index 44e916b..d7a9501 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -31,24 +31,26 @@
*
* @throws a EX_UNSUPPORTED_OPERATION if device capability/resource is not enough or system
* failure happens.
- * @note Open an already-opened effect instance should do nothing and not result in throw error.
+ * @note Open an already-opened effect instance should do nothing and should not throw an error.
*/
void open();
/**
- * Called by the client to close the effect instance, instance context will be kept after
- * close, but processing thread should be destroyed and consume no CPU. It is recommended to
- * close the effect on the client side as soon as it becomes unused, it's client responsibility
- * to make sure all parameter/buffer is correct if client wants to reopen a closed instance.
+ * Called by the client to close the effect instance, processing thread should be destroyed and
+ * consume no CPU after close.
*
- * Effect instance close interface should always success unless:
+ * It is recommended to close the effect on the client side as soon as it becomes unused, it's
+ * client responsibility to make sure all parameter/buffer is correct if client wants to reopen
+ * a closed instance.
+ *
+ * Effect instance close interface should always succeed unless:
* 1. The effect instance is not in a proper state to be closed, for example it's still in
* processing state.
* 2. There is system/hardware related failure when close.
*
* @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be closed.
* @throws EX_UNSUPPORTED_OPERATION if the effect instance failed to close for any other reason.
- * @note Close an already-closed effect should do nothing and not result in throw error.
+ * @note Close an already-closed effect should do nothing and should not throw an error.
*/
void close();
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index ea9d470..a9848fd 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -29,23 +29,9 @@
// TODO: implement this with xml parser on audio_effect.xml, and filter with optional
// parameters.
Descriptor::Identity id;
- id.type = {static_cast<int32_t>(0x0bed4300),
- 0xddd6,
- 0x11db,
- 0x8f34,
- {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
- id.uuid = EqualizerUUID;
+ id.type = EqualizerTypeUUID;
+ id.uuid = EqualizerSwImplUUID;
mIdentityList.push_back(id);
- // TODO: Add visualizer with default implementation later
-#if 0
- id.type = {static_cast<int32_t>(0xd3467faa),
- 0xacc7,
- 0x4d34,
- 0xacaf,
- {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
- id.uuid = VisualizerUUID;
- mIdentityList.push_back(id);
-#endif
}
ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type,
@@ -63,7 +49,7 @@
const AudioUuid& in_impl_uuid,
std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return) {
LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
- if (in_impl_uuid == EqualizerUUID) {
+ if (in_impl_uuid == EqualizerSwImplUUID) {
*_aidl_return = ndk::SharedRefBase::make<Equalizer>();
} else {
LOG(ERROR) << __func__ << ": UUID "
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index b30f2e7..3219dd6 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -23,7 +23,7 @@
int main() {
// This is a debug implementation, always enable debug logging.
android::base::SetMinimumLogSeverity(::android::base::DEBUG);
- ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
auto effectFactory =
ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
index dae3ab7..8b157fa 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -21,15 +21,6 @@
namespace aidl::android::hardware::audio::effect {
-Equalizer::Equalizer() {
- // Implementation UUID
- mDesc.common.id.uuid = {static_cast<int32_t>(0xce772f20),
- 0x847d,
- 0x11df,
- 0xbb17,
- {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-}
-
ndk::ScopedAStatus Equalizer::open() {
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
diff --git a/audio/aidl/default/include/equalizer-impl/Equalizer.h b/audio/aidl/default/include/equalizer-impl/Equalizer.h
index 44b1d6d..ea16cb9 100644
--- a/audio/aidl/default/include/equalizer-impl/Equalizer.h
+++ b/audio/aidl/default/include/equalizer-impl/Equalizer.h
@@ -21,23 +21,31 @@
namespace aidl::android::hardware::audio::effect {
-// Equalizer implementation UUID.
-static const ::aidl::android::media::audio::common::AudioUuid EqualizerUUID = {
+// Equalizer type UUID.
+static const ::aidl::android::media::audio::common::AudioUuid EqualizerTypeUUID = {
static_cast<int32_t>(0x0bed4300),
0xddd6,
0x11db,
0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// Equalizer implementation UUID.
+static const ::aidl::android::media::audio::common::AudioUuid EqualizerSwImplUUID = {
+ static_cast<int32_t>(0x0bed4300),
+ 0x847d,
+ 0x11df,
+ 0xbb17,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
class Equalizer : public BnEffect {
public:
- Equalizer();
+ Equalizer() = default;
ndk::ScopedAStatus open() override;
ndk::ScopedAStatus close() override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
private:
// Effect descriptor.
- Descriptor mDesc = {.common.id.type = EqualizerUUID};
+ Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 9b100b1..8b5eb13 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -33,6 +33,7 @@
#include <aidl/android/hardware/audio/effect/IFactory.h>
#include "AudioHalBinderServiceUtil.h"
+#include "TestUtils.h"
using namespace android;
@@ -45,7 +46,7 @@
class EffectFactoryHelper {
public:
- EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
+ explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
void ConnectToFactoryService() {
mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
@@ -60,27 +61,22 @@
void QueryAllEffects() {
EXPECT_NE(mEffectFactory, nullptr);
- ScopedAStatus status =
- mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds));
}
void QueryEffects(const std::optional<AudioUuid>& in_type,
const std::optional<AudioUuid>& in_instance,
std::vector<Descriptor::Identity>* _aidl_return) {
EXPECT_NE(mEffectFactory, nullptr);
- ScopedAStatus status = mEffectFactory->queryEffects(in_type, in_instance, _aidl_return);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, _aidl_return));
mIds = *_aidl_return;
}
void CreateEffects() {
EXPECT_NE(mEffectFactory, nullptr);
- ScopedAStatus status;
for (const auto& id : mIds) {
std::shared_ptr<IEffect> effect;
- status = mEffectFactory->createEffect(id.uuid, &effect);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE) << id.toString();
+ EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
EXPECT_NE(effect, nullptr) << id.toString();
mEffectIdMap[effect] = id;
}
@@ -88,10 +84,8 @@
void DestroyEffects() {
EXPECT_NE(mEffectFactory, nullptr);
- ScopedAStatus status;
for (const auto& it : mEffectIdMap) {
- status = mEffectFactory->destroyEffect(it.first);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE) << it.second.toString();
+ EXPECT_IS_OK(mEffectFactory->destroyEffect(it.first));
}
mEffectIdMap.clear();
}
@@ -143,7 +137,7 @@
TEST_P(EffectFactoryTest, QueriedDescriptorList) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
- EXPECT_NE(static_cast<int>(descriptors.size()), 0);
+ EXPECT_NE(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
@@ -159,52 +153,52 @@
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
- EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+ EXPECT_EQ(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
- EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+ EXPECT_EQ(descriptors.size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
- int numIds = static_cast<int>(mFactory.GetEffectIds().size());
- EXPECT_NE(numIds, 0);
+ auto numIds = mFactory.GetEffectIds().size();
+ EXPECT_NE(numIds, 0UL);
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
mFactory.CreateEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
mFactory.DestroyEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
// Create and destroy again
mFactory.CreateEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
mFactory.DestroyEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
- int numIds = static_cast<int>(mFactory.GetEffectIds().size());
- EXPECT_NE(numIds, 0);
+ auto numIds = mFactory.GetEffectIds().size();
+ EXPECT_NE(numIds, 0UL);
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
mFactory.CreateEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
// Create effect instances of same implementation
mFactory.CreateEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 2 * numIds);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 2 * numIds);
mFactory.CreateEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 3 * numIds);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 3 * numIds);
mFactory.DestroyEffects();
- EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
}
INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
@@ -226,26 +220,19 @@
}
void OpenEffects() {
- auto open = [](const std::shared_ptr<IEffect>& effect) {
- ScopedAStatus status = effect->open();
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
- };
+ auto open = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->open()); };
EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
}
void CloseEffects() {
- auto close = [](const std::shared_ptr<IEffect>& effect) {
- ScopedAStatus status = effect->close();
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
- };
+ auto close = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->close()); };
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
}
void GetEffectDescriptors() {
auto get = [](const std::shared_ptr<IEffect>& effect) {
Descriptor desc;
- ScopedAStatus status = effect->getDescriptor(&desc);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ EXPECT_IS_OK(effect->getDescriptor(&desc));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
}
@@ -253,7 +240,6 @@
template <typename Functor>
void ForEachEffect(Functor functor) {
auto effectMap = mFactory.GetEffectMap();
- ScopedAStatus status;
for (const auto& it : effectMap) {
SCOPED_TRACE(it.second.toString());
functor(it.first);
@@ -299,10 +285,9 @@
auto checker = [&](const std::shared_ptr<IEffect>& effect) {
Descriptor desc;
std::vector<Descriptor::Identity> idList;
- ScopedAStatus status = effect->getDescriptor(&desc);
- EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ EXPECT_IS_OK(effect->getDescriptor(&desc));
mFactory.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
- EXPECT_EQ(static_cast<int>(idList.size()), 1);
+ EXPECT_EQ(idList.size(), 1UL);
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
@@ -313,7 +298,7 @@
auto vec = mFactory.GetCompleteEffectIdList();
std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
for (auto it : vec) {
- EXPECT_EQ(static_cast<int>(idSet.count(it)), 0);
+ EXPECT_EQ(idSet.count(it), 0UL);
idSet.insert(it);
}
}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 0c949d6..b6811b6 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -110,6 +110,16 @@
"minSampleRate": 1.0
},
{
+ "property": "VehicleProperty::PERF_VEHICLE_SPEED_DISPLAY",
+ "defaultValue": {
+ "floatValues": [
+ 0.0
+ ]
+ },
+ "maxSampleRate": 10.0,
+ "minSampleRate": 1.0
+ },
+ {
"property": "VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS",
"defaultValue": {
"int32Values": [
diff --git a/broadcastradio/aidl/Android.bp b/broadcastradio/aidl/Android.bp
new file mode 100644
index 0000000..41d637c
--- /dev/null
+++ b/broadcastradio/aidl/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2022 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.
+//
+
+aidl_interface {
+ name: "android.hardware.broadcastradio",
+ vendor_available: true,
+ srcs: ["android/hardware/broadcastradio/*.aidl"],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ sdk_version: "module_current",
+ min_sdk_version: "Tiramisu",
+ },
+ },
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmBandRange.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmBandRange.aidl
new file mode 100644
index 0000000..ca511aa
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmBandRange.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AmFmBandRange {
+ int lowerBound;
+ int upperBound;
+ int spacing;
+ int seekSpacing;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl
new file mode 100644
index 0000000..f3aecdf
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AmFmRegionConfig.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable AmFmRegionConfig {
+ android.hardware.broadcastradio.AmFmBandRange[] ranges;
+ int fmDeemphasis;
+ int fmRds;
+ const int DEEMPHASIS_D50 = 1;
+ const int DEEMPHASIS_D75 = 2;
+ const int RDS = 1;
+ const int RBDS = 2;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Announcement.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Announcement.aidl
new file mode 100644
index 0000000..bbdd86f
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Announcement.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Announcement {
+ android.hardware.broadcastradio.ProgramSelector selector;
+ android.hardware.broadcastradio.AnnouncementType type = android.hardware.broadcastradio.AnnouncementType.INVALID;
+ android.hardware.broadcastradio.VendorKeyValue[] vendorInfo;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AnnouncementType.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AnnouncementType.aidl
new file mode 100644
index 0000000..237b868
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/AnnouncementType.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@Backing(type="byte") @JavaDerive(equals=true, toString=true) @VintfStability
+enum AnnouncementType {
+ INVALID = 0,
+ EMERGENCY = 1,
+ WARNING = 2,
+ TRAFFIC = 3,
+ WEATHER = 4,
+ NEWS = 5,
+ EVENT = 6,
+ SPORT = 7,
+ MISC = 8,
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl
new file mode 100644
index 0000000..6fb9a62
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ConfigFlag.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum ConfigFlag {
+ FORCE_MONO = 1,
+ FORCE_ANALOG = 2,
+ FORCE_DIGITAL = 3,
+ RDS_AF = 4,
+ RDS_REG = 5,
+ DAB_DAB_LINKING = 6,
+ DAB_FM_LINKING = 7,
+ DAB_DAB_SOFT_LINKING = 8,
+ DAB_FM_SOFT_LINKING = 9,
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/DabTableEntry.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/DabTableEntry.aidl
new file mode 100644
index 0000000..162f4abd
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/DabTableEntry.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable DabTableEntry {
+ String label;
+ int frequencyKhz;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IAnnouncementListener.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IAnnouncementListener.aidl
new file mode 100644
index 0000000..346af58
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IAnnouncementListener.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@VintfStability
+interface IAnnouncementListener {
+ oneway void onListUpdated(in android.hardware.broadcastradio.Announcement[] announcements);
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IBroadcastRadio.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IBroadcastRadio.aidl
new file mode 100644
index 0000000..39eb04c
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IBroadcastRadio.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@VintfStability
+interface IBroadcastRadio {
+ android.hardware.broadcastradio.Properties getProperties();
+ android.hardware.broadcastradio.AmFmRegionConfig getAmFmRegionConfig(in boolean full);
+ android.hardware.broadcastradio.DabTableEntry[] getDabRegionConfig();
+ void setTunerCallback(in android.hardware.broadcastradio.ITunerCallback callback);
+ void unsetTunerCallback();
+ void tune(in android.hardware.broadcastradio.ProgramSelector program);
+ void seek(in boolean directionUp, in boolean skipSubChannel);
+ void step(in boolean directionUp);
+ void cancel();
+ void startProgramListUpdates(in android.hardware.broadcastradio.ProgramFilter filter);
+ void stopProgramListUpdates();
+ boolean isConfigFlagSet(in android.hardware.broadcastradio.ConfigFlag flag);
+ void setConfigFlag(in android.hardware.broadcastradio.ConfigFlag flag, in boolean value);
+ android.hardware.broadcastradio.VendorKeyValue[] setParameters(in android.hardware.broadcastradio.VendorKeyValue[] parameters);
+ android.hardware.broadcastradio.VendorKeyValue[] getParameters(in String[] keys);
+ byte[] getImage(in int id);
+ android.hardware.broadcastradio.ICloseHandle registerAnnouncementListener(in android.hardware.broadcastradio.IAnnouncementListener listener, in android.hardware.broadcastradio.AnnouncementType[] enabled);
+ const int INVALID_IMAGE = 0;
+ const int ANTENNA_STATE_CHANGE_TIMEOUT_MS = 100;
+ const int LIST_COMPLETE_TIMEOUT_MS = 300000;
+ const int TUNER_TIMEOUT_MS = 30000;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ICloseHandle.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ICloseHandle.aidl
new file mode 100644
index 0000000..75e7f2a
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ICloseHandle.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@VintfStability
+interface ICloseHandle {
+ void close();
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ITunerCallback.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ITunerCallback.aidl
new file mode 100644
index 0000000..f5badad
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ITunerCallback.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@VintfStability
+interface ITunerCallback {
+ oneway void onTuneFailed(in android.hardware.broadcastradio.Result result, in android.hardware.broadcastradio.ProgramSelector selector);
+ oneway void onCurrentProgramInfoChanged(in android.hardware.broadcastradio.ProgramInfo info);
+ oneway void onProgramListUpdated(in android.hardware.broadcastradio.ProgramListChunk chunk);
+ oneway void onAntennaStateChange(in boolean connected);
+ oneway void onConfigFlagUpdated(in android.hardware.broadcastradio.ConfigFlag flag, in boolean value);
+ oneway void onParametersUpdated(in android.hardware.broadcastradio.VendorKeyValue[] parameters);
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl
new file mode 100644
index 0000000..4e8296a
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/IdentifierType.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@Backing(type="int") @JavaDerive(equals=true, toString=true) @VintfStability
+enum IdentifierType {
+ VENDOR_START = 1000,
+ VENDOR_END = 1999,
+ INVALID = 0,
+ AMFM_FREQUENCY_KHZ = 1,
+ RDS_PI = 2,
+ HD_STATION_ID_EXT = 3,
+ HD_STATION_NAME = 4,
+ DAB_SID_EXT = 5,
+ DAB_ENSEMBLE = 6,
+ DAB_SCID = 7,
+ DAB_FREQUENCY_KHZ = 8,
+ DRMO_SERVICE_ID = 9,
+ DRMO_FREQUENCY_KHZ = 10,
+ SXM_SERVICE_ID = 12,
+ SXM_CHANNEL = 13,
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl
new file mode 100644
index 0000000..e02b6b1
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Metadata.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+union Metadata {
+ String rdsPs;
+ int rdsPty;
+ int rbdsPty;
+ String rdsRt;
+ String songTitle;
+ String songArtist;
+ String songAlbum;
+ int stationIcon;
+ int albumArt;
+ String programName;
+ String dabEnsembleName;
+ String dabEnsembleNameShort;
+ String dabServiceName;
+ String dabServiceNameShort;
+ String dabComponentName;
+ String dabComponentNameShort;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramFilter.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramFilter.aidl
new file mode 100644
index 0000000..9edeb8d
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramFilter.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ProgramFilter {
+ android.hardware.broadcastradio.IdentifierType[] identifierTypes;
+ android.hardware.broadcastradio.ProgramIdentifier[] identifiers;
+ boolean includeCategories;
+ boolean excludeModifications;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramIdentifier.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramIdentifier.aidl
new file mode 100644
index 0000000..6676350
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramIdentifier.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ProgramIdentifier {
+ android.hardware.broadcastradio.IdentifierType type = android.hardware.broadcastradio.IdentifierType.INVALID;
+ long value;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
new file mode 100644
index 0000000..5e662d2
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ProgramInfo {
+ android.hardware.broadcastradio.ProgramSelector selector;
+ android.hardware.broadcastradio.ProgramIdentifier logicallyTunedTo;
+ android.hardware.broadcastradio.ProgramIdentifier physicallyTunedTo;
+ @nullable android.hardware.broadcastradio.ProgramIdentifier[] relatedContent;
+ int infoFlags;
+ int signalQuality;
+ android.hardware.broadcastradio.Metadata[] metadata;
+ android.hardware.broadcastradio.VendorKeyValue[] vendorInfo;
+ const int FLAG_LIVE = 1;
+ const int FLAG_MUTED = 2;
+ const int FLAG_TRAFFIC_PROGRAM = 4;
+ const int FLAG_TRAFFIC_ANNOUNCEMENT = 8;
+ const int FLAG_TUNABLE = 16;
+ const int FLAG_STEREO = 32;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramListChunk.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramListChunk.aidl
new file mode 100644
index 0000000..5d53b99
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramListChunk.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ProgramListChunk {
+ boolean purge;
+ boolean complete;
+ android.hardware.broadcastradio.ProgramInfo[] modified;
+ @nullable android.hardware.broadcastradio.ProgramIdentifier[] removed;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramSelector.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramSelector.aidl
new file mode 100644
index 0000000..9af1dc8
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/ProgramSelector.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ProgramSelector {
+ android.hardware.broadcastradio.ProgramIdentifier primaryId;
+ android.hardware.broadcastradio.ProgramIdentifier[] secondaryIds;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Properties.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Properties.aidl
new file mode 100644
index 0000000..643b819
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Properties.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable Properties {
+ String maker;
+ String product;
+ String version;
+ String serial;
+ android.hardware.broadcastradio.IdentifierType[] supportedIdentifierTypes;
+ android.hardware.broadcastradio.VendorKeyValue[] vendorInfo;
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
new file mode 100644
index 0000000..07edae8
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@Backing(type="int") @VintfStability
+enum Result {
+ OK = 0,
+ INTERNAL_ERROR = 1,
+ INVALID_ARGUMENTS = 2,
+ INVALID_STATE = 3,
+ NOT_SUPPORTED = 4,
+ TIMEOUT = 5,
+ UNKNOWN_ERROR = 6,
+}
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/VendorKeyValue.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/VendorKeyValue.aidl
new file mode 100644
index 0000000..3c6b194
--- /dev/null
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/VendorKeyValue.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.broadcastradio;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VendorKeyValue {
+ String key;
+ String value;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AmFmBandRange.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AmFmBandRange.aidl
new file mode 100644
index 0000000..562631f
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AmFmBandRange.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Defines the AM/FM band range for configuring different regions.
+ *
+ * <p>Channel grid is defined as: each possible channel is set at
+ * lowerBound + channelNumber * spacing, up to upperBound.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable AmFmBandRange {
+ /**
+ * The frequency (in kHz) of the first channel within the range.
+ *
+ * Lower bound must be a tunable frequency.
+ */
+ int lowerBound;
+
+ /**
+ * The frequency (in kHz) of the last channel within the range.
+ */
+ int upperBound;
+
+ /**
+ * Channel grid resolution (in kHz), telling how far the channels are apart.
+ */
+ int spacing;
+
+ /**
+ * Channel spacing (in kHz) used to speed up seeking to the next station
+ * via the {@link IBroadcastRadio#seek} operation.
+ *
+ * It must be a multiple of channel grid resolution.
+ *
+ * Tuner may first quickly check every n-th channel and if it detects echo
+ * from a station, it fine-tunes to find the exact frequency.
+ *
+ * It's ignored for capabilities check (with full=true when calling
+ * getAmFmRegionConfig).
+ */
+ int seekSpacing;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AmFmRegionConfig.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AmFmRegionConfig.aidl
new file mode 100644
index 0000000..a3086c6
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AmFmRegionConfig.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.AmFmBandRange;
+
+/**
+ * Regional configuration for AM/FM.
+ *
+ * <p>For hardware capabilities check (with full=true when calling
+ * {@link IBroadcastRadio#getAmFmRegionConfig}), HAL implementation fills
+ * entire supported range of frequencies and features.
+ *
+ * When checking current configuration, at most one bit in each bitset
+ * can be set.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable AmFmRegionConfig {
+ /**
+ * Noth D50 and D75 are FM de-emphasis filter supported or configured.
+ *
+ * Both might be set for hardware capabilities check (with full={@code true}
+ * when calling getAmFmRegionConfig), but exactly one for specific region
+ * settings.
+ */
+ const int DEEMPHASIS_D50 = 1 << 0;
+
+ const int DEEMPHASIS_D75 = 1 << 1;
+
+ /**
+ * Both RDS and RBDS are supported or configured RDS variants.
+ *
+ * Both might be set for hardware capabilities check (with full={@code true}
+ * when calling getAmFmRegionConfig), but only one (or none) for specific
+ * region settings.
+ *
+ * RDS is Standard variant, used everywhere except North America.
+ */
+ const int RDS = 1 << 0;
+
+ /**
+ * Variant used in North America (see RDS).
+ */
+ const int RBDS = 1 << 1;
+
+ /**
+ * All supported or configured AM/FM bands.
+ *
+ * AM/FM bands are identified by frequency value
+ * (see {@link IdentifierType#AMFM_FREQUENCY_KHZ}).
+ *
+ * With typical configuration, it's expected to have two frequency ranges
+ * for capabilities check (AM and FM) and four ranges for specific region
+ * configuration (AM LW, AM MW, AM SW, FM).
+ */
+ AmFmBandRange[] ranges;
+
+ /**
+ * De-emphasis filter supported/configured.
+ *
+ * It is a bitset of de-emphasis values (DEEMPHASIS_D50 and DEEMPHASIS_D75).
+ */
+ int fmDeemphasis;
+
+ /**
+ * RDS/RBDS variant supported/configured.
+ *
+ * It is a bitset of RDS values (RDS and RBDS).
+ */
+ int fmRds;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Announcement.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Announcement.aidl
new file mode 100644
index 0000000..a972d4d
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Announcement.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.AnnouncementType;
+import android.hardware.broadcastradio.ProgramSelector;
+import android.hardware.broadcastradio.VendorKeyValue;
+
+/**
+ * Station broadcasting active announcement.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Announcement {
+ /**
+ * Program selector to tune to the announcement.
+ */
+ ProgramSelector selector;
+
+ /**
+ * Announcement type.
+ */
+ AnnouncementType type = AnnouncementType.INVALID;
+
+ /**
+ * Vendor-specific information.
+ *
+ * It may be used for extra features, not supported by the platform,
+ * for example: com.me.hdradio.urgency=100; com.me.hdradio.certainity=50.
+ */
+ VendorKeyValue[] vendorInfo;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/AnnouncementType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/AnnouncementType.aidl
new file mode 100644
index 0000000..8df8025
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/AnnouncementType.aidl
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Type of an announcement.
+ *
+ * <p>It maps to different announcement types for each radio technology.
+ */
+@VintfStability
+@Backing(type="byte")
+@JavaDerive(equals=true, toString=true)
+enum AnnouncementType {
+ /**
+ * Undefined announcement type
+ */
+ INVALID = 0,
+
+ /**
+ * DAB alarm, RDS emergency program type (PTY 31).
+ */
+ EMERGENCY = 1,
+
+ /**
+ * DAB warning.
+ */
+ WARNING,
+
+ /**
+ * DAB road traffic, RDS TA, HD Radio transportation.
+ */
+ TRAFFIC,
+
+ /**
+ * Weather.
+ */
+ WEATHER,
+
+ /**
+ * News.
+ */
+ NEWS,
+
+ /**
+ * DAB event, special event.
+ */
+ EVENT,
+
+ /**
+ * DAB sport report, RDS sports.
+ */
+ SPORT,
+
+ /**
+ * All others.
+ */
+ MISC,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl
new file mode 100644
index 0000000..11da39c
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ConfigFlag.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Configuration flags to be used with isConfigFlagSet and setConfigFlag methods
+ * of IBroadcastRadio.
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum ConfigFlag {
+ /**
+ * Forces mono audio stream reception.
+ *
+ * Analog broadcasts can recover poor reception conditions by jointing
+ * stereo channels into one. Mainly for, but not limited to AM/FM.
+ */
+ FORCE_MONO = 1,
+
+ /**
+ * Forces the analog playback for the supporting radio technology.
+ *
+ * User may disable digital playback for FM HD Radio or hybrid FM/DAB with
+ * this option. This is purely user choice, ie. does not reflect digital-
+ * analog handover state managed from the HAL implementation side.
+ *
+ * Some radio technologies may not support this, ie. DAB.
+ */
+ FORCE_ANALOG,
+
+ /**
+ * Forces the digital playback for the supporting radio technology.
+ *
+ * User may disable digital-analog handover that happens with poor
+ * reception conditions. With digital forced, the radio will remain silent
+ * instead of switching to analog channel if it's available. This is purely
+ * user choice, it does not reflect the actual state of handover.
+ */
+ FORCE_DIGITAL,
+
+ /**
+ * RDS Alternative Frequencies.
+ *
+ * If set and the currently tuned RDS station broadcasts on multiple
+ * channels, radio tuner automatically switches to the best available
+ * alternative.
+ */
+ RDS_AF,
+
+ /**
+ * RDS region-specific program lock-down.
+ *
+ * Allows user to lock to the current region as they move into the
+ * other region.
+ */
+ RDS_REG,
+
+ /**
+ * Enables DAB-DAB hard- and implicit-linking (the same content).
+ */
+ DAB_DAB_LINKING,
+
+ /**
+ * Enables DAB-FM hard- and implicit-linking (the same content).
+ */
+ DAB_FM_LINKING,
+
+ /**
+ * Enables DAB-DAB soft-linking (related content).
+ */
+ DAB_DAB_SOFT_LINKING,
+
+ /**
+ * Enables DAB-FM soft-linking (related content).
+ */
+ DAB_FM_SOFT_LINKING,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/DabTableEntry.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/DabTableEntry.aidl
new file mode 100644
index 0000000..13c20b0
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/DabTableEntry.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * An entry in regional configuration for DAB.
+ *
+ * <p>This defines a frequency table row for ensembles.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable DabTableEntry {
+ /**
+ * Channel name, i.e. 5A, 7B.
+ *
+ * It must match the following regular expression:
+ * /^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$/ (2-7 uppercase alphanumeric characters
+ * without spaces allowed at the beginning nor end).
+ */
+ String label;
+
+ /**
+ * Frequency, in kHz.
+ */
+ int frequencyKhz;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IAnnouncementListener.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IAnnouncementListener.aidl
new file mode 100644
index 0000000..f6021c1
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IAnnouncementListener.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.Announcement;
+
+/**
+ * Callback interface for announcement listener.
+ *
+ * For typical configuration, the listener is a broadcast radio service.
+ */
+@VintfStability
+interface IAnnouncementListener {
+ /**
+ * Called whenever announcement list has changed.
+ *
+ * @param announcements The complete list of currently active announcements.
+ */
+ oneway void onListUpdated(in Announcement[] announcements);
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IBroadcastRadio.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IBroadcastRadio.aidl
new file mode 100644
index 0000000..0f88fc0
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IBroadcastRadio.aidl
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.AmFmRegionConfig;
+import android.hardware.broadcastradio.AnnouncementType;
+import android.hardware.broadcastradio.ConfigFlag;
+import android.hardware.broadcastradio.DabTableEntry;
+import android.hardware.broadcastradio.IAnnouncementListener;
+import android.hardware.broadcastradio.ICloseHandle;
+import android.hardware.broadcastradio.ITunerCallback;
+import android.hardware.broadcastradio.ProgramFilter;
+import android.hardware.broadcastradio.ProgramSelector;
+import android.hardware.broadcastradio.Properties;
+import android.hardware.broadcastradio.VendorKeyValue;
+
+/**
+ * Represents a hardware broadcast radio module. A single module may contain
+ * multiple hardware tuners (i.e. with an additional background tuner), but the
+ * layers above the HAL see them as a single logical unit.
+ */
+@VintfStability
+interface IBroadcastRadio {
+ /**
+ * Invalid identifier for {@link IBroadcastRadio#getImage}.
+ */
+ const int INVALID_IMAGE = 0;
+
+ /**
+ * If the antenna is disconnected from the beginning, the
+ * {@link ITunerCallback#onAntennaStateChange} callback must be
+ * called within this time.
+ */
+ const int ANTENNA_STATE_CHANGE_TIMEOUT_MS = 100;
+
+ /**
+ * All chunks of a signal program list update must be transmitted
+ * within this time.
+ */
+ const int LIST_COMPLETE_TIMEOUT_MS = 300000;
+
+ /**
+ * All tune, seek and step operations must be completed within
+ * this time.
+ */
+ const int TUNER_TIMEOUT_MS = 30000;
+
+ /**
+ * Returns module properties: a description of a module and its
+ * capabilities. This method must not fail.
+ *
+ * @return Module description.
+ */
+ Properties getProperties();
+
+ /**
+ * Fetches current or possible AM/FM region configuration.
+ *
+ * If the tuner doesn't support AM/FM, a service-specific error
+ * {@link Result#NOT_SUPPORTED} will be returned.
+ *
+ * @param full If {@code true}, returns full hardware capabilities.
+ * If {@code false}, returns current regional configuration.
+ * @return config Hardware capabilities (full={@code true}) or current configuration
+ * (full={@code false}).
+ */
+ AmFmRegionConfig getAmFmRegionConfig(in boolean full);
+
+ /**
+ * Fetches current DAB region configuration.
+ *
+ * If tuner doesn't support DAB, a service-specific error
+ * {@link Result#NOT_SUPPORTED} wiil be returned.
+ *
+ * @return config Current configuration.
+ */
+ DabTableEntry[] getDabRegionConfig();
+
+ /**
+ * Sets callback interface.
+ *
+ * It is expected that there will only ever be a single callback set.
+ * If called when a callback is already set, the existing one should be
+ * replaced with the new callback.
+ *
+ * If the callback to be set is null, a service-specific error
+ * {@link Result#INVALID_ARGUMENTS} will be returned; if the callback
+ * is not set successfully, a service-specific error
+ * {@link Result#NOT_SUPPORTED} should be returned.
+ *
+ * @param callback The callback interface used for BroadcastRadio HAL.
+ */
+ void setTunerCallback(in ITunerCallback callback);
+
+ /**
+ * Unsets callback interface.
+ *
+ * The existing callback is set to null.
+ */
+ void unsetTunerCallback();
+
+ /**
+ * Tunes to a specified program.
+ *
+ * Automatically cancels pending tune(), seek() or step().
+ * The method should first check whether tune can be processed by the status
+ * of tuner and inputs, schedule tune task, and then return status
+ * immediately. If a non-null callback is not set, a service-specific
+ * error {@link Result#INVALID_STATE} will be returned; if the program
+ * selector doesn't contain any supported identifier, a service-specific error
+ * {@link Result#NOT_SUPPORTED} will be returned; if the program selector
+ * contains identifiers in invalid format (i.e. out of range), a
+ * service-specific error {@link Result#INVALID_ARGUMENTS} will be returned;
+ * otherwise, OK will be returned as status. Tune task should be processed
+ * asynchronously after the method returns status. If the method returns OK,
+ * {@link ITunerCallback#tuneFailed} or
+ * {@link ITunerCallback#currentProgramInfoChanged} callback must be called
+ * after the tune task completes.
+ *
+ * @param program Program to tune to.
+ */
+ void tune(in ProgramSelector program);
+
+ /**
+ * Seeks the next valid program on the "air".
+ *
+ * Advance to the next detected program and stay there.
+ *
+ * Automatically cancels pending tune(), seek() or step().
+ * The method should first check whether seek can be processed by the status
+ * of tuner and inputs, schedule seek task, and then return status
+ * immediately. If a non-null callback is not set, a service-specific
+ * error {@link Result#INVALID_STATE} will be returned; otherwise, OK will
+ * be returned as status. Seek task should be processed asynchronously
+ * after the method returns status. If the method returns OK,
+ * {@link ITunerCallback#tuneFailed} or
+ * {@link ITunerCallback#currentProgramInfoChanged} callback must be called
+ * after the seek task completes.
+ *
+ * The skipSubChannel parameter is used to skip digital radio subchannels:
+ * - HD Radio SPS;
+ * - DAB secondary service.
+ *
+ * As an implementation detail, the HAL has the option to perform an actual
+ * seek or select the next program from the list retrieved in the
+ * background.
+ *
+ * @param directionUp {@code true} to change towards higher numeric values
+ * (frequency, channel number), {@code false} towards
+ * lower.
+ * @param skipSubChannel Don't tune to subchannels.
+ */
+ void seek(in boolean directionUp, in boolean skipSubChannel);
+
+ /**
+ * Steps to the adjacent channel, which may not be occupied by any program.
+ *
+ * Automatically cancels pending tune(), seek() or step().
+ * The method should first check whether step can be processed by the status
+ * of tuner and inputs, schedule step task, and then return status
+ * immediately. If a non-null callback is not set, service-specific
+ * error {@link Result#INVALID_STATE} will be returned; if tuning to an
+ * unoccupied channel is not supported (i.e. for satellite radio), a
+ * service-specific error {@link Result#NOT_SUPPORTED} will be returned;
+ * otherwise, OK should be returned as status. Step task should be
+ * processed asynchronously after the method returns status. If the
+ * method returns OK, {@link ITunerCallback#tuneFailed} or
+ * {@link currentProgramInfoChanged} callback must be called after the
+ * step task completes.
+ *
+ * @param directionUp {@code true} to change towards higher numeric values
+ * (frequency, channel number), {@code false} towards lower.
+ */
+ void step(in boolean directionUp);
+
+ /**
+ * Cancels pending tune(), seek() or step().
+ *
+ * If there is no such operation running, the call can be ignored.
+ * If cancel is called after the HAL completes an operation (tune, seek, and step)
+ * and before the callback completions, the cancel can be ignored and the callback
+ * should complete.
+ */
+ void cancel();
+
+ /**
+ * Applies a filter to the program list and starts sending program list
+ * update over {@link ITunerCallback#onProgramListUpdated} callback.
+ *
+ * There may be only one updates stream active at the moment. Calling this
+ * method again must result in cancelling the pending update request.
+ *
+ * This call clears the program list on the client side, the HAL must send
+ * the whole list again.
+ *
+ * If the program list scanning hardware (i.e. background tuner) is
+ * unavailable at the moment, the call must succeed and start updates
+ * when it becomes available.
+ *
+ * If the program list scanning is not supported by the hardware, a
+ * service-specific error {@link Result#NOT_SUPPORTED} will be returned.
+ *
+ * @param filter Filter to apply on the fetched program list.
+ */
+ void startProgramListUpdates(in ProgramFilter filter);
+
+ /**
+ * Stops sending program list updates.
+ *
+ * If stopProgramListUpdates is called after the HAL completes a program list update
+ * and before the onCurrentProgramInfoChanged callback completions,
+ * stopProgramListUpdates can be ignored and the callback should complete.
+ */
+ void stopProgramListUpdates();
+
+ /**
+ * Fetches the current setting of a given config flag.
+ *
+ * The success/failure result must be consistent with setConfigFlag.
+ *
+ * If the flag is not applicable, a service-specific error
+ * {@link Result#INVALID_STATE} will be returned. If the flag is not
+ * supported at all, a service-specific error {@link Result#NOT_SUPPORTED}
+ * will be returned.
+ *
+ * @return the current value of the flag, if succeed.
+ */
+ boolean isConfigFlagSet(in ConfigFlag flag);
+
+ /**
+ * Sets the config flag.
+ *
+ * The success/failure result must be consistent with isConfigFlagSet.
+ *
+ * If the flag is not applicable, a service-specific error
+ * {@link Result#INVALID_STATE} will be returned. If the flag is not
+ * supported at all, a service-specific error {@link Result#NOT_SUPPORTED}
+ * will be returned.
+ *
+ * @param flag Flag to set.
+ * @param value The new value of a given flag.
+ */
+ void setConfigFlag(in ConfigFlag flag, in boolean value);
+
+ /**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Framework does not make any assumptions on the keys or values, other than
+ * ones stated in VendorKeyValue documentation (a requirement of key
+ * prefixes).
+ *
+ * For each pair in the result array, the key must be one of the keys
+ * contained in the input (possibly with wildcards expanded), and the value
+ * must be a vendor-specific result status (i.e. the string "OK" or an error
+ * code). The implementation may choose to return an empty array, or only
+ * return a status for a subset of the provided inputs, at its discretion.
+ *
+ * Application and HAL must not use keys with unknown prefix. In particular,
+ * it must not place a key-value pair in results array for unknown key from
+ * parameters array - instead, an unknown key should simply be ignored.
+ * In other words, results array may contain a subset of parameter keys
+ * (however, the framework doesn't enforce a strict subset - the only
+ * formal requirement is vendor domain prefix for keys).
+ *
+ * @param parameters Vendor-specific key-value pairs.
+ * @return Operation completion status for parameters being set.
+ */
+ VendorKeyValue[] setParameters(in VendorKeyValue[] parameters);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Framework does not cache set/get requests, so it's allowed for
+ * getParameter to return a different value than previous setParameter call.
+ *
+ * The syntax and semantics of keys are up to the vendor (as long as prefix
+ * rules are obeyed). For instance, vendors may include some form of
+ * wildcard support. In such case, result array may be of different size
+ * than requested keys array. However, wildcards are not recognized by
+ * framework and they are passed as-is to the HAL implementation.
+ *
+ * Unknown keys must be ignored and not placed into results array.
+ *
+ * @param keys Parameter keys to fetch.
+ * @return Vendor-specific key-value pairs.
+ */
+ VendorKeyValue[] getParameters(in String[] keys);
+
+ /**
+ * Fetches image from radio module cache.
+ *
+ * This is out-of-band transport mechanism for images carried with metadata.
+ * The metadata array only passes the identifier, so the client may cache
+ * images or even not fetch them.
+ *
+ * The identifier may be any arbitrary number (i.e. sha256 prefix) selected
+ * by the vendor. It must be stable so the application may cache it.
+ *
+ * The data must be a valid PNG, JPEG, GIF or BMP file, and must be less
+ * than 1MB, due to hard limit on binder transaction buffer.
+ *
+ * Image data with an invalid format must be handled gracefully in the same
+ * way as a missing image.
+ *
+ * The image identifier may become invalid after some time from passing it
+ * with metadata struct (due to resource cleanup at the HAL implementation).
+ * However, it must remain valid for a currently tuned program at least
+ * until onCurrentProgramInfoChanged is called.
+ *
+ * @param id Identifier of an image (value of {@link IBroadcastRadio#INVALID_IMAGE}
+ * is reserved and must be treated as invalid image).
+ * @return A binary blob with image data
+ * or a zero-length array if identifier doesn't exist.
+ */
+ byte[] getImage(in int id);
+
+ /**
+ * Registers announcement listener.
+ *
+ * If there is at least one observer registered, HAL implementation must
+ * notify about announcements.
+ *
+ * If the observer dies, the HAL implementation must unregister observer
+ * automatically.
+ *
+ * If the tuner doesn't support announcements, a service-specific error
+ * {@link Result#NOT_SUPPORTED} will be returned.
+ *
+ * @param listener The listener interface.
+ * @param enabled The list of announcement types to watch for.
+ * @return a handle to unregister observer.
+ */
+ ICloseHandle registerAnnouncementListener(
+ in IAnnouncementListener listener, in AnnouncementType[] enabled);
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ICloseHandle.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ICloseHandle.aidl
new file mode 100644
index 0000000..4a3240b
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ICloseHandle.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ */
+@VintfStability
+interface ICloseHandle {
+ /**
+ * Closes the handle.
+ *
+ * The call must not fail and must only be issued once.
+ *
+ * After the close call is executed, no other calls to this interface
+ * are allowed. If the call is issued second time, a service-specific
+ * error {@link Result#INVALID_STATE} will be returned.
+ */
+ void close();
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
new file mode 100644
index 0000000..1f0221c
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.ConfigFlag;
+import android.hardware.broadcastradio.ProgramInfo;
+import android.hardware.broadcastradio.ProgramListChunk;
+import android.hardware.broadcastradio.ProgramSelector;
+import android.hardware.broadcastradio.Result;
+import android.hardware.broadcastradio.VendorKeyValue;
+
+@VintfStability
+oneway interface ITunerCallback {
+ /**
+ * Method called by the HAL when a tuning operation fails asynchronously
+ * following {@link IBroadcastRadio#tune}, {@link IBroadcastRadio#seek}
+ * or {@link IBroadcastRadio#step}.
+ *
+ * This callback is only called when the tune(), seek() or step() command
+ * succeeds without returning any error at first.
+ *
+ * @param result {@link Result#TIMEOUT} in case that tune(), seek() or
+ * step() is not completed within
+ * @link IBroadcastRadio#TUNER_TIMEOUT_MS}
+ * @param selector A ProgramSelector structure passed from tune() call;
+ * empty for step() and seek().
+ */
+ void onTuneFailed(in Result result, in ProgramSelector selector);
+
+ /**
+ * Method called by the HAL when current program information (including
+ * metadata) is updated. It must be called when {@link IBroadcastRadio#tune}
+ * {@link IBroadcastRadio#seek} or {@link IBroadcastRadio#step} command
+ * succeeds.
+ *
+ * This is also called when the radio tuned to the static (not a valid
+ * station), see {@link ProgramInfo#FLAG_TUNABLE} flag.
+ *
+ * @param info Current program information.
+ */
+ void onCurrentProgramInfoChanged(in ProgramInfo info);
+
+ /**
+ * A delta update of the program list, called whenever there's a change in
+ * the list.
+ *
+ * If there are frequent changes, HAL implementation must throttle the rate
+ * of the updates.
+ *
+ * There is a hard limit on binder transaction buffer, and the list must
+ * not exceed it. For large lists, HAL implementation must split them to
+ * multiple chunks, no larger than 500kiB each, and call this program list
+ * update callback method separately.
+ *
+ * @param chunk A chunk of the program list update.
+ */
+ void onProgramListUpdated(in ProgramListChunk chunk);
+
+ /**
+ * Method called by the HAL when the antenna gets connected or disconnected.
+ *
+ * For broadcast radio service, client must assume the antenna is connected.
+ * If it's not, then antennaStateChange must be called within
+ * {@link IBroadcastRadio#ANTENNA_STATE_CHANGE_TIMEOUT_MS} to indicate that.
+ *
+ * @param connected {@code true} if the antenna is now connected, {@code false}
+ * otherwise.
+ */
+ void onAntennaStateChange(in boolean connected);
+
+ /**
+ * Generic callback for passing updates to config flags.
+ *
+ * It's up to the HAL implementation if and how to implement this callback,
+ * as long as it obeys the prefix rule. However, setConfigFlag must not
+ * trigger this callback, while an internal event can change config flag
+ * asynchronously at the HAL layer.
+ *
+ * @param flag Flag that has changed.
+ * @param value The new value of the given flag.
+ */
+ void onConfigFlagUpdated(in ConfigFlag flag, in boolean value);
+
+ /**
+ * Generic callback for passing updates to vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * It's up to the HAL implementation if and how to implement this callback,
+ * as long as it obeys the prefix rule. In particular, only selected keys
+ * may be notified this way. However, setParameters must not trigger
+ * this callback, while an internal event can change parameters
+ * asynchronously at the HAL layer.
+ *
+ * @param parameters Vendor-specific key-value pairs,
+ * opaque to Android framework.
+ */
+ void onParametersUpdated(in VendorKeyValue[] parameters);
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
new file mode 100644
index 0000000..0484d02
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Type of program identifier component.
+ *
+ * Each identifier type corresponds to exactly one radio technology,
+ * i.e. DAB_ENSEMBLE is specifically for DAB.
+ *
+ * VENDOR identifier types must be opaque to the framework.
+ *
+ * The value format for each (but VENDOR_*) identifier is strictly defined
+ * to maintain interoperability between devices made by different vendors.
+ *
+ * All other values are reserved for future use.
+ * Values not matching any enumerated constant must be ignored.
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(equals=true, toString=true)
+enum IdentifierType {
+ /**
+ * Primary/secondary identifier for vendor-specific radio technology.
+ * The value format is determined by a vendor.
+ *
+ * The vendor identifiers have limited serialization capabilities - see
+ * ProgramSelector description.
+ */
+ VENDOR_START = 1000,
+
+ /**
+ * See VENDOR_START
+ */
+ VENDOR_END = 1999,
+
+ /**
+ * Undefined identifier type.
+ */
+ INVALID = 0,
+
+ /**
+ * Primary identifier for analogue (without RDS) AM/FM stations:
+ * frequency in kHz.
+ *
+ * This identifier also contains band information:
+ * - <500kHz: AM LW;
+ * - 500kHz - 1705kHz: AM MW;
+ * - 1.71MHz - 30MHz: AM SW;
+ * - >60MHz: FM.
+ */
+ AMFM_FREQUENCY_KHZ,
+
+ /**
+ * 16bit primary identifier for FM RDS station.
+ */
+ RDS_PI,
+
+ /**
+ * 64bit compound primary identifier for HD Radio.
+ *
+ * Consists of (from the LSB):
+ * - 32bit: Station ID number;
+ * - 4bit: HD Radio subchannel;
+ * - 18bit: AMFM_FREQUENCY_KHZ.
+ *
+ * While station ID number should be unique globally, it sometimes get
+ * abused by broadcasters (i.e. not being set at all). To ensure local
+ * uniqueness, AMFM_FREQUENCY_KHZ was added here. Global uniqueness is
+ * a best-effort - see HD_STATION_NAME.
+ *
+ * HD Radio subchannel is a value in range 0-7.
+ * This index is 0-based (where 0 is MPS and 1..7 are SPS),
+ * as opposed to HD Radio standard (where it's 1-based).
+ *
+ * The remaining bits should be set to zeros when writing on the chip side
+ * and ignored when read.
+ */
+
+ HD_STATION_ID_EXT,
+
+ /**
+ * 64bit additional identifier for HD Radio.
+ *
+ * Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
+ * globally unique. To provide a best-effort solution, a short version of
+ * station name may be carried as additional identifier and may be used
+ * by the tuner hardware to double-check tuning.
+ *
+ * The name is limited to the first 8 A-Z0-9 characters (lowercase letters
+ * must be converted to uppercase). Encoded in little-endian ASCII:
+ * the first character of the name is the LSB.
+ *
+ * For example: "Abc" is encoded as 0x434241.
+ */
+ HD_STATION_NAME,
+
+ /**
+ * 28bit compound primary identifier for Digital Audio Broadcasting.
+ *
+ * Consists of (from the LSB):
+ * - 16bit: SId;
+ * - 8bit: ECC code;
+ * - 4bit: SCIdS.
+ *
+ * SCIdS (Service Component Identifier within the Service) value
+ * of 0 represents the main service, while 1 and above represents
+ * secondary services.
+ *
+ * The remaining bits should be set to zeros when writing on the chip side
+ * and ignored when read.
+ */
+ DAB_SID_EXT,
+
+ /**
+ * 16bit
+ */
+ DAB_ENSEMBLE,
+
+ /**
+ * 12bit
+ */
+ DAB_SCID,
+
+ /**
+ * kHz (see AMFM_FREQUENCY_KHZ)
+ */
+ DAB_FREQUENCY_KHZ,
+
+ /**
+ * 24bit primary identifier for Digital Radio Mondiale.
+ */
+ DRMO_SERVICE_ID,
+
+ /**
+ * kHz (see AMFM_FREQUENCY_KHZ)
+ */
+ DRMO_FREQUENCY_KHZ,
+
+ /**
+ * 32bit primary identifier for SiriusXM Satellite Radio.
+ */
+ SXM_SERVICE_ID = DRMO_FREQUENCY_KHZ + 2,
+
+ /**
+ * 0-999 range
+ */
+ SXM_CHANNEL,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
new file mode 100644
index 0000000..3298cac
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Metadata.aidl
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * An element of metadata array.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+union Metadata {
+ /**
+ * RDS PS (string)
+ */
+ String rdsPs;
+
+ /**
+ * RDS PTY (uint8_t)
+ */
+ int rdsPty;
+
+ /**
+ * RBDS PTY (uint8_t)
+ */
+ int rbdsPty;
+
+ /**
+ * RDS RT (string)
+ */
+ String rdsRt;
+
+ /**
+ * Song title (string)
+ */
+ String songTitle;
+
+ /**
+ * Artist name (string)
+ */
+ String songArtist;
+
+ /**
+ * Album name (string)
+ */
+ String songAlbum;
+
+ /**
+ * Station icon (uint32_t, see {@link IBroadcastRadio#getImage})
+ */
+ int stationIcon;
+
+ /**
+ * Album art (uint32_t, see {@link IBroadcastRadio#getImage})
+ */
+ int albumArt;
+
+ /**
+ * Station name.
+ *
+ * This is a generic field to cover any radio technology.
+ *
+ * If the PROGRAM_NAME has the same content as DAB_*_NAME or RDS_PS,
+ * it may not be present, to preserve space - framework must repopulate
+ * it on the client side.
+ */
+ String programName;
+
+ /**
+ * DAB ensemble name (string)
+ */
+ String dabEnsembleName;
+
+ /**
+ * DAB ensemble name abbreviated (string).
+ *
+ * The string must be up to 8 characters long.
+ *
+ * If the short variant is present, the long (DAB_ENSEMBLE_NAME) one must be
+ * present as well.
+ */
+ String dabEnsembleNameShort;
+
+ /**
+ * DAB service name (string)
+ */
+ String dabServiceName;
+
+ /**
+ * DAB service name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
+ */
+ String dabServiceNameShort;
+
+ /**
+ * DAB component name (string)
+ */
+ String dabComponentName;
+
+ /**
+ * DAB component name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
+ */
+ String dabComponentNameShort;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramFilter.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramFilter.aidl
new file mode 100644
index 0000000..3dd10eb
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramFilter.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.IdentifierType;
+import android.hardware.broadcastradio.ProgramIdentifier;
+
+/**
+ * Large-grain filter to the program list.
+ *
+ * This is meant to reduce binder transaction bandwidth, not for fine-grained
+ * filtering user might expect.
+ *
+ * The filter is designed as conjunctive normal form: the entry that passes the
+ * filter must satisfy all the clauses (members of this struct). Vector clauses
+ * are disjunctions of literals. In other words, there is AND between each
+ * high-level group and OR inside it.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ProgramFilter {
+ /**
+ * List of identifier types that are filtered by the filter.
+ *
+ * If the program list entry contains at least one identifier of the type
+ * listed, it satisfies this condition.
+ *
+ * Empty list means no filtering on identifier type.
+ */
+ IdentifierType[] identifierTypes;
+
+ /**
+ * List of identifiers that are filtered by the filter.
+ *
+ * If the program list entry contains at least one listed identifier,
+ * it satisfies this condition.
+ *
+ * Empty list means no filtering on identifier.
+ */
+ ProgramIdentifier[] identifiers;
+
+ /**
+ * Includes non-tunable entries that define tree structure on the
+ * program list (i.e. DAB ensembles).
+ */
+ boolean includeCategories;
+
+ /**
+ * Disables updates on entry modifications.
+ *
+ * If {@code true}, 'modified' vector of {@link ProgramListChunk} must contain
+ * list additions only. Once the program is added to the list, it's not
+ * updated anymore.
+ */
+ boolean excludeModifications;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl
new file mode 100644
index 0000000..2057d97
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramIdentifier.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.IdentifierType;
+
+/**
+ * A single program identifier component, i.e. frequency or channel ID.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ProgramIdentifier {
+ /**
+ * Maps to IdentifierType enum.
+ */
+ IdentifierType type = IdentifierType.INVALID;
+
+ /**
+ * The uint64_t value field holds the value in format described in comments
+ * for IdentifierType enum.
+ */
+ long value;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
new file mode 100644
index 0000000..3e2c9cc
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.Metadata;
+import android.hardware.broadcastradio.ProgramIdentifier;
+import android.hardware.broadcastradio.ProgramSelector;
+import android.hardware.broadcastradio.VendorKeyValue;
+
+/**
+ * Program (channel, station) information.
+ *
+ * Carries both user-visible information (like station name) and technical
+ * details (tuning selector).
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ProgramInfo {
+ /**
+ * Set when the program is currently playing live stream.
+ * This may result in a slightly altered reception parameters,
+ * usually targeted at reduced latency.
+ */
+ const int FLAG_LIVE = 1 << 0;
+
+ /**
+ * Radio stream is not playing, ie. due to bad reception conditions or
+ * buffering. In this state volume knob MAY be disabled to prevent user
+ * increasing volume too much.
+ */
+ const int FLAG_MUTED = 1 << 1;
+
+ /**
+ * Station broadcasts traffic information regularly,
+ * but not necessarily right now.
+ */
+ const int FLAG_TRAFFIC_PROGRAM = 1 << 2;
+
+ /**
+ * Station is broadcasting traffic information at the very moment.
+ */
+ const int FLAG_TRAFFIC_ANNOUNCEMENT = 1 << 3;
+
+ /**
+ * Station can be tuned to (not playing static).
+ *
+ * It's the same condition that would stop a seek operation
+ * (i.e. {@link IBroadcastRadio#seek}).
+ *
+ * By definition, this flag must be set for all items on the program list.
+ */
+ const int FLAG_TUNABLE = 1 << 4;
+
+ /**
+ * Audio stream is MONO if this bit is not set.
+ */
+ const int FLAG_STEREO = 1 << 5;
+
+ /**
+ * An identifier used to point at the program (primarily to tune to it).
+ *
+ * This field is required - its type field must not be set to
+ * {@link IdentifierType#INVALID}.
+ */
+ ProgramSelector selector;
+
+ /**
+ * Identifier currently used for program selection.
+ *
+ * It allows to determine which technology is currently used for reception.
+ *
+ * Some program selectors contain tuning information for different radio
+ * technologies (i.e. FM RDS and DAB). For example, user may tune using
+ * a ProgramSelector with RDS_PI primary identifier, but the tuner hardware
+ * may choose to use DAB technology to make actual tuning. This identifier
+ * must reflect that.
+ *
+ * This field is required for currently tuned program only.
+ * For all other items on the program list, its type field must be
+ * initialized to {@link IdentifierType#INVALID}.
+ *
+ * Only primary identifiers for a given radio technology are valid:
+ * - AMFM_FREQUENCY_KHZ for analog AM/FM;
+ * - RDS_PI for FM RDS;
+ * - HD_STATION_ID_EXT;
+ * - DAB_SID_EXT;
+ * - DRMO_SERVICE_ID;
+ * - SXM_SERVICE_ID;
+ * - VENDOR_*;
+ * - more might come in next minor versions of this HAL.
+ */
+ ProgramIdentifier logicallyTunedTo;
+
+ /**
+ * Identifier currently used by hardware to physically tune to a channel.
+ *
+ * Some radio technologies broadcast the same program on multiple channels,
+ * i.e. with RDS AF the same program may be broadcasted on multiple
+ * alternative frequencies; the same DAB program may be broadcast on
+ * multiple ensembles. This identifier points to the channel to which the
+ * radio hardware is physically tuned to.
+ *
+ * This field is required for currently tuned program only.
+ * For all other items on the program list, its type field must be
+ * initialized to {@link IdentifierType#INVALID}.
+ *
+ * Only physical identifiers are valid:
+ * - AMFM_FREQUENCY_KHZ;
+ * - DAB_ENSEMBLE;
+ * - DRMO_FREQUENCY_KHZ;
+ * - SXM_CHANNEL;
+ * - VENDOR_*;
+ * - more might come in next minor versions of this HAL.
+ */
+ ProgramIdentifier physicallyTunedTo;
+
+ /**
+ * Primary identifiers of related contents.
+ *
+ * Some radio technologies provide pointers to other programs that carry
+ * related content (i.e. DAB soft-links). This field is a list of pointers
+ * to other programs on the program list.
+ *
+ * This is not a list of programs that carry the same content (i.e.
+ * DAB hard-links, RDS AF). Switching to programs from this list usually
+ * require user action.
+ *
+ * Please note, that these identifiers do not have to exist on the program
+ * list - i.e. DAB tuner may provide information on FM RDS alternatives
+ * despite not supporting FM RDS. If the system has multiple tuners, another
+ * one may have it on its list.
+ *
+ * This field is optional.
+ */
+ @nullable ProgramIdentifier[] relatedContent;
+
+ /**
+ * Program flags.
+ */
+ int infoFlags;
+
+ /**
+ * Signal quality measured in 0% to 100% range to be shown in the UI.
+ */
+ int signalQuality;
+
+ /**
+ * Program metadata (station name, PTY, song title).
+ */
+ Metadata[] metadata;
+
+ /**
+ * Vendor-specific information.
+ *
+ * It may be used for extra features, not supported by the platform,
+ * for example: paid-service=true; bitrate=320kbps.
+ */
+ VendorKeyValue[] vendorInfo;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramListChunk.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramListChunk.aidl
new file mode 100644
index 0000000..a62d461
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramListChunk.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.ProgramIdentifier;
+import android.hardware.broadcastradio.ProgramInfo;
+
+/**
+ * An update packet of the program list.
+ *
+ * The order of entries in the arrays is unspecified.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ProgramListChunk {
+ /**
+ * Treats all previously added entries as removed.
+ *
+ * This is meant to save binder transaction bandwidth on 'removed' array
+ * and provide a clear empty state.
+ *
+ * If set, 'removed' array must be null.
+ *
+ * The client may wait with taking action on this until it received the
+ * chunk with complete flag set (to avoid part of stations temporarily
+ * disappearing from the list).
+ */
+ boolean purge;
+
+ /**
+ * If false, it means there are still programs not transmitted,
+ * due for transmission in following updates.
+ *
+ * Used by UIs that wait for complete list instead of displaying
+ * programs while scanning.
+ *
+ * After the whole channel range was scanned and all discovered programs
+ * were transmitted, the last chunk must have set this flag to {@code true}.
+ * This must happen within {@link IBroadcastRadio#LIST_COMPLETE_TIMEOUT_MS}
+ * from the startProgramListUpdates call. If it doesn't, client may assume
+ * the tuner came into a bad state and display error message.
+ */
+ boolean complete;
+
+ /**
+ * Added or modified program list entries.
+ *
+ * Two entries with the same primaryId (ProgramSelector member)
+ * are considered the same.
+ */
+ ProgramInfo[] modified;
+
+ /**
+ * Removed program list entries.
+ *
+ * Contains primaryId (ProgramSelector member) of a program to remove.
+ */
+ @nullable ProgramIdentifier[] removed;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
new file mode 100644
index 0000000..8bd3fd4
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.ProgramIdentifier;
+
+/**
+ * A set of identifiers necessary to tune to a given station.
+ *
+ * This can hold a combination of various identifiers, like:
+ * - AM/FM frequency,
+ * - HD Radio subchannel,
+ * - DAB service ID.
+ *
+ * The type of radio technology is determined by the primary identifier - if the
+ * primary identifier is for DAB, the program is DAB. However, a program of a
+ * specific radio technology may have additional secondary identifiers for other
+ * technologies, i.e. a satellite program may have FM fallback frequency,
+ * if a station broadcasts both via satellite and FM.
+ *
+ * The identifiers from VENDOR_START..VENDOR_END range have limited
+ * serialization capabilities: they are serialized locally, but ignored by the
+ * cloud services. If a program has primary id from vendor range, it's not
+ * synchronized with other devices at all.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ProgramSelector {
+ /**
+ * Primary program identifier.
+ *
+ * This identifier uniquely identifies a station and can be used for
+ * equality check.
+ *
+ * It can hold only a subset of identifier types, one per each
+ * radio technology:
+ * - analogue AM/FM: AMFM_FREQUENCY_KHZ;
+ * - FM RDS: RDS_PI;
+ * - HD Radio: HD_STATION_ID_EXT;
+ * - DAB: DAB_SID_EXT;
+ * - Digital Radio Mondiale: DRMO_SERVICE_ID;
+ * - SiriusXM: SXM_SERVICE_ID;
+ * - vendor-specific: VENDOR_START..VENDOR_END.
+ */
+ ProgramIdentifier primaryId;
+
+ /**
+ * Secondary program identifiers.
+ *
+ * These identifiers are supplementary and can speed up tuning process,
+ * but the primary ID must be sufficient (i.e. RDS PI is enough to select
+ * a station from the list after a full band scan).
+ *
+ * Two selectors with different secondary IDs, but the same primary ID are
+ * considered equal. In particular, secondary IDs array may get updated for
+ * an entry on the program list (ie. when a better frequency for a given
+ * station is found).
+ */
+ ProgramIdentifier[] secondaryIds;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Properties.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Properties.aidl
new file mode 100644
index 0000000..36cbaff
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Properties.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+import android.hardware.broadcastradio.IdentifierType;
+import android.hardware.broadcastradio.VendorKeyValue;
+
+/**
+ * Properties of a given broadcast radio module.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable Properties {
+ /**
+ * A company name who made the radio module. Must be a valid, registered
+ * name of the company itself.
+ *
+ * It must be opaque to the Android framework.
+ */
+ String maker;
+
+ /**
+ * A product name. Must be unique within the company.
+ *
+ * It must be opaque to the Android framework.
+ */
+ String product;
+
+ /**
+ * Version of the hardware module.
+ *
+ * It must be opaque to the Android framework.
+ */
+ String version;
+
+ /**
+ * Hardware serial number (for subscription services).
+ *
+ * It must be opaque to the Android framework.
+ */
+ String serial;
+
+ /**
+ * A list of supported {@link IdentifierType} values.
+ *
+ * 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.
+ *
+ * Support for VENDOR identifier type does not guarantee compatibility, as
+ * other module properties (implementor, product, version) must be checked.
+ */
+ IdentifierType[] supportedIdentifierTypes;
+
+ /**
+ * Vendor-specific information.
+ *
+ * It may be used for extra features, not supported by the platform,
+ * for example: com.me.preset-slots=6; com.me.ultra-hd-capable={@code false}.
+ */
+ VendorKeyValue[] vendorInfo;
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
new file mode 100644
index 0000000..9985ccb
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * Result for methods of BroadcastRadio AIDL HAL interfaces.
+ */
+@VintfStability
+@Backing(type="int")
+enum Result {
+ /**
+ * Methods run without error.
+ */
+ OK,
+
+ /**
+ * Internal error in HAL.
+ */
+ INTERNAL_ERROR,
+
+ /**
+ * Error used when the input argument for the method is invalid.
+ */
+ INVALID_ARGUMENTS,
+
+ /**
+ * Error used when the service is of invalid state (i.e. callback
+ * is not registered for IBroadcastRadio).
+ */
+ INVALID_STATE,
+
+ /**
+ * Error used when an operation is not supported.
+ */
+ NOT_SUPPORTED,
+
+ /**
+ * Error used when a tune, seek, step or operation is not completed
+ * within {@link IBroadcastRadio#LIST_COMPLETE_TIMEOUT_MS}.
+ */
+ TIMEOUT,
+
+ /**
+ * Error that does not follow into the error categories above.
+ */
+ UNKNOWN_ERROR,
+}
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/VendorKeyValue.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/VendorKeyValue.aidl
new file mode 100644
index 0000000..c923e92
--- /dev/null
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/VendorKeyValue.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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 android.hardware.broadcastradio;
+
+/**
+ * A key-value pair for vendor-specific information to be passed as-is through
+ * Android framework to the front-end application.
+ */
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable VendorKeyValue {
+ /**
+ * Key must start with unique vendor Java-style namespace,
+ * eg. 'com.somecompany.parameter1'.
+ */
+ String key;
+
+ /**
+ * Value must be passed through the framework without any changes.
+ * Format of this string can vary across vendors.
+ */
+ String value;
+}
diff --git a/broadcastradio/aidl/default/Android.bp b/broadcastradio/aidl/default/Android.bp
new file mode 100644
index 0000000..720aa8a
--- /dev/null
+++ b/broadcastradio/aidl/default/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+ name: "android.hardware.broadcastradio-service.default",
+ relative_install_path: "hw",
+ init_rc: ["broadcastradio-default.rc"],
+ vintf_fragments: ["broadcastradio-default.xml"],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "BroadcastRadio.cpp",
+ "main.cpp",
+ "VirtualProgram.cpp",
+ "VirtualRadio.cpp",
+ ],
+ static_libs: [
+ "android.hardware.broadcastradio@common-utils-aidl-lib",
+ "android.hardware.broadcastradio@common-utils-lib",
+ ],
+ shared_libs: [
+ "android.hardware.broadcastradio-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libcutils",
+ ],
+}
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..57c5133
--- /dev/null
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "BroadcastRadio.h"
+#include <broadcastradio-utils-aidl/Utils.h>
+#include "resources.h"
+
+#include <aidl/android/hardware/broadcastradio/IdentifierType.h>
+#include <aidl/android/hardware/broadcastradio/Result.h>
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
+using ::aidl::android::hardware::broadcastradio::utils::tunesTo;
+using ::ndk::ScopedAStatus;
+using ::std::literals::chrono_literals::operator""ms;
+using ::std::literals::chrono_literals::operator""s;
+using ::std::lock_guard;
+using ::std::mutex;
+using ::std::string;
+using ::std::vector;
+
+namespace {
+
+inline constexpr std::chrono::milliseconds kSeekDelayTimeMs = 200ms;
+inline constexpr std::chrono::milliseconds kStepDelayTimeMs = 100ms;
+inline constexpr std::chrono::milliseconds kTuneDelayTimeMs = 150ms;
+inline constexpr std::chrono::seconds kListDelayTimeS = 1s;
+
+// clang-format off
+const AmFmRegionConfig kDefaultAmFmConfig = {
+ {
+ {87500, 108000, 100, 100}, // FM
+ {153, 282, 3, 9}, // AM LW
+ {531, 1620, 9, 9}, // AM MW
+ {1600, 30000, 1, 5}, // AM SW
+ },
+ AmFmRegionConfig::DEEMPHASIS_D50,
+ AmFmRegionConfig::RDS};
+// clang-format on
+
+Properties initProperties(const VirtualRadio& virtualRadio) {
+ Properties prop = {};
+
+ prop.maker = "Android";
+ prop.product = virtualRadio.getName();
+ prop.supportedIdentifierTypes = vector<IdentifierType>({
+ IdentifierType::AMFM_FREQUENCY_KHZ,
+ IdentifierType::RDS_PI,
+ IdentifierType::HD_STATION_ID_EXT,
+ IdentifierType::DAB_SID_EXT,
+ });
+ prop.vendorInfo = vector<VendorKeyValue>({
+ {"com.android.sample", "sample"},
+ });
+
+ return prop;
+}
+
+// Makes ProgramInfo that does not point to any particular program
+ProgramInfo makeSampleProgramInfo(const ProgramSelector& selector) {
+ ProgramInfo info = {};
+ info.selector = selector;
+ info.logicallyTunedTo =
+ utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
+ utils::getId(selector, IdentifierType::AMFM_FREQUENCY_KHZ));
+ info.physicallyTunedTo = info.logicallyTunedTo;
+ return info;
+}
+
+} // namespace
+
+BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
+ : mVirtualRadio(virtualRadio),
+ mAmFmConfig(kDefaultAmFmConfig),
+ mProperties(initProperties(virtualRadio)) {
+ const auto& ranges = kDefaultAmFmConfig.ranges;
+ if (ranges.size() > 0) {
+ ProgramSelector sel = utils::makeSelectorAmfm(ranges[0].lowerBound);
+ VirtualProgram virtualProgram = {};
+ if (mVirtualRadio.getProgram(sel, &virtualProgram)) {
+ mCurrentProgram = virtualProgram.selector;
+ } else {
+ mCurrentProgram = sel;
+ }
+ }
+}
+
+BroadcastRadio::~BroadcastRadio() {
+ mThread.reset();
+}
+
+ScopedAStatus BroadcastRadio::getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs) {
+ if (full) {
+ *returnConfigs = {};
+ returnConfigs->ranges = vector<AmFmBandRange>({
+ {65000, 108000, 10, 0}, // FM
+ {150, 30000, 1, 0}, // AM
+ });
+ returnConfigs->fmDeemphasis =
+ AmFmRegionConfig::DEEMPHASIS_D50 | AmFmRegionConfig::DEEMPHASIS_D75;
+ returnConfigs->fmRds = AmFmRegionConfig::RDS | AmFmRegionConfig::RBDS;
+ return ScopedAStatus::ok();
+ }
+ lock_guard<mutex> lk(mMutex);
+ *returnConfigs = mAmFmConfig;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::getDabRegionConfig(vector<DabTableEntry>* returnConfigs) {
+ *returnConfigs = {
+ {"5A", 174928}, {"7D", 194064}, {"8A", 195936}, {"8B", 197648}, {"9A", 202928},
+ {"9B", 204640}, {"9C", 206352}, {"10B", 211648}, {"10C", 213360}, {"10D", 215072},
+ {"11A", 216928}, {"11B", 218640}, {"11C", 220352}, {"11D", 222064}, {"12A", 223936},
+ {"12B", 225648}, {"12C", 227360}, {"12D", 229072},
+ };
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::getImage(int32_t id, vector<uint8_t>* returnImage) {
+ LOG(DEBUG) << __func__ << ": fetching image " << std::hex << id;
+
+ if (id == resources::kDemoPngId) {
+ *returnImage = vector<uint8_t>(resources::kDemoPng, std::end(resources::kDemoPng));
+ return ScopedAStatus::ok();
+ }
+
+ LOG(WARNING) << __func__ << ": image of id " << std::hex << id << " doesn't exist";
+ *returnImage = {};
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::getProperties(Properties* returnProperties) {
+ lock_guard<mutex> lk(mMutex);
+ *returnProperties = mProperties;
+ return ScopedAStatus::ok();
+}
+
+ProgramInfo BroadcastRadio::tuneInternalLocked(const ProgramSelector& sel) {
+ LOG(DEBUG) << __func__ << ": tune (internal) to " << sel.toString();
+
+ VirtualProgram virtualProgram = {};
+ ProgramInfo programInfo;
+ if (mVirtualRadio.getProgram(sel, &virtualProgram)) {
+ mCurrentProgram = virtualProgram.selector;
+ programInfo = virtualProgram;
+ } else {
+ mCurrentProgram = sel;
+ programInfo = makeSampleProgramInfo(sel);
+ }
+ mIsTuneCompleted = true;
+
+ return programInfo;
+}
+
+ScopedAStatus BroadcastRadio::setTunerCallback(const std::shared_ptr<ITunerCallback>& callback) {
+ LOG(DEBUG) << __func__ << ": setTunerCallback";
+
+ if (callback == nullptr) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INVALID_ARGUMENTS), "cannot set tuner callback to null");
+ }
+
+ lock_guard<mutex> lk(mMutex);
+ mCallback = callback;
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::unsetTunerCallback() {
+ LOG(DEBUG) << __func__ << ": unsetTunerCallback";
+
+ lock_guard<mutex> lk(mMutex);
+ mCallback = nullptr;
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::tune(const ProgramSelector& program) {
+ LOG(DEBUG) << __func__ << ": tune to " << program.toString() << "...";
+
+ lock_guard<mutex> lk(mMutex);
+ if (mCallback == nullptr) {
+ LOG(ERROR) << __func__ << ": callback is not registered.";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INVALID_STATE), "callback is not registered");
+ }
+
+ if (!utils::isSupported(mProperties, program)) {
+ LOG(WARNING) << __func__ << ": selector not supported: " << program.toString();
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::NOT_SUPPORTED), "selector is not supported");
+ }
+
+ if (!utils::isValid(program)) {
+ LOG(ERROR) << __func__ << ": selector is not valid: " << program.toString();
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INVALID_ARGUMENTS), "selector is not valid");
+ }
+
+ cancelLocked();
+
+ mIsTuneCompleted = false;
+ std::shared_ptr<ITunerCallback> callback = mCallback;
+ auto task = [this, program, callback]() {
+ ProgramInfo programInfo = {};
+ {
+ lock_guard<mutex> lk(mMutex);
+ programInfo = tuneInternalLocked(program);
+ }
+ callback->onCurrentProgramInfoChanged(programInfo);
+ };
+ mThread->schedule(task, kTuneDelayTimeMs);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::seek(bool directionUp, bool skipSubChannel) {
+ LOG(DEBUG) << __func__ << ": seek " << (directionUp ? "up" : "down") << " with skipSubChannel? "
+ << (skipSubChannel ? "yes" : "no") << "...";
+
+ lock_guard<mutex> lk(mMutex);
+ if (mCallback == nullptr) {
+ LOG(ERROR) << __func__ << ": callback is not registered.";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INVALID_STATE), "callback is not registered");
+ }
+
+ cancelLocked();
+
+ const auto& list = mVirtualRadio.getProgramList();
+ std::shared_ptr<ITunerCallback> callback = mCallback;
+ if (list.empty()) {
+ mIsTuneCompleted = false;
+ auto task = [callback]() {
+ LOG(DEBUG) << "seek: program list is empty, seek couldn't stop";
+
+ callback->onTuneFailed(Result::TIMEOUT, {});
+ };
+ mThread->schedule(task, kSeekDelayTimeMs);
+
+ return ScopedAStatus::ok();
+ }
+
+ // The list is not sorted here since it has already stored in VirtualRadio.
+ // If the list is not sorted in advance, it should be sorted here.
+ const auto& current = mCurrentProgram;
+ auto found = std::lower_bound(list.begin(), list.end(), VirtualProgram({current}));
+ if (directionUp) {
+ if (found < list.end() - 1) {
+ if (tunesTo(current, found->selector)) found++;
+ } else {
+ found = list.begin();
+ }
+ } else {
+ if (found > list.begin() && found != list.end()) {
+ found--;
+ } else {
+ found = list.end() - 1;
+ }
+ }
+ const ProgramSelector tuneTo = found->selector;
+
+ mIsTuneCompleted = false;
+ auto task = [this, tuneTo, callback]() {
+ ProgramInfo programInfo = {};
+ {
+ lock_guard<mutex> lk(mMutex);
+ programInfo = tuneInternalLocked(tuneTo);
+ }
+ callback->onCurrentProgramInfoChanged(programInfo);
+ };
+ mThread->schedule(task, kSeekDelayTimeMs);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::step(bool directionUp) {
+ LOG(DEBUG) << __func__ << ": step " << (directionUp ? "up" : "down") << "...";
+
+ lock_guard<mutex> lk(mMutex);
+ if (mCallback == nullptr) {
+ LOG(ERROR) << __func__ << ": callback is not registered.";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INVALID_STATE), "callback is not registered");
+ }
+
+ cancelLocked();
+
+ if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+ LOG(WARNING) << __func__ << ": can't step in anything else than AM/FM";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::NOT_SUPPORTED), "cannot step in anything else than AM/FM");
+ }
+
+ int64_t stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
+ std::optional<AmFmBandRange> range = getAmFmRangeLocked();
+ if (!range) {
+ LOG(ERROR) << __func__ << ": can't find current band or tune operation is in process";
+ ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::INTERNAL_ERROR),
+ "can't find current band or tune operation is in process");
+ }
+
+ if (directionUp) {
+ stepTo += range->spacing;
+ } else {
+ stepTo -= range->spacing;
+ }
+ if (stepTo > range->upperBound) {
+ stepTo = range->lowerBound;
+ }
+ if (stepTo < range->lowerBound) {
+ stepTo = range->upperBound;
+ }
+
+ mIsTuneCompleted = false;
+ std::shared_ptr<ITunerCallback> callback = mCallback;
+ auto task = [this, stepTo, callback]() {
+ ProgramInfo programInfo;
+ {
+ lock_guard<mutex> lk(mMutex);
+ programInfo = tuneInternalLocked(utils::makeSelectorAmfm(stepTo));
+ }
+ callback->onCurrentProgramInfoChanged(programInfo);
+ };
+ mThread->schedule(task, kStepDelayTimeMs);
+
+ return ScopedAStatus::ok();
+}
+
+void BroadcastRadio::cancelLocked() {
+ LOG(DEBUG) << __func__ << ": cancelling current operations...";
+
+ mThread->cancelAll();
+ if (mCurrentProgram.primaryId.type != IdentifierType::INVALID) {
+ mIsTuneCompleted = true;
+ }
+}
+
+ScopedAStatus BroadcastRadio::cancel() {
+ LOG(DEBUG) << __func__ << ": cancel pending tune, seek and step...";
+
+ lock_guard<mutex> lk(mMutex);
+ cancelLocked();
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filter) {
+ LOG(DEBUG) << __func__ << ": requested program list updates, filter = " << filter.toString()
+ << "...";
+
+ auto filterCb = [&filter](const VirtualProgram& program) {
+ return utils::satisfies(filter, program.selector);
+ };
+
+ lock_guard<mutex> lk(mMutex);
+
+ const auto& list = mVirtualRadio.getProgramList();
+ vector<VirtualProgram> filteredList;
+ std::copy_if(list.begin(), list.end(), std::back_inserter(filteredList), filterCb);
+
+ auto task = [this, filteredList]() {
+ std::shared_ptr<ITunerCallback> callback;
+ {
+ lock_guard<mutex> lk(mMutex);
+ if (mCallback == nullptr) {
+ LOG(WARNING) << "Callback is null when updating program List";
+ return;
+ }
+ callback = mCallback;
+ }
+
+ ProgramListChunk chunk = {};
+ chunk.purge = true;
+ chunk.complete = true;
+ chunk.modified = vector<ProgramInfo>(filteredList.begin(), filteredList.end());
+
+ callback->onProgramListUpdated(chunk);
+ };
+ mThread->schedule(task, kListDelayTimeS);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::stopProgramListUpdates() {
+ LOG(DEBUG) << __func__ << ": requested program list updates to stop...";
+ // TODO(b/243681584) Implement stop program list updates method
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::isConfigFlagSet(ConfigFlag flag, [[maybe_unused]] bool* returnIsSet) {
+ LOG(DEBUG) << __func__ << ": flag = " << toString(flag);
+
+ LOG(INFO) << __func__ << ": getting ConfigFlag is not supported";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::NOT_SUPPORTED), "getting ConfigFlag is not supported");
+}
+
+ScopedAStatus BroadcastRadio::setConfigFlag(ConfigFlag flag, bool value) {
+ LOG(DEBUG) << __func__ << ": flag = " << toString(flag) << ", value = " << value;
+
+ LOG(INFO) << __func__ << ": setting ConfigFlag is not supported";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::NOT_SUPPORTED), "setting ConfigFlag is not supported");
+}
+
+ScopedAStatus BroadcastRadio::setParameters(
+ [[maybe_unused]] const vector<VendorKeyValue>& parameters,
+ vector<VendorKeyValue>* returnParameters) {
+ // TODO(b/243682330) Support vendor parameter functionality
+ *returnParameters = {};
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus BroadcastRadio::getParameters([[maybe_unused]] const vector<string>& keys,
+ vector<VendorKeyValue>* returnParameters) {
+ // TODO(b/243682330) Support vendor parameter functionality
+ *returnParameters = {};
+ return ScopedAStatus::ok();
+}
+
+std::optional<AmFmBandRange> BroadcastRadio::getAmFmRangeLocked() const {
+ if (!mIsTuneCompleted) {
+ LOG(WARNING) << __func__ << ": tune operation is in process";
+ return {};
+ }
+ if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
+ LOG(WARNING) << __func__ << ": current program does not has AMFM_FREQUENCY_KHZ identifier";
+ return {};
+ }
+
+ int64_t freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
+ for (const auto& range : mAmFmConfig.ranges) {
+ if (range.lowerBound <= freq && range.upperBound >= freq) {
+ return range;
+ }
+ }
+
+ return {};
+}
+
+ScopedAStatus BroadcastRadio::registerAnnouncementListener(
+ [[maybe_unused]] const std::shared_ptr<IAnnouncementListener>& listener,
+ const vector<AnnouncementType>& enabled, std::shared_ptr<ICloseHandle>* returnCloseHandle) {
+ LOG(DEBUG) << __func__ << ": registering announcement listener for "
+ << utils::vectorToString(enabled);
+
+ // TODO(b/243683842) Support announcement listener
+ *returnCloseHandle = nullptr;
+ LOG(INFO) << __func__ << ": registering announcementListener is not supported";
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ resultToInt(Result::NOT_SUPPORTED),
+ "registering announcementListener is not supported");
+}
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/BroadcastRadio.h b/broadcastradio/aidl/default/BroadcastRadio.h
new file mode 100644
index 0000000..52d394e
--- /dev/null
+++ b/broadcastradio/aidl/default/BroadcastRadio.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include "VirtualRadio.h"
+
+#include <aidl/android/hardware/broadcastradio/AmFmBandRange.h>
+#include <aidl/android/hardware/broadcastradio/AmFmRegionConfig.h>
+#include <aidl/android/hardware/broadcastradio/AnnouncementType.h>
+#include <aidl/android/hardware/broadcastradio/BnBroadcastRadio.h>
+#include <aidl/android/hardware/broadcastradio/DabTableEntry.h>
+#include <aidl/android/hardware/broadcastradio/IAnnouncementListener.h>
+#include <aidl/android/hardware/broadcastradio/ICloseHandle.h>
+#include <aidl/android/hardware/broadcastradio/ITunerCallback.h>
+#include <aidl/android/hardware/broadcastradio/Properties.h>
+#include <broadcastradio-utils/WorkerThread.h>
+
+#include <android-base/thread_annotations.h>
+
+#include <optional>
+
+namespace aidl::android::hardware::broadcastradio {
+
+class BroadcastRadio final : public BnBroadcastRadio {
+ public:
+ explicit BroadcastRadio(const VirtualRadio& virtualRadio);
+ ~BroadcastRadio();
+ ndk::ScopedAStatus getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs) override;
+ ndk::ScopedAStatus getDabRegionConfig(std::vector<DabTableEntry>* returnConfigs) override;
+ ndk::ScopedAStatus getImage(int32_t id, std::vector<uint8_t>* returnImage) override;
+ ndk::ScopedAStatus getProperties(Properties* returnProperties) override;
+
+ ndk::ScopedAStatus setTunerCallback(const std::shared_ptr<ITunerCallback>& callback) override;
+ ndk::ScopedAStatus unsetTunerCallback() override;
+ ndk::ScopedAStatus tune(const ProgramSelector& program) override;
+ ndk::ScopedAStatus seek(bool directionUp, bool skipSubChannel) override;
+ ndk::ScopedAStatus step(bool directionUp) override;
+ ndk::ScopedAStatus cancel() override;
+ ndk::ScopedAStatus startProgramListUpdates(const ProgramFilter& filter) override;
+ ndk::ScopedAStatus stopProgramListUpdates() override;
+ ndk::ScopedAStatus isConfigFlagSet(ConfigFlag flag, bool* returnIsSet) override;
+ ndk::ScopedAStatus setConfigFlag(ConfigFlag flag, bool in_value) override;
+ ndk::ScopedAStatus setParameters(const std::vector<VendorKeyValue>& parameters,
+ std::vector<VendorKeyValue>* returnParameters) override;
+ ndk::ScopedAStatus getParameters(const std::vector<std::string>& keys,
+ std::vector<VendorKeyValue>* returnParameters) override;
+ ndk::ScopedAStatus registerAnnouncementListener(
+ const std::shared_ptr<IAnnouncementListener>& listener,
+ const std::vector<AnnouncementType>& enabled,
+ std::shared_ptr<ICloseHandle>* returnCloseHandle) override;
+
+ private:
+ const VirtualRadio& mVirtualRadio;
+ std::mutex mMutex;
+ AmFmRegionConfig mAmFmConfig GUARDED_BY(mMutex);
+ std::unique_ptr<::android::WorkerThread> mThread GUARDED_BY(mMutex) =
+ std::unique_ptr<::android::WorkerThread>(new ::android::WorkerThread());
+ bool mIsTuneCompleted GUARDED_BY(mMutex) = true;
+ Properties mProperties GUARDED_BY(mMutex);
+ ProgramSelector mCurrentProgram GUARDED_BY(mMutex) = {};
+ std::shared_ptr<ITunerCallback> mCallback GUARDED_BY(mMutex);
+
+ std::optional<AmFmBandRange> getAmFmRangeLocked() const;
+ void cancelLocked();
+ ProgramInfo tuneInternalLocked(const ProgramSelector& sel);
+};
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualProgram.cpp b/broadcastradio/aidl/default/VirtualProgram.cpp
new file mode 100644
index 0000000..0df0a82
--- /dev/null
+++ b/broadcastradio/aidl/default/VirtualProgram.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "VirtualProgram.h"
+
+#include <broadcastradio-utils-aidl/Utils.h>
+#include "resources.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+using ::std::vector;
+
+VirtualProgram::operator ProgramInfo() const {
+ ProgramInfo info = {};
+
+ info.selector = selector;
+
+ IdentifierType programType = selector.primaryId.type;
+ bool isDigital = (programType != IdentifierType::AMFM_FREQUENCY_KHZ &&
+ programType != IdentifierType::RDS_PI);
+
+ auto selectId = [&info](const IdentifierType& type) {
+ return utils::makeIdentifier(type, utils::getId(info.selector, type));
+ };
+
+ switch (programType) {
+ case IdentifierType::AMFM_FREQUENCY_KHZ:
+ info.logicallyTunedTo = info.physicallyTunedTo =
+ selectId(IdentifierType::AMFM_FREQUENCY_KHZ);
+ break;
+ case IdentifierType::RDS_PI:
+ info.logicallyTunedTo = selectId(IdentifierType::RDS_PI);
+ info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY_KHZ);
+ break;
+ case IdentifierType::HD_STATION_ID_EXT:
+ info.logicallyTunedTo = selectId(IdentifierType::HD_STATION_ID_EXT);
+ info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY_KHZ);
+ break;
+ case IdentifierType::DAB_SID_EXT:
+ info.logicallyTunedTo = selectId(IdentifierType::DAB_SID_EXT);
+ info.physicallyTunedTo = selectId(IdentifierType::DAB_ENSEMBLE);
+ break;
+ case IdentifierType::DRMO_SERVICE_ID:
+ info.logicallyTunedTo = selectId(IdentifierType::DRMO_SERVICE_ID);
+ info.physicallyTunedTo = selectId(IdentifierType::DRMO_FREQUENCY_KHZ);
+ break;
+ case IdentifierType::SXM_SERVICE_ID:
+ info.logicallyTunedTo = selectId(IdentifierType::SXM_SERVICE_ID);
+ info.physicallyTunedTo = selectId(IdentifierType::SXM_CHANNEL);
+ break;
+ default:
+ LOG(FATAL) << "unsupported program type: " << toString(programType);
+ return {};
+ }
+
+ info.infoFlags |= (ProgramInfo::FLAG_TUNABLE | ProgramInfo::FLAG_STEREO);
+ info.signalQuality = isDigital ? kSignalQualityDigital : kSignalQualityNonDigital;
+
+ info.metadata = vector<Metadata>({
+ Metadata::make<Metadata::rdsPs>(programName),
+ Metadata::make<Metadata::songTitle>(songTitle),
+ Metadata::make<Metadata::songArtist>(songArtist),
+ Metadata::make<Metadata::stationIcon>(resources::kDemoPngId),
+ Metadata::make<Metadata::albumArt>(resources::kDemoPngId),
+ });
+
+ info.vendorInfo = vector<VendorKeyValue>({
+ {"com.android.sample", "sample"},
+ {"com.android.sample.VirtualProgram", "VirtualProgram"},
+ });
+
+ return info;
+}
+
+bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
+ auto& l = lhs.selector;
+ auto& r = rhs.selector;
+
+ // Two programs with the same primaryId are considered the same.
+ if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+
+ return l.primaryId.value < r.primaryId.value;
+}
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualProgram.h b/broadcastradio/aidl/default/VirtualProgram.h
new file mode 100644
index 0000000..0c20721
--- /dev/null
+++ b/broadcastradio/aidl/default/VirtualProgram.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/broadcastradio/IdentifierType.h>
+#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
+#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+constexpr int kSignalQualityDigital = 100;
+constexpr int kSignalQualityNonDigital = 80;
+/**
+ * A radio program mock.
+ *
+ * This represents broadcast waves flying over the air,
+ * not an entry for a captured station in the radio tuner memory.
+ */
+struct VirtualProgram {
+ ProgramSelector selector;
+
+ std::string programName = "";
+ std::string songArtist = "";
+ std::string songTitle = "";
+
+ operator ProgramInfo() const;
+
+ /**
+ * Defines order in which virtual programs appear on the "air" with
+ * ITunerSession::scan().
+ *
+ * It's for default implementation purposes, may not be complete or correct.
+ */
+ friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
+};
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp
new file mode 100644
index 0000000..851543b
--- /dev/null
+++ b/broadcastradio/aidl/default/VirtualRadio.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "VirtualRadio.h"
+#include <broadcastradio-utils-aidl/Utils.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
+using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
+using ::std::string;
+using ::std::vector;
+
+VirtualRadio::VirtualRadio(const string& name, const vector<VirtualProgram>& initialList)
+ : mName(name), mPrograms(initialList) {
+ sort(mPrograms.begin(), mPrograms.end());
+}
+
+string VirtualRadio::getName() const {
+ return mName;
+}
+
+const vector<VirtualProgram>& VirtualRadio::getProgramList() const {
+ return mPrograms;
+}
+
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram* programOut) const {
+ for (const auto& program : mPrograms) {
+ if (utils::tunesTo(selector, program.selector)) {
+ *programOut = program;
+ return true;
+ }
+ }
+ return false;
+}
+
+// get singleton of AMFM Virtual Radio
+const VirtualRadio& VirtualRadio::getAmFmRadio() {
+ // clang-format off
+ static VirtualRadio amFmRadioMock(
+ "AM/FM radio mock",
+ {
+ {makeSelectorAmfm(94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+ {makeSelectorAmfm(96500), "KOIT", "Celine Dion", "All By Myself"},
+ {makeSelectorAmfm(97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+ {makeSelectorAmfm(99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+ {makeSelectorAmfm(101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+ {makeSelectorAmfm(103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+ {makeSelectorAmfm(106100), "106 KMEL", "Drake", "Marvins Room"},
+ {makeSelectorAmfm(700), "700 AM", "Artist700", "Title700"},
+ {makeSelectorAmfm(1700), "1700 AM", "Artist1700", "Title1700"},
+ });
+ // clang-format on
+ return amFmRadioMock;
+}
+
+// get singleton of DAB Virtual Radio
+const VirtualRadio& VirtualRadio::getDabRadio() {
+ // clang-format off
+ static VirtualRadio dabRadioMock(
+ "DAB radio mock",
+ {
+ {makeSelectorDab(0xA00001u, 0x0001u), "BBC Radio 1", "Khalid", "Talk"},
+ {makeSelectorDab(0xB00001u, 0x1001u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
+ {makeSelectorDab(0xB00002u, 0x1001u), "Absolute Radio", "Coldplay", "Clocks"},
+ });
+ // clang-format on
+ return dabRadioMock;
+}
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/VirtualRadio.h b/broadcastradio/aidl/default/VirtualRadio.h
new file mode 100644
index 0000000..ae039c4
--- /dev/null
+++ b/broadcastradio/aidl/default/VirtualRadio.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include "VirtualProgram.h"
+
+#include <vector>
+
+namespace aidl::android::hardware::broadcastradio {
+
+/**
+ * A radio frequency space mock.
+ *
+ * This represents all broadcast waves in the air for a given radio technology,
+ * not a captured station list in the radio tuner memory.
+ *
+ * It's meant to abstract out radio content from default tuner implementation.
+ */
+class VirtualRadio final {
+ public:
+ VirtualRadio(const std::string& name, const std::vector<VirtualProgram>& initialList);
+ std::string getName() const;
+ const std::vector<VirtualProgram>& getProgramList() const;
+ bool getProgram(const ProgramSelector& selector, VirtualProgram* program) const;
+
+ static const VirtualRadio& getAmFmRadio();
+ static const VirtualRadio& getDabRadio();
+
+ private:
+ const std::string mName;
+ std::vector<VirtualProgram> mPrograms;
+};
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/aidl/default/broadcastradio-default.rc b/broadcastradio/aidl/default/broadcastradio-default.rc
new file mode 100644
index 0000000..49389e6
--- /dev/null
+++ b/broadcastradio/aidl/default/broadcastradio-default.rc
@@ -0,0 +1,6 @@
+service vendor.broadcastradio-default /vendor/bin/hw/android.hardware.broadcastradio-service.default
+ interface aidl android.hardware.broadcastradio.IBroadcastRadio/amfm
+ interface aidl android.hardware.broadcastradio.IBroadcastRadio/dab
+ class hal
+ user audioserver
+ group audio
diff --git a/broadcastradio/aidl/default/broadcastradio-default.xml b/broadcastradio/aidl/default/broadcastradio-default.xml
new file mode 100644
index 0000000..1555822
--- /dev/null
+++ b/broadcastradio/aidl/default/broadcastradio-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.broadcastradio</name>
+ <fqname>IBroadcastRadio/amfm</fqname>
+ <fqname>IBroadcastRadio/dab</fqname>
+ </hal>
+</manifest>
diff --git a/broadcastradio/aidl/default/main.cpp b/broadcastradio/aidl/default/main.cpp
new file mode 100644
index 0000000..6bf20d5
--- /dev/null
+++ b/broadcastradio/aidl/default/main.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "BroadcastRadio.h"
+#include "VirtualRadio.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::broadcastradio::BroadcastRadio;
+using ::aidl::android::hardware::broadcastradio::VirtualRadio;
+
+int main() {
+ android::base::SetDefaultTag("BcRadioAidlDef");
+ ABinderProcess_setThreadPoolMaxThreadCount(4);
+ ABinderProcess_startThreadPool();
+
+ const VirtualRadio& amFmRadioMock = VirtualRadio::getAmFmRadio();
+ std::shared_ptr<BroadcastRadio> broadcastRadio =
+ ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMock);
+ const std::string instanceAmFm = std::string() + BroadcastRadio::descriptor + "/amfm";
+ binder_status_t statusAmFm =
+ AServiceManager_addService(broadcastRadio->asBinder().get(), instanceAmFm.c_str());
+ CHECK_EQ(statusAmFm, STATUS_OK)
+ << "Failed to register Broadcast Radio AM/FM HAL implementation";
+
+ const VirtualRadio& dabRadioMock = VirtualRadio::getDabRadio();
+ std::shared_ptr<BroadcastRadio> dabRadio =
+ ::ndk::SharedRefBase::make<BroadcastRadio>(dabRadioMock);
+ const std::string instanceDab = std::string() + BroadcastRadio::descriptor + "/dab";
+ binder_status_t statusDab =
+ AServiceManager_addService(dabRadio->asBinder().get(), instanceDab.c_str());
+ CHECK_EQ(statusDab, STATUS_OK) << "Failed to register Broadcast Radio DAB HAL implementation";
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/broadcastradio/aidl/default/resources.h b/broadcastradio/aidl/default/resources.h
new file mode 100644
index 0000000..beffc76
--- /dev/null
+++ b/broadcastradio/aidl/default/resources.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
+
+namespace aidl::android::hardware::broadcastradio::resources {
+
+constexpr int32_t kDemoPngId = 123456;
+constexpr uint8_t kDemoPng[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
+ 0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25,
+ 0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9,
+ 0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04,
+ 0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba,
+ 0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f,
+ 0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd,
+ 0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+
+} // namespace aidl::android::hardware::broadcastradio::resources
diff --git a/broadcastradio/common/utilsaidl/Android.bp b/broadcastradio/common/utilsaidl/Android.bp
new file mode 100644
index 0000000..fa6de19
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2022 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "android.hardware.broadcastradio@common-utils-aidl-lib",
+ vendor_available: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-error=implicit-fallthrough",
+ ],
+ cppflags: [
+ "-std=c++1z",
+ ],
+ srcs: [
+ "Utils.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.broadcastradio-V1-ndk",
+ "libbase",
+ ],
+ static_libs: [
+ "libmath",
+ ],
+}
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
new file mode 100644
index 0000000..a284651
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/Utils.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#define LOG_TAG "BcRadioAidlDef.utils"
+
+#include "broadcastradio-utils-aidl/Utils.h"
+
+#include <android-base/logging.h>
+
+#include <math/HashCombine.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+namespace {
+
+using ::std::string;
+using ::std::vector;
+
+const int64_t kValueForNotFoundIdentifier = 0;
+
+bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+ return hasId(a, type) && hasId(b, type);
+}
+
+bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+ if (!bothHaveId(a, b, type)) {
+ return false;
+ }
+ /* We should check all Ids of a given type (ie. other AF),
+ * but it doesn't matter for default implementation.
+ */
+ return getId(a, type) == getId(b, type);
+}
+
+int getHdSubchannel(const ProgramSelector& sel) {
+ int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, /* defaultValue */ 0);
+ hdSidExt >>= 32; // Station ID number
+ return hdSidExt & 0xF; // HD Radio subchannel
+}
+
+bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
+ // iterate through primaryId and secondaryIds
+ for (auto it = begin(sel); it != end(sel); it++) {
+ if (it->type == type) {
+ if (val != nullptr) {
+ *val = it->value;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
+ : mSel(sel), mPos(pos) {}
+
+const IdentifierIterator IdentifierIterator::operator++(int) {
+ IdentifierIterator i = *this;
+ mPos++;
+ return i;
+}
+
+IdentifierIterator& IdentifierIterator::operator++() {
+ ++mPos;
+ return *this;
+}
+
+IdentifierIterator::refType IdentifierIterator::operator*() const {
+ if (mPos == 0) {
+ return getSelector().primaryId;
+ }
+
+ // mPos is 1-based for secondary identifiers
+ DCHECK(mPos <= getSelector().secondaryIds.size());
+ return getSelector().secondaryIds[mPos - 1];
+}
+
+bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
+ // Check, if both iterators points at the same selector.
+ if (reinterpret_cast<intptr_t>(&getSelector()) !=
+ reinterpret_cast<intptr_t>(&rhs.getSelector())) {
+ return false;
+ }
+
+ return mPos == rhs.mPos;
+}
+
+int32_t resultToInt(Result result) {
+ return static_cast<int32_t>(result);
+}
+
+FrequencyBand getBand(int64_t freq) {
+ // keep in sync with
+ // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
+ if (freq < 30) return FrequencyBand::UNKNOWN;
+ if (freq < 500) return FrequencyBand::AM_LW;
+ if (freq < 1705) return FrequencyBand::AM_MW;
+ if (freq < 30000) return FrequencyBand::AM_SW;
+ if (freq < 60000) return FrequencyBand::UNKNOWN;
+ if (freq < 110000) return FrequencyBand::FM;
+ return FrequencyBand::UNKNOWN;
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+ IdentifierType type = b.primaryId.type;
+
+ switch (type) {
+ case IdentifierType::HD_STATION_ID_EXT:
+ case IdentifierType::RDS_PI:
+ case IdentifierType::AMFM_FREQUENCY_KHZ:
+ if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+ if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+ return getHdSubchannel(b) == 0 &&
+ haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
+ case IdentifierType::DAB_SID_EXT:
+ return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+ case IdentifierType::DRMO_SERVICE_ID:
+ return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+ case IdentifierType::SXM_SERVICE_ID:
+ return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+ default: // includes all vendor types
+ LOG(WARNING) << "unsupported program type: " << toString(type);
+ return false;
+ }
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
+ return maybeGetId(sel, type, /* val */ nullptr);
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
+ int64_t val;
+
+ if (maybeGetId(sel, type, &val)) {
+ return val;
+ }
+
+ LOG(WARNING) << "identifier not found: " << toString(type);
+ return kValueForNotFoundIdentifier;
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
+ if (!hasId(sel, type)) {
+ return defaultValue;
+ }
+ return getId(sel, type);
+}
+
+vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
+ vector<int> ret;
+
+ // iterate through primaryId and secondaryIds
+ for (auto it = begin(sel); it != end(sel); it++) {
+ if (it->type == type) {
+ ret.push_back(it->value);
+ }
+ }
+
+ return ret;
+}
+
+bool isSupported(const Properties& prop, const ProgramSelector& sel) {
+ for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
+ it++) {
+ if (hasId(sel, *it)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isValid(const ProgramIdentifier& id) {
+ int64_t val = id.value;
+ bool valid = true;
+
+ auto expect = [&valid](bool condition, const string& message) {
+ if (!condition) {
+ valid = false;
+ LOG(ERROR) << "identifier not valid, expected " << message;
+ }
+ };
+
+ switch (id.type) {
+ case IdentifierType::INVALID:
+ expect(false, "IdentifierType::INVALID");
+ break;
+ case IdentifierType::DAB_FREQUENCY_KHZ:
+ expect(val > 100000u, "f > 100MHz");
+ [[fallthrough]];
+ case IdentifierType::AMFM_FREQUENCY_KHZ:
+ case IdentifierType::DRMO_FREQUENCY_KHZ:
+ expect(val > 100u, "f > 100kHz");
+ expect(val < 10000000u, "f < 10GHz");
+ break;
+ case IdentifierType::RDS_PI:
+ expect(val != 0u, "RDS PI != 0");
+ expect(val <= 0xFFFFu, "16bit id");
+ break;
+ case IdentifierType::HD_STATION_ID_EXT: {
+ int64_t stationId = val & 0xFFFFFFFF; // 32bit
+ val >>= 32;
+ int64_t subchannel = val & 0xF; // 4bit
+ val >>= 4;
+ int64_t freq = val & 0x3FFFF; // 18bit
+ expect(stationId != 0u, "HD station id != 0");
+ expect(subchannel < 8u, "HD subch < 8");
+ expect(freq > 100u, "f > 100kHz");
+ expect(freq < 10000000u, "f < 10GHz");
+ break;
+ }
+ case IdentifierType::HD_STATION_NAME: {
+ while (val > 0) {
+ char ch = static_cast<char>(val & 0xFF);
+ val >>= 8;
+ expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
+ "HD_STATION_NAME does not match [A-Z0-9]+");
+ }
+ break;
+ }
+ case IdentifierType::DAB_SID_EXT: {
+ int64_t sid = val & 0xFFFF; // 16bit
+ val >>= 16;
+ int64_t ecc = val & 0xFF; // 8bit
+ expect(sid != 0u, "DAB SId != 0");
+ expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+ break;
+ }
+ case IdentifierType::DAB_ENSEMBLE:
+ expect(val != 0u, "DAB ensemble != 0");
+ expect(val <= 0xFFFFu, "16bit id");
+ break;
+ case IdentifierType::DAB_SCID:
+ expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+ expect(val <= 0xFFFu, "12bit id");
+ break;
+ case IdentifierType::DRMO_SERVICE_ID:
+ expect(val != 0u, "DRM SId != 0");
+ expect(val <= 0xFFFFFFu, "24bit id");
+ break;
+ case IdentifierType::SXM_SERVICE_ID:
+ expect(val != 0u, "SXM SId != 0");
+ expect(val <= 0xFFFFFFFFu, "32bit id");
+ break;
+ case IdentifierType::SXM_CHANNEL:
+ expect(val < 1000u, "SXM channel < 1000");
+ break;
+ case IdentifierType::VENDOR_START:
+ case IdentifierType::VENDOR_END:
+ // skip
+ break;
+ }
+
+ return valid;
+}
+
+bool isValid(const ProgramSelector& sel) {
+ // iterate through primaryId and secondaryIds
+ for (auto it = begin(sel); it != end(sel); it++) {
+ if (!isValid(*it)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
+ return {type, value};
+}
+
+ProgramSelector makeSelectorAmfm(int32_t frequency) {
+ ProgramSelector sel = {};
+ sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
+ return sel;
+}
+
+ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble) {
+ ProgramSelector sel = {};
+ // TODO(243686545): Have a helper function to create the sidExt instead of
+ // passing the whole identifier here. Something like makeDabSidExt.
+ sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
+ vector<ProgramIdentifier> secondaryIds = {
+ makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
+ // TODO(243686545): Include frequency here when the helper method to
+ // translate between ensemble and frequency is implemented.
+ };
+ sel.secondaryIds = std::move(secondaryIds);
+ return sel;
+}
+
+bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
+ if (filter.identifierTypes.size() > 0) {
+ auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
+ return id.type == type;
+ };
+ auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
+ filter.identifierTypes.end(), typeEquals);
+ if (it == end(sel)) {
+ return false;
+ }
+ }
+
+ if (filter.identifiers.size() > 0) {
+ auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
+ filter.identifiers.end());
+ if (it == end(sel)) {
+ return false;
+ }
+ }
+
+ if (!filter.includeCategories && sel.primaryId.type == IdentifierType::DAB_ENSEMBLE) {
+ return false;
+ }
+
+ return true;
+}
+
+size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
+ const ProgramIdentifier& id = info.selector.primaryId;
+
+ // This is not the best hash implementation, but good enough for default HAL
+ // implementation and tests.
+ size_t h = 0;
+ ::android::hashCombineSingle(h, id.type);
+ ::android::hashCombineSingle(h, id.value);
+ return h;
+}
+
+bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
+ const ProgramIdentifier& id1 = info1.selector.primaryId;
+ const ProgramIdentifier& id2 = info2.selector.primaryId;
+ return id1.type == id2.type && id1.value == id2.value;
+}
+
+void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
+ if (chunk.purge) {
+ list->clear();
+ }
+
+ list->insert(chunk.modified.begin(), chunk.modified.end());
+
+ if (!chunk.removed.has_value()) {
+ return;
+ }
+
+ for (auto& id : chunk.removed.value()) {
+ if (id.has_value()) {
+ ProgramInfo info = {};
+ info.selector.primaryId = id.value();
+ list->erase(info);
+ }
+ }
+}
+
+std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
+ auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
+
+ auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
+ if (it == info.metadata.end()) {
+ return std::nullopt;
+ }
+
+ std::string metadataString;
+ switch (it->getTag()) {
+ case Metadata::rdsPs:
+ metadataString = it->get<Metadata::rdsPs>();
+ break;
+ case Metadata::rdsPty:
+ metadataString = std::to_string(it->get<Metadata::rdsPty>());
+ break;
+ case Metadata::rbdsPty:
+ metadataString = std::to_string(it->get<Metadata::rbdsPty>());
+ break;
+ case Metadata::rdsRt:
+ metadataString = it->get<Metadata::rdsRt>();
+ break;
+ case Metadata::songTitle:
+ metadataString = it->get<Metadata::songTitle>();
+ break;
+ case Metadata::songArtist:
+ metadataString = it->get<Metadata::songArtist>();
+ break;
+ case Metadata::songAlbum:
+ metadataString = it->get<Metadata::songAlbum>();
+ break;
+ case Metadata::stationIcon:
+ metadataString = std::to_string(it->get<Metadata::stationIcon>());
+ break;
+ case Metadata::albumArt:
+ metadataString = std::to_string(it->get<Metadata::albumArt>());
+ break;
+ case Metadata::programName:
+ metadataString = it->get<Metadata::programName>();
+ break;
+ case Metadata::dabEnsembleName:
+ metadataString = it->get<Metadata::dabEnsembleName>();
+ break;
+ case Metadata::dabEnsembleNameShort:
+ metadataString = it->get<Metadata::dabEnsembleNameShort>();
+ break;
+ case Metadata::dabServiceName:
+ metadataString = it->get<Metadata::dabServiceName>();
+ break;
+ case Metadata::dabServiceNameShort:
+ metadataString = it->get<Metadata::dabServiceNameShort>();
+ break;
+ case Metadata::dabComponentName:
+ metadataString = it->get<Metadata::dabComponentName>();
+ break;
+ case Metadata::dabComponentNameShort:
+ metadataString = it->get<Metadata::dabComponentNameShort>();
+ break;
+ default:
+ LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
+ return std::nullopt;
+ }
+ return metadataString;
+}
+
+ProgramIdentifier makeHdRadioStationName(const string& name) {
+ constexpr size_t maxlen = 8;
+
+ string shortName;
+ shortName.reserve(maxlen);
+
+ const auto& loc = std::locale::classic();
+ for (const char& ch : name) {
+ if (!std::isalnum(ch, loc)) {
+ continue;
+ }
+ shortName.push_back(std::toupper(ch, loc));
+ if (shortName.length() >= maxlen) {
+ break;
+ }
+ }
+
+ // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
+ // in little-endian order. For example, "Abc" is converted to 0x434241.
+ int64_t val = 0;
+ for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
+ val <<= 8;
+ val |= static_cast<char>(*rit);
+ }
+
+ return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
+}
+
+} // namespace utils
+
+utils::IdentifierIterator begin(const ProgramSelector& sel) {
+ return utils::IdentifierIterator(sel);
+}
+
+utils::IdentifierIterator end(const ProgramSelector& sel) {
+ return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
+}
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
new file mode 100644
index 0000000..c79c5c5
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/broadcastradio/IdentifierType.h>
+#include <aidl/android/hardware/broadcastradio/Metadata.h>
+#include <aidl/android/hardware/broadcastradio/ProgramFilter.h>
+#include <aidl/android/hardware/broadcastradio/ProgramIdentifier.h>
+#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
+#include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
+#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
+#include <aidl/android/hardware/broadcastradio/Properties.h>
+#include <aidl/android/hardware/broadcastradio/Result.h>
+
+#include <numeric>
+#include <optional>
+#include <thread>
+#include <unordered_set>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+enum class FrequencyBand {
+ UNKNOWN,
+ FM,
+ AM_LW,
+ AM_MW,
+ AM_SW,
+};
+
+class IdentifierIterator final
+ : public std::iterator<std::random_access_iterator_tag, ProgramIdentifier, ssize_t,
+ const ProgramIdentifier*, const ProgramIdentifier&> {
+ using ptrType = typename std::iterator_traits<IdentifierIterator>::pointer;
+ using refType = typename std::iterator_traits<IdentifierIterator>::reference;
+ using diffType = typename std::iterator_traits<IdentifierIterator>::difference_type;
+
+ public:
+ explicit IdentifierIterator(const ProgramSelector& sel);
+
+ const IdentifierIterator operator++(int);
+ IdentifierIterator& operator++();
+ refType operator*() const;
+ inline ptrType operator->() const { return &operator*(); }
+ IdentifierIterator operator+(diffType v) const { return IdentifierIterator(mSel, mPos + v); }
+ bool operator==(const IdentifierIterator& rhs) const;
+ inline bool operator!=(const IdentifierIterator& rhs) const { return !operator==(rhs); };
+
+ private:
+ explicit IdentifierIterator(const ProgramSelector& sel, size_t pos);
+
+ std::reference_wrapper<const ProgramSelector> mSel;
+
+ const ProgramSelector& getSelector() const { return mSel.get(); }
+
+ /** 0 is the primary identifier, 1-n are secondary identifiers. */
+ size_t mPos = 0;
+};
+
+/**
+ * Convert Result to int
+ */
+int32_t resultToInt(Result result);
+
+/**
+ * Guesses band from the frequency value.
+ *
+ * The band bounds are not exact to cover multiple regions.
+ * The function is biased towards success, i.e. it never returns
+ * FrequencyBand::UNKNOWN for correct frequency, but a result for
+ * incorrect one is undefined (it doesn't have to return UNKNOWN).
+ */
+FrequencyBand getBand(int64_t frequency);
+
+/**
+ * Checks, if {@code pointer} tunes to {@channel}.
+ *
+ * For example, having a channel {AMFM_FREQUENCY_KHZ = 103.3}:
+ * - selector {AMFM_FREQUENCY_KHZ = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
+ * - selector {AMFM_FREQUENCY_KHZ = 103.3, HD_SUBCHANNEL = 1} can't.
+ *
+ * @param pointer selector we're trying to match against channel.
+ * @param channel existing channel.
+ */
+bool tunesTo(const ProgramSelector& pointer, const ProgramSelector& channel);
+
+/**
+ * Checks whether a given program selector has the given ID (either primary or secondary).
+ */
+bool hasId(const ProgramSelector& sel, const IdentifierType& type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns kValueForNotFoundIdentifier
+ * and emits a warning.
+ */
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns default value.
+ */
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue);
+
+/**
+ * Returns all IDs of a given type.
+ */
+std::vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type);
+
+/**
+ * Checks, if a given selector is supported by the radio module.
+ *
+ * @param prop Module description.
+ * @param sel The selector to check.
+ * @return True, if the selector is supported, false otherwise.
+ */
+bool isSupported(const Properties& prop, const ProgramSelector& sel);
+
+bool isValid(const ProgramIdentifier& id);
+bool isValid(const ProgramSelector& sel);
+
+ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
+ProgramSelector makeSelectorAmfm(int32_t frequency);
+ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble);
+
+bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
+
+struct ProgramInfoHasher {
+ size_t operator()(const ProgramInfo& info) const;
+};
+
+struct ProgramInfoKeyEqual {
+ bool operator()(const ProgramInfo& info1, const ProgramInfo& info2) const;
+};
+
+typedef std::unordered_set<ProgramInfo, ProgramInfoHasher, ProgramInfoKeyEqual> ProgramInfoSet;
+
+void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list);
+
+std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag);
+
+ProgramIdentifier makeHdRadioStationName(const std::string& name);
+
+template <typename aidl_type>
+inline std::string vectorToString(const std::vector<aidl_type>& in_values) {
+ return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
+ [](const std::string& ls, const aidl_type& rs) {
+ return ls + (ls.empty() ? "" : ",") + toString(rs);
+ });
+}
+
+} // namespace utils
+
+utils::IdentifierIterator begin(const ProgramSelector& sel);
+utils::IdentifierIterator end(const ProgramSelector& sel);
+
+} // namespace aidl::android::hardware::broadcastradio
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 7e24085..9b8e560 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -152,17 +152,8 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
+ <hal format="aidl" optional="true">
<name>android.hardware.broadcastradio</name>
- <version>1.0-1</version>
- <interface>
- <name>IBroadcastRadioFactory</name>
- <instance>default</instance>
- </interface>
- </hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.broadcastradio</name>
- <version>2.0</version>
<interface>
<name>IBroadcastRadio</name>
<regex-instance>.*</regex-instance>
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index 1d81f7b..775ae9f 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -59,13 +59,13 @@
namespace aidl::android::hardware::graphics::composer3 {
-class ComposerClientWriter {
+class ComposerClientWriter final {
public:
static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
ComposerClientWriter() { reset(); }
- virtual ~ComposerClientWriter() { reset(); }
+ ~ComposerClientWriter() { reset(); }
void reset() {
mDisplayCommand.reset();
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
index cb598f3..523d1aa 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -40,4 +40,6 @@
boolean isEmcBearerSupported;
byte nwProvidedEmc;
byte nwProvidedEmf;
+ String mcc;
+ String mnc;
}
diff --git a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
index cf5caa4..c22317a 100644
--- a/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/EmergencyRegResult.aidl
@@ -54,4 +54,10 @@
* This should not be set if UE is not in 5G mode.
*/
byte nwProvidedEmf;
+
+ /** 3-digit Mobile Country Code, 000..999, empty string if unknown. */
+ String mcc;
+
+ /** 2 or 3-digit Mobile Network Code, 00..999, empty string if unknown. */
+ String mnc;
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index d98a31b..243e949 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -580,7 +580,6 @@
*
* Valid errors returned:
* RadioError:NONE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
@@ -592,7 +591,6 @@
*
* Valid errors returned:
* RadioError:NONE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
@@ -604,7 +602,6 @@
*
* Valid errors returned:
* RadioError:NONE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
*/
@@ -615,7 +612,6 @@
*
* Valid errors returned:
* RadioError:NONE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
*/
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index c83571e..25c42d3 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -1833,3 +1833,81 @@
}
LOG(DEBUG) << "supplyNetworkDepersonalization finished";
}
+
+/*
+ * Test IRadioNetwork.setEmergencyMode() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setEmergencyMode) {
+ LOG(DEBUG) << "setEmergencyMode";
+ serial = GetRandomSerialNumber();
+
+ radio_network->setEmergencyMode(serial, EmergencyMode::EMERGENCY_WWAN);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
+ LOG(DEBUG) << "setEmergencyMode finished";
+}
+
+/*
+ * Test IRadioNetwork.triggerEmergencyNetworkScan() for the response returned.
+ */
+TEST_P(RadioNetworkTest, triggerEmergencyNetworkScan) {
+ LOG(DEBUG) << "triggerEmergencyNetworkScan";
+ serial = GetRandomSerialNumber();
+
+ EmergencyNetworkScanTrigger scanRequest;
+ scanRequest.accessNetwork = {AccessNetwork::EUTRAN};
+ scanRequest.scanType = EmergencyScanType::NO_PREFERENCE;
+
+ radio_network->triggerEmergencyNetworkScan(serial, scanRequest);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::INVALID_ARGUMENTS}));
+ LOG(DEBUG) << "triggerEmergencyNetworkScan finished";
+}
+
+/*
+ * Test IRadioNetwork.cancelEmergencyNetworkScan() for the response returned.
+ */
+TEST_P(RadioNetworkTest, cancelEmergencyNetworkScan) {
+ LOG(DEBUG) << "cancelEmergencyNetworkScan";
+ serial = GetRandomSerialNumber();
+
+ radio_network->cancelEmergencyNetworkScan(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ LOG(DEBUG) << "cancelEmergencyNetworkScan finished";
+}
+
+/*
+ * Test IRadioNetwork.exitEmergencyMode() for the response returned.
+ */
+TEST_P(RadioNetworkTest, exitEmergencyMode) {
+ LOG(DEBUG) << "exitEmergencyMode";
+ serial = GetRandomSerialNumber();
+
+ radio_network->exitEmergencyMode(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ LOG(DEBUG) << "exitEmergencyMode finished";
+}