blob: ee0c63988dd9990fd912e412b887d66444c14da3 [file] [log] [blame]
Weilin Xub23d0ea2022-05-09 18:26:23 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define EGMOCK_VERBOSE 1
18
19#include <aidl/android/hardware/broadcastradio/BnAnnouncementListener.h>
20#include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
21#include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
22#include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
23#include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
24#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
25#include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>
26#include <android-base/logging.h>
27#include <android-base/strings.h>
28#include <android-base/thread_annotations.h>
29#include <android/binder_manager.h>
30#include <android/binder_process.h>
31
32#include <aidl/Gtest.h>
33#include <aidl/Vintf.h>
34#include <broadcastradio-utils-aidl/Utils.h>
Weilin Xu25409e52023-09-06 10:36:24 -070035#include <broadcastradio-utils-aidl/UtilsV2.h>
Weilin Xub23d0ea2022-05-09 18:26:23 +000036#include <cutils/bitops.h>
37#include <gmock/gmock.h>
Weilin Xuc3301592023-12-06 16:45:24 -080038#include <gtest/gtest.h>
Weilin Xub23d0ea2022-05-09 18:26:23 +000039
40#include <chrono>
Weilin Xu4420c1d2023-06-21 22:49:04 +000041#include <condition_variable>
Weilin Xub23d0ea2022-05-09 18:26:23 +000042#include <optional>
43#include <regex>
44
45namespace aidl::android::hardware::broadcastradio::vts {
46
47namespace {
48
49using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
50using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
Weilin Xu0d4207d2022-12-09 00:37:44 +000051using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
Weilin Xub23d0ea2022-05-09 18:26:23 +000052using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
53using ::ndk::ScopedAStatus;
54using ::ndk::SharedRefBase;
Weilin Xub23d0ea2022-05-09 18:26:23 +000055using ::std::vector;
56using ::testing::_;
57using ::testing::AnyNumber;
58using ::testing::ByMove;
59using ::testing::DoAll;
60using ::testing::Invoke;
61using ::testing::SaveArg;
62
63namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
64
Weilin Xu3277a212022-09-01 19:08:17 +000065const ConfigFlag kConfigFlagValues[] = {
66 ConfigFlag::FORCE_MONO,
67 ConfigFlag::FORCE_ANALOG,
68 ConfigFlag::FORCE_DIGITAL,
69 ConfigFlag::RDS_AF,
70 ConfigFlag::RDS_REG,
71 ConfigFlag::DAB_DAB_LINKING,
72 ConfigFlag::DAB_FM_LINKING,
73 ConfigFlag::DAB_DAB_SOFT_LINKING,
74 ConfigFlag::DAB_FM_SOFT_LINKING,
75};
76
Weilin Xu25409e52023-09-06 10:36:24 -070077constexpr int32_t kAidlVersion1 = 1;
78constexpr int32_t kAidlVersion2 = 2;
79
Weilin Xu25409e52023-09-06 10:36:24 -070080bool isValidAmFmFreq(int64_t freq, int aidlVersion) {
Weilin Xu3277a212022-09-01 19:08:17 +000081 ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
Weilin Xu25409e52023-09-06 10:36:24 -070082 if (aidlVersion == kAidlVersion1) {
83 return bcutils::isValid(id);
84 } else if (aidlVersion == kAidlVersion2) {
85 return bcutils::isValidV2(id);
86 }
87 LOG(ERROR) << "Unknown AIDL version " << aidlVersion;
88 return false;
Weilin Xu3277a212022-09-01 19:08:17 +000089}
90
Weilin Xu25409e52023-09-06 10:36:24 -070091void validateRange(const AmFmBandRange& range, int aidlVersion) {
92 EXPECT_TRUE(isValidAmFmFreq(range.lowerBound, aidlVersion));
93 EXPECT_TRUE(isValidAmFmFreq(range.upperBound, aidlVersion));
Weilin Xu3277a212022-09-01 19:08:17 +000094 EXPECT_LT(range.lowerBound, range.upperBound);
95 EXPECT_GT(range.spacing, 0u);
96 EXPECT_EQ((range.upperBound - range.lowerBound) % range.spacing, 0u);
97}
98
99bool supportsFM(const AmFmRegionConfig& config) {
100 for (const auto& range : config.ranges) {
101 if (bcutils::getBand(range.lowerBound) == bcutils::FrequencyBand::FM) {
102 return true;
103 }
104 }
105 return false;
106}
107
Weilin Xub23d0ea2022-05-09 18:26:23 +0000108} // namespace
109
Weilin Xu4420c1d2023-06-21 22:49:04 +0000110class CallbackFlag final {
Weilin Xub23d0ea2022-05-09 18:26:23 +0000111 public:
Weilin Xu4420c1d2023-06-21 22:49:04 +0000112 CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
113 /**
114 * Notify that the callback is called.
115 */
116 void notify() {
117 std::unique_lock<std::mutex> lock(mMutex);
118 mCalled = true;
119 lock.unlock();
120 mCv.notify_all();
121 };
122
123 /**
124 * Wait for the timeout passed into the constructor.
125 */
126 bool wait() {
127 std::unique_lock<std::mutex> lock(mMutex);
128 return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
129 [this] { return mCalled; });
130 };
131
132 /**
133 * Reset the callback to not called.
134 */
135 void reset() {
136 std::unique_lock<std::mutex> lock(mMutex);
137 mCalled = false;
138 }
139
140 private:
141 std::mutex mMutex;
142 bool mCalled GUARDED_BY(mMutex) = false;
143 std::condition_variable mCv;
144 int mTimeoutMs;
145};
146
147class TunerCallbackImpl final : public BnTunerCallback {
148 public:
Weilin Xu25409e52023-09-06 10:36:24 -0700149 explicit TunerCallbackImpl(int32_t aidlVersion);
Weilin Xu0d4207d2022-12-09 00:37:44 +0000150 ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000151 ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
152 ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000153 ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
154 ScopedAStatus onAntennaStateChange(bool connected) override;
155 ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000156
Weilin Xu4420c1d2023-06-21 22:49:04 +0000157 bool waitOnCurrentProgramInfoChangedCallback();
158 bool waitProgramReady();
159 void reset();
160
161 bool getAntennaConnectionState();
162 ProgramInfo getCurrentProgramInfo();
163 bcutils::ProgramInfoSet getProgramList();
164
165 private:
Weilin Xub23d0ea2022-05-09 18:26:23 +0000166 std::mutex mLock;
Weilin Xu25409e52023-09-06 10:36:24 -0700167 int32_t mCallbackAidlVersion;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000168 bool mAntennaConnectionState GUARDED_BY(mLock);
169 ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000170 bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
Weilin Xu4420c1d2023-06-21 22:49:04 +0000171 CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
172 CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000173};
174
175struct AnnouncementListenerMock : public BnAnnouncementListener {
176 MOCK_METHOD1(onListUpdated, ScopedAStatus(const vector<Announcement>&));
177};
178
Weilin Xu25409e52023-09-06 10:36:24 -0700179class BroadcastRadioHalTest : public testing::TestWithParam<std::string> {
Weilin Xub23d0ea2022-05-09 18:26:23 +0000180 protected:
181 void SetUp() override;
182 void TearDown() override;
183
184 bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
185 std::optional<bcutils::ProgramInfoSet> getProgramList();
186 std::optional<bcutils::ProgramInfoSet> getProgramList(const ProgramFilter& filter);
187
188 std::shared_ptr<IBroadcastRadio> mModule;
189 Properties mProperties;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000190 std::shared_ptr<TunerCallbackImpl> mCallback;
Weilin Xu25409e52023-09-06 10:36:24 -0700191 int32_t mAidlVersion;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000192};
193
Weilin Xu25409e52023-09-06 10:36:24 -0700194MATCHER_P(InfoHasId, id,
195 std::string(negation ? "does not contain" : "contains") + " " + id.toString()) {
Weilin Xu4db4b7b2024-04-05 14:03:15 -0700196 vector<int64_t> ids = bcutils::getAllIds(arg.selector, id.type);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000197 return ids.end() != find(ids.begin(), ids.end(), id.value);
198}
199
Weilin Xu25409e52023-09-06 10:36:24 -0700200TunerCallbackImpl::TunerCallbackImpl(int32_t aidlVersion) {
201 mCallbackAidlVersion = aidlVersion;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000202 mAntennaConnectionState = true;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000203}
204
Weilin Xu4420c1d2023-06-21 22:49:04 +0000205ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
Weilin Xu0d4207d2022-12-09 00:37:44 +0000206 LOG(DEBUG) << "Tune failed for selector" << selector.toString();
207 EXPECT_TRUE(result == Result::CANCELED);
208 return ndk::ScopedAStatus::ok();
209}
210
Weilin Xu4420c1d2023-06-21 22:49:04 +0000211ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
212 LOG(DEBUG) << "onCurrentProgramInfoChanged called";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000213 for (const auto& id : info.selector) {
214 EXPECT_NE(id.type, IdentifierType::INVALID);
215 }
216
217 IdentifierType logically = info.logicallyTunedTo.type;
218 // This field is required for currently tuned program and should be INVALID
219 // for entries from the program list.
220 EXPECT_TRUE(logically == IdentifierType::AMFM_FREQUENCY_KHZ ||
221 logically == IdentifierType::RDS_PI ||
222 logically == IdentifierType::HD_STATION_ID_EXT ||
223 logically == IdentifierType::DAB_SID_EXT ||
224 logically == IdentifierType::DRMO_SERVICE_ID ||
225 logically == IdentifierType::SXM_SERVICE_ID ||
226 (logically >= IdentifierType::VENDOR_START &&
227 logically <= IdentifierType::VENDOR_END) ||
228 logically > IdentifierType::SXM_CHANNEL);
229
230 IdentifierType physically = info.physicallyTunedTo.type;
231 // ditto (see "logically" above)
232 EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
Weilin Xu0d4207d2022-12-09 00:37:44 +0000233 physically == IdentifierType::DAB_FREQUENCY_KHZ ||
Weilin Xub23d0ea2022-05-09 18:26:23 +0000234 physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
235 physically == IdentifierType::SXM_CHANNEL ||
236 (physically >= IdentifierType::VENDOR_START &&
237 physically <= IdentifierType::VENDOR_END) ||
238 physically > IdentifierType::SXM_CHANNEL);
239
240 if (logically == IdentifierType::AMFM_FREQUENCY_KHZ) {
Weilin Xu25409e52023-09-06 10:36:24 -0700241 std::optional<std::string> ps;
242 if (mCallbackAidlVersion == kAidlVersion1) {
243 ps = bcutils::getMetadataString(info, Metadata::rdsPs);
244 } else {
245 ps = bcutils::getMetadataStringV2(info, Metadata::rdsPs);
246 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000247 if (ps.has_value()) {
248 EXPECT_NE(::android::base::Trim(*ps), "")
249 << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
250 }
251 }
252
Weilin Xu2f1dd4c2024-01-10 15:13:43 -0800253 for (const auto& metadataItem : info.metadata) {
254 bool validMetadata = false;
255 if (mCallbackAidlVersion == kAidlVersion1) {
256 validMetadata = bcutils::isValidMetadata(metadataItem);
257 } else {
258 validMetadata = bcutils::isValidMetadataV2(metadataItem);
259 }
260 EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
261 }
262
Weilin Xu4420c1d2023-06-21 22:49:04 +0000263 {
264 std::lock_guard<std::mutex> lk(mLock);
265 mCurrentProgramInfo = info;
266 }
267
268 mOnCurrentProgramInfoChangedFlag.notify();
269 return ndk::ScopedAStatus::ok();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000270}
271
Weilin Xu4420c1d2023-06-21 22:49:04 +0000272ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
273 LOG(DEBUG) << "onProgramListUpdated called";
274 {
275 std::lock_guard<std::mutex> lk(mLock);
276 updateProgramList(chunk, &mProgramList);
277 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000278
279 if (chunk.complete) {
Weilin Xu4420c1d2023-06-21 22:49:04 +0000280 mOnProgramListReadyFlag.notify();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000281 }
282
283 return ndk::ScopedAStatus::ok();
284}
285
Weilin Xu4420c1d2023-06-21 22:49:04 +0000286ScopedAStatus TunerCallbackImpl::onParametersUpdated(
287 [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
288 return ndk::ScopedAStatus::ok();
289}
290
291ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
292 if (!connected) {
293 std::lock_guard<std::mutex> lk(mLock);
294 mAntennaConnectionState = false;
295 }
296 return ndk::ScopedAStatus::ok();
297}
298
299ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
300 [[maybe_unused]] bool in_value) {
301 return ndk::ScopedAStatus::ok();
302}
303
304bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
305 return mOnCurrentProgramInfoChangedFlag.wait();
306}
307
308bool TunerCallbackImpl::waitProgramReady() {
309 return mOnProgramListReadyFlag.wait();
310}
311
312void TunerCallbackImpl::reset() {
313 mOnCurrentProgramInfoChangedFlag.reset();
314 mOnProgramListReadyFlag.reset();
315}
316
317bool TunerCallbackImpl::getAntennaConnectionState() {
318 std::lock_guard<std::mutex> lk(mLock);
319 return mAntennaConnectionState;
320}
321
322ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
323 std::lock_guard<std::mutex> lk(mLock);
324 return mCurrentProgramInfo;
325}
326
327bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
328 std::lock_guard<std::mutex> lk(mLock);
329 return mProgramList;
330}
331
Weilin Xub23d0ea2022-05-09 18:26:23 +0000332void BroadcastRadioHalTest::SetUp() {
333 EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
334
335 // lookup AIDL service (radio module)
336 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
337 ASSERT_NE(binder, nullptr);
338 mModule = IBroadcastRadio::fromBinder(ndk::SpAIBinder(binder));
339 ASSERT_NE(mModule, nullptr) << "Couldn't find broadcast radio HAL implementation";
340
341 // get module properties
342 auto propResult = mModule->getProperties(&mProperties);
343
344 ASSERT_TRUE(propResult.isOk());
345 EXPECT_FALSE(mProperties.maker.empty());
346 EXPECT_FALSE(mProperties.product.empty());
347 EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
348
Weilin Xu25409e52023-09-06 10:36:24 -0700349 // get AIDL HAL version
350 ASSERT_TRUE(mModule->getInterfaceVersion(&mAidlVersion).isOk());
351 EXPECT_GE(mAidlVersion, kAidlVersion1);
352 EXPECT_LE(mAidlVersion, kAidlVersion2);
Weilin Xu4420c1d2023-06-21 22:49:04 +0000353
Weilin Xub23d0ea2022-05-09 18:26:23 +0000354 // set callback
Weilin Xu25409e52023-09-06 10:36:24 -0700355 mCallback = SharedRefBase::make<TunerCallbackImpl>(mAidlVersion);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000356 EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
357}
358
359void BroadcastRadioHalTest::TearDown() {
360 if (mModule) {
361 ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
362 }
Weilin Xu4420c1d2023-06-21 22:49:04 +0000363 if (mCallback) {
364 // we expect the antenna is connected through the whole test
365 EXPECT_TRUE(mCallback->getAntennaConnectionState());
366 mCallback = nullptr;
367 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000368}
369
370bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
371 auto halResult = mModule->getAmFmRegionConfig(full, config);
372
373 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
374 return false;
375 }
376
377 EXPECT_TRUE(halResult.isOk());
378 return halResult.isOk();
379}
380
381std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
382 ProgramFilter emptyFilter = {};
383 return getProgramList(emptyFilter);
384}
385
386std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
387 const ProgramFilter& filter) {
Weilin Xu4420c1d2023-06-21 22:49:04 +0000388 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000389
390 auto startResult = mModule->startProgramListUpdates(filter);
391
392 if (startResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
Weilin Xuc3301592023-12-06 16:45:24 -0800393 LOG(WARNING) << "Program list not supported";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000394 return std::nullopt;
395 }
396 EXPECT_TRUE(startResult.isOk());
397 if (!startResult.isOk()) {
398 return std::nullopt;
399 }
Weilin Xu4420c1d2023-06-21 22:49:04 +0000400 EXPECT_TRUE(mCallback->waitProgramReady());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000401
402 auto stopResult = mModule->stopProgramListUpdates();
403
404 EXPECT_TRUE(stopResult.isOk());
405
Weilin Xu4420c1d2023-06-21 22:49:04 +0000406 return mCallback->getProgramList();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000407}
408
409/**
410 * Test setting tuner callback to null.
411 *
412 * Verifies that:
413 * - Setting to a null tuner callback results with INVALID_ARGUMENTS.
414 */
415TEST_P(BroadcastRadioHalTest, TunerCallbackFailsWithNull) {
416 LOG(DEBUG) << "TunerCallbackFailsWithNull Test";
417
418 auto halResult = mModule->setTunerCallback(nullptr);
419
420 EXPECT_EQ(halResult.getServiceSpecificError(), resultToInt(Result::INVALID_ARGUMENTS));
421}
422
423/**
Weilin Xu3277a212022-09-01 19:08:17 +0000424 * Test fetching AM/FM regional configuration.
425 *
426 * Verifies that:
427 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
428 * - FM Deemphasis and RDS are correctly configured for FM-capable radio;
429 */
430TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
431 LOG(DEBUG) << "GetAmFmRegionConfig Test";
432
433 AmFmRegionConfig config;
434
435 bool supported = getAmFmRegionConfig(/* full= */ false, &config);
436
437 if (!supported) {
Weilin Xuc3301592023-12-06 16:45:24 -0800438 GTEST_SKIP() << "AM/FM not supported";
Weilin Xu3277a212022-09-01 19:08:17 +0000439 }
440
441 EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
442 EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmRds)), 1);
443
444 if (supportsFM(config)) {
445 EXPECT_EQ(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
446 }
447}
448
449/**
450 * Test fetching ranges of AM/FM regional configuration.
451 *
452 * Verifies that:
453 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
454 * - there is at least one AM/FM band configured;
455 * - all channel grids (frequency ranges and spacings) are valid;
456 * - seek spacing is a multiple of the manual spacing value.
457 */
458TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigRanges) {
459 LOG(DEBUG) << "GetAmFmRegionConfigRanges Test";
460
461 AmFmRegionConfig config;
462
463 bool supported = getAmFmRegionConfig(/* full= */ false, &config);
464
465 if (!supported) {
Weilin Xuc3301592023-12-06 16:45:24 -0800466 GTEST_SKIP() << "AM/FM not supported";
Weilin Xu3277a212022-09-01 19:08:17 +0000467 }
468
469 EXPECT_GT(config.ranges.size(), 0u);
470 for (const auto& range : config.ranges) {
Weilin Xu25409e52023-09-06 10:36:24 -0700471 validateRange(range, mAidlVersion);
Weilin Xu3277a212022-09-01 19:08:17 +0000472 EXPECT_EQ(range.seekSpacing % range.spacing, 0u);
473 EXPECT_GE(range.seekSpacing, range.spacing);
474 }
475}
476
477/**
478 * Test fetching FM regional capabilities.
479 *
480 * Verifies that:
481 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
482 * - there is at least one de-emphasis filter mode supported for FM-capable radio;
483 */
484TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesForFM) {
485 LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesForFM Test";
486
487 AmFmRegionConfig config;
488
489 bool supported = getAmFmRegionConfig(/* full= */ true, &config);
490
491 if (supported && supportsFM(config)) {
492 EXPECT_GE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
493 } else {
Weilin Xuc3301592023-12-06 16:45:24 -0800494 GTEST_SKIP() << "FM not supported";
Weilin Xu3277a212022-09-01 19:08:17 +0000495 }
496}
497
498/**
499 * Test fetching the ranges of AM/FM regional capabilities.
500 *
501 * Verifies that:
502 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
503 * - there is at least one AM/FM range supported;
504 * - all channel grids (frequency ranges and spacings) are valid;
505 * - seek spacing is not set.
506 */
507TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesRanges) {
508 LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesRanges Test";
509
510 AmFmRegionConfig config;
511
512 bool supported = getAmFmRegionConfig(/* full= */ true, &config);
513
514 if (!supported) {
Weilin Xuc3301592023-12-06 16:45:24 -0800515 GTEST_SKIP() << "AM/FM not supported";
Weilin Xu3277a212022-09-01 19:08:17 +0000516 }
517
518 EXPECT_GT(config.ranges.size(), 0u);
519
520 for (const auto& range : config.ranges) {
Weilin Xu25409e52023-09-06 10:36:24 -0700521 validateRange(range, mAidlVersion);
Weilin Xu3277a212022-09-01 19:08:17 +0000522 EXPECT_EQ(range.seekSpacing, 0u);
523 }
524}
525
526/**
527 * Test fetching DAB regional configuration.
528 *
529 * Verifies that:
530 * - DAB regional configuration is either set at startup or not supported at all by the hardware;
531 * - all channel labels match correct format;
532 * - all channel frequencies are in correct range.
533 */
534TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
535 LOG(DEBUG) << "GetDabRegionConfig Test";
536 vector<DabTableEntry> config;
537
538 auto halResult = mModule->getDabRegionConfig(&config);
539
540 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
Weilin Xuc3301592023-12-06 16:45:24 -0800541 GTEST_SKIP() << "DAB not supported";
Weilin Xu3277a212022-09-01 19:08:17 +0000542 }
543 ASSERT_TRUE(halResult.isOk());
544
545 std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
546
547 for (const auto& entry : config) {
Weilin Xu25409e52023-09-06 10:36:24 -0700548 EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
Weilin Xu3277a212022-09-01 19:08:17 +0000549
550 ProgramIdentifier id =
551 bcutils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, entry.frequencyKhz);
Weilin Xu25409e52023-09-06 10:36:24 -0700552 if (mAidlVersion == kAidlVersion1) {
553 EXPECT_TRUE(bcutils::isValid(id));
554 } else if (mAidlVersion == kAidlVersion2) {
555 EXPECT_TRUE(bcutils::isValidV2(id));
556 } else {
557 LOG(ERROR) << "Unknown callback AIDL version " << mAidlVersion;
558 }
Weilin Xu3277a212022-09-01 19:08:17 +0000559 }
560}
561
562/**
Weilin Xub23d0ea2022-05-09 18:26:23 +0000563 * Test tuning without tuner callback set.
564 *
565 * Verifies that:
566 * - No tuner callback set results in INVALID_STATE, regardless of whether the selector is
567 * supported.
568 */
569TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) {
570 LOG(DEBUG) << "TuneFailsWithoutTunerCallback Test";
571
572 mModule->unsetTunerCallback();
573 int64_t freq = 90900; // 90.9 FM
574 ProgramSelector sel = makeSelectorAmfm(freq);
575
576 auto result = mModule->tune(sel);
577
578 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
579}
580
581/**
582 * Test tuning with selectors that can be not supported.
583 *
584 * Verifies that:
585 * - if the selector is not supported, an invalid value results with NOT_SUPPORTED, regardless of
586 * whether it is valid;
587 * - if it is supported, the test is ignored;
588 */
589TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
Weilin Xu4420c1d2023-06-21 22:49:04 +0000590 LOG(DEBUG) << "TuneFailsWithNotSupported Test";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000591
592 vector<ProgramIdentifier> supportTestId = {
593 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid
594 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 94900), // valid
595 makeIdentifier(IdentifierType::RDS_PI, 0x10000), // invalid
596 makeIdentifier(IdentifierType::RDS_PI, 0x1001), // valid
597 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000), // invalid
598 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x10000001), // valid
599 makeIdentifier(IdentifierType::DAB_SID_EXT, 0), // invalid
600 makeIdentifier(IdentifierType::DAB_SID_EXT, 0xA00001), // valid
601 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000), // invalid
602 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x10000001), // valid
603 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000), // invalid
604 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x10000001), // valid
605 };
606
607 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
608 for (const auto& id : supportTestId) {
609 ProgramSelector sel{id, {}};
610
Weilin Xub23d0ea2022-05-09 18:26:23 +0000611 if (!bcutils::isSupported(mProperties, sel)) {
Weilin Xu4420c1d2023-06-21 22:49:04 +0000612 auto result = mModule->tune(sel);
613
Weilin Xub23d0ea2022-05-09 18:26:23 +0000614 EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
615 }
616 }
617}
618
619/**
620 * Test tuning with invalid selectors.
621 *
622 * Verifies that:
623 * - if the selector is not supported, it's ignored;
624 * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
625 */
626TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
627 LOG(DEBUG) << "TuneFailsWithInvalid Test";
628
629 vector<ProgramIdentifier> invalidId = {
630 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),
631 makeIdentifier(IdentifierType::RDS_PI, 0x10000),
632 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
633 makeIdentifier(IdentifierType::DAB_SID_EXT, 0),
634 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
635 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
636 };
637
638 auto invalidArgumentsError = resultToInt(Result::INVALID_ARGUMENTS);
639 for (const auto& id : invalidId) {
640 ProgramSelector sel{id, {}};
641
Weilin Xub23d0ea2022-05-09 18:26:23 +0000642 if (bcutils::isSupported(mProperties, sel)) {
Weilin Xu4420c1d2023-06-21 22:49:04 +0000643 auto result = mModule->tune(sel);
644
Weilin Xub23d0ea2022-05-09 18:26:23 +0000645 EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
646 }
647 }
648}
649
650/**
651 * Test tuning with empty program selector.
652 *
653 * Verifies that:
654 * - tune fails with NOT_SUPPORTED when program selector is not initialized.
655 */
656TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
657 LOG(DEBUG) << "TuneFailsWithEmpty Test";
658
659 // Program type is 1-based, so 0 will always be invalid.
660 ProgramSelector sel = {};
661
662 auto result = mModule->tune(sel);
663
664 ASSERT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
665}
666
667/**
668 * Test tuning with FM selector.
669 *
670 * Verifies that:
671 * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
672 * - if it is supported, the method succeeds;
673 * - after a successful tune call, onCurrentProgramInfoChanged callback is
674 * invoked carrying a proper selector;
Weilin Xuc3301592023-12-06 16:45:24 -0800675 * - program changes to a program info with the program selector requested.
Weilin Xub23d0ea2022-05-09 18:26:23 +0000676 */
677TEST_P(BroadcastRadioHalTest, FmTune) {
678 LOG(DEBUG) << "FmTune Test";
679
680 int64_t freq = 90900; // 90.9 FM
681 ProgramSelector sel = makeSelectorAmfm(freq);
682 // try tuning
Weilin Xu4420c1d2023-06-21 22:49:04 +0000683 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000684 auto result = mModule->tune(sel);
685
686 // expect a failure if it's not supported
687 if (!bcutils::isSupported(mProperties, sel)) {
688 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
689 return;
690 }
691
692 // expect a callback if it succeeds
693 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000694 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
695 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000696
697 LOG(DEBUG) << "Current program info: " << infoCb.toString();
698
699 // it should tune exactly to what was requested
Weilin Xu4db4b7b2024-04-05 14:03:15 -0700700 vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000701 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
702 << "FM freq " << freq << " kHz is not sent back by callback.";
703}
704
705/**
Weilin Xu3bab6132023-12-06 16:07:43 -0800706 * Test tuning with HD selector.
707 *
708 * Verifies that:
709 * - if AM/FM HD selector is not supported, the method returns NOT_SUPPORTED;
710 * - if it is supported, the method succeeds;
711 * - after a successful tune call, onCurrentProgramInfoChanged callback is
712 * invoked carrying a proper selector;
713 * - program changes to a program info with the program selector requested.
714 */
715TEST_P(BroadcastRadioHalTest, HdTune) {
716 LOG(DEBUG) << "HdTune Test";
717 auto programList = getProgramList();
718 if (!programList) {
Weilin Xuc3301592023-12-06 16:45:24 -0800719 GTEST_SKIP() << "Empty station list, tune cannot be performed";
Weilin Xu3bab6132023-12-06 16:07:43 -0800720 }
721 ProgramSelector hdSel = {};
722 ProgramIdentifier physicallyTunedToExpected = {};
723 bool hdStationPresent = false;
724 for (auto&& programInfo : *programList) {
725 if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
726 continue;
727 }
728 hdSel = programInfo.selector;
729 hdStationPresent = true;
730 physicallyTunedToExpected = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
731 bcutils::getAmFmFrequency(hdSel));
732 break;
733 }
734 if (!hdStationPresent) {
Weilin Xuc3301592023-12-06 16:45:24 -0800735 GTEST_SKIP() << "No HD stations in the list, tune cannot be performed";
Weilin Xu3bab6132023-12-06 16:07:43 -0800736 }
737
738 // try tuning
739 auto result = mModule->tune(hdSel);
740
741 // expect a failure if it's not supported
742 if (!bcutils::isSupported(mProperties, hdSel)) {
743 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
744 return;
745 }
746 // expect a callback if it succeeds
747 EXPECT_TRUE(result.isOk());
748 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
749 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
750 LOG(DEBUG) << "Current program info: " << infoCb.toString();
751 // it should tune exactly to what was requested
Weilin Xuaba14a22023-12-13 13:11:22 -0800752 EXPECT_EQ(infoCb.selector.primaryId, hdSel.primaryId);
Weilin Xu3bab6132023-12-06 16:07:43 -0800753 EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
754}
755
756/**
Weilin Xub23d0ea2022-05-09 18:26:23 +0000757 * Test tuning with DAB selector.
758 *
759 * Verifies that:
760 * - if DAB selector is not supported, the method returns NOT_SUPPORTED;
761 * - if it is supported, the method succeeds;
762 * - after a successful tune call, onCurrentProgramInfoChanged callback is
763 * invoked carrying a proper selector;
Weilin Xuc3301592023-12-06 16:45:24 -0800764 * - program changes to a program info with the program selector requested.
Weilin Xub23d0ea2022-05-09 18:26:23 +0000765 */
766TEST_P(BroadcastRadioHalTest, DabTune) {
767 LOG(DEBUG) << "DabTune Test";
768 vector<DabTableEntry> config;
769
770 auto halResult = mModule->getDabRegionConfig(&config);
771
772 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
Weilin Xuc3301592023-12-06 16:45:24 -0800773 GTEST_SKIP() << "DAB not supported";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000774 }
775 ASSERT_TRUE(halResult.isOk());
776 ASSERT_NE(config.size(), 0U);
777
Weilin Xu0d4207d2022-12-09 00:37:44 +0000778 auto programList = getProgramList();
779
780 if (!programList) {
Weilin Xuc3301592023-12-06 16:45:24 -0800781 GTEST_SKIP() << "Empty DAB station list, tune cannot be performed";
Weilin Xu0d4207d2022-12-09 00:37:44 +0000782 }
783
Weilin Xub23d0ea2022-05-09 18:26:23 +0000784 ProgramSelector sel = {};
Weilin Xu0d4207d2022-12-09 00:37:44 +0000785 uint64_t freq = 0;
786 bool dabStationPresent = false;
787 for (auto&& programInfo : *programList) {
788 if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
789 continue;
790 }
791 for (auto&& config_entry : config) {
792 if (config_entry.frequencyKhz ==
793 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
794 freq = config_entry.frequencyKhz;
795 break;
796 }
797 }
798 // Do not trigger a tune request if the programList entry does not contain
799 // a valid DAB frequency.
800 if (freq == 0) {
801 continue;
802 }
803 int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
804 int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
805 sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
806 dabStationPresent = true;
807 break;
808 }
809
810 if (!dabStationPresent) {
Weilin Xuc3301592023-12-06 16:45:24 -0800811 GTEST_SKIP() << "No DAB stations in the list, tune cannot be performed";
Weilin Xu0d4207d2022-12-09 00:37:44 +0000812 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000813
814 // try tuning
Weilin Xub23d0ea2022-05-09 18:26:23 +0000815
816 auto result = mModule->tune(sel);
817
818 // expect a failure if it's not supported
819 if (!bcutils::isSupported(mProperties, sel)) {
820 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
821 return;
822 }
823
824 // expect a callback if it succeeds
825 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000826 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
827 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
828
Weilin Xub23d0ea2022-05-09 18:26:23 +0000829 LOG(DEBUG) << "Current program info: " << infoCb.toString();
830
831 // it should tune exactly to what was requested
Weilin Xu4db4b7b2024-04-05 14:03:15 -0700832 vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000833 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
834 << "DAB freq " << freq << " kHz is not sent back by callback.";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000835}
836
837/**
838 * Test seeking to next/prev station via IBroadcastRadio::seek().
839 *
840 * Verifies that:
841 * - the method succeeds;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000842 * - the program info is changed within kTuneTimeoutMs;
Weilin Xuc3301592023-12-06 16:45:24 -0800843 * - works both directions and with or without ing sub-channel.
Weilin Xub23d0ea2022-05-09 18:26:23 +0000844 */
845TEST_P(BroadcastRadioHalTest, Seek) {
846 LOG(DEBUG) << "Seek Test";
847
Weilin Xu4420c1d2023-06-21 22:49:04 +0000848 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000849
850 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
851
852 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
Weilin Xuc3301592023-12-06 16:45:24 -0800853 GTEST_SKIP() << "Seek not supported";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000854 }
855
856 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000857 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000858
Weilin Xu4420c1d2023-06-21 22:49:04 +0000859 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000860
861 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
862
863 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000864 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000865}
866
867/**
868 * Test seeking without tuner callback set.
869 *
870 * Verifies that:
871 * - No tuner callback set results in INVALID_STATE.
872 */
873TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
874 LOG(DEBUG) << "SeekFailsWithoutTunerCallback Test";
875
876 mModule->unsetTunerCallback();
877
878 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
879
880 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
881
882 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
883
884 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
885}
886
887/**
888 * Test step operation.
889 *
890 * Verifies that:
891 * - the method succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000892 * - the program info is changed within kTuneTimeoutMs if the method succeeded;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000893 * - works both directions.
894 */
895TEST_P(BroadcastRadioHalTest, Step) {
896 LOG(DEBUG) << "Step Test";
897
Weilin Xu4420c1d2023-06-21 22:49:04 +0000898 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000899
900 auto result = mModule->step(/* in_directionUp= */ true);
901
902 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
Weilin Xuc3301592023-12-06 16:45:24 -0800903 GTEST_SKIP() << "Step not supported";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000904 }
905 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000906 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000907
Weilin Xu4420c1d2023-06-21 22:49:04 +0000908 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000909
910 result = mModule->step(/* in_directionUp= */ false);
911
912 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000913 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000914}
915
916/**
917 * Test step operation without tuner callback set.
918 *
919 * Verifies that:
920 * - No tuner callback set results in INVALID_STATE.
921 */
922TEST_P(BroadcastRadioHalTest, StepFailsWithoutTunerCallback) {
923 LOG(DEBUG) << "StepFailsWithoutTunerCallback Test";
924
925 mModule->unsetTunerCallback();
926
927 auto result = mModule->step(/* in_directionUp= */ true);
928
929 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
930
931 result = mModule->step(/* in_directionUp= */ false);
932
933 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
934}
935
936/**
937 * Test tune cancellation.
938 *
939 * Verifies that:
940 * - the method does not crash after being invoked multiple times.
941 *
942 * Since cancel() might be called after the HAL completes an operation (tune, seek, and step)
943 * and before the callback completions, the operation might not be actually canceled and the
944 * effect of cancel() is not deterministic to be tested here.
945 */
946TEST_P(BroadcastRadioHalTest, Cancel) {
947 LOG(DEBUG) << "Cancel Test";
948
949 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
950 for (int i = 0; i < 10; i++) {
951 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
952
953 if (result.getServiceSpecificError() == notSupportedError) {
Weilin Xuc3301592023-12-06 16:45:24 -0800954 GTEST_SKIP() << "Cancel is skipped because of seek not supported";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000955 }
956 EXPECT_TRUE(result.isOk());
957
958 auto cancelResult = mModule->cancel();
959
960 ASSERT_TRUE(cancelResult.isOk());
961 }
962}
963
964/**
Weilin Xu3277a212022-09-01 19:08:17 +0000965 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
966 *
967 * Verifies that:
968 * - callback is called for empty parameters set.
969 */
970TEST_P(BroadcastRadioHalTest, NoParameters) {
971 LOG(DEBUG) << "NoParameters Test";
972
973 vector<VendorKeyValue> parametersResults = {};
974
975 auto halResult = mModule->setParameters({}, &parametersResults);
976
977 ASSERT_TRUE(halResult.isOk());
978 ASSERT_EQ(parametersResults.size(), 0u);
979
980 parametersResults.clear();
981
982 halResult = mModule->getParameters({}, &parametersResults);
983
984 ASSERT_TRUE(halResult.isOk());
985 ASSERT_EQ(parametersResults.size(), 0u);
986}
987
988/**
989 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
990 *
991 * Verifies that:
992 * - unknown parameters are ignored;
993 * - callback is called also for empty results set.
994 */
995TEST_P(BroadcastRadioHalTest, UnknownParameters) {
996 LOG(DEBUG) << "UnknownParameters Test";
997
998 vector<VendorKeyValue> parametersResults = {};
999
1000 auto halResult =
1001 mModule->setParameters({{"com.android.unknown", "sample"}}, &parametersResults);
1002
1003 ASSERT_TRUE(halResult.isOk());
1004 ASSERT_EQ(parametersResults.size(), 0u);
1005
1006 parametersResults.clear();
1007
1008 halResult = mModule->getParameters({"com.android.unknown*", "sample"}, &parametersResults);
1009
1010 ASSERT_TRUE(halResult.isOk());
1011 ASSERT_EQ(parametersResults.size(), 0u);
1012}
1013
1014/**
1015 * Test geting image of invalid ID.
1016 *
1017 * Verifies that:
1018 * - getImage call handles argument 0 gracefully.
1019 */
1020TEST_P(BroadcastRadioHalTest, GetNoImage) {
1021 LOG(DEBUG) << "GetNoImage Test";
1022 vector<uint8_t> rawImage;
1023
1024 auto result = mModule->getImage(IBroadcastRadio::INVALID_IMAGE, &rawImage);
1025
1026 ASSERT_TRUE(result.isOk());
1027 ASSERT_EQ(rawImage.size(), 0u);
1028}
1029
1030/**
1031 * Test getting config flags.
1032 *
1033 * Verifies that:
1034 * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1035 * - call success or failure is consistent with setConfigFlag.
1036 */
1037TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
1038 LOG(DEBUG) << "FetchConfigFlags Test";
1039
1040 for (const auto& flag : kConfigFlagValues) {
1041 bool gotValue = false;
1042
1043 auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1044
1045 if (halResult.getServiceSpecificError() != resultToInt(Result::NOT_SUPPORTED) &&
1046 halResult.getServiceSpecificError() != resultToInt(Result::INVALID_STATE)) {
1047 ASSERT_TRUE(halResult.isOk());
1048 }
1049
1050 // set must fail or succeed the same way as get
1051 auto setResult = mModule->setConfigFlag(flag, /* value= */ false);
1052
1053 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1054 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1055
1056 setResult = mModule->setConfigFlag(flag, /* value= */ true);
1057
1058 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1059 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1060 }
1061}
1062
1063/**
1064 * Test setting config flags.
1065 *
1066 * Verifies that:
1067 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1068 * - isConfigFlagSet reflects the state requested immediately after the set call.
1069 */
1070TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
1071 LOG(DEBUG) << "SetConfigFlags Test";
1072
1073 auto get = [&](ConfigFlag flag) -> bool {
Weilin Xu978de0a2023-07-19 17:20:19 +00001074 bool gotValue;
Weilin Xu3277a212022-09-01 19:08:17 +00001075
Weilin Xu978de0a2023-07-19 17:20:19 +00001076 auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
Weilin Xu3277a212022-09-01 19:08:17 +00001077
Weilin Xu3277a212022-09-01 19:08:17 +00001078 EXPECT_TRUE(halResult.isOk());
Weilin Xu978de0a2023-07-19 17:20:19 +00001079 return gotValue;
Weilin Xu3277a212022-09-01 19:08:17 +00001080 };
1081
1082 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
1083 auto invalidStateError = resultToInt(Result::INVALID_STATE);
1084 for (const auto& flag : kConfigFlagValues) {
1085 auto result = mModule->setConfigFlag(flag, /* value= */ false);
1086
1087 if (result.getServiceSpecificError() == notSupportedError ||
1088 result.getServiceSpecificError() == invalidStateError) {
1089 // setting to true must result in the same error as false
1090 auto secondResult = mModule->setConfigFlag(flag, /* value= */ true);
1091
1092 EXPECT_TRUE((result.isOk() && secondResult.isOk()) ||
1093 result.getServiceSpecificError() == secondResult.getServiceSpecificError());
1094 continue;
1095 } else {
1096 ASSERT_TRUE(result.isOk());
1097 }
1098
1099 // verify false is set
1100 bool value = get(flag);
1101 EXPECT_FALSE(value);
1102
1103 // try setting true this time
1104 result = mModule->setConfigFlag(flag, /* value= */ true);
1105
1106 ASSERT_TRUE(result.isOk());
1107 value = get(flag);
1108 EXPECT_TRUE(value);
1109
1110 // false again
1111 result = mModule->setConfigFlag(flag, /* value= */ false);
1112
1113 ASSERT_TRUE(result.isOk());
1114 value = get(flag);
1115 EXPECT_FALSE(value);
1116 }
1117}
1118
1119/**
Weilin Xub23d0ea2022-05-09 18:26:23 +00001120 * Test getting program list using empty program filter.
1121 *
1122 * Verifies that:
1123 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001124 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001125 * - stopProgramListUpdates does not crash.
1126 */
1127TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
1128 LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
1129
1130 getProgramList();
1131}
1132
1133/**
1134 * Test getting program list using AMFM frequency program filter.
1135 *
1136 * Verifies that:
1137 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001138 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001139 * - stopProgramListUpdates does not crash;
1140 * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
1141 * AMFM program matches the expected result.
1142 */
1143TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
1144 LOG(DEBUG) << "GetProgramListFromAmFmFilter Test";
1145
1146 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1147 if (!completeList) {
Weilin Xuc3301592023-12-06 16:45:24 -08001148 GTEST_SKIP() << "No program list available";
Weilin Xub23d0ea2022-05-09 18:26:23 +00001149 }
1150
1151 ProgramFilter amfmFilter = {};
1152 int expectedResultSize = 0;
1153 uint64_t expectedFreq = 0;
1154 for (const auto& program : *completeList) {
Weilin Xu4db4b7b2024-04-05 14:03:15 -07001155 vector<int64_t> amfmIds =
Weilin Xub23d0ea2022-05-09 18:26:23 +00001156 bcutils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
1157 EXPECT_LE(amfmIds.size(), 1u);
1158 if (amfmIds.size() == 0) {
1159 continue;
1160 }
1161
1162 if (expectedResultSize == 0) {
1163 expectedFreq = amfmIds[0];
1164 amfmFilter.identifiers = {
1165 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, expectedFreq)};
1166 expectedResultSize = 1;
1167 } else if (amfmIds[0] == expectedFreq) {
1168 expectedResultSize++;
1169 }
1170 }
1171
1172 if (expectedResultSize == 0) {
Weilin Xuc3301592023-12-06 16:45:24 -08001173 GTEST_SKIP() << "No Am/FM programs available";
Weilin Xub23d0ea2022-05-09 18:26:23 +00001174 }
1175 std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
1176 ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
1177}
1178
1179/**
1180 * Test getting program list using DAB ensemble program filter.
1181 *
1182 * Verifies that:
1183 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001184 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001185 * - stopProgramListUpdates does not crash;
1186 * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
1187 * program matches the expected result.
1188 */
1189TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
1190 LOG(DEBUG) << "GetProgramListFromDabFilter Test";
1191
1192 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1193 if (!completeList) {
Weilin Xuc3301592023-12-06 16:45:24 -08001194 GTEST_SKIP() << "No program list available";
Weilin Xub23d0ea2022-05-09 18:26:23 +00001195 }
1196
1197 ProgramFilter dabFilter = {};
1198 int expectedResultSize = 0;
1199 uint64_t expectedEnsemble = 0;
1200 for (const auto& program : *completeList) {
1201 auto dabEnsembles = bcutils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
1202 EXPECT_LE(dabEnsembles.size(), 1u);
1203 if (dabEnsembles.size() == 0) {
1204 continue;
1205 }
1206
1207 if (expectedResultSize == 0) {
1208 expectedEnsemble = dabEnsembles[0];
1209 dabFilter.identifiers = {
1210 makeIdentifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
1211 expectedResultSize = 1;
1212 } else if (dabEnsembles[0] == expectedEnsemble) {
1213 expectedResultSize++;
1214 }
1215 }
1216
1217 if (expectedResultSize == 0) {
Weilin Xuc3301592023-12-06 16:45:24 -08001218 GTEST_SKIP() << "No DAB programs available";
Weilin Xub23d0ea2022-05-09 18:26:23 +00001219 }
1220 std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
1221 ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
1222}
1223
Weilin Xu3277a212022-09-01 19:08:17 +00001224/**
1225 * Test HD_STATION_NAME correctness.
1226 *
1227 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
1228 * - the program provides station name in its metadata;
1229 * - the identifier matches the name;
1230 * - there is only one identifier of that type.
1231 */
1232TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
1233 LOG(DEBUG) << "HdRadioStationNameId Test";
1234
1235 std::optional<bcutils::ProgramInfoSet> list = getProgramList();
1236 if (!list) {
Weilin Xuc3301592023-12-06 16:45:24 -08001237 GTEST_SKIP() << "No program list";
Weilin Xu3277a212022-09-01 19:08:17 +00001238 }
1239
1240 for (const auto& program : *list) {
Weilin Xu4db4b7b2024-04-05 14:03:15 -07001241 vector<int64_t> nameIds =
1242 bcutils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
Weilin Xu3277a212022-09-01 19:08:17 +00001243 EXPECT_LE(nameIds.size(), 1u);
1244 if (nameIds.size() == 0) {
1245 continue;
1246 }
1247
Weilin Xu25409e52023-09-06 10:36:24 -07001248 std::optional<std::string> name;
1249 if (mAidlVersion == kAidlVersion1) {
1250 name = bcutils::getMetadataString(program, Metadata::programName);
1251 if (!name) {
1252 name = bcutils::getMetadataString(program, Metadata::rdsPs);
1253 }
1254 } else if (mAidlVersion == kAidlVersion2) {
1255 name = bcutils::getMetadataStringV2(program, Metadata::programName);
1256 if (!name) {
1257 name = bcutils::getMetadataStringV2(program, Metadata::rdsPs);
1258 }
1259 } else {
1260 LOG(ERROR) << "Unknown HAL AIDL version " << mAidlVersion;
Weilin Xu3277a212022-09-01 19:08:17 +00001261 }
Weilin Xu25409e52023-09-06 10:36:24 -07001262
Weilin Xu3277a212022-09-01 19:08:17 +00001263 ASSERT_TRUE(name.has_value());
1264
1265 ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
1266 EXPECT_EQ(nameIds[0], expectedId.value);
1267 }
1268}
1269
1270/**
1271 * Test announcement listener registration.
1272 *
1273 * Verifies that:
1274 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
1275 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
1276 * - closing handle does not crash.
1277 */
1278TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
1279 LOG(DEBUG) << "AnnouncementListenerRegistration Test";
1280 std::shared_ptr<AnnouncementListenerMock> listener =
1281 SharedRefBase::make<AnnouncementListenerMock>();
1282 std::shared_ptr<ICloseHandle> closeHandle = nullptr;
1283
1284 auto halResult = mModule->registerAnnouncementListener(listener, {AnnouncementType::EMERGENCY},
1285 &closeHandle);
1286
1287 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
1288 ASSERT_EQ(closeHandle.get(), nullptr);
Weilin Xuc3301592023-12-06 16:45:24 -08001289 GTEST_SKIP() << "Announcements not supported";
Weilin Xu3277a212022-09-01 19:08:17 +00001290 }
1291
1292 ASSERT_TRUE(halResult.isOk());
1293 ASSERT_NE(closeHandle.get(), nullptr);
1294
1295 closeHandle->close();
1296}
1297
Weilin Xub23d0ea2022-05-09 18:26:23 +00001298GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
1299INSTANTIATE_TEST_SUITE_P(
1300 PerInstance, BroadcastRadioHalTest,
1301 testing::ValuesIn(::android::getAidlHalInstanceNames(IBroadcastRadio::descriptor)),
1302 ::android::PrintInstanceNameToString);
1303
1304} // namespace aidl::android::hardware::broadcastradio::vts
1305
1306int main(int argc, char** argv) {
1307 android::base::SetDefaultTag("BcRadio.vts");
1308 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1309 ::testing::InitGoogleTest(&argc, argv);
1310 ABinderProcess_setThreadPoolMaxThreadCount(4);
1311 ABinderProcess_startThreadPool();
1312 return RUN_ALL_TESTS();
1313}