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