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