blob: 598926f95b6e664916156f8208d3f48e4c75ef57 [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"
Tomasz Wasilczykdb902862018-01-14 17:22:03 -080018#define LOG_NDEBUG 0
19#define EGMOCK_VERBOSE 1
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080020
21#include <VtsHalHidlTargetTestBase.h>
22#include <android-base/logging.h>
23#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
24#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
25#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
26#include <android/hardware/broadcastradio/2.0/types.h>
27#include <broadcastradio-utils-2x/Utils.h>
28#include <broadcastradio-vts-utils/call-barrier.h>
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080029#include <broadcastradio-vts-utils/environment-utils.h>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080030#include <broadcastradio-vts-utils/mock-timeout.h>
31#include <broadcastradio-vts-utils/pointer-utils.h>
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -080032#include <cutils/bitops.h>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080033#include <gmock/gmock.h>
34
35#include <chrono>
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -080036#include <optional>
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -080037#include <regex>
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080038
39namespace android {
40namespace hardware {
41namespace broadcastradio {
42namespace V2_0 {
43namespace vts {
44
45using namespace std::chrono_literals;
46
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080047using std::unordered_set;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080048using std::vector;
49using testing::_;
50using testing::AnyNumber;
51using testing::ByMove;
52using testing::DoAll;
53using testing::Invoke;
54using testing::SaveArg;
55
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080056using broadcastradio::vts::BroadcastRadioHidlEnvironment;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080057using broadcastradio::vts::CallBarrier;
58using broadcastradio::vts::clearAndWait;
59using utils::make_identifier;
60using utils::make_selector_amfm;
61
62namespace timeout {
63
64static constexpr auto tune = 30s;
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080065static constexpr auto programListScan = 5min;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080066
67} // namespace timeout
68
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -070069static constexpr auto gTuneWorkaround = 200ms;
70
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080071static const ConfigFlag gConfigFlagValues[] = {
Tomasz Wasilczyk30240f62017-12-20 14:19:21 -080072 ConfigFlag::FORCE_MONO,
73 ConfigFlag::FORCE_ANALOG,
74 ConfigFlag::FORCE_DIGITAL,
75 ConfigFlag::RDS_AF,
76 ConfigFlag::RDS_REG,
77 ConfigFlag::DAB_DAB_LINKING,
78 ConfigFlag::DAB_FM_LINKING,
79 ConfigFlag::DAB_DAB_SOFT_LINKING,
80 ConfigFlag::DAB_FM_SOFT_LINKING,
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -080081};
82
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080083class TunerCallbackMock : public ITunerCallback {
84 public:
85 TunerCallbackMock();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080086
87 MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
Tomasz Wasilczyk67360522018-02-10 14:05:18 -080088 MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged_, Return<void>(const ProgramInfo&));
89 virtual Return<void> onCurrentProgramInfoChanged(const ProgramInfo& info);
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080090 Return<void> onProgramListUpdated(const ProgramListChunk& chunk);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080091 MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
92 MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -080093
94 MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
95
96 std::mutex mLock;
97 utils::ProgramInfoSet mProgramList;
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -080098};
99
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800100struct AnnouncementListenerMock : public IAnnouncementListener {
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800101 MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
102};
103
Zhuoyao Zhang190548f2018-02-08 20:40:23 -0800104static BroadcastRadioHidlEnvironment<IBroadcastRadio>* gEnv = nullptr;
105
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800106class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
107 protected:
108 virtual void SetUp() override;
109 virtual void TearDown() override;
110
111 bool openSession();
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800112 bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800113 std::optional<utils::ProgramInfoSet> getProgramList();
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800114
115 sp<IBroadcastRadio> mModule;
116 Properties mProperties;
117 sp<ITunerSession> mSession;
118 sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
119};
120
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800121static void printSkipped(std::string msg) {
122 std::cout << "[ SKIPPED ] " << msg << std::endl;
123}
124
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800125MATCHER_P(InfoHasId, id,
126 std::string(negation ? "does not contain" : "contains") + " " + toString(id)) {
127 auto ids = utils::getAllIds(arg.selector, utils::getType(id));
128 return ids.end() != find(ids.begin(), ids.end(), id.value);
129}
130
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800131TunerCallbackMock::TunerCallbackMock() {
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800132 EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800133
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800134 // we expect the antenna is connected through the whole test
135 EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
136}
137
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800138Return<void> TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
139 auto logically = utils::getType(info.logicallyTunedTo);
140 if (logically != IdentifierType::INVALID) {
141 EXPECT_TRUE(logically == IdentifierType::AMFM_FREQUENCY ||
142 logically == IdentifierType::RDS_PI ||
143 logically == IdentifierType::HD_STATION_ID_EXT ||
144 logically == IdentifierType::DAB_SID_EXT ||
145 logically == IdentifierType::DRMO_SERVICE_ID ||
146 logically == IdentifierType::SXM_SERVICE_ID ||
147 (logically >= IdentifierType::VENDOR_START &&
148 logically <= IdentifierType::VENDOR_END) ||
149 logically > IdentifierType::SXM_CHANNEL);
150 }
151
152 auto physically = utils::getType(info.physicallyTunedTo);
153 if (physically != IdentifierType::INVALID) {
154 EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY ||
155 physically == IdentifierType::DAB_ENSEMBLE ||
156 physically == IdentifierType::DRMO_FREQUENCY ||
157 physically == IdentifierType::SXM_CHANNEL ||
158 (physically >= IdentifierType::VENDOR_START &&
159 physically <= IdentifierType::VENDOR_END) ||
160 physically > IdentifierType::SXM_CHANNEL);
161 }
162
163 return onCurrentProgramInfoChanged_(info);
164}
165
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800166Return<void> TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
167 std::lock_guard<std::mutex> lk(mLock);
168
169 updateProgramList(mProgramList, chunk);
170
171 if (chunk.complete) onProgramListReady();
172
173 return {};
174}
175
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800176void BroadcastRadioHalTest::SetUp() {
177 EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
178
179 // lookup HIDL service (radio module)
Zhuoyao Zhang190548f2018-02-08 20:40:23 -0800180 mModule = getService<IBroadcastRadio>(gEnv->getServiceName<IBroadcastRadio>());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800181 ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
182
183 // get module properties
184 auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; });
185 ASSERT_TRUE(propResult.isOk());
186
187 EXPECT_FALSE(mProperties.maker.empty());
188 EXPECT_FALSE(mProperties.product.empty());
189 EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
190}
191
192void BroadcastRadioHalTest::TearDown() {
193 mSession.clear();
194 mModule.clear();
195 clearAndWait(mCallback, 1s);
196}
197
198bool BroadcastRadioHalTest::openSession() {
199 EXPECT_EQ(nullptr, mSession.get()) << "Session is already open";
200
201 Result halResult = Result::UNKNOWN_ERROR;
202 auto openCb = [&](Result result, const sp<ITunerSession>& session) {
203 halResult = result;
204 if (result != Result::OK) return;
205 mSession = session;
206 };
207 auto hidlResult = mModule->openSession(mCallback, openCb);
208
209 EXPECT_TRUE(hidlResult.isOk());
210 EXPECT_EQ(Result::OK, halResult);
211 EXPECT_NE(nullptr, mSession.get());
212
213 return nullptr != mSession.get();
214}
215
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800216bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
217 auto halResult = Result::UNKNOWN_ERROR;
218 auto cb = [&](Result result, AmFmRegionConfig configCb) {
219 halResult = result;
220 if (config) *config = configCb;
221 };
222
223 auto hidlResult = mModule->getAmFmRegionConfig(full, cb);
224 EXPECT_TRUE(hidlResult.isOk());
225
226 if (halResult == Result::NOT_SUPPORTED) return false;
227
228 EXPECT_EQ(Result::OK, halResult);
229 return halResult == Result::OK;
230}
231
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800232std::optional<utils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
233 EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
234
235 auto startResult = mSession->startProgramListUpdates({});
236 if (startResult == Result::NOT_SUPPORTED) {
237 printSkipped("Program list not supported");
238 return nullopt;
239 }
240 EXPECT_EQ(Result::OK, startResult);
241 if (startResult != Result::OK) return nullopt;
242
243 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
244
245 auto stopResult = mSession->stopProgramListUpdates();
246 EXPECT_TRUE(stopResult.isOk());
247
248 return mCallback->mProgramList;
249}
250
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800251/**
252 * Test session opening.
253 *
254 * Verifies that:
255 * - the method succeeds on a first and subsequent calls;
256 * - the method succeeds when called for the second time without
257 * closing previous session.
258 */
259TEST_F(BroadcastRadioHalTest, OpenSession) {
260 // simply open session for the first time
261 ASSERT_TRUE(openSession());
262
263 // drop (without explicit close) and re-open the session
264 mSession.clear();
265 ASSERT_TRUE(openSession());
266
267 // open the second session (the first one should be forcibly closed)
268 auto secondSession = mSession;
269 mSession.clear();
270 ASSERT_TRUE(openSession());
271}
272
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800273static bool isValidAmFmFreq(uint64_t freq) {
274 auto id = utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq);
275 return utils::isValid(id);
276}
277
278static void validateRange(const AmFmBandRange& range) {
279 EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
280 EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
281 EXPECT_LT(range.lowerBound, range.upperBound);
282 EXPECT_GT(range.spacing, 0u);
283 EXPECT_EQ(0u, (range.upperBound - range.lowerBound) % range.spacing);
284}
285
286static bool supportsFM(const AmFmRegionConfig& config) {
287 for (auto&& range : config.ranges) {
288 if (utils::getBand(range.lowerBound) == utils::FrequencyBand::FM) return true;
289 }
290 return false;
291}
292
293/**
294 * Test fetching AM/FM regional configuration.
295 *
296 * Verifies that:
297 * - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
298 * - there is at least one AM/FM band configured;
299 * - FM Deemphasis and RDS are correctly configured for FM-capable radio;
300 * - all channel grids (frequency ranges and spacings) are valid;
301 * - scan spacing is a multiply of manual spacing value.
302 */
303TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) {
304 AmFmRegionConfig config;
305 bool supported = getAmFmRegionConfig(false, &config);
306 if (!supported) {
307 printSkipped("AM/FM not supported");
308 return;
309 }
310
311 EXPECT_GT(config.ranges.size(), 0u);
312 EXPECT_LE(popcountll(config.fmDeemphasis), 1);
313 EXPECT_LE(popcountll(config.fmRds), 1);
314
315 for (auto&& range : config.ranges) {
316 validateRange(range);
317 EXPECT_EQ(0u, range.scanSpacing % range.spacing);
318 EXPECT_GE(range.scanSpacing, range.spacing);
319 }
320
321 if (supportsFM(config)) {
322 EXPECT_EQ(popcountll(config.fmDeemphasis), 1);
323 }
324}
325
326/**
327 * Test fetching AM/FM regional capabilities.
328 *
329 * Verifies that:
330 * - AM/FM regional capabilities are either available or not supported at all by the hardware;
331 * - there is at least one AM/FM range supported;
332 * - there is at least one de-emphasis filter mode supported for FM-capable radio;
333 * - all channel grids (frequency ranges and spacings) are valid;
334 * - scan spacing is not set.
335 */
336TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
337 AmFmRegionConfig config;
338 bool supported = getAmFmRegionConfig(true, &config);
339 if (!supported) {
340 printSkipped("AM/FM not supported");
341 return;
342 }
343
344 EXPECT_GT(config.ranges.size(), 0u);
345
346 for (auto&& range : config.ranges) {
347 validateRange(range);
348 EXPECT_EQ(0u, range.scanSpacing);
349 }
350
351 if (supportsFM(config)) {
352 EXPECT_GE(popcountll(config.fmDeemphasis), 1);
353 }
354}
355
356/**
357 * Test fetching DAB regional configuration.
358 *
359 * Verifies that:
360 * - DAB regional configuration is either set at startup or not supported at all by the hardware;
361 * - all channel labels match correct format;
362 * - all channel frequencies are in correct range.
363 */
364TEST_F(BroadcastRadioHalTest, GetDabRegionConfig) {
365 Result halResult;
366 hidl_vec<DabTableEntry> config;
367 auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
368 halResult = result;
369 config = configCb;
370 };
371 auto hidlResult = mModule->getDabRegionConfig(cb);
372 ASSERT_TRUE(hidlResult.isOk());
373
374 if (halResult == Result::NOT_SUPPORTED) {
375 printSkipped("DAB not supported");
376 return;
377 }
378 ASSERT_EQ(Result::OK, halResult);
379
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800380 std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800381 // double-check correctness of the test
382 ASSERT_TRUE(std::regex_match("5A", re));
383 ASSERT_FALSE(std::regex_match("5a", re));
Tomasz Wasilczyka425ded2018-01-12 15:15:59 -0800384 ASSERT_FALSE(std::regex_match("1234ABCD", re));
385 ASSERT_TRUE(std::regex_match("CN 12D", re));
386 ASSERT_FALSE(std::regex_match(" 5A", re));
Tomasz Wasilczyk8b70ee42017-12-21 11:51:29 -0800387
388 for (auto&& entry : config) {
389 EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
390
391 auto id = utils::make_identifier(IdentifierType::DAB_FREQUENCY, entry.frequency);
392 EXPECT_TRUE(utils::isValid(id));
393 }
394}
395
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800396/**
397 * Test tuning with FM selector.
398 *
399 * Verifies that:
400 * - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
401 * - if it is supported, the method succeeds;
402 * - after a successful tune call, onCurrentProgramInfoChanged callback is
403 * invoked carrying a proper selector;
404 * - program changes exactly to what was requested.
405 */
406TEST_F(BroadcastRadioHalTest, FmTune) {
407 ASSERT_TRUE(openSession());
408
409 uint64_t freq = 100100; // 100.1 FM
410 auto sel = make_selector_amfm(freq);
411
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800412 /* TODO(b/69958777): there is a race condition between tune() and onCurrentProgramInfoChanged
413 * callback setting infoCb, because egmock cannot distinguish calls with different matchers
414 * (there is one here and one in callback constructor).
415 *
416 * This sleep workaround will fix default implementation, but the real HW tests will still be
417 * flaky. We probably need to implement egmock alternative based on actions.
418 */
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700419 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800420
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800421 // try tuning
422 ProgramInfo infoCb = {};
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800423 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_,
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800424 InfoHasId(utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq)))
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800425 .Times(AnyNumber())
426 .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
427 auto result = mSession->tune(sel);
428
429 // expect a failure if it's not supported
430 if (!utils::isSupported(mProperties, sel)) {
431 EXPECT_EQ(Result::NOT_SUPPORTED, result);
432 return;
433 }
434
435 // expect a callback if it succeeds
436 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800437 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800438
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800439 ALOGD("current program info: %s", toString(infoCb).c_str());
440
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800441 // it should tune exactly to what was requested
442 auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
443 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
444}
445
446/**
447 * Test tuning with invalid selectors.
448 *
449 * Verifies that:
450 * - if the selector is not supported, it's ignored;
451 * - if it is supported, an invalid value results with INVALID_ARGUMENTS;
452 */
453TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) {
454 ASSERT_TRUE(openSession());
455
456 vector<ProgramIdentifier> invalid = {
457 make_identifier(IdentifierType::AMFM_FREQUENCY, 0),
458 make_identifier(IdentifierType::RDS_PI, 0x10000),
459 make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
460 make_identifier(IdentifierType::DAB_SID_EXT, 0),
461 make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
462 make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
463 };
464
465 for (auto&& id : invalid) {
466 ProgramSelector sel{id, {}};
467
468 auto result = mSession->tune(sel);
469
470 if (utils::isSupported(mProperties, sel)) {
471 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
472 } else {
473 EXPECT_EQ(Result::NOT_SUPPORTED, result);
474 }
475 }
476}
477
478/**
479 * Test tuning with empty program selector.
480 *
481 * Verifies that:
482 * - tune fails with NOT_SUPPORTED when program selector is not initialized.
483 */
484TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
485 ASSERT_TRUE(openSession());
486
487 // Program type is 1-based, so 0 will always be invalid.
488 ProgramSelector sel = {};
489 auto result = mSession->tune(sel);
490 ASSERT_EQ(Result::NOT_SUPPORTED, result);
491}
492
493/**
494 * Test scanning to next/prev station.
495 *
496 * Verifies that:
497 * - the method succeeds;
498 * - the program info is changed within timeout::tune;
499 * - works both directions and with or without skipping sub-channel.
500 */
501TEST_F(BroadcastRadioHalTest, Scan) {
502 ASSERT_TRUE(openSession());
503
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800504 // TODO(b/69958777): see FmTune workaround
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700505 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800506
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800507 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800508 auto result = mSession->scan(true /* up */, true /* skip subchannel */);
509 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800510 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800511
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800512 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800513 result = mSession->scan(false /* down */, false /* don't skip subchannel */);
514 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800515 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800516}
517
518/**
519 * Test step operation.
520 *
521 * Verifies that:
522 * - the method succeeds or returns NOT_SUPPORTED;
523 * - the program info is changed within timeout::tune if the method succeeded;
524 * - works both directions.
525 */
526TEST_F(BroadcastRadioHalTest, Step) {
527 ASSERT_TRUE(openSession());
528
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800529 // TODO(b/69958777): see FmTune workaround
Tomasz Wasilczyk55241f72018-04-30 08:53:24 -0700530 std::this_thread::sleep_for(gTuneWorkaround);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800531
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800532 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _).Times(AnyNumber());
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800533 auto result = mSession->step(true /* up */);
Tomasz Wasilczykdb902862018-01-14 17:22:03 -0800534 if (result == Result::NOT_SUPPORTED) {
535 printSkipped("step not supported");
536 return;
537 }
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800538 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800539 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800540
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800541 EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged_, _);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800542 result = mSession->step(false /* down */);
543 EXPECT_EQ(Result::OK, result);
Tomasz Wasilczyk67360522018-02-10 14:05:18 -0800544 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged_, timeout::tune);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800545}
546
547/**
548 * Test tune cancellation.
549 *
550 * Verifies that:
551 * - the method does not crash after being invoked multiple times.
552 */
553TEST_F(BroadcastRadioHalTest, Cancel) {
554 ASSERT_TRUE(openSession());
555
556 for (int i = 0; i < 10; i++) {
557 auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */);
558 ASSERT_EQ(Result::OK, scanResult);
559
560 auto cancelResult = mSession->cancel();
561 ASSERT_TRUE(cancelResult.isOk());
562 }
563}
564
565/**
566 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
567 *
568 * Verifies that:
569 * - callback is called for empty parameters set.
570 */
571TEST_F(BroadcastRadioHalTest, NoParameters) {
572 ASSERT_TRUE(openSession());
573
574 hidl_vec<VendorKeyValue> halResults = {};
575 bool wasCalled = false;
576 auto cb = [&](hidl_vec<VendorKeyValue> results) {
577 wasCalled = true;
578 halResults = results;
579 };
580
581 auto hidlResult = mSession->setParameters({}, cb);
582 ASSERT_TRUE(hidlResult.isOk());
583 ASSERT_TRUE(wasCalled);
584 ASSERT_EQ(0u, halResults.size());
585
586 wasCalled = false;
587 hidlResult = mSession->getParameters({}, cb);
588 ASSERT_TRUE(hidlResult.isOk());
589 ASSERT_TRUE(wasCalled);
590 ASSERT_EQ(0u, halResults.size());
591}
592
593/**
594 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
595 *
596 * Verifies that:
597 * - unknown parameters are ignored;
598 * - callback is called also for empty results set.
599 */
600TEST_F(BroadcastRadioHalTest, UnknownParameters) {
601 ASSERT_TRUE(openSession());
602
603 hidl_vec<VendorKeyValue> halResults = {};
604 bool wasCalled = false;
605 auto cb = [&](hidl_vec<VendorKeyValue> results) {
606 wasCalled = true;
607 halResults = results;
608 };
609
610 auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb);
611 ASSERT_TRUE(hidlResult.isOk());
612 ASSERT_TRUE(wasCalled);
613 ASSERT_EQ(0u, halResults.size());
614
615 wasCalled = false;
616 hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb);
617 ASSERT_TRUE(hidlResult.isOk());
618 ASSERT_TRUE(wasCalled);
619 ASSERT_EQ(0u, halResults.size());
620}
621
622/**
623 * Test session closing.
624 *
625 * Verifies that:
626 * - the method does not crash after being invoked multiple times.
627 */
628TEST_F(BroadcastRadioHalTest, Close) {
629 ASSERT_TRUE(openSession());
630
631 for (int i = 0; i < 10; i++) {
632 auto cancelResult = mSession->close();
633 ASSERT_TRUE(cancelResult.isOk());
634 }
635}
636
637/**
638 * Test geting image of invalid ID.
639 *
640 * Verifies that:
641 * - getImage call handles argument 0 gracefully.
642 */
643TEST_F(BroadcastRadioHalTest, GetNoImage) {
644 size_t len = 0;
645 auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
646
647 ASSERT_TRUE(result.isOk());
648 ASSERT_EQ(0u, len);
649}
650
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800651/**
652 * Test getting config flags.
653 *
654 * Verifies that:
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800655 * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800656 * - call success or failure is consistent with setConfigFlag.
657 */
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800658TEST_F(BroadcastRadioHalTest, FetchConfigFlags) {
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800659 ASSERT_TRUE(openSession());
660
661 for (auto flag : gConfigFlagValues) {
662 auto halResult = Result::UNKNOWN_ERROR;
663 auto cb = [&](Result result, bool) { halResult = result; };
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800664 auto hidlResult = mSession->isConfigFlagSet(flag, cb);
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800665 EXPECT_TRUE(hidlResult.isOk());
666
667 if (halResult != Result::NOT_SUPPORTED && halResult != Result::INVALID_STATE) {
668 ASSERT_EQ(Result::OK, halResult);
669 }
670
671 // set must fail or succeed the same way as get
672 auto setResult = mSession->setConfigFlag(flag, false);
673 EXPECT_EQ(halResult, setResult);
674 setResult = mSession->setConfigFlag(flag, true);
675 EXPECT_EQ(halResult, setResult);
676 }
677}
678
679/**
680 * Test setting config flags.
681 *
682 * Verifies that:
683 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800684 * - isConfigFlagSet reflects the state requested immediately after the set call.
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800685 */
686TEST_F(BroadcastRadioHalTest, SetConfigFlags) {
687 ASSERT_TRUE(openSession());
688
689 auto get = [&](ConfigFlag flag) {
690 auto halResult = Result::UNKNOWN_ERROR;
691 bool gotValue = false;
692 auto cb = [&](Result result, bool value) {
693 halResult = result;
694 gotValue = value;
695 };
Tomasz Wasilczyk3dd452a2018-01-12 14:57:45 -0800696 auto hidlResult = mSession->isConfigFlagSet(flag, cb);
Tomasz Wasilczyk43fe8942017-12-14 11:44:12 -0800697 EXPECT_TRUE(hidlResult.isOk());
698 EXPECT_EQ(Result::OK, halResult);
699 return gotValue;
700 };
701
702 for (auto flag : gConfigFlagValues) {
703 auto result = mSession->setConfigFlag(flag, false);
704 if (result == Result::NOT_SUPPORTED || result == Result::INVALID_STATE) {
705 // setting to true must result in the same error as false
706 auto secondResult = mSession->setConfigFlag(flag, true);
707 EXPECT_EQ(result, secondResult);
708 continue;
709 }
710 ASSERT_EQ(Result::OK, result);
711
712 // verify false is set
713 auto value = get(flag);
714 EXPECT_FALSE(value);
715
716 // try setting true this time
717 result = mSession->setConfigFlag(flag, true);
718 ASSERT_EQ(Result::OK, result);
719 value = get(flag);
720 EXPECT_TRUE(value);
721
722 // false again
723 result = mSession->setConfigFlag(flag, false);
724 ASSERT_EQ(Result::OK, result);
725 value = get(flag);
726 EXPECT_FALSE(value);
727 }
728}
729
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800730/**
731 * Test getting program list.
732 *
733 * Verifies that:
734 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
735 * - the complete list is fetched within timeout::programListScan;
736 * - stopProgramListUpdates does not crash.
737 */
738TEST_F(BroadcastRadioHalTest, GetProgramList) {
739 ASSERT_TRUE(openSession());
740
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800741 getProgramList();
742}
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800743
Tomasz Wasilczykc71624f2017-12-22 10:54:34 -0800744/**
745 * Test HD_STATION_NAME correctness.
746 *
747 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
748 * - the program provides station name in its metadata;
749 * - the identifier matches the name;
750 * - there is only one identifier of that type.
751 */
752TEST_F(BroadcastRadioHalTest, HdRadioStationNameId) {
753 ASSERT_TRUE(openSession());
754
755 auto list = getProgramList();
756 if (!list) return;
757
758 for (auto&& program : *list) {
759 auto nameIds = utils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
760 EXPECT_LE(nameIds.size(), 1u);
761 if (nameIds.size() == 0) continue;
762
763 auto name = utils::getMetadataString(program, MetadataKey::PROGRAM_NAME);
764 if (!name) name = utils::getMetadataString(program, MetadataKey::RDS_PS);
765 ASSERT_TRUE(name.has_value());
766
767 auto expectedId = utils::make_hdradio_station_name(*name);
768 EXPECT_EQ(expectedId.value, nameIds[0]);
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800769 }
Tomasz Wasilczykbceb8852017-12-18 13:59:29 -0800770}
771
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800772/**
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800773 * Test announcement listener registration.
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800774 *
775 * Verifies that:
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800776 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800777 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
778 * - closing handle does not crash.
779 */
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800780TEST_F(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
781 sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800782
783 Result halResult = Result::UNKNOWN_ERROR;
784 sp<ICloseHandle> closeHandle = nullptr;
785 auto cb = [&](Result result, const sp<ICloseHandle>& closeHandle_) {
786 halResult = result;
787 closeHandle = closeHandle_;
788 };
789
790 auto hidlResult =
Tomasz Wasilczyk0d5ef5d2018-01-10 10:58:20 -0800791 mModule->registerAnnouncementListener({AnnouncementType::EMERGENCY}, listener, cb);
Tomasz Wasilczyk6a9f8562017-12-27 09:46:43 -0800792 ASSERT_TRUE(hidlResult.isOk());
793
794 if (halResult == Result::NOT_SUPPORTED) {
795 ASSERT_EQ(nullptr, closeHandle.get());
796 printSkipped("Announcements not supported");
797 return;
798 }
799
800 ASSERT_EQ(Result::OK, halResult);
801 ASSERT_NE(nullptr, closeHandle.get());
802
803 closeHandle->close();
804}
805
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800806} // namespace vts
807} // namespace V2_0
808} // namespace broadcastradio
809} // namespace hardware
810} // namespace android
811
812int main(int argc, char** argv) {
Zhuoyao Zhang190548f2018-02-08 20:40:23 -0800813 using android::hardware::broadcastradio::V2_0::vts::gEnv;
814 using android::hardware::broadcastradio::V2_0::IBroadcastRadio;
815 using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
816 gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadio>;
817 ::testing::AddGlobalTestEnvironment(gEnv);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800818 ::testing::InitGoogleTest(&argc, argv);
Zhuoyao Zhang190548f2018-02-08 20:40:23 -0800819 gEnv->init(&argc, argv);
Tomasz Wasilczyk31e86322017-12-05 09:36:11 -0800820 int status = RUN_ALL_TESTS();
821 ALOGI("Test result = %d", status);
822 return status;
823}