blob: 8bee1b2d1f26e6fc952ac901b101ecbeb9690ff5 [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 Xub23d0ea2022-05-09 18:26:23 +000035#include <cutils/bitops.h>
36#include <gmock/gmock.h>
37
38#include <chrono>
Weilin Xu3729b0b2023-06-21 22:49:04 +000039#include <condition_variable>
Weilin Xub23d0ea2022-05-09 18:26:23 +000040#include <optional>
41#include <regex>
42
43namespace aidl::android::hardware::broadcastradio::vts {
44
45namespace {
46
47using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
48using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
Weilin Xu0d4207d2022-12-09 00:37:44 +000049using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
Weilin Xub23d0ea2022-05-09 18:26:23 +000050using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
51using ::ndk::ScopedAStatus;
52using ::ndk::SharedRefBase;
53using ::std::string;
54using ::std::vector;
55using ::testing::_;
56using ::testing::AnyNumber;
57using ::testing::ByMove;
58using ::testing::DoAll;
59using ::testing::Invoke;
60using ::testing::SaveArg;
61
62namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
63
Weilin Xu3277a212022-09-01 19:08:17 +000064const ConfigFlag kConfigFlagValues[] = {
65 ConfigFlag::FORCE_MONO,
66 ConfigFlag::FORCE_ANALOG,
67 ConfigFlag::FORCE_DIGITAL,
68 ConfigFlag::RDS_AF,
69 ConfigFlag::RDS_REG,
70 ConfigFlag::DAB_DAB_LINKING,
71 ConfigFlag::DAB_FM_LINKING,
72 ConfigFlag::DAB_DAB_SOFT_LINKING,
73 ConfigFlag::DAB_FM_SOFT_LINKING,
74};
75
Weilin Xub23d0ea2022-05-09 18:26:23 +000076void printSkipped(const string& msg) {
77 const auto testInfo = testing::UnitTest::GetInstance()->current_test_info();
78 LOG(INFO) << "[ SKIPPED ] " << testInfo->test_case_name() << "." << testInfo->name()
79 << " with message: " << msg;
80}
81
Weilin Xu3277a212022-09-01 19:08:17 +000082bool isValidAmFmFreq(int64_t freq) {
83 ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
84 return bcutils::isValid(id);
85}
86
87void validateRange(const AmFmBandRange& range) {
88 EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
89 EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
90 EXPECT_LT(range.lowerBound, range.upperBound);
91 EXPECT_GT(range.spacing, 0u);
92 EXPECT_EQ((range.upperBound - range.lowerBound) % range.spacing, 0u);
93}
94
95bool supportsFM(const AmFmRegionConfig& config) {
96 for (const auto& range : config.ranges) {
97 if (bcutils::getBand(range.lowerBound) == bcutils::FrequencyBand::FM) {
98 return true;
99 }
100 }
101 return false;
102}
103
Weilin Xub23d0ea2022-05-09 18:26:23 +0000104} // namespace
105
Weilin Xu3729b0b2023-06-21 22:49:04 +0000106class CallbackFlag final {
Weilin Xub23d0ea2022-05-09 18:26:23 +0000107 public:
Weilin Xu3729b0b2023-06-21 22:49:04 +0000108 CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
109 /**
110 * Notify that the callback is called.
111 */
112 void notify() {
113 std::unique_lock<std::mutex> lock(mMutex);
114 mCalled = true;
115 lock.unlock();
116 mCv.notify_all();
117 };
118
119 /**
120 * Wait for the timeout passed into the constructor.
121 */
122 bool wait() {
123 std::unique_lock<std::mutex> lock(mMutex);
124 return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
125 [this] { return mCalled; });
126 };
127
128 /**
129 * Reset the callback to not called.
130 */
131 void reset() {
132 std::unique_lock<std::mutex> lock(mMutex);
133 mCalled = false;
134 }
135
136 private:
137 std::mutex mMutex;
138 bool mCalled GUARDED_BY(mMutex) = false;
139 std::condition_variable mCv;
140 int mTimeoutMs;
141};
142
143class TunerCallbackImpl final : public BnTunerCallback {
144 public:
145 TunerCallbackImpl();
Weilin Xu0d4207d2022-12-09 00:37:44 +0000146 ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000147 ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
148 ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
Weilin Xu3729b0b2023-06-21 22:49:04 +0000149 ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
150 ScopedAStatus onAntennaStateChange(bool connected) override;
151 ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000152
Weilin Xu3729b0b2023-06-21 22:49:04 +0000153 bool waitOnCurrentProgramInfoChangedCallback();
154 bool waitProgramReady();
155 void reset();
156
157 bool getAntennaConnectionState();
158 ProgramInfo getCurrentProgramInfo();
159 bcutils::ProgramInfoSet getProgramList();
160
161 private:
Weilin Xub23d0ea2022-05-09 18:26:23 +0000162 std::mutex mLock;
Weilin Xu3729b0b2023-06-21 22:49:04 +0000163 bool mAntennaConnectionState GUARDED_BY(mLock);
164 ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000165 bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
Weilin Xu3729b0b2023-06-21 22:49:04 +0000166 CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
167 CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
Weilin Xub23d0ea2022-05-09 18:26:23 +0000168};
169
170struct AnnouncementListenerMock : public BnAnnouncementListener {
171 MOCK_METHOD1(onListUpdated, ScopedAStatus(const vector<Announcement>&));
172};
173
174class BroadcastRadioHalTest : public testing::TestWithParam<string> {
175 protected:
176 void SetUp() override;
177 void TearDown() override;
178
179 bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
180 std::optional<bcutils::ProgramInfoSet> getProgramList();
181 std::optional<bcutils::ProgramInfoSet> getProgramList(const ProgramFilter& filter);
182
183 std::shared_ptr<IBroadcastRadio> mModule;
184 Properties mProperties;
Weilin Xu3729b0b2023-06-21 22:49:04 +0000185 std::shared_ptr<TunerCallbackImpl> mCallback;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000186};
187
188MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) {
189 vector<int> ids = bcutils::getAllIds(arg.selector, id.type);
190 return ids.end() != find(ids.begin(), ids.end(), id.value);
191}
192
Weilin Xu3729b0b2023-06-21 22:49:04 +0000193TunerCallbackImpl::TunerCallbackImpl() {
194 mAntennaConnectionState = true;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000195}
196
Weilin Xu3729b0b2023-06-21 22:49:04 +0000197ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
Weilin Xu0d4207d2022-12-09 00:37:44 +0000198 LOG(DEBUG) << "Tune failed for selector" << selector.toString();
199 EXPECT_TRUE(result == Result::CANCELED);
200 return ndk::ScopedAStatus::ok();
201}
202
Weilin Xu3729b0b2023-06-21 22:49:04 +0000203ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
204 LOG(DEBUG) << "onCurrentProgramInfoChanged called";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000205 for (const auto& id : info.selector) {
206 EXPECT_NE(id.type, IdentifierType::INVALID);
207 }
208
209 IdentifierType logically = info.logicallyTunedTo.type;
210 // This field is required for currently tuned program and should be INVALID
211 // for entries from the program list.
212 EXPECT_TRUE(logically == IdentifierType::AMFM_FREQUENCY_KHZ ||
213 logically == IdentifierType::RDS_PI ||
214 logically == IdentifierType::HD_STATION_ID_EXT ||
215 logically == IdentifierType::DAB_SID_EXT ||
216 logically == IdentifierType::DRMO_SERVICE_ID ||
217 logically == IdentifierType::SXM_SERVICE_ID ||
218 (logically >= IdentifierType::VENDOR_START &&
219 logically <= IdentifierType::VENDOR_END) ||
220 logically > IdentifierType::SXM_CHANNEL);
221
222 IdentifierType physically = info.physicallyTunedTo.type;
223 // ditto (see "logically" above)
224 EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
Weilin Xu0d4207d2022-12-09 00:37:44 +0000225 physically == IdentifierType::DAB_FREQUENCY_KHZ ||
Weilin Xub23d0ea2022-05-09 18:26:23 +0000226 physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
227 physically == IdentifierType::SXM_CHANNEL ||
228 (physically >= IdentifierType::VENDOR_START &&
229 physically <= IdentifierType::VENDOR_END) ||
230 physically > IdentifierType::SXM_CHANNEL);
231
232 if (logically == IdentifierType::AMFM_FREQUENCY_KHZ) {
233 std::optional<string> ps = bcutils::getMetadataString(info, Metadata::rdsPs);
234 if (ps.has_value()) {
235 EXPECT_NE(::android::base::Trim(*ps), "")
236 << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
237 }
238 }
239
Weilin Xu3729b0b2023-06-21 22:49:04 +0000240 {
241 std::lock_guard<std::mutex> lk(mLock);
242 mCurrentProgramInfo = info;
243 }
244
245 mOnCurrentProgramInfoChangedFlag.notify();
246 return ndk::ScopedAStatus::ok();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000247}
248
Weilin Xu3729b0b2023-06-21 22:49:04 +0000249ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
250 LOG(DEBUG) << "onProgramListUpdated called";
251 {
252 std::lock_guard<std::mutex> lk(mLock);
253 updateProgramList(chunk, &mProgramList);
254 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000255
256 if (chunk.complete) {
Weilin Xu3729b0b2023-06-21 22:49:04 +0000257 mOnProgramListReadyFlag.notify();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000258 }
259
260 return ndk::ScopedAStatus::ok();
261}
262
Weilin Xu3729b0b2023-06-21 22:49:04 +0000263ScopedAStatus TunerCallbackImpl::onParametersUpdated(
264 [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
265 return ndk::ScopedAStatus::ok();
266}
267
268ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
269 if (!connected) {
270 std::lock_guard<std::mutex> lk(mLock);
271 mAntennaConnectionState = false;
272 }
273 return ndk::ScopedAStatus::ok();
274}
275
276ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
277 [[maybe_unused]] bool in_value) {
278 return ndk::ScopedAStatus::ok();
279}
280
281bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
282 return mOnCurrentProgramInfoChangedFlag.wait();
283}
284
285bool TunerCallbackImpl::waitProgramReady() {
286 return mOnProgramListReadyFlag.wait();
287}
288
289void TunerCallbackImpl::reset() {
290 mOnCurrentProgramInfoChangedFlag.reset();
291 mOnProgramListReadyFlag.reset();
292}
293
294bool TunerCallbackImpl::getAntennaConnectionState() {
295 std::lock_guard<std::mutex> lk(mLock);
296 return mAntennaConnectionState;
297}
298
299ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
300 std::lock_guard<std::mutex> lk(mLock);
301 return mCurrentProgramInfo;
302}
303
304bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
305 std::lock_guard<std::mutex> lk(mLock);
306 return mProgramList;
307}
308
Weilin Xub23d0ea2022-05-09 18:26:23 +0000309void BroadcastRadioHalTest::SetUp() {
310 EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
311
312 // lookup AIDL service (radio module)
313 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
314 ASSERT_NE(binder, nullptr);
315 mModule = IBroadcastRadio::fromBinder(ndk::SpAIBinder(binder));
316 ASSERT_NE(mModule, nullptr) << "Couldn't find broadcast radio HAL implementation";
317
318 // get module properties
319 auto propResult = mModule->getProperties(&mProperties);
320
321 ASSERT_TRUE(propResult.isOk());
322 EXPECT_FALSE(mProperties.maker.empty());
323 EXPECT_FALSE(mProperties.product.empty());
324 EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
325
Weilin Xu3729b0b2023-06-21 22:49:04 +0000326 mCallback = SharedRefBase::make<TunerCallbackImpl>();
327
Weilin Xub23d0ea2022-05-09 18:26:23 +0000328 // set callback
329 EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
330}
331
332void BroadcastRadioHalTest::TearDown() {
333 if (mModule) {
334 ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
335 }
Weilin Xu3729b0b2023-06-21 22:49:04 +0000336 if (mCallback) {
337 // we expect the antenna is connected through the whole test
338 EXPECT_TRUE(mCallback->getAntennaConnectionState());
339 mCallback = nullptr;
340 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000341}
342
343bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
344 auto halResult = mModule->getAmFmRegionConfig(full, config);
345
346 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
347 return false;
348 }
349
350 EXPECT_TRUE(halResult.isOk());
351 return halResult.isOk();
352}
353
354std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
355 ProgramFilter emptyFilter = {};
356 return getProgramList(emptyFilter);
357}
358
359std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
360 const ProgramFilter& filter) {
Weilin Xu3729b0b2023-06-21 22:49:04 +0000361 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000362
363 auto startResult = mModule->startProgramListUpdates(filter);
364
365 if (startResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
366 printSkipped("Program list not supported");
367 return std::nullopt;
368 }
369 EXPECT_TRUE(startResult.isOk());
370 if (!startResult.isOk()) {
371 return std::nullopt;
372 }
Weilin Xu3729b0b2023-06-21 22:49:04 +0000373 EXPECT_TRUE(mCallback->waitProgramReady());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000374
375 auto stopResult = mModule->stopProgramListUpdates();
376
377 EXPECT_TRUE(stopResult.isOk());
378
Weilin Xu3729b0b2023-06-21 22:49:04 +0000379 return mCallback->getProgramList();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000380}
381
382/**
383 * Test setting tuner callback to null.
384 *
385 * Verifies that:
386 * - Setting to a null tuner callback results with INVALID_ARGUMENTS.
387 */
388TEST_P(BroadcastRadioHalTest, TunerCallbackFailsWithNull) {
389 LOG(DEBUG) << "TunerCallbackFailsWithNull Test";
390
391 auto halResult = mModule->setTunerCallback(nullptr);
392
393 EXPECT_EQ(halResult.getServiceSpecificError(), resultToInt(Result::INVALID_ARGUMENTS));
394}
395
396/**
Weilin Xu3277a212022-09-01 19:08:17 +0000397 * Test fetching AM/FM regional configuration.
398 *
399 * Verifies that:
400 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
401 * - FM Deemphasis and RDS are correctly configured for FM-capable radio;
402 */
403TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
404 LOG(DEBUG) << "GetAmFmRegionConfig Test";
405
406 AmFmRegionConfig config;
407
408 bool supported = getAmFmRegionConfig(/* full= */ false, &config);
409
410 if (!supported) {
411 printSkipped("AM/FM not supported");
412 return;
413 }
414
415 EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
416 EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmRds)), 1);
417
418 if (supportsFM(config)) {
419 EXPECT_EQ(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
420 }
421}
422
423/**
424 * Test fetching ranges of 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 * - there is at least one AM/FM band configured;
429 * - all channel grids (frequency ranges and spacings) are valid;
430 * - seek spacing is a multiple of the manual spacing value.
431 */
432TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigRanges) {
433 LOG(DEBUG) << "GetAmFmRegionConfigRanges Test";
434
435 AmFmRegionConfig config;
436
437 bool supported = getAmFmRegionConfig(/* full= */ false, &config);
438
439 if (!supported) {
440 printSkipped("AM/FM not supported");
441 return;
442 }
443
444 EXPECT_GT(config.ranges.size(), 0u);
445 for (const auto& range : config.ranges) {
446 validateRange(range);
447 EXPECT_EQ(range.seekSpacing % range.spacing, 0u);
448 EXPECT_GE(range.seekSpacing, range.spacing);
449 }
450}
451
452/**
453 * Test fetching FM regional capabilities.
454 *
455 * Verifies that:
456 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
457 * - there is at least one de-emphasis filter mode supported for FM-capable radio;
458 */
459TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesForFM) {
460 LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesForFM Test";
461
462 AmFmRegionConfig config;
463
464 bool supported = getAmFmRegionConfig(/* full= */ true, &config);
465
466 if (supported && supportsFM(config)) {
467 EXPECT_GE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
468 } else {
469 printSkipped("FM not supported");
470 }
471}
472
473/**
474 * Test fetching the ranges of AM/FM regional capabilities.
475 *
476 * Verifies that:
477 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
478 * - there is at least one AM/FM range supported;
479 * - all channel grids (frequency ranges and spacings) are valid;
480 * - seek spacing is not set.
481 */
482TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesRanges) {
483 LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesRanges Test";
484
485 AmFmRegionConfig config;
486
487 bool supported = getAmFmRegionConfig(/* full= */ true, &config);
488
489 if (!supported) {
490 printSkipped("AM/FM not supported");
491 return;
492 }
493
494 EXPECT_GT(config.ranges.size(), 0u);
495
496 for (const auto& range : config.ranges) {
497 validateRange(range);
498 EXPECT_EQ(range.seekSpacing, 0u);
499 }
500}
501
502/**
503 * Test fetching DAB regional configuration.
504 *
505 * Verifies that:
506 * - DAB regional configuration is either set at startup or not supported at all by the hardware;
507 * - all channel labels match correct format;
508 * - all channel frequencies are in correct range.
509 */
510TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
511 LOG(DEBUG) << "GetDabRegionConfig Test";
512 vector<DabTableEntry> config;
513
514 auto halResult = mModule->getDabRegionConfig(&config);
515
516 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
517 printSkipped("DAB not supported");
518 return;
519 }
520 ASSERT_TRUE(halResult.isOk());
521
522 std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
523
524 for (const auto& entry : config) {
525 EXPECT_TRUE(std::regex_match(string(entry.label), re));
526
527 ProgramIdentifier id =
528 bcutils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, entry.frequencyKhz);
529 EXPECT_TRUE(bcutils::isValid(id));
530 }
531}
532
533/**
Weilin Xub23d0ea2022-05-09 18:26:23 +0000534 * Test tuning without tuner callback set.
535 *
536 * Verifies that:
537 * - No tuner callback set results in INVALID_STATE, regardless of whether the selector is
538 * supported.
539 */
540TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) {
541 LOG(DEBUG) << "TuneFailsWithoutTunerCallback Test";
542
543 mModule->unsetTunerCallback();
544 int64_t freq = 90900; // 90.9 FM
545 ProgramSelector sel = makeSelectorAmfm(freq);
546
547 auto result = mModule->tune(sel);
548
549 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
550}
551
552/**
553 * Test tuning with selectors that can be not supported.
554 *
555 * Verifies that:
556 * - if the selector is not supported, an invalid value results with NOT_SUPPORTED, regardless of
557 * whether it is valid;
558 * - if it is supported, the test is ignored;
559 */
560TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
Weilin Xu3729b0b2023-06-21 22:49:04 +0000561 LOG(DEBUG) << "TuneFailsWithNotSupported Test";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000562
563 vector<ProgramIdentifier> supportTestId = {
564 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid
565 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 94900), // valid
566 makeIdentifier(IdentifierType::RDS_PI, 0x10000), // invalid
567 makeIdentifier(IdentifierType::RDS_PI, 0x1001), // valid
568 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000), // invalid
569 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x10000001), // valid
570 makeIdentifier(IdentifierType::DAB_SID_EXT, 0), // invalid
571 makeIdentifier(IdentifierType::DAB_SID_EXT, 0xA00001), // valid
572 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000), // invalid
573 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x10000001), // valid
574 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000), // invalid
575 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x10000001), // valid
576 };
577
578 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
579 for (const auto& id : supportTestId) {
580 ProgramSelector sel{id, {}};
581
Weilin Xub23d0ea2022-05-09 18:26:23 +0000582 if (!bcutils::isSupported(mProperties, sel)) {
Weilin Xu3729b0b2023-06-21 22:49:04 +0000583 auto result = mModule->tune(sel);
584
Weilin Xub23d0ea2022-05-09 18:26:23 +0000585 EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
586 }
587 }
588}
589
590/**
591 * Test tuning with invalid selectors.
592 *
593 * Verifies that:
594 * - if the selector is not supported, it's ignored;
595 * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
596 */
597TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
598 LOG(DEBUG) << "TuneFailsWithInvalid Test";
599
600 vector<ProgramIdentifier> invalidId = {
601 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),
602 makeIdentifier(IdentifierType::RDS_PI, 0x10000),
603 makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
604 makeIdentifier(IdentifierType::DAB_SID_EXT, 0),
605 makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
606 makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
607 };
608
609 auto invalidArgumentsError = resultToInt(Result::INVALID_ARGUMENTS);
610 for (const auto& id : invalidId) {
611 ProgramSelector sel{id, {}};
612
Weilin Xub23d0ea2022-05-09 18:26:23 +0000613 if (bcutils::isSupported(mProperties, sel)) {
Weilin Xu3729b0b2023-06-21 22:49:04 +0000614 auto result = mModule->tune(sel);
615
Weilin Xub23d0ea2022-05-09 18:26:23 +0000616 EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
617 }
618 }
619}
620
621/**
622 * Test tuning with empty program selector.
623 *
624 * Verifies that:
625 * - tune fails with NOT_SUPPORTED when program selector is not initialized.
626 */
627TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
628 LOG(DEBUG) << "TuneFailsWithEmpty Test";
629
630 // Program type is 1-based, so 0 will always be invalid.
631 ProgramSelector sel = {};
632
633 auto result = mModule->tune(sel);
634
635 ASSERT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
636}
637
638/**
639 * Test tuning with FM selector.
640 *
641 * Verifies that:
642 * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
643 * - if it is supported, the method succeeds;
644 * - after a successful tune call, onCurrentProgramInfoChanged callback is
645 * invoked carrying a proper selector;
646 * - program changes exactly to what was requested.
647 */
648TEST_P(BroadcastRadioHalTest, FmTune) {
649 LOG(DEBUG) << "FmTune Test";
650
651 int64_t freq = 90900; // 90.9 FM
652 ProgramSelector sel = makeSelectorAmfm(freq);
653 // try tuning
Weilin Xu3729b0b2023-06-21 22:49:04 +0000654 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000655 auto result = mModule->tune(sel);
656
657 // expect a failure if it's not supported
658 if (!bcutils::isSupported(mProperties, sel)) {
659 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
660 return;
661 }
662
663 // expect a callback if it succeeds
664 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000665 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
666 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000667
668 LOG(DEBUG) << "Current program info: " << infoCb.toString();
669
670 // it should tune exactly to what was requested
671 vector<int> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
672 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
673 << "FM freq " << freq << " kHz is not sent back by callback.";
674}
675
676/**
677 * Test tuning with DAB selector.
678 *
679 * Verifies that:
680 * - if DAB selector is not supported, the method returns NOT_SUPPORTED;
681 * - if it is supported, the method succeeds;
682 * - after a successful tune call, onCurrentProgramInfoChanged callback is
683 * invoked carrying a proper selector;
684 * - program changes exactly to what was requested.
685 */
686TEST_P(BroadcastRadioHalTest, DabTune) {
687 LOG(DEBUG) << "DabTune Test";
688 vector<DabTableEntry> config;
689
690 auto halResult = mModule->getDabRegionConfig(&config);
691
692 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
693 printSkipped("DAB not supported");
694 return;
695 }
696 ASSERT_TRUE(halResult.isOk());
697 ASSERT_NE(config.size(), 0U);
698
Weilin Xu0d4207d2022-12-09 00:37:44 +0000699 auto programList = getProgramList();
700
701 if (!programList) {
702 printSkipped("Empty DAB station list, tune cannot be performed");
703 return;
704 }
705
Weilin Xub23d0ea2022-05-09 18:26:23 +0000706 ProgramSelector sel = {};
Weilin Xu0d4207d2022-12-09 00:37:44 +0000707 uint64_t freq = 0;
708 bool dabStationPresent = false;
709 for (auto&& programInfo : *programList) {
710 if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
711 continue;
712 }
713 for (auto&& config_entry : config) {
714 if (config_entry.frequencyKhz ==
715 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
716 freq = config_entry.frequencyKhz;
717 break;
718 }
719 }
720 // Do not trigger a tune request if the programList entry does not contain
721 // a valid DAB frequency.
722 if (freq == 0) {
723 continue;
724 }
725 int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
726 int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
727 sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
728 dabStationPresent = true;
729 break;
730 }
731
732 if (!dabStationPresent) {
733 printSkipped("No DAB stations in the list, tune cannot be performed");
734 return;
735 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000736
737 // try tuning
Weilin Xub23d0ea2022-05-09 18:26:23 +0000738
739 auto result = mModule->tune(sel);
740
741 // expect a failure if it's not supported
742 if (!bcutils::isSupported(mProperties, sel)) {
743 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
744 return;
745 }
746
747 // expect a callback if it succeeds
748 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000749 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
750 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
751
Weilin Xub23d0ea2022-05-09 18:26:23 +0000752 LOG(DEBUG) << "Current program info: " << infoCb.toString();
753
754 // it should tune exactly to what was requested
755 vector<int> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
756 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
757 << "DAB freq " << freq << " kHz is not sent back by callback.";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000758}
759
760/**
761 * Test seeking to next/prev station via IBroadcastRadio::seek().
762 *
763 * Verifies that:
764 * - the method succeeds;
Weilin Xu3729b0b2023-06-21 22:49:04 +0000765 * - the program info is changed within kTuneTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000766 * - works both directions and with or without skipping sub-channel.
767 */
768TEST_P(BroadcastRadioHalTest, Seek) {
769 LOG(DEBUG) << "Seek Test";
770
Weilin Xu3729b0b2023-06-21 22:49:04 +0000771 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000772
773 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
774
775 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
776 printSkipped("Seek not supported");
777 return;
778 }
779
780 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000781 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000782
Weilin Xu3729b0b2023-06-21 22:49:04 +0000783 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000784
785 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
786
787 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000788 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000789}
790
791/**
792 * Test seeking without tuner callback set.
793 *
794 * Verifies that:
795 * - No tuner callback set results in INVALID_STATE.
796 */
797TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
798 LOG(DEBUG) << "SeekFailsWithoutTunerCallback Test";
799
800 mModule->unsetTunerCallback();
801
802 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
803
804 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
805
806 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
807
808 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
809}
810
811/**
812 * Test step operation.
813 *
814 * Verifies that:
815 * - the method succeeds or returns NOT_SUPPORTED;
Weilin Xu3729b0b2023-06-21 22:49:04 +0000816 * - the program info is changed within kTuneTimeoutMs if the method succeeded;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000817 * - works both directions.
818 */
819TEST_P(BroadcastRadioHalTest, Step) {
820 LOG(DEBUG) << "Step Test";
821
Weilin Xu3729b0b2023-06-21 22:49:04 +0000822 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000823
824 auto result = mModule->step(/* in_directionUp= */ true);
825
826 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
827 printSkipped("Step not supported");
828 return;
829 }
830 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000831 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000832
Weilin Xu3729b0b2023-06-21 22:49:04 +0000833 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000834
835 result = mModule->step(/* in_directionUp= */ false);
836
837 EXPECT_TRUE(result.isOk());
Weilin Xu3729b0b2023-06-21 22:49:04 +0000838 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000839}
840
841/**
842 * Test step operation without tuner callback set.
843 *
844 * Verifies that:
845 * - No tuner callback set results in INVALID_STATE.
846 */
847TEST_P(BroadcastRadioHalTest, StepFailsWithoutTunerCallback) {
848 LOG(DEBUG) << "StepFailsWithoutTunerCallback Test";
849
850 mModule->unsetTunerCallback();
851
852 auto result = mModule->step(/* in_directionUp= */ true);
853
854 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
855
856 result = mModule->step(/* in_directionUp= */ false);
857
858 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
859}
860
861/**
862 * Test tune cancellation.
863 *
864 * Verifies that:
865 * - the method does not crash after being invoked multiple times.
866 *
867 * Since cancel() might be called after the HAL completes an operation (tune, seek, and step)
868 * and before the callback completions, the operation might not be actually canceled and the
869 * effect of cancel() is not deterministic to be tested here.
870 */
871TEST_P(BroadcastRadioHalTest, Cancel) {
872 LOG(DEBUG) << "Cancel Test";
873
874 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
875 for (int i = 0; i < 10; i++) {
876 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
877
878 if (result.getServiceSpecificError() == notSupportedError) {
879 printSkipped("Cancel is skipped because of seek not supported");
880 return;
881 }
882 EXPECT_TRUE(result.isOk());
883
884 auto cancelResult = mModule->cancel();
885
886 ASSERT_TRUE(cancelResult.isOk());
887 }
888}
889
890/**
Weilin Xu3277a212022-09-01 19:08:17 +0000891 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
892 *
893 * Verifies that:
894 * - callback is called for empty parameters set.
895 */
896TEST_P(BroadcastRadioHalTest, NoParameters) {
897 LOG(DEBUG) << "NoParameters Test";
898
899 vector<VendorKeyValue> parametersResults = {};
900
901 auto halResult = mModule->setParameters({}, &parametersResults);
902
903 ASSERT_TRUE(halResult.isOk());
904 ASSERT_EQ(parametersResults.size(), 0u);
905
906 parametersResults.clear();
907
908 halResult = mModule->getParameters({}, &parametersResults);
909
910 ASSERT_TRUE(halResult.isOk());
911 ASSERT_EQ(parametersResults.size(), 0u);
912}
913
914/**
915 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
916 *
917 * Verifies that:
918 * - unknown parameters are ignored;
919 * - callback is called also for empty results set.
920 */
921TEST_P(BroadcastRadioHalTest, UnknownParameters) {
922 LOG(DEBUG) << "UnknownParameters Test";
923
924 vector<VendorKeyValue> parametersResults = {};
925
926 auto halResult =
927 mModule->setParameters({{"com.android.unknown", "sample"}}, &parametersResults);
928
929 ASSERT_TRUE(halResult.isOk());
930 ASSERT_EQ(parametersResults.size(), 0u);
931
932 parametersResults.clear();
933
934 halResult = mModule->getParameters({"com.android.unknown*", "sample"}, &parametersResults);
935
936 ASSERT_TRUE(halResult.isOk());
937 ASSERT_EQ(parametersResults.size(), 0u);
938}
939
940/**
941 * Test geting image of invalid ID.
942 *
943 * Verifies that:
944 * - getImage call handles argument 0 gracefully.
945 */
946TEST_P(BroadcastRadioHalTest, GetNoImage) {
947 LOG(DEBUG) << "GetNoImage Test";
948 vector<uint8_t> rawImage;
949
950 auto result = mModule->getImage(IBroadcastRadio::INVALID_IMAGE, &rawImage);
951
952 ASSERT_TRUE(result.isOk());
953 ASSERT_EQ(rawImage.size(), 0u);
954}
955
956/**
957 * Test getting config flags.
958 *
959 * Verifies that:
960 * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
961 * - call success or failure is consistent with setConfigFlag.
962 */
963TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
964 LOG(DEBUG) << "FetchConfigFlags Test";
965
966 for (const auto& flag : kConfigFlagValues) {
967 bool gotValue = false;
968
969 auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
970
971 if (halResult.getServiceSpecificError() != resultToInt(Result::NOT_SUPPORTED) &&
972 halResult.getServiceSpecificError() != resultToInt(Result::INVALID_STATE)) {
973 ASSERT_TRUE(halResult.isOk());
974 }
975
976 // set must fail or succeed the same way as get
977 auto setResult = mModule->setConfigFlag(flag, /* value= */ false);
978
979 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
980 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
981
982 setResult = mModule->setConfigFlag(flag, /* value= */ true);
983
984 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
985 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
986 }
987}
988
989/**
990 * Test setting config flags.
991 *
992 * Verifies that:
993 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
994 * - isConfigFlagSet reflects the state requested immediately after the set call.
995 */
996TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
997 LOG(DEBUG) << "SetConfigFlags Test";
998
999 auto get = [&](ConfigFlag flag) -> bool {
1000 bool* gotValue = nullptr;
1001
1002 auto halResult = mModule->isConfigFlagSet(flag, gotValue);
1003
1004 EXPECT_FALSE(gotValue == nullptr);
1005 EXPECT_TRUE(halResult.isOk());
1006 return *gotValue;
1007 };
1008
1009 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
1010 auto invalidStateError = resultToInt(Result::INVALID_STATE);
1011 for (const auto& flag : kConfigFlagValues) {
1012 auto result = mModule->setConfigFlag(flag, /* value= */ false);
1013
1014 if (result.getServiceSpecificError() == notSupportedError ||
1015 result.getServiceSpecificError() == invalidStateError) {
1016 // setting to true must result in the same error as false
1017 auto secondResult = mModule->setConfigFlag(flag, /* value= */ true);
1018
1019 EXPECT_TRUE((result.isOk() && secondResult.isOk()) ||
1020 result.getServiceSpecificError() == secondResult.getServiceSpecificError());
1021 continue;
1022 } else {
1023 ASSERT_TRUE(result.isOk());
1024 }
1025
1026 // verify false is set
1027 bool value = get(flag);
1028 EXPECT_FALSE(value);
1029
1030 // try setting true this time
1031 result = mModule->setConfigFlag(flag, /* value= */ true);
1032
1033 ASSERT_TRUE(result.isOk());
1034 value = get(flag);
1035 EXPECT_TRUE(value);
1036
1037 // false again
1038 result = mModule->setConfigFlag(flag, /* value= */ false);
1039
1040 ASSERT_TRUE(result.isOk());
1041 value = get(flag);
1042 EXPECT_FALSE(value);
1043 }
1044}
1045
1046/**
Weilin Xub23d0ea2022-05-09 18:26:23 +00001047 * Test getting program list using empty program filter.
1048 *
1049 * Verifies that:
1050 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu3729b0b2023-06-21 22:49:04 +00001051 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001052 * - stopProgramListUpdates does not crash.
1053 */
1054TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
1055 LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
1056
1057 getProgramList();
1058}
1059
1060/**
1061 * Test getting program list using AMFM frequency program filter.
1062 *
1063 * Verifies that:
1064 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu3729b0b2023-06-21 22:49:04 +00001065 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001066 * - stopProgramListUpdates does not crash;
1067 * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
1068 * AMFM program matches the expected result.
1069 */
1070TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
1071 LOG(DEBUG) << "GetProgramListFromAmFmFilter Test";
1072
1073 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1074 if (!completeList) {
1075 printSkipped("No program list available");
1076 return;
1077 }
1078
1079 ProgramFilter amfmFilter = {};
1080 int expectedResultSize = 0;
1081 uint64_t expectedFreq = 0;
1082 for (const auto& program : *completeList) {
1083 vector<int> amfmIds =
1084 bcutils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
1085 EXPECT_LE(amfmIds.size(), 1u);
1086 if (amfmIds.size() == 0) {
1087 continue;
1088 }
1089
1090 if (expectedResultSize == 0) {
1091 expectedFreq = amfmIds[0];
1092 amfmFilter.identifiers = {
1093 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, expectedFreq)};
1094 expectedResultSize = 1;
1095 } else if (amfmIds[0] == expectedFreq) {
1096 expectedResultSize++;
1097 }
1098 }
1099
1100 if (expectedResultSize == 0) {
1101 printSkipped("No Am/FM programs available");
1102 return;
1103 }
1104 std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
1105 ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
1106}
1107
1108/**
1109 * Test getting program list using DAB ensemble program filter.
1110 *
1111 * Verifies that:
1112 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu3729b0b2023-06-21 22:49:04 +00001113 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001114 * - stopProgramListUpdates does not crash;
1115 * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
1116 * program matches the expected result.
1117 */
1118TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
1119 LOG(DEBUG) << "GetProgramListFromDabFilter Test";
1120
1121 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1122 if (!completeList) {
1123 printSkipped("No program list available");
1124 return;
1125 }
1126
1127 ProgramFilter dabFilter = {};
1128 int expectedResultSize = 0;
1129 uint64_t expectedEnsemble = 0;
1130 for (const auto& program : *completeList) {
1131 auto dabEnsembles = bcutils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
1132 EXPECT_LE(dabEnsembles.size(), 1u);
1133 if (dabEnsembles.size() == 0) {
1134 continue;
1135 }
1136
1137 if (expectedResultSize == 0) {
1138 expectedEnsemble = dabEnsembles[0];
1139 dabFilter.identifiers = {
1140 makeIdentifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
1141 expectedResultSize = 1;
1142 } else if (dabEnsembles[0] == expectedEnsemble) {
1143 expectedResultSize++;
1144 }
1145 }
1146
1147 if (expectedResultSize == 0) {
1148 printSkipped("No DAB programs available");
1149 return;
1150 }
1151 std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
1152 ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
1153}
1154
Weilin Xu3277a212022-09-01 19:08:17 +00001155/**
1156 * Test HD_STATION_NAME correctness.
1157 *
1158 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
1159 * - the program provides station name in its metadata;
1160 * - the identifier matches the name;
1161 * - there is only one identifier of that type.
1162 */
1163TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
1164 LOG(DEBUG) << "HdRadioStationNameId Test";
1165
1166 std::optional<bcutils::ProgramInfoSet> list = getProgramList();
1167 if (!list) {
1168 printSkipped("No program list");
1169 return;
1170 }
1171
1172 for (const auto& program : *list) {
1173 vector<int> nameIds = bcutils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
1174 EXPECT_LE(nameIds.size(), 1u);
1175 if (nameIds.size() == 0) {
1176 continue;
1177 }
1178
1179 std::optional<string> name = bcutils::getMetadataString(program, Metadata::programName);
1180 if (!name) {
1181 name = bcutils::getMetadataString(program, Metadata::rdsPs);
1182 }
1183 ASSERT_TRUE(name.has_value());
1184
1185 ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
1186 EXPECT_EQ(nameIds[0], expectedId.value);
1187 }
1188}
1189
1190/**
1191 * Test announcement listener registration.
1192 *
1193 * Verifies that:
1194 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
1195 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
1196 * - closing handle does not crash.
1197 */
1198TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
1199 LOG(DEBUG) << "AnnouncementListenerRegistration Test";
1200 std::shared_ptr<AnnouncementListenerMock> listener =
1201 SharedRefBase::make<AnnouncementListenerMock>();
1202 std::shared_ptr<ICloseHandle> closeHandle = nullptr;
1203
1204 auto halResult = mModule->registerAnnouncementListener(listener, {AnnouncementType::EMERGENCY},
1205 &closeHandle);
1206
1207 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
1208 ASSERT_EQ(closeHandle.get(), nullptr);
1209 printSkipped("Announcements not supported");
1210 return;
1211 }
1212
1213 ASSERT_TRUE(halResult.isOk());
1214 ASSERT_NE(closeHandle.get(), nullptr);
1215
1216 closeHandle->close();
1217}
1218
Weilin Xub23d0ea2022-05-09 18:26:23 +00001219GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
1220INSTANTIATE_TEST_SUITE_P(
1221 PerInstance, BroadcastRadioHalTest,
1222 testing::ValuesIn(::android::getAidlHalInstanceNames(IBroadcastRadio::descriptor)),
1223 ::android::PrintInstanceNameToString);
1224
1225} // namespace aidl::android::hardware::broadcastradio::vts
1226
1227int main(int argc, char** argv) {
1228 android::base::SetDefaultTag("BcRadio.vts");
1229 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1230 ::testing::InitGoogleTest(&argc, argv);
1231 ABinderProcess_setThreadPoolMaxThreadCount(4);
1232 ABinderProcess_startThreadPool();
1233 return RUN_ALL_TESTS();
1234}