blob: 9695d3299885f1a163fa420bd961c6d87be0c0bd [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
17#define LOG_TAG "BcRadio.vts"
18
19#include <VtsHalHidlTargetTestBase.h>
20#include <android-base/logging.h>
21#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>
31
32#include <chrono>
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -080033#include <optional>
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -080034#include <regex>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080035
36namespace android {
37namespace hardware {
38namespace broadcastradio {
39namespace V2_0 {
40namespace vts {
41
42using namespace std::chrono_literals;
43
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080044using std::unordered_set;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080045using std::vector;
46using testing::_;
47using testing::AnyNumber;
48using testing::ByMove;
49using testing::DoAll;
50using testing::Invoke;
51using testing::SaveArg;
52
53using broadcastradio::vts::CallBarrier;
54using broadcastradio::vts::clearAndWait;
55using utils::make_identifier;
56using utils::make_selector_amfm;
57
58namespace timeout {
59
60static constexpr auto tune = 30s;
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080061static constexpr auto programListScan = 5min;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080062
63} // namespace timeout
64
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080065static const ConfigFlag gConfigFlagValues[] = {
Tomasz Wasilczyk30240f62017-12-20 14:19:21 -080066 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,
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080075};
76
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080077class TunerCallbackMock : public ITunerCallback {
78 public:
79 TunerCallbackMock();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080080
81 MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
82 MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&));
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080083 Return<void> onProgramListUpdated(const ProgramListChunk& chunk);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080084 MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
85 MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080086
87 MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
88
89 std::mutex mLock;
90 utils::ProgramInfoSet mProgramList;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080091};
92
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -080093struct AnnouncementListenerMock : public IAnnouncementListener {
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -080094 MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
95};
96
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080097class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
98 protected:
99 virtual void SetUp() override;
100 virtual void TearDown() override;
101
102 bool openSession();
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800103 bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800104 std::optional<utils::ProgramInfoSet> getProgramList();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800105
106 sp<IBroadcastRadio> mModule;
107 Properties mProperties;
108 sp<ITunerSession> mSession;
109 sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
110};
111
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800112static void printSkipped(std::string msg) {
113 std::cout << "[ SKIPPED ] " << msg << std::endl;
114}
115
116TunerCallbackMock::TunerCallbackMock() {
117 // we expect the antenna is connected through the whole test
118 EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
119}
120
121Return<void> TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
122 std::lock_guard<std::mutex> lk(mLock);
123
124 updateProgramList(mProgramList, chunk);
125
126 if (chunk.complete) onProgramListReady();
127
128 return {};
129}
130
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800131void BroadcastRadioHalTest::SetUp() {
132 EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
133
134 // lookup HIDL service (radio module)
135 mModule = getService<IBroadcastRadio>();
136 ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
137
138 // get module properties
139 auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; });
140 ASSERT_TRUE(propResult.isOk());
141
142 EXPECT_FALSE(mProperties.maker.empty());
143 EXPECT_FALSE(mProperties.product.empty());
144 EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
145}
146
147void BroadcastRadioHalTest::TearDown() {
148 mSession.clear();
149 mModule.clear();
150 clearAndWait(mCallback, 1s);
151}
152
153bool BroadcastRadioHalTest::openSession() {
154 EXPECT_EQ(nullptr, mSession.get()) << "Session is already open";
155
156 Result halResult = Result::UNKNOWN_ERROR;
157 auto openCb = [&](Result result, const sp<ITunerSession>& session) {
158 halResult = result;
159 if (result != Result::OK) return;
160 mSession = session;
161 };
162 auto hidlResult = mModule->openSession(mCallback, openCb);
163
164 EXPECT_TRUE(hidlResult.isOk());
165 EXPECT_EQ(Result::OK, halResult);
166 EXPECT_NE(nullptr, mSession.get());
167
168 return nullptr != mSession.get();
169}
170
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800171bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
172 auto halResult = Result::UNKNOWN_ERROR;
173 auto cb = [&](Result result, AmFmRegionConfig configCb) {
174 halResult = result;
175 if (config) *config = configCb;
176 };
177
178 auto hidlResult = mModule->getAmFmRegionConfig(full, cb);
179 EXPECT_TRUE(hidlResult.isOk());
180
181 if (halResult == Result::NOT_SUPPORTED) return false;
182
183 EXPECT_EQ(Result::OK, halResult);
184 return halResult == Result::OK;
185}
186
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800187std::optional<utils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
188 EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
189
190 auto startResult = mSession->startProgramListUpdates({});
191 if (startResult == Result::NOT_SUPPORTED) {
192 printSkipped("Program list not supported");
193 return nullopt;
194 }
195 EXPECT_EQ(Result::OK, startResult);
196 if (startResult != Result::OK) return nullopt;
197
198 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
199
200 auto stopResult = mSession->stopProgramListUpdates();
201 EXPECT_TRUE(stopResult.isOk());
202
203 return mCallback->mProgramList;
204}
205
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800206/**
207 * Test session opening.
208 *
209 * Verifies that:
210 * - the method succeeds on a first and subsequent calls;
211 * - the method succeeds when called for the second time without
212 * closing previous session.
213 */
214TEST_F(BroadcastRadioHalTest, OpenSession) {
215 // simply open session for the first time
216 ASSERT_TRUE(openSession());
217
218 // drop (without explicit close) and re-open the session
219 mSession.clear();
220 ASSERT_TRUE(openSession());
221
222 // open the second session (the first one should be forcibly closed)
223 auto secondSession = mSession;
224 mSession.clear();
225 ASSERT_TRUE(openSession());
226}
227
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800228static bool isValidAmFmFreq(uint64_t freq) {
229 auto id = utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq);
230 return utils::isValid(id);
231}
232
233static void validateRange(const AmFmBandRange& range) {
234 EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
235 EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
236 EXPECT_LT(range.lowerBound, range.upperBound);
237 EXPECT_GT(range.spacing, 0u);
238 EXPECT_EQ(0u, (range.upperBound - range.lowerBound) % range.spacing);
239}
240
241static bool supportsFM(const AmFmRegionConfig& config) {
242 for (auto&& range : config.ranges) {
243 if (utils::getBand(range.lowerBound) == utils::FrequencyBand::FM) return true;
244 }
245 return false;
246}
247
248/**
249 * Test fetching AM/FM regional configuration.
250 *
251 * Verifies that:
252 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
253 * - there is at least one AM/FM band configured;
254 * - FM Deemphasis and RDS are correctly configured for FM-capable radio;
255 * - all channel grids (frequency ranges and spacings) are valid;
256 * - scan spacing is a multiply of manual spacing value.
257 */
258TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) {
259 AmFmRegionConfig config;
260 bool supported = getAmFmRegionConfig(false, &config);
261 if (!supported) {
262 printSkipped("AM/FM not supported");
263 return;
264 }
265
266 EXPECT_GT(config.ranges.size(), 0u);
267 EXPECT_LE(popcountll(config.fmDeemphasis), 1);
268 EXPECT_LE(popcountll(config.fmRds), 1);
269
270 for (auto&& range : config.ranges) {
271 validateRange(range);
272 EXPECT_EQ(0u, range.scanSpacing % range.spacing);
273 EXPECT_GE(range.scanSpacing, range.spacing);
274 }
275
276 if (supportsFM(config)) {
277 EXPECT_EQ(popcountll(config.fmDeemphasis), 1);
278 }
279}
280
281/**
282 * Test fetching AM/FM regional capabilities.
283 *
284 * Verifies that:
285 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
286 * - there is at least one AM/FM range supported;
287 * - there is at least one de-emphasis filter mode supported for FM-capable radio;
288 * - all channel grids (frequency ranges and spacings) are valid;
289 * - scan spacing is not set.
290 */
291TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
292 AmFmRegionConfig config;
293 bool supported = getAmFmRegionConfig(true, &config);
294 if (!supported) {
295 printSkipped("AM/FM not supported");
296 return;
297 }
298
299 EXPECT_GT(config.ranges.size(), 0u);
300
301 for (auto&& range : config.ranges) {
302 validateRange(range);
303 EXPECT_EQ(0u, range.scanSpacing);
304 }
305
306 if (supportsFM(config)) {
307 EXPECT_GE(popcountll(config.fmDeemphasis), 1);
308 }
309}
310
311/**
312 * Test fetching DAB regional configuration.
313 *
314 * Verifies that:
315 * - DAB regional configuration is either set at startup or not supported at all by the hardware;
316 * - all channel labels match correct format;
317 * - all channel frequencies are in correct range.
318 */
319TEST_F(BroadcastRadioHalTest, GetDabRegionConfig) {
320 Result halResult;
321 hidl_vec<DabTableEntry> config;
322 auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
323 halResult = result;
324 config = configCb;
325 };
326 auto hidlResult = mModule->getDabRegionConfig(cb);
327 ASSERT_TRUE(hidlResult.isOk());
328
329 if (halResult == Result::NOT_SUPPORTED) {
330 printSkipped("DAB not supported");
331 return;
332 }
333 ASSERT_EQ(Result::OK, halResult);
334
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800335 std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800336 // double-check correctness of the test
337 ASSERT_TRUE(std::regex_match("5A", re));
338 ASSERT_FALSE(std::regex_match("5a", re));
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800339 ASSERT_FALSE(std::regex_match("1234ABCD", re));
340 ASSERT_TRUE(std::regex_match("CN 12D", re));
341 ASSERT_FALSE(std::regex_match(" 5A", re));
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800342
343 for (auto&& entry : config) {
344 EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
345
346 auto id = utils::make_identifier(IdentifierType::DAB_FREQUENCY, entry.frequency);
347 EXPECT_TRUE(utils::isValid(id));
348 }
349}
350
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800351/**
352 * Test tuning with FM selector.
353 *
354 * Verifies that:
355 * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
356 * - if it is supported, the method succeeds;
357 * - after a successful tune call, onCurrentProgramInfoChanged callback is
358 * invoked carrying a proper selector;
359 * - program changes exactly to what was requested.
360 */
361TEST_F(BroadcastRadioHalTest, FmTune) {
362 ASSERT_TRUE(openSession());
363
364 uint64_t freq = 100100; // 100.1 FM
365 auto sel = make_selector_amfm(freq);
366
367 // try tuning
368 ProgramInfo infoCb = {};
369 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _)
370 .Times(AnyNumber())
371 .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
372 auto result = mSession->tune(sel);
373
374 // expect a failure if it's not supported
375 if (!utils::isSupported(mProperties, sel)) {
376 EXPECT_EQ(Result::NOT_SUPPORTED, result);
377 return;
378 }
379
380 // expect a callback if it succeeds
381 EXPECT_EQ(Result::OK, result);
382 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
383
384 // it should tune exactly to what was requested
385 auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
386 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
387}
388
389/**
390 * Test tuning with invalid selectors.
391 *
392 * Verifies that:
393 * - if the selector is not supported, it's ignored;
394 * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
395 */
396TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) {
397 ASSERT_TRUE(openSession());
398
399 vector<ProgramIdentifier> invalid = {
400 make_identifier(IdentifierType::AMFM_FREQUENCY, 0),
401 make_identifier(IdentifierType::RDS_PI, 0x10000),
402 make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
403 make_identifier(IdentifierType::DAB_SID_EXT, 0),
404 make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
405 make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
406 };
407
408 for (auto&& id : invalid) {
409 ProgramSelector sel{id, {}};
410
411 auto result = mSession->tune(sel);
412
413 if (utils::isSupported(mProperties, sel)) {
414 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
415 } else {
416 EXPECT_EQ(Result::NOT_SUPPORTED, result);
417 }
418 }
419}
420
421/**
422 * Test tuning with empty program selector.
423 *
424 * Verifies that:
425 * - tune fails with NOT_SUPPORTED when program selector is not initialized.
426 */
427TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
428 ASSERT_TRUE(openSession());
429
430 // Program type is 1-based, so 0 will always be invalid.
431 ProgramSelector sel = {};
432 auto result = mSession->tune(sel);
433 ASSERT_EQ(Result::NOT_SUPPORTED, result);
434}
435
436/**
437 * Test scanning to next/prev station.
438 *
439 * Verifies that:
440 * - the method succeeds;
441 * - the program info is changed within timeout::tune;
442 * - works both directions and with or without skipping sub-channel.
443 */
444TEST_F(BroadcastRadioHalTest, Scan) {
445 ASSERT_TRUE(openSession());
446
447 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
448 auto result = mSession->scan(true /* up */, true /* skip subchannel */);
449 EXPECT_EQ(Result::OK, result);
450 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
451
452 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
453 result = mSession->scan(false /* down */, false /* don't skip subchannel */);
454 EXPECT_EQ(Result::OK, result);
455 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
456}
457
458/**
459 * Test step operation.
460 *
461 * Verifies that:
462 * - the method succeeds or returns NOT_SUPPORTED;
463 * - the program info is changed within timeout::tune if the method succeeded;
464 * - works both directions.
465 */
466TEST_F(BroadcastRadioHalTest, Step) {
467 ASSERT_TRUE(openSession());
468
469 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber());
470 auto result = mSession->step(true /* up */);
471 if (result == Result::NOT_SUPPORTED) return;
472 EXPECT_EQ(Result::OK, result);
473 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
474
475 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
476 result = mSession->step(false /* down */);
477 EXPECT_EQ(Result::OK, result);
478 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
479}
480
481/**
482 * Test tune cancellation.
483 *
484 * Verifies that:
485 * - the method does not crash after being invoked multiple times.
486 */
487TEST_F(BroadcastRadioHalTest, Cancel) {
488 ASSERT_TRUE(openSession());
489
490 for (int i = 0; i < 10; i++) {
491 auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */);
492 ASSERT_EQ(Result::OK, scanResult);
493
494 auto cancelResult = mSession->cancel();
495 ASSERT_TRUE(cancelResult.isOk());
496 }
497}
498
499/**
500 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
501 *
502 * Verifies that:
503 * - callback is called for empty parameters set.
504 */
505TEST_F(BroadcastRadioHalTest, NoParameters) {
506 ASSERT_TRUE(openSession());
507
508 hidl_vec<VendorKeyValue> halResults = {};
509 bool wasCalled = false;
510 auto cb = [&](hidl_vec<VendorKeyValue> results) {
511 wasCalled = true;
512 halResults = results;
513 };
514
515 auto hidlResult = mSession->setParameters({}, cb);
516 ASSERT_TRUE(hidlResult.isOk());
517 ASSERT_TRUE(wasCalled);
518 ASSERT_EQ(0u, halResults.size());
519
520 wasCalled = false;
521 hidlResult = mSession->getParameters({}, cb);
522 ASSERT_TRUE(hidlResult.isOk());
523 ASSERT_TRUE(wasCalled);
524 ASSERT_EQ(0u, halResults.size());
525}
526
527/**
528 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
529 *
530 * Verifies that:
531 * - unknown parameters are ignored;
532 * - callback is called also for empty results set.
533 */
534TEST_F(BroadcastRadioHalTest, UnknownParameters) {
535 ASSERT_TRUE(openSession());
536
537 hidl_vec<VendorKeyValue> halResults = {};
538 bool wasCalled = false;
539 auto cb = [&](hidl_vec<VendorKeyValue> results) {
540 wasCalled = true;
541 halResults = results;
542 };
543
544 auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb);
545 ASSERT_TRUE(hidlResult.isOk());
546 ASSERT_TRUE(wasCalled);
547 ASSERT_EQ(0u, halResults.size());
548
549 wasCalled = false;
550 hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb);
551 ASSERT_TRUE(hidlResult.isOk());
552 ASSERT_TRUE(wasCalled);
553 ASSERT_EQ(0u, halResults.size());
554}
555
556/**
557 * Test session closing.
558 *
559 * Verifies that:
560 * - the method does not crash after being invoked multiple times.
561 */
562TEST_F(BroadcastRadioHalTest, Close) {
563 ASSERT_TRUE(openSession());
564
565 for (int i = 0; i < 10; i++) {
566 auto cancelResult = mSession->close();
567 ASSERT_TRUE(cancelResult.isOk());
568 }
569}
570
571/**
572 * Test geting image of invalid ID.
573 *
574 * Verifies that:
575 * - getImage call handles argument 0 gracefully.
576 */
577TEST_F(BroadcastRadioHalTest, GetNoImage) {
578 size_t len = 0;
579 auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
580
581 ASSERT_TRUE(result.isOk());
582 ASSERT_EQ(0u, len);
583}
584
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800585/**
586 * Test getting config flags.
587 *
588 * Verifies that:
589 * - getConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
590 * - call success or failure is consistent with setConfigFlag.
591 */
592TEST_F(BroadcastRadioHalTest, GetConfigFlags) {
593 ASSERT_TRUE(openSession());
594
595 for (auto flag : gConfigFlagValues) {
596 auto halResult = Result::UNKNOWN_ERROR;
597 auto cb = [&](Result result, bool) { halResult = result; };
598 auto hidlResult = mSession->getConfigFlag(flag, cb);
599 EXPECT_TRUE(hidlResult.isOk());
600
601 if (halResult != Result::NOT_SUPPORTED && halResult != Result::INVALID_STATE) {
602 ASSERT_EQ(Result::OK, halResult);
603 }
604
605 // set must fail or succeed the same way as get
606 auto setResult = mSession->setConfigFlag(flag, false);
607 EXPECT_EQ(halResult, setResult);
608 setResult = mSession->setConfigFlag(flag, true);
609 EXPECT_EQ(halResult, setResult);
610 }
611}
612
613/**
614 * Test setting config flags.
615 *
616 * Verifies that:
617 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
618 * - getConfigFlag reflects the state requested immediately after the set call.
619 */
620TEST_F(BroadcastRadioHalTest, SetConfigFlags) {
621 ASSERT_TRUE(openSession());
622
623 auto get = [&](ConfigFlag flag) {
624 auto halResult = Result::UNKNOWN_ERROR;
625 bool gotValue = false;
626 auto cb = [&](Result result, bool value) {
627 halResult = result;
628 gotValue = value;
629 };
630 auto hidlResult = mSession->getConfigFlag(flag, cb);
631 EXPECT_TRUE(hidlResult.isOk());
632 EXPECT_EQ(Result::OK, halResult);
633 return gotValue;
634 };
635
636 for (auto flag : gConfigFlagValues) {
637 auto result = mSession->setConfigFlag(flag, false);
638 if (result == Result::NOT_SUPPORTED || result == Result::INVALID_STATE) {
639 // setting to true must result in the same error as false
640 auto secondResult = mSession->setConfigFlag(flag, true);
641 EXPECT_EQ(result, secondResult);
642 continue;
643 }
644 ASSERT_EQ(Result::OK, result);
645
646 // verify false is set
647 auto value = get(flag);
648 EXPECT_FALSE(value);
649
650 // try setting true this time
651 result = mSession->setConfigFlag(flag, true);
652 ASSERT_EQ(Result::OK, result);
653 value = get(flag);
654 EXPECT_TRUE(value);
655
656 // false again
657 result = mSession->setConfigFlag(flag, false);
658 ASSERT_EQ(Result::OK, result);
659 value = get(flag);
660 EXPECT_FALSE(value);
661 }
662}
663
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800664/**
665 * Test getting program list.
666 *
667 * Verifies that:
668 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
669 * - the complete list is fetched within timeout::programListScan;
670 * - stopProgramListUpdates does not crash.
671 */
672TEST_F(BroadcastRadioHalTest, GetProgramList) {
673 ASSERT_TRUE(openSession());
674
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800675 getProgramList();
676}
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800677
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800678/**
679 * Test HD_STATION_NAME correctness.
680 *
681 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
682 * - the program provides station name in its metadata;
683 * - the identifier matches the name;
684 * - there is only one identifier of that type.
685 */
686TEST_F(BroadcastRadioHalTest, HdRadioStationNameId) {
687 ASSERT_TRUE(openSession());
688
689 auto list = getProgramList();
690 if (!list) return;
691
692 for (auto&& program : *list) {
693 auto nameIds = utils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
694 EXPECT_LE(nameIds.size(), 1u);
695 if (nameIds.size() == 0) continue;
696
697 auto name = utils::getMetadataString(program, MetadataKey::PROGRAM_NAME);
698 if (!name) name = utils::getMetadataString(program, MetadataKey::RDS_PS);
699 ASSERT_TRUE(name.has_value());
700
701 auto expectedId = utils::make_hdradio_station_name(*name);
702 EXPECT_EQ(expectedId.value, nameIds[0]);
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800703 }
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800704}
705
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800706/**
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800707 * Test announcement listener registration.
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800708 *
709 * Verifies that:
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800710 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800711 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
712 * - closing handle does not crash.
713 */
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800714TEST_F(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
715 sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800716
717 Result halResult = Result::UNKNOWN_ERROR;
718 sp<ICloseHandle> closeHandle = nullptr;
719 auto cb = [&](Result result, const sp<ICloseHandle>& closeHandle_) {
720 halResult = result;
721 closeHandle = closeHandle_;
722 };
723
724 auto hidlResult =
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800725 mModule->registerAnnouncementListener({AnnouncementType::EMERGENCY}, listener, cb);
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800726 ASSERT_TRUE(hidlResult.isOk());
727
728 if (halResult == Result::NOT_SUPPORTED) {
729 ASSERT_EQ(nullptr, closeHandle.get());
730 printSkipped("Announcements not supported");
731 return;
732 }
733
734 ASSERT_EQ(Result::OK, halResult);
735 ASSERT_NE(nullptr, closeHandle.get());
736
737 closeHandle->close();
738}
739
Tomasz Wasilczyk4ce63822017-12-21 14:25:54 -0800740// TODO(b/70939328): test ProgramInfo's currentlyTunedId and
741// currentlyTunedChannel once the program list is implemented.
742
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800743} // namespace vts
744} // namespace V2_0
745} // namespace broadcastradio
746} // namespace hardware
747} // namespace android
748
749int main(int argc, char** argv) {
750 ::testing::InitGoogleTest(&argc, argv);
751 int status = RUN_ALL_TESTS();
752 ALOGI("Test result = %d", status);
753 return status;
754}