1/* 2 * Copyright (C) 2016 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 "BroadcastRadioHidlHalTest" 18#include <VtsHalHidlTargetTestBase.h> 19#include <android-base/logging.h> 20#include <cutils/native_handle.h> 21#include <cutils/properties.h> 22#include <hidl/HidlTransportSupport.h> 23#include <utils/threads.h> 24 25#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> 26#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> 27#include <android/hardware/broadcastradio/1.0/ITuner.h> 28#include <android/hardware/broadcastradio/1.0/ITunerCallback.h> 29#include <android/hardware/broadcastradio/1.0/types.h> 30 31 32using ::android::sp; 33using ::android::Mutex; 34using ::android::Condition; 35using ::android::hardware::Return; 36using ::android::hardware::Void; 37using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; 38using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; 39using ::android::hardware::broadcastradio::V1_0::ITuner; 40using ::android::hardware::broadcastradio::V1_0::ITunerCallback; 41using ::android::hardware::broadcastradio::V1_0::Result; 42using ::android::hardware::broadcastradio::V1_0::Class; 43using ::android::hardware::broadcastradio::V1_0::Properties; 44using ::android::hardware::broadcastradio::V1_0::Band; 45using ::android::hardware::broadcastradio::V1_0::BandConfig; 46using ::android::hardware::broadcastradio::V1_0::Direction; 47using ::android::hardware::broadcastradio::V1_0::ProgramInfo; 48using ::android::hardware::broadcastradio::V1_0::MetaData; 49using ::android::hardware::broadcastradio::V1_0::MetadataKey; 50using ::android::hardware::broadcastradio::V1_0::MetadataType; 51 52#define RETURN_IF_SKIPPED \ 53 if (skipped) { \ 54 std::cout << "[ SKIPPED ] This device class is not supported. " << std::endl; \ 55 return; \ 56 } 57 58// The main test class for Broadcast Radio HIDL HAL. 59 60class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase, 61 public ::testing::WithParamInterface<Class> { 62 protected: 63 virtual void SetUp() override { 64 ASSERT_EQ(nullptr, mRadio.get()); 65 66 radioClass = GetParam(); 67 skipped = false; 68 69 sp<IBroadcastRadioFactory> factory = 70 ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); 71 ASSERT_NE(nullptr, factory.get()); 72 73 Result connectResult; 74 factory->connectModule(radioClass, [&](Result ret, const sp<IBroadcastRadio>& radio) { 75 connectResult = ret; 76 mRadio = radio; 77 onCallback_l(); 78 }); 79 EXPECT_EQ(true, waitForCallback(kConnectCallbacktimeoutNs)); 80 mCallbackCalled = false; 81 82 if (connectResult == Result::INVALID_ARGUMENTS) { 83 skipped = true; 84 return; 85 } 86 ASSERT_EQ(connectResult, Result::OK); 87 88 mTunerCallback = new MyCallback(this); 89 ASSERT_NE(nullptr, mRadio.get()); 90 ASSERT_NE(nullptr, mTunerCallback.get()); 91 } 92 93 virtual void TearDown() override { 94 mTuner.clear(); 95 mRadio.clear(); 96 } 97 98 class MyCallback : public ITunerCallback { 99 public: 100 101 // ITunerCallback methods (see doc in ITunerCallback.hal) 102 virtual Return<void> hardwareFailure() { 103 ALOGI("%s", __FUNCTION__); 104 mParentTest->onHwFailureCallback(); 105 return Void(); 106 } 107 108 virtual Return<void> configChange(Result result, const BandConfig& config) { 109 ALOGI("%s result %d", __FUNCTION__, result); 110 mParentTest->onConfigChangeCallback(result, config); 111 return Void(); 112 } 113 114 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) { 115 ALOGI("%s result %d", __FUNCTION__, result); 116 mParentTest->onTuneCompleteCallback(result, info); 117 return Void(); 118 } 119 120 virtual Return<void> afSwitch(const ProgramInfo& info __unused) { 121 return Void(); 122 } 123 124 virtual Return<void> antennaStateChange(bool connected) { 125 ALOGI("%s connected %d", __FUNCTION__, connected); 126 return Void(); 127 } 128 129 virtual Return<void> trafficAnnouncement(bool active) { 130 ALOGI("%s active %d", __FUNCTION__, active); 131 return Void(); 132 } 133 134 virtual Return<void> emergencyAnnouncement(bool active) { 135 ALOGI("%s active %d", __FUNCTION__, active); 136 return Void(); 137 } 138 139 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, 140 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { 141 ALOGI("%s", __FUNCTION__); 142 return Void(); 143 } 144 145 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} 146 147 private: 148 // BroadcastRadioHidlTest instance to which callbacks will be notified. 149 BroadcastRadioHidlTest *mParentTest; 150 }; 151 152 153 /** 154 * Method called by MyCallback when a callback with no status or boolean value is received 155 */ 156 void onCallback() { 157 Mutex::Autolock _l(mLock); 158 onCallback_l(); 159 } 160 161 /** 162 * Method called by MyCallback when hardwareFailure() callback is received 163 */ 164 void onHwFailureCallback() { 165 Mutex::Autolock _l(mLock); 166 mHwFailure = true; 167 onCallback_l(); 168 } 169 170 /** 171 * Method called by MyCallback when configChange() callback is received. 172 */ 173 void onConfigChangeCallback(Result result, const BandConfig& config) { 174 Mutex::Autolock _l(mLock); 175 mResultCallbackData = result; 176 mBandConfigCallbackData = config; 177 onCallback_l(); 178 } 179 180 /** 181 * Method called by MyCallback when tuneComplete() callback is received. 182 */ 183 void onTuneCompleteCallback(Result result, const ProgramInfo& info) { 184 Mutex::Autolock _l(mLock); 185 mResultCallbackData = result; 186 mProgramInfoCallbackData = info; 187 onCallback_l(); 188 } 189 190 /** 191 * Method called by MyCallback when a boolean indication is received 192 */ 193 void onBoolCallback(bool result) { 194 Mutex::Autolock _l(mLock); 195 mBoolCallbackData = result; 196 onCallback_l(); 197 } 198 199 200 BroadcastRadioHidlTest() 201 : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK), 202 mHwFailure(false) {} 203 204 void onCallback_l() { 205 if (!mCallbackCalled) { 206 mCallbackCalled = true; 207 mCallbackCond.broadcast(); 208 } 209 } 210 211 212 bool waitForCallback(nsecs_t reltime = 0) { 213 Mutex::Autolock _l(mLock); 214 nsecs_t endTime = systemTime() + reltime; 215 while (!mCallbackCalled) { 216 if (reltime == 0) { 217 mCallbackCond.wait(mLock); 218 } else { 219 nsecs_t now = systemTime(); 220 if (now > endTime) { 221 return false; 222 } 223 mCallbackCond.waitRelative(mLock, endTime - now); 224 } 225 } 226 return true; 227 } 228 229 bool getProperties(); 230 bool openTuner(); 231 bool checkAntenna(); 232 233 /** 234 * Retrieves AM/FM band configuration from module properties. 235 * 236 * The configuration may not exist: if radio type is other than AM/FM 237 * or provided index is out of bounds. 238 * In such case, empty configuration is returned. 239 * 240 * @param idx Band index to retrieve. 241 * @return Band configuration reference. 242 */ 243 const BandConfig& getBand(unsigned idx); 244 245 static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1); 246 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); 247 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); 248 249 Class radioClass; 250 bool skipped; 251 sp<IBroadcastRadio> mRadio; 252 Properties mHalProperties; 253 bool mHalPropertiesInitialized = false; 254 sp<ITuner> mTuner; 255 sp<MyCallback> mTunerCallback; 256 Mutex mLock; 257 Condition mCallbackCond; 258 bool mCallbackCalled; 259 bool mBoolCallbackData; 260 Result mResultCallbackData; 261 ProgramInfo mProgramInfoCallbackData; 262 BandConfig mBandConfigCallbackData; 263 bool mHwFailure; 264}; 265 266namespace android { 267namespace hardware { 268namespace broadcastradio { 269namespace V1_0 { 270 271/** 272 * Compares two BandConfig objects for testing purposes. 273 */ 274static bool operator==(const BandConfig& l, const BandConfig& r) { 275 if (l.type != r.type) return false; 276 if (l.antennaConnected != r.antennaConnected) return false; 277 if (l.lowerLimit != r.lowerLimit) return false; 278 if (l.upperLimit != r.upperLimit) return false; 279 if (l.spacings != r.spacings) return false; 280 if (l.type == Band::AM || l.type == Band::AM_HD) { 281 return l.ext.am == r.ext.am; 282 } else if (l.type == Band::FM || l.type == Band::FM_HD) { 283 return l.ext.fm == r.ext.fm; 284 } else { 285 // unsupported type 286 return false; 287 } 288} 289 290} // V1_0 291} // broadcastradio 292} // hardware 293} // android 294 295bool BroadcastRadioHidlTest::getProperties() 296{ 297 if (mHalPropertiesInitialized) return true; 298 299 Result halResult = Result::NOT_INITIALIZED; 300 auto hidlReturn = mRadio->getProperties([&](Result result, const Properties& properties) { 301 halResult = result; 302 if (result == Result::OK) { 303 mHalProperties = properties; 304 } 305 }); 306 307 EXPECT_TRUE(hidlReturn.isOk()); 308 EXPECT_EQ(Result::OK, halResult); 309 EXPECT_EQ(radioClass, mHalProperties.classId); 310 EXPECT_GT(mHalProperties.numTuners, 0u); 311 if (radioClass == Class::AM_FM) { 312 EXPECT_GT(mHalProperties.bands.size(), 0u); 313 } 314 315 if (hidlReturn.isOk() && halResult == Result::OK) { 316 mHalPropertiesInitialized = true; 317 return true; 318 } 319 return false; 320} 321 322bool BroadcastRadioHidlTest::openTuner() 323{ 324 if (!getProperties()) { 325 return false; 326 } 327 if (mTuner.get() == nullptr) { 328 Result halResult = Result::NOT_INITIALIZED; 329 auto openCb = [&](Result result, const sp<ITuner>& tuner) { 330 halResult = result; 331 if (result == Result::OK) { 332 mTuner = tuner; 333 } 334 }; 335 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb); 336 EXPECT_TRUE(hidlReturn.isOk()); 337 EXPECT_EQ(Result::OK, halResult); 338 if (radioClass == Class::AM_FM) { 339 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 340 } 341 } 342 EXPECT_NE(nullptr, mTuner.get()); 343 return nullptr != mTuner.get(); 344} 345 346bool BroadcastRadioHidlTest::checkAntenna() 347{ 348 if (radioClass != Class::AM_FM) return true; 349 350 BandConfig halConfig; 351 Result halResult = Result::NOT_INITIALIZED; 352 Return<void> hidlReturn = 353 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 354 halResult = result; 355 if (result == Result::OK) { 356 halConfig = config; 357 } 358 }); 359 360 return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); 361} 362 363const BandConfig& BroadcastRadioHidlTest::getBand(unsigned idx) { 364 static BandConfig dummyBandConfig = {}; 365 if (radioClass == Class::AM_FM) { 366 EXPECT_GT(mHalProperties.bands.size(), idx); 367 if (mHalProperties.bands.size() > idx) { 368 return mHalProperties.bands[idx]; 369 } else { 370 return dummyBandConfig; 371 } 372 } else { 373 return dummyBandConfig; 374 } 375} 376 377/** 378 * Test IBroadcastRadio::getProperties() method 379 * 380 * Verifies that: 381 * - the HAL implements the method 382 * - the method returns 0 (no error) 383 * - the implementation class is radioClass 384 * - the implementation supports at least one tuner 385 * - the implementation supports at one band 386 */ 387TEST_P(BroadcastRadioHidlTest, GetProperties) { 388 RETURN_IF_SKIPPED; 389 EXPECT_EQ(true, getProperties()); 390} 391 392/** 393 * Test IBroadcastRadio::openTuner() method 394 * 395 * Verifies that: 396 * - the HAL implements the method 397 * - the method returns 0 (no error) and a valid ITuner interface 398 */ 399TEST_P(BroadcastRadioHidlTest, OpenTuner) { 400 RETURN_IF_SKIPPED; 401 EXPECT_EQ(true, openTuner()); 402} 403 404/** 405 * Test IBroadcastRadio::openTuner() after ITuner disposal. 406 * 407 * Verifies that: 408 * - ITuner destruction gets propagated through HAL 409 * - the openTuner method works well when called for the second time 410 */ 411TEST_P(BroadcastRadioHidlTest, ReopenTuner) { 412 RETURN_IF_SKIPPED; 413 EXPECT_TRUE(openTuner()); 414 mTuner.clear(); 415 EXPECT_TRUE(openTuner()); 416} 417 418/** 419 * Test IBroadcastRadio::openTuner() method called twice. 420 * 421 * Verifies that: 422 * - the openTuner method fails with INVALID_STATE or succeeds when called for the second time 423 * without deleting previous ITuner instance 424 */ 425TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) { 426 RETURN_IF_SKIPPED; 427 EXPECT_TRUE(openTuner()); 428 429 Result halResult = Result::NOT_INITIALIZED; 430 auto openCb = [&](Result result, const sp<ITuner>&) { halResult = result; }; 431 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb); 432 EXPECT_TRUE(hidlReturn.isOk()); 433 if (halResult == Result::OK) { 434 if (radioClass == Class::AM_FM) { 435 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); 436 } 437 } else { 438 EXPECT_EQ(Result::INVALID_STATE, halResult); 439 } 440} 441 442/** 443 * Test ITuner::setConfiguration() and getConfiguration methods 444 * 445 * Verifies that: 446 * - the HAL implements both methods 447 * - the methods return 0 (no error) 448 * - the configuration callback is received within kConfigCallbacktimeoutNs ns 449 * - the configuration read back from HAl has the same class Id 450 * 451 * Skipped for other radio classes than AM/FM, because setConfiguration 452 * applies only for these bands. 453 */ 454TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) { 455 if (radioClass != Class::AM_FM) skipped = true; 456 RETURN_IF_SKIPPED; 457 ASSERT_EQ(true, openTuner()); 458 // test setConfiguration 459 mCallbackCalled = false; 460 Return<Result> hidlResult = mTuner->setConfiguration(getBand(1)); 461 EXPECT_TRUE(hidlResult.isOk()); 462 EXPECT_EQ(Result::OK, hidlResult); 463 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 464 EXPECT_EQ(Result::OK, mResultCallbackData); 465 EXPECT_EQ(getBand(1), mBandConfigCallbackData); 466 467 // test getConfiguration 468 BandConfig halConfig; 469 Result halResult; 470 Return<void> hidlReturn = 471 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 472 halResult = result; 473 if (result == Result::OK) { 474 halConfig = config; 475 } 476 }); 477 EXPECT_TRUE(hidlReturn.isOk()); 478 EXPECT_EQ(Result::OK, halResult); 479 EXPECT_EQ(getBand(1), halConfig); 480} 481 482/** 483 * Test ITuner::setConfiguration() with invalid arguments. 484 * 485 * Verifies that: 486 * - the methods returns INVALID_ARGUMENTS on invalid arguments 487 * - the method recovers and succeeds after passing correct arguments 488 * 489 * Skipped for other radio classes than AM/FM, because setConfiguration 490 * applies only for these bands. 491 */ 492TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) { 493 if (radioClass != Class::AM_FM) skipped = true; 494 RETURN_IF_SKIPPED; 495 ASSERT_EQ(true, openTuner()); 496 497 // Let's define a config that's bad for sure. 498 BandConfig badConfig = {}; 499 badConfig.type = Band::FM; 500 badConfig.lowerLimit = 0xFFFFFFFF; 501 badConfig.upperLimit = 0; 502 badConfig.spacings = (std::vector<uint32_t>){ 0 }; 503 504 // Test setConfiguration failing on bad data. 505 mCallbackCalled = false; 506 auto setResult = mTuner->setConfiguration(badConfig); 507 EXPECT_TRUE(setResult.isOk()); 508 EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult); 509 510 // Test setConfiguration recovering after passing good data. 511 mCallbackCalled = false; 512 setResult = mTuner->setConfiguration(getBand(0)); 513 EXPECT_TRUE(setResult.isOk()); 514 EXPECT_EQ(Result::OK, setResult); 515 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 516 EXPECT_EQ(Result::OK, mResultCallbackData); 517} 518 519/** 520 * Test ITuner::scan 521 * 522 * Verifies that: 523 * - the HAL implements the method 524 * - the method returns 0 (no error) 525 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 526 * - skipping sub-channel or not does not fail the call 527 */ 528TEST_P(BroadcastRadioHidlTest, Scan) { 529 RETURN_IF_SKIPPED; 530 ASSERT_EQ(true, openTuner()); 531 ASSERT_TRUE(checkAntenna()); 532 // test scan UP 533 mCallbackCalled = false; 534 Return<Result> hidlResult = mTuner->scan(Direction::UP, true); 535 EXPECT_TRUE(hidlResult.isOk()); 536 EXPECT_EQ(Result::OK, hidlResult); 537 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 538 539 // test scan DOWN 540 mCallbackCalled = false; 541 hidlResult = mTuner->scan(Direction::DOWN, false); 542 EXPECT_TRUE(hidlResult.isOk()); 543 EXPECT_EQ(Result::OK, hidlResult); 544 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 545} 546 547/** 548 * Test ITuner::step 549 * 550 * Verifies that: 551 * - the HAL implements the method 552 * - the method returns 0 (no error) 553 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 554 * - skipping sub-channel or not does not fail the call 555 * 556 * Skipped for other radio classes than AM/FM, because step is not possible 557 * on DAB nor satellite. 558 */ 559TEST_P(BroadcastRadioHidlTest, Step) { 560 if (radioClass != Class::AM_FM) skipped = true; 561 RETURN_IF_SKIPPED; 562 ASSERT_EQ(true, openTuner()); 563 ASSERT_TRUE(checkAntenna()); 564 // test step UP 565 mCallbackCalled = false; 566 Return<Result> hidlResult = mTuner->step(Direction::UP, false); 567 EXPECT_TRUE(hidlResult.isOk()); 568 EXPECT_EQ(Result::OK, hidlResult); 569 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 570 571 // test step DOWN 572 mCallbackCalled = false; 573 hidlResult = mTuner->step(Direction::DOWN, true); 574 EXPECT_TRUE(hidlResult.isOk()); 575 EXPECT_EQ(Result::OK, hidlResult); 576 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 577} 578 579/** 580 * Test ITuner::tune, getProgramInformation and cancel methods 581 * 582 * Verifies that: 583 * - the HAL implements the methods 584 * - the methods return 0 (no error) 585 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() 586 * 587 * Skipped for other radio classes than AM/FM, because tune to frequency 588 * is not possible on DAB nor satellite. 589 */ 590TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { 591 if (radioClass != Class::AM_FM) skipped = true; 592 RETURN_IF_SKIPPED; 593 ASSERT_EQ(true, openTuner()); 594 ASSERT_TRUE(checkAntenna()); 595 596 auto& band = getBand(0); 597 598 // test tune 599 ASSERT_GT(band.spacings.size(), 0u); 600 ASSERT_GT(band.upperLimit, band.lowerLimit); 601 602 // test scan UP 603 uint32_t lowerLimit = band.lowerLimit; 604 uint32_t upperLimit = band.upperLimit; 605 uint32_t spacing = band.spacings[0]; 606 607 uint32_t channel = 608 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; 609 mCallbackCalled = false; 610 mResultCallbackData = Result::NOT_INITIALIZED; 611 Return<Result> hidlResult = mTuner->tune(channel, 0); 612 EXPECT_TRUE(hidlResult.isOk()); 613 EXPECT_EQ(Result::OK, hidlResult); 614 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 615 EXPECT_EQ(channel, mProgramInfoCallbackData.channel); 616 617 // test getProgramInformation 618 ProgramInfo halInfo; 619 Result halResult = Result::NOT_INITIALIZED; 620 Return<void> hidlReturn = mTuner->getProgramInformation( 621 [&](Result result, const ProgramInfo& info) { 622 halResult = result; 623 if (result == Result::OK) { 624 halInfo = info; 625 } 626 }); 627 EXPECT_TRUE(hidlReturn.isOk()); 628 EXPECT_EQ(Result::OK, halResult); 629 if (mResultCallbackData == Result::OK) { 630 EXPECT_LE(halInfo.channel, upperLimit); 631 EXPECT_GE(halInfo.channel, lowerLimit); 632 } 633 634 // test cancel 635 mTuner->tune(lowerLimit, 0); 636 hidlResult = mTuner->cancel(); 637 EXPECT_TRUE(hidlResult.isOk()); 638 EXPECT_EQ(Result::OK, hidlResult); 639} 640 641/** 642 * Test ITuner::tune failing when channel out of the range is provided. 643 * 644 * Verifies that: 645 * - the method returns INVALID_ARGUMENTS when applicable 646 * - the method recovers and succeeds after passing correct arguments 647 * 648 * Skipped for other radio classes than AM/FM, because tune to frequency 649 * is not possible on DAB nor satellite. 650 */ 651TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) { 652 if (radioClass != Class::AM_FM) skipped = true; 653 RETURN_IF_SKIPPED; 654 ASSERT_TRUE(openTuner()); 655 ASSERT_TRUE(checkAntenna()); 656 657 // get current channel bounds 658 BandConfig halConfig; 659 Result halResult; 660 auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) { 661 halResult = result; 662 halConfig = config; 663 }); 664 ASSERT_TRUE(configResult.isOk()); 665 ASSERT_EQ(Result::OK, halResult); 666 667 // try to tune slightly above the limit and expect to fail 668 auto badChannel = halConfig.upperLimit + halConfig.spacings[0]; 669 auto tuneResult = mTuner->tune(badChannel, 0); 670 EXPECT_TRUE(tuneResult.isOk()); 671 EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult); 672 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 673 674 // tuning exactly at the limit should succeed 675 auto goodChannel = halConfig.upperLimit; 676 tuneResult = mTuner->tune(goodChannel, 0); 677 EXPECT_TRUE(tuneResult.isOk()); 678 EXPECT_EQ(Result::OK, tuneResult); 679 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 680} 681 682/** 683 * Test proper image format in metadata. 684 * 685 * Verifies that: 686 * - all images in metadata are provided in-band (as a binary blob, not by id) 687 * 688 * This is a counter-test for OobImagesOnly from 1.1 VTS. 689 */ 690TEST_P(BroadcastRadioHidlTest, IbImagesOnly) { 691 RETURN_IF_SKIPPED; 692 ASSERT_TRUE(openTuner()); 693 ASSERT_TRUE(checkAntenna()); 694 695 bool firstScan = true; 696 uint32_t firstChannel, prevChannel; 697 while (true) { 698 mCallbackCalled = false; 699 auto hidlResult = mTuner->scan(Direction::UP, true); 700 ASSERT_TRUE(hidlResult.isOk()); 701 if (hidlResult == Result::TIMEOUT) { 702 ALOGI("Got timeout on scan operation"); 703 break; 704 } 705 ASSERT_EQ(Result::OK, hidlResult); 706 ASSERT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 707 708 if (firstScan) { 709 firstScan = false; 710 firstChannel = mProgramInfoCallbackData.channel; 711 } else { 712 // scanned the whole band 713 if (mProgramInfoCallbackData.channel >= firstChannel && prevChannel <= firstChannel) { 714 break; 715 } 716 } 717 prevChannel = mProgramInfoCallbackData.channel; 718 719 for (auto&& entry : mProgramInfoCallbackData.metadata) { 720 if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue; 721 EXPECT_EQ(MetadataType::RAW, entry.type); 722 EXPECT_EQ(0, entry.intValue); 723 EXPECT_GT(entry.rawValue.size(), 0u); 724 } 725 } 726} 727 728INSTANTIATE_TEST_CASE_P( 729 BroadcastRadioHidlTestCases, 730 BroadcastRadioHidlTest, 731 ::testing::Values(Class::AM_FM, Class::SAT, Class::DT)); 732 733int main(int argc, char** argv) { 734 ::testing::InitGoogleTest(&argc, argv); 735 int status = RUN_ALL_TESTS(); 736 ALOGI("Test result = %d", status); 737 return status; 738} 739