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