blob: 5e8a5cfa4578ce06ccb83ba70a07d3aa9ddbda47 [file] [log] [blame]
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -08001/*
2 * Copyright (C) 2017 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
Tomasz Wasilczykdb902862018-01-14 17:22:03 -080017#define EGMOCK_VERBOSE 1
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080018
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080019#include <android-base/logging.h>
Tomasz Wasilczyk8acabf22018-04-30 10:22:20 -070020#include <android-base/strings.h>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080021#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
22#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
23#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
24#include <android/hardware/broadcastradio/2.0/types.h>
25#include <broadcastradio-utils-2x/Utils.h>
26#include <broadcastradio-vts-utils/call-barrier.h>
27#include <broadcastradio-vts-utils/mock-timeout.h>
28#include <broadcastradio-vts-utils/pointer-utils.h>
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -080029#include <cutils/bitops.h>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080030#include <gmock/gmock.h>
Dan Shi27506e62019-12-12 10:54:49 -080031#include <gtest/gtest.h>
32#include <hidl/GtestPrinter.h>
33#include <hidl/ServiceManagement.h>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080034
35#include <chrono>
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -080036#include <optional>
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -080037#include <regex>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080038
39namespace android {
40namespace hardware {
41namespace broadcastradio {
42namespace V2_0 {
43namespace vts {
44
45using namespace std::chrono_literals;
46
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080047using std::unordered_set;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080048using std::vector;
49using testing::_;
50using testing::AnyNumber;
51using testing::ByMove;
52using testing::DoAll;
53using testing::Invoke;
54using testing::SaveArg;
55
56using broadcastradio::vts::CallBarrier;
57using broadcastradio::vts::clearAndWait;
58using utils::make_identifier;
59using utils::make_selector_amfm;
60
61namespace timeout {
62
63static constexpr auto tune = 30s;
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080064static constexpr auto programListScan = 5min;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080065
66} // namespace timeout
67
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -070068static constexpr auto gTuneWorkaround = 200ms;
69
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080070static const ConfigFlag gConfigFlagValues[] = {
Tomasz Wasilczyk30240f62017-12-20 14:19:21 -080071 ConfigFlag::FORCE_MONO,
72 ConfigFlag::FORCE_ANALOG,
73 ConfigFlag::FORCE_DIGITAL,
74 ConfigFlag::RDS_AF,
75 ConfigFlag::RDS_REG,
76 ConfigFlag::DAB_DAB_LINKING,
77 ConfigFlag::DAB_FM_LINKING,
78 ConfigFlag::DAB_DAB_SOFT_LINKING,
79 ConfigFlag::DAB_FM_SOFT_LINKING,
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080080};
81
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080082class TunerCallbackMock : public ITunerCallback {
83 public:
84 TunerCallbackMock();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080085
86 MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
Tomasz Wasilczyk67360522018-02-10 14:05:18 -080087 MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged_, Return<void>(const ProgramInfo&));
88 virtual Return<void> onCurrentProgramInfoChanged(const ProgramInfo& info);
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080089 Return<void> onProgramListUpdated(const ProgramListChunk& chunk);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080090 MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
91 MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080092
93 MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
94
95 std::mutex mLock;
96 utils::ProgramInfoSet mProgramList;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080097};
98
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -080099struct AnnouncementListenerMock : public IAnnouncementListener {
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800100 MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
101};
102
Dan Shi27506e62019-12-12 10:54:49 -0800103class BroadcastRadioHalTest : public ::testing::TestWithParam<std::string> {
104 protected:
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800105 virtual void SetUp() override;
106 virtual void TearDown() override;
107
108 bool openSession();
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800109 bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800110 std::optional<utils::ProgramInfoSet> getProgramList();
Weilin Xu8de55ff2022-06-28 18:12:11 +0000111 std::optional<utils::ProgramInfoSet> getProgramList(const ProgramFilter& filter);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800112
113 sp<IBroadcastRadio> mModule;
114 Properties mProperties;
115 sp<ITunerSession> mSession;
116 sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
117};
118
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800119static void printSkipped(std::string msg) {
Tomasz Wasilczyk751855d2020-06-29 10:22:43 -0700120 const auto testInfo = testing::UnitTest::GetInstance()->current_test_info();
121 std::cout << "[ SKIPPED ] " << testInfo->test_case_name() << "." << testInfo->name()
122 << std::endl;
123 std::cout << msg << std::endl;
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800124}
125
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800126MATCHER_P(InfoHasId, id,
127 std::string(negation ? "does not contain" : "contains") + " " + toString(id)) {
128 auto ids = utils::getAllIds(arg.selector, utils::getType(id));
129 return ids.end() != find(ids.begin(), ids.end(), id.value);
130}
131
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800132TunerCallbackMock::TunerCallbackMock() {
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800133 EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800134
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800135 // we expect the antenna is connected through the whole test
136 EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
137}
138
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800139Return<void> TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
Tomasz Wasilczykcea64962018-05-23 09:56:58 -0700140 for (auto&& id : info.selector) {
141 EXPECT_NE(IdentifierType::INVALID, utils::getType(id));
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800142 }
143
Tomasz Wasilczykcea64962018-05-23 09:56:58 -0700144 auto logically = utils::getType(info.logicallyTunedTo);
145 /* This field is required for currently tuned program and should be INVALID
146 * for entries from the program list.
147 */
148 EXPECT_TRUE(
149 logically == IdentifierType::AMFM_FREQUENCY || logically == IdentifierType::RDS_PI ||
150 logically == IdentifierType::HD_STATION_ID_EXT ||
151 logically == IdentifierType::DAB_SID_EXT || logically == IdentifierType::DRMO_SERVICE_ID ||
152 logically == IdentifierType::SXM_SERVICE_ID ||
153 (logically >= IdentifierType::VENDOR_START && logically <= IdentifierType::VENDOR_END) ||
154 logically > IdentifierType::SXM_CHANNEL);
155
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800156 auto physically = utils::getType(info.physicallyTunedTo);
Tomasz Wasilczykcea64962018-05-23 09:56:58 -0700157 // ditto (see "logically" above)
158 EXPECT_TRUE(
159 physically == IdentifierType::AMFM_FREQUENCY ||
160 physically == IdentifierType::DAB_ENSEMBLE ||
161 physically == IdentifierType::DRMO_FREQUENCY || physically == IdentifierType::SXM_CHANNEL ||
162 (physically >= IdentifierType::VENDOR_START && physically <= IdentifierType::VENDOR_END) ||
163 physically > IdentifierType::SXM_CHANNEL);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800164
Tomasz Wasilczyk8acabf22018-04-30 10:22:20 -0700165 if (logically == IdentifierType::AMFM_FREQUENCY) {
166 auto ps = utils::getMetadataString(info, MetadataKey::RDS_PS);
167 if (ps.has_value()) {
168 EXPECT_NE("", android::base::Trim(*ps))
169 << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
170 }
171 }
172
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800173 return onCurrentProgramInfoChanged_(info);
174}
175
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800176Return<void> TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
177 std::lock_guard<std::mutex> lk(mLock);
178
179 updateProgramList(mProgramList, chunk);
180
181 if (chunk.complete) onProgramListReady();
182
183 return {};
184}
185
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800186void BroadcastRadioHalTest::SetUp() {
187 EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
188
189 // lookup HIDL service (radio module)
Dan Shi27506e62019-12-12 10:54:49 -0800190 mModule = IBroadcastRadio::getService(GetParam());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800191 ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
192
193 // get module properties
194 auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; });
195 ASSERT_TRUE(propResult.isOk());
196
197 EXPECT_FALSE(mProperties.maker.empty());
198 EXPECT_FALSE(mProperties.product.empty());
199 EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
200}
201
202void BroadcastRadioHalTest::TearDown() {
203 mSession.clear();
204 mModule.clear();
205 clearAndWait(mCallback, 1s);
206}
207
208bool BroadcastRadioHalTest::openSession() {
209 EXPECT_EQ(nullptr, mSession.get()) << "Session is already open";
210
211 Result halResult = Result::UNKNOWN_ERROR;
212 auto openCb = [&](Result result, const sp<ITunerSession>& session) {
213 halResult = result;
214 if (result != Result::OK) return;
215 mSession = session;
216 };
217 auto hidlResult = mModule->openSession(mCallback, openCb);
218
219 EXPECT_TRUE(hidlResult.isOk());
220 EXPECT_EQ(Result::OK, halResult);
221 EXPECT_NE(nullptr, mSession.get());
222
223 return nullptr != mSession.get();
224}
225
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800226bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
227 auto halResult = Result::UNKNOWN_ERROR;
228 auto cb = [&](Result result, AmFmRegionConfig configCb) {
229 halResult = result;
230 if (config) *config = configCb;
231 };
232
233 auto hidlResult = mModule->getAmFmRegionConfig(full, cb);
234 EXPECT_TRUE(hidlResult.isOk());
235
236 if (halResult == Result::NOT_SUPPORTED) return false;
237
238 EXPECT_EQ(Result::OK, halResult);
239 return halResult == Result::OK;
240}
241
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800242std::optional<utils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
Weilin Xu8de55ff2022-06-28 18:12:11 +0000243 ProgramFilter emptyFilter = {};
244 return getProgramList(emptyFilter);
245}
246
247std::optional<utils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
248 const ProgramFilter& filter) {
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800249 EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
250
Weilin Xu8de55ff2022-06-28 18:12:11 +0000251 auto startResult = mSession->startProgramListUpdates(filter);
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800252 if (startResult == Result::NOT_SUPPORTED) {
253 printSkipped("Program list not supported");
Dan Shi27506e62019-12-12 10:54:49 -0800254 return std::nullopt;
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800255 }
256 EXPECT_EQ(Result::OK, startResult);
Dan Shi27506e62019-12-12 10:54:49 -0800257 if (startResult != Result::OK) return std::nullopt;
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800258
259 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
260
261 auto stopResult = mSession->stopProgramListUpdates();
262 EXPECT_TRUE(stopResult.isOk());
263
264 return mCallback->mProgramList;
265}
266
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800267/**
268 * Test session opening.
269 *
270 * Verifies that:
271 * - the method succeeds on a first and subsequent calls;
272 * - the method succeeds when called for the second time without
273 * closing previous session.
274 */
Dan Shi27506e62019-12-12 10:54:49 -0800275TEST_P(BroadcastRadioHalTest, OpenSession) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800276 // simply open session for the first time
277 ASSERT_TRUE(openSession());
278
279 // drop (without explicit close) and re-open the session
280 mSession.clear();
281 ASSERT_TRUE(openSession());
282
283 // open the second session (the first one should be forcibly closed)
284 auto secondSession = mSession;
285 mSession.clear();
286 ASSERT_TRUE(openSession());
287}
288
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800289static bool isValidAmFmFreq(uint64_t freq) {
290 auto id = utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq);
291 return utils::isValid(id);
292}
293
294static void validateRange(const AmFmBandRange& range) {
295 EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
296 EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
297 EXPECT_LT(range.lowerBound, range.upperBound);
298 EXPECT_GT(range.spacing, 0u);
299 EXPECT_EQ(0u, (range.upperBound - range.lowerBound) % range.spacing);
300}
301
302static bool supportsFM(const AmFmRegionConfig& config) {
303 for (auto&& range : config.ranges) {
304 if (utils::getBand(range.lowerBound) == utils::FrequencyBand::FM) return true;
305 }
306 return false;
307}
308
309/**
310 * Test fetching AM/FM regional configuration.
311 *
312 * Verifies that:
313 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
314 * - there is at least one AM/FM band configured;
315 * - FM Deemphasis and RDS are correctly configured for FM-capable radio;
316 * - all channel grids (frequency ranges and spacings) are valid;
Tomasz Wasilczykb557e0b2018-06-05 10:10:39 -0700317 * - seek spacing is a multiple of the manual spacing value.
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800318 */
Dan Shi27506e62019-12-12 10:54:49 -0800319TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800320 AmFmRegionConfig config;
321 bool supported = getAmFmRegionConfig(false, &config);
322 if (!supported) {
323 printSkipped("AM/FM not supported");
324 return;
325 }
326
327 EXPECT_GT(config.ranges.size(), 0u);
328 EXPECT_LE(popcountll(config.fmDeemphasis), 1);
329 EXPECT_LE(popcountll(config.fmRds), 1);
330
331 for (auto&& range : config.ranges) {
332 validateRange(range);
333 EXPECT_EQ(0u, range.scanSpacing % range.spacing);
334 EXPECT_GE(range.scanSpacing, range.spacing);
335 }
336
337 if (supportsFM(config)) {
338 EXPECT_EQ(popcountll(config.fmDeemphasis), 1);
339 }
340}
341
342/**
343 * Test fetching AM/FM regional capabilities.
344 *
345 * Verifies that:
346 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
347 * - there is at least one AM/FM range supported;
348 * - there is at least one de-emphasis filter mode supported for FM-capable radio;
349 * - all channel grids (frequency ranges and spacings) are valid;
Tomasz Wasilczykb557e0b2018-06-05 10:10:39 -0700350 * - seek spacing is not set.
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800351 */
Dan Shi27506e62019-12-12 10:54:49 -0800352TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800353 AmFmRegionConfig config;
354 bool supported = getAmFmRegionConfig(true, &config);
355 if (!supported) {
356 printSkipped("AM/FM not supported");
357 return;
358 }
359
360 EXPECT_GT(config.ranges.size(), 0u);
361
362 for (auto&& range : config.ranges) {
363 validateRange(range);
364 EXPECT_EQ(0u, range.scanSpacing);
365 }
366
367 if (supportsFM(config)) {
368 EXPECT_GE(popcountll(config.fmDeemphasis), 1);
369 }
370}
371
372/**
373 * Test fetching DAB regional configuration.
374 *
375 * Verifies that:
376 * - DAB regional configuration is either set at startup or not supported at all by the hardware;
377 * - all channel labels match correct format;
378 * - all channel frequencies are in correct range.
379 */
Dan Shi27506e62019-12-12 10:54:49 -0800380TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800381 Result halResult;
382 hidl_vec<DabTableEntry> config;
383 auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
384 halResult = result;
385 config = configCb;
386 };
387 auto hidlResult = mModule->getDabRegionConfig(cb);
388 ASSERT_TRUE(hidlResult.isOk());
389
390 if (halResult == Result::NOT_SUPPORTED) {
391 printSkipped("DAB not supported");
392 return;
393 }
394 ASSERT_EQ(Result::OK, halResult);
395
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800396 std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800397 // double-check correctness of the test
398 ASSERT_TRUE(std::regex_match("5A", re));
399 ASSERT_FALSE(std::regex_match("5a", re));
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800400 ASSERT_FALSE(std::regex_match("1234ABCD", re));
401 ASSERT_TRUE(std::regex_match("CN 12D", re));
402 ASSERT_FALSE(std::regex_match(" 5A", re));
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800403
404 for (auto&& entry : config) {
405 EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
406
407 auto id = utils::make_identifier(IdentifierType::DAB_FREQUENCY, entry.frequency);
408 EXPECT_TRUE(utils::isValid(id));
409 }
410}
411
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800412/**
413 * Test tuning with FM selector.
414 *
415 * Verifies that:
416 * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
417 * - if it is supported, the method succeeds;
418 * - after a successful tune call, onCurrentProgramInfoChanged callback is
419 * invoked carrying a proper selector;
420 * - program changes exactly to what was requested.
421 */
Dan Shi27506e62019-12-12 10:54:49 -0800422TEST_P(BroadcastRadioHalTest, FmTune) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800423 ASSERT_TRUE(openSession());
424
Jan Kowal4e041502021-01-21 12:44:44 +0100425 uint64_t freq = 90900; // 90.9 FM
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800426 auto sel = make_selector_amfm(freq);
427
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800428 /* TODO(b/69958777): there is a race condition between tune() and onCurrentProgramInfoChanged
429 * callback setting infoCb, because egmock cannot distinguish calls with different matchers
430 * (there is one here and one in callback constructor).
431 *
432 * This sleep workaround will fix default implementation, but the real HW tests will still be
433 * flaky. We probably need to implement egmock alternative based on actions.
434 */
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700435 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800436
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800437 // try tuning
438 ProgramInfo infoCb = {};
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800439 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_,
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800440 InfoHasId(utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq)))
Tomasz Wasilczyk751855d2020-06-29 10:22:43 -0700441 .Times(AnyNumber())
442 .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))))
443 .WillRepeatedly(testing::InvokeWithoutArgs([] { return Void(); }));
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800444 auto result = mSession->tune(sel);
445
446 // expect a failure if it's not supported
447 if (!utils::isSupported(mProperties, sel)) {
448 EXPECT_EQ(Result::NOT_SUPPORTED, result);
449 return;
450 }
451
452 // expect a callback if it succeeds
453 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800454 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800455
Tomasz Wasilczyk84ec4e12018-11-13 11:26:23 -0800456 LOG(DEBUG) << "current program info: " << toString(infoCb);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800457
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800458 // it should tune exactly to what was requested
459 auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
460 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
461}
462
463/**
464 * Test tuning with invalid selectors.
465 *
466 * Verifies that:
467 * - if the selector is not supported, it's ignored;
468 * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
469 */
Dan Shi27506e62019-12-12 10:54:49 -0800470TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800471 ASSERT_TRUE(openSession());
472
473 vector<ProgramIdentifier> invalid = {
474 make_identifier(IdentifierType::AMFM_FREQUENCY, 0),
475 make_identifier(IdentifierType::RDS_PI, 0x10000),
476 make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
477 make_identifier(IdentifierType::DAB_SID_EXT, 0),
478 make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
479 make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
480 };
481
482 for (auto&& id : invalid) {
483 ProgramSelector sel{id, {}};
484
485 auto result = mSession->tune(sel);
486
487 if (utils::isSupported(mProperties, sel)) {
488 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
489 } else {
490 EXPECT_EQ(Result::NOT_SUPPORTED, result);
491 }
492 }
493}
494
495/**
hyewon.eum96b542d2020-12-04 12:09:17 +0900496 * Test tuning with DAB selector.
497 *
498 * Verifies that:
499 * - if DAB selector is not supported, the method returns NOT_SUPPORTED;
500 * - if it is supported, the method succeeds;
501 * - after a successful tune call, onCurrentProgramInfoChanged callback is
502 * invoked carrying a proper selector;
503 * - program changes exactly to what was requested.
504 */
Kihyung Leec3d3abc2021-03-11 16:29:55 +0900505TEST_P(BroadcastRadioHalTest, DabTune) {
Jan Kowal7aa628d2021-05-31 16:48:19 +0200506 Result halResult;
507 hidl_vec<DabTableEntry> config;
508 auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
509 halResult = result;
510 config = configCb;
511 };
512 auto hidlResult = mModule->getDabRegionConfig(cb);
513 ASSERT_TRUE(hidlResult.isOk());
514
515 if (halResult == Result::NOT_SUPPORTED) {
516 printSkipped("DAB not supported");
517 return;
518 }
519 ASSERT_EQ(Result::OK, halResult);
520 ASSERT_NE(config.size(), 0U);
521
hyewon.eum96b542d2020-12-04 12:09:17 +0900522 ASSERT_TRUE(openSession());
523
524 ProgramSelector sel = {};
Jan Kowal7aa628d2021-05-31 16:48:19 +0200525 uint64_t freq = config[config.size() / 2].frequency;
hyewon.eum96b542d2020-12-04 12:09:17 +0900526 sel.primaryId = make_identifier(IdentifierType::DAB_FREQUENCY,freq);
527
528 std::this_thread::sleep_for(gTuneWorkaround);
529
530 // try tuning
531 ProgramInfo infoCb = {};
532 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_,
533 InfoHasId(utils::make_identifier(IdentifierType::DAB_FREQUENCY, freq)))
534 .Times(AnyNumber())
535 .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
536 auto result = mSession->tune(sel);
537
538 // expect a failure if it's not supported
539 if (!utils::isSupported(mProperties, sel)) {
540 EXPECT_EQ(Result::NOT_SUPPORTED, result);
541 return;
542 }
543
544 // expect a callback if it succeeds
545 EXPECT_EQ(Result::OK, result);
546 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
547
548 LOG(DEBUG) << "current program info: " << toString(infoCb);
549
550 // it should tune exactly to what was requested
551 auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY);
552 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
553}
554
555/**
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800556 * Test tuning with empty program selector.
557 *
558 * Verifies that:
559 * - tune fails with NOT_SUPPORTED when program selector is not initialized.
560 */
Dan Shi27506e62019-12-12 10:54:49 -0800561TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800562 ASSERT_TRUE(openSession());
563
564 // Program type is 1-based, so 0 will always be invalid.
565 ProgramSelector sel = {};
566 auto result = mSession->tune(sel);
567 ASSERT_EQ(Result::NOT_SUPPORTED, result);
568}
569
570/**
Tomasz Wasilczykb557e0b2018-06-05 10:10:39 -0700571 * Test seeking to next/prev station via ITunerSession::scan().
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800572 *
573 * Verifies that:
574 * - the method succeeds;
575 * - the program info is changed within timeout::tune;
576 * - works both directions and with or without skipping sub-channel.
577 */
Dan Shi27506e62019-12-12 10:54:49 -0800578TEST_P(BroadcastRadioHalTest, Seek) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800579 ASSERT_TRUE(openSession());
580
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800581 // TODO(b/69958777): see FmTune workaround
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700582 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800583
Tomasz Wasilczykaf898822018-12-03 13:15:50 -0800584 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800585 auto result = mSession->scan(true /* up */, true /* skip subchannel */);
hyewon.eum96b542d2020-12-04 12:09:17 +0900586
587 if (result == Result::NOT_SUPPORTED) {
588 printSkipped("seek not supported");
589 return;
590 }
591
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800592 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800593 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800594
Tomasz Wasilczykaf898822018-12-03 13:15:50 -0800595 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800596 result = mSession->scan(false /* down */, false /* don't skip subchannel */);
597 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800598 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800599}
600
601/**
602 * Test step operation.
603 *
604 * Verifies that:
605 * - the method succeeds or returns NOT_SUPPORTED;
606 * - the program info is changed within timeout::tune if the method succeeded;
607 * - works both directions.
608 */
Dan Shi27506e62019-12-12 10:54:49 -0800609TEST_P(BroadcastRadioHalTest, Step) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800610 ASSERT_TRUE(openSession());
611
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800612 // TODO(b/69958777): see FmTune workaround
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700613 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800614
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800615 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800616 auto result = mSession->step(true /* up */);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800617 if (result == Result::NOT_SUPPORTED) {
618 printSkipped("step not supported");
619 return;
620 }
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800621 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800622 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800623
Tomasz Wasilczykaf898822018-12-03 13:15:50 -0800624 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800625 result = mSession->step(false /* down */);
626 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800627 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800628}
629
630/**
631 * Test tune cancellation.
632 *
633 * Verifies that:
634 * - the method does not crash after being invoked multiple times.
635 */
Dan Shi27506e62019-12-12 10:54:49 -0800636TEST_P(BroadcastRadioHalTest, Cancel) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800637 ASSERT_TRUE(openSession());
638
639 for (int i = 0; i < 10; i++) {
Tomasz Wasilczykb557e0b2018-06-05 10:10:39 -0700640 auto result = mSession->scan(true /* up */, true /* skip subchannel */);
hyewon.eum96b542d2020-12-04 12:09:17 +0900641
642 if (result == Result::NOT_SUPPORTED) {
643 printSkipped("cancel is skipped because of seek not supported");
644 return;
645 }
646
Tomasz Wasilczykb557e0b2018-06-05 10:10:39 -0700647 ASSERT_EQ(Result::OK, result);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800648
649 auto cancelResult = mSession->cancel();
650 ASSERT_TRUE(cancelResult.isOk());
651 }
652}
653
654/**
655 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
656 *
657 * Verifies that:
658 * - callback is called for empty parameters set.
659 */
Dan Shi27506e62019-12-12 10:54:49 -0800660TEST_P(BroadcastRadioHalTest, NoParameters) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800661 ASSERT_TRUE(openSession());
662
663 hidl_vec<VendorKeyValue> halResults = {};
664 bool wasCalled = false;
665 auto cb = [&](hidl_vec<VendorKeyValue> results) {
666 wasCalled = true;
667 halResults = results;
668 };
669
670 auto hidlResult = mSession->setParameters({}, cb);
671 ASSERT_TRUE(hidlResult.isOk());
672 ASSERT_TRUE(wasCalled);
673 ASSERT_EQ(0u, halResults.size());
674
675 wasCalled = false;
676 hidlResult = mSession->getParameters({}, cb);
677 ASSERT_TRUE(hidlResult.isOk());
678 ASSERT_TRUE(wasCalled);
679 ASSERT_EQ(0u, halResults.size());
680}
681
682/**
683 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
684 *
685 * Verifies that:
686 * - unknown parameters are ignored;
687 * - callback is called also for empty results set.
688 */
Dan Shi27506e62019-12-12 10:54:49 -0800689TEST_P(BroadcastRadioHalTest, UnknownParameters) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800690 ASSERT_TRUE(openSession());
691
692 hidl_vec<VendorKeyValue> halResults = {};
693 bool wasCalled = false;
694 auto cb = [&](hidl_vec<VendorKeyValue> results) {
695 wasCalled = true;
696 halResults = results;
697 };
698
699 auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb);
700 ASSERT_TRUE(hidlResult.isOk());
701 ASSERT_TRUE(wasCalled);
702 ASSERT_EQ(0u, halResults.size());
703
704 wasCalled = false;
705 hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb);
706 ASSERT_TRUE(hidlResult.isOk());
707 ASSERT_TRUE(wasCalled);
708 ASSERT_EQ(0u, halResults.size());
709}
710
711/**
712 * Test session closing.
713 *
714 * Verifies that:
715 * - the method does not crash after being invoked multiple times.
716 */
Dan Shi27506e62019-12-12 10:54:49 -0800717TEST_P(BroadcastRadioHalTest, Close) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800718 ASSERT_TRUE(openSession());
719
720 for (int i = 0; i < 10; i++) {
721 auto cancelResult = mSession->close();
722 ASSERT_TRUE(cancelResult.isOk());
723 }
724}
725
726/**
727 * Test geting image of invalid ID.
728 *
729 * Verifies that:
730 * - getImage call handles argument 0 gracefully.
731 */
Dan Shi27506e62019-12-12 10:54:49 -0800732TEST_P(BroadcastRadioHalTest, GetNoImage) {
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800733 size_t len = 0;
734 auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
735
736 ASSERT_TRUE(result.isOk());
737 ASSERT_EQ(0u, len);
738}
739
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800740/**
741 * Test getting config flags.
742 *
743 * Verifies that:
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800744 * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800745 * - call success or failure is consistent with setConfigFlag.
746 */
Dan Shi27506e62019-12-12 10:54:49 -0800747TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800748 ASSERT_TRUE(openSession());
749
750 for (auto flag : gConfigFlagValues) {
751 auto halResult = Result::UNKNOWN_ERROR;
752 auto cb = [&](Result result, bool) { halResult = result; };
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800753 auto hidlResult = mSession->isConfigFlagSet(flag, cb);
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800754 EXPECT_TRUE(hidlResult.isOk());
755
756 if (halResult != Result::NOT_SUPPORTED && halResult != Result::INVALID_STATE) {
757 ASSERT_EQ(Result::OK, halResult);
758 }
759
760 // set must fail or succeed the same way as get
761 auto setResult = mSession->setConfigFlag(flag, false);
762 EXPECT_EQ(halResult, setResult);
763 setResult = mSession->setConfigFlag(flag, true);
764 EXPECT_EQ(halResult, setResult);
765 }
766}
767
768/**
769 * Test setting config flags.
770 *
771 * Verifies that:
772 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800773 * - isConfigFlagSet reflects the state requested immediately after the set call.
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800774 */
Dan Shi27506e62019-12-12 10:54:49 -0800775TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800776 ASSERT_TRUE(openSession());
777
778 auto get = [&](ConfigFlag flag) {
779 auto halResult = Result::UNKNOWN_ERROR;
780 bool gotValue = false;
781 auto cb = [&](Result result, bool value) {
782 halResult = result;
783 gotValue = value;
784 };
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800785 auto hidlResult = mSession->isConfigFlagSet(flag, cb);
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800786 EXPECT_TRUE(hidlResult.isOk());
787 EXPECT_EQ(Result::OK, halResult);
788 return gotValue;
789 };
790
791 for (auto flag : gConfigFlagValues) {
792 auto result = mSession->setConfigFlag(flag, false);
793 if (result == Result::NOT_SUPPORTED || result == Result::INVALID_STATE) {
794 // setting to true must result in the same error as false
795 auto secondResult = mSession->setConfigFlag(flag, true);
796 EXPECT_EQ(result, secondResult);
797 continue;
798 }
799 ASSERT_EQ(Result::OK, result);
800
801 // verify false is set
802 auto value = get(flag);
803 EXPECT_FALSE(value);
804
805 // try setting true this time
806 result = mSession->setConfigFlag(flag, true);
807 ASSERT_EQ(Result::OK, result);
808 value = get(flag);
809 EXPECT_TRUE(value);
810
811 // false again
812 result = mSession->setConfigFlag(flag, false);
813 ASSERT_EQ(Result::OK, result);
814 value = get(flag);
815 EXPECT_FALSE(value);
816 }
817}
818
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800819/**
Weilin Xu8de55ff2022-06-28 18:12:11 +0000820 * Test getting program list using empty program filter.
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800821 *
822 * Verifies that:
823 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
824 * - the complete list is fetched within timeout::programListScan;
825 * - stopProgramListUpdates does not crash.
826 */
Weilin Xu8de55ff2022-06-28 18:12:11 +0000827TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800828 ASSERT_TRUE(openSession());
829
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800830 getProgramList();
831}
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800832
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800833/**
Weilin Xu8de55ff2022-06-28 18:12:11 +0000834 * Test getting program list using AMFM frequency program filter.
835 *
836 * Verifies that:
837 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
838 * - the complete list is fetched within timeout::programListScan;
839 * - stopProgramListUpdates does not crash;
840 * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY value of the first AMFM
841 * program matches the expected result.
842 */
843TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
844 ASSERT_TRUE(openSession());
845
846 auto completeList = getProgramList();
847 if (!completeList) return;
848
849 ProgramFilter amfmFilter = {};
850 int expectedResultSize = 0;
851 uint64_t expectedFreq = 0;
852 for (auto&& program : *completeList) {
853 auto amfmIds = utils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY);
854 EXPECT_LE(amfmIds.size(), 1u);
855 if (amfmIds.size() == 0) continue;
856
857 if (expectedResultSize == 0) {
858 expectedFreq = amfmIds[0];
859 amfmFilter.identifiers = {
860 make_identifier(IdentifierType::AMFM_FREQUENCY, expectedFreq)};
861 expectedResultSize = 1;
862 } else if (amfmIds[0] == expectedFreq) {
863 expectedResultSize++;
864 }
865 }
866
867 if (expectedResultSize == 0) return;
868 auto amfmList = getProgramList(amfmFilter);
869 ASSERT_EQ(expectedResultSize, amfmList->size()) << "amfm filter result size is wrong";
870}
871
872/**
873 * Test getting program list using DAB ensemble program filter.
874 *
875 * Verifies that:
876 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
877 * - the complete list is fetched within timeout::programListScan;
878 * - stopProgramListUpdates does not crash;
879 * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
880 * program matches the expected result.
881 */
882TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
883 ASSERT_TRUE(openSession());
884
885 auto completeList = getProgramList();
886 if (!completeList) return;
887
888 ProgramFilter dabFilter = {};
889 int expectedResultSize = 0;
890 uint64_t expectedEnsemble = 0;
891 for (auto&& program : *completeList) {
892 auto dabEnsembles = utils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
893 EXPECT_LE(dabEnsembles.size(), 1u);
894 if (dabEnsembles.size() == 0) continue;
895
896 if (expectedResultSize == 0) {
897 expectedEnsemble = dabEnsembles[0];
898 dabFilter.identifiers = {
899 make_identifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
900 expectedResultSize = 1;
901 } else if (dabEnsembles[0] == expectedEnsemble) {
902 expectedResultSize++;
903 }
904 }
905
906 if (expectedResultSize == 0) return;
907 auto dabList = getProgramList(dabFilter);
908 ASSERT_EQ(expectedResultSize, dabList->size()) << "dab filter result size is wrong";
909}
910
911/**
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800912 * Test HD_STATION_NAME correctness.
913 *
914 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
915 * - the program provides station name in its metadata;
916 * - the identifier matches the name;
917 * - there is only one identifier of that type.
918 */
Dan Shi27506e62019-12-12 10:54:49 -0800919TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800920 ASSERT_TRUE(openSession());
921
922 auto list = getProgramList();
923 if (!list) return;
924
925 for (auto&& program : *list) {
926 auto nameIds = utils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
927 EXPECT_LE(nameIds.size(), 1u);
928 if (nameIds.size() == 0) continue;
929
930 auto name = utils::getMetadataString(program, MetadataKey::PROGRAM_NAME);
931 if (!name) name = utils::getMetadataString(program, MetadataKey::RDS_PS);
932 ASSERT_TRUE(name.has_value());
933
934 auto expectedId = utils::make_hdradio_station_name(*name);
935 EXPECT_EQ(expectedId.value, nameIds[0]);
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800936 }
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800937}
938
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800939/**
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800940 * Test announcement listener registration.
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800941 *
942 * Verifies that:
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800943 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800944 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
945 * - closing handle does not crash.
946 */
Dan Shi27506e62019-12-12 10:54:49 -0800947TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800948 sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800949
950 Result halResult = Result::UNKNOWN_ERROR;
951 sp<ICloseHandle> closeHandle = nullptr;
952 auto cb = [&](Result result, const sp<ICloseHandle>& closeHandle_) {
953 halResult = result;
954 closeHandle = closeHandle_;
955 };
956
957 auto hidlResult =
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800958 mModule->registerAnnouncementListener({AnnouncementType::EMERGENCY}, listener, cb);
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800959 ASSERT_TRUE(hidlResult.isOk());
960
961 if (halResult == Result::NOT_SUPPORTED) {
962 ASSERT_EQ(nullptr, closeHandle.get());
963 printSkipped("Announcements not supported");
964 return;
965 }
966
967 ASSERT_EQ(Result::OK, halResult);
968 ASSERT_NE(nullptr, closeHandle.get());
969
970 closeHandle->close();
971}
972
Dan Shiba4d5322020-07-28 13:09:30 -0700973GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
Dan Shi27506e62019-12-12 10:54:49 -0800974INSTANTIATE_TEST_SUITE_P(
975 PerInstance, BroadcastRadioHalTest,
976 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBroadcastRadio::descriptor)),
977 android::hardware::PrintInstanceNameToString);
978
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800979} // namespace vts
980} // namespace V2_0
981} // namespace broadcastradio
982} // namespace hardware
983} // namespace android
984
985int main(int argc, char** argv) {
Tomasz Wasilczyk84ec4e12018-11-13 11:26:23 -0800986 android::base::SetDefaultTag("BcRadio.vts");
987 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800988 ::testing::InitGoogleTest(&argc, argv);
Tomasz Wasilczyk84ec4e12018-11-13 11:26:23 -0800989 return RUN_ALL_TESTS();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800990}