• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 using ::android::sp;
33 using ::android::Mutex;
34 using ::android::Condition;
35 using ::android::hardware::Return;
36 using ::android::hardware::Void;
37 using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
38 using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
39 using ::android::hardware::broadcastradio::V1_0::ITuner;
40 using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
41 using ::android::hardware::broadcastradio::V1_0::Result;
42 using ::android::hardware::broadcastradio::V1_0::Class;
43 using ::android::hardware::broadcastradio::V1_0::Properties;
44 using ::android::hardware::broadcastradio::V1_0::Band;
45 using ::android::hardware::broadcastradio::V1_0::BandConfig;
46 using ::android::hardware::broadcastradio::V1_0::Direction;
47 using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
48 using ::android::hardware::broadcastradio::V1_0::MetaData;
49 using ::android::hardware::broadcastradio::V1_0::MetadataKey;
50 using ::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 
60 class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase,
61         public ::testing::WithParamInterface<Class> {
62  protected:
SetUp()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 
TearDown()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)
hardwareFailure()102         virtual Return<void> hardwareFailure() {
103             ALOGI("%s", __FUNCTION__);
104             mParentTest->onHwFailureCallback();
105             return Void();
106         }
107 
configChange(Result result,const BandConfig & config)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 
tuneComplete(Result result,const ProgramInfo & info)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 
afSwitch(const ProgramInfo & info __unused)120         virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
121             return Void();
122         }
123 
antennaStateChange(bool connected)124         virtual Return<void> antennaStateChange(bool connected) {
125             ALOGI("%s connected %d", __FUNCTION__, connected);
126             return Void();
127         }
128 
trafficAnnouncement(bool active)129         virtual Return<void> trafficAnnouncement(bool active) {
130             ALOGI("%s active %d", __FUNCTION__, active);
131             return Void();
132         }
133 
emergencyAnnouncement(bool active)134         virtual Return<void> emergencyAnnouncement(bool active) {
135             ALOGI("%s active %d", __FUNCTION__, active);
136             return Void();
137         }
138 
newMetadata(uint32_t channel __unused,uint32_t subChannel __unused,const::android::hardware::hidl_vec<MetaData> & metadata __unused)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 
MyCallback(BroadcastRadioHidlTest * parentTest)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      */
onCallback()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      */
onHwFailureCallback()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      */
onConfigChangeCallback(Result result,const BandConfig & config)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      */
onTuneCompleteCallback(Result result,const ProgramInfo & info)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      */
onBoolCallback(bool result)193     void onBoolCallback(bool result) {
194         Mutex::Autolock _l(mLock);
195         mBoolCallbackData = result;
196         onCallback_l();
197     }
198 
199 
BroadcastRadioHidlTest()200     BroadcastRadioHidlTest()
201         : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK),
202         mHwFailure(false) {}
203 
onCallback_l()204     void onCallback_l() {
205         if (!mCallbackCalled) {
206             mCallbackCalled = true;
207             mCallbackCond.broadcast();
208         }
209     }
210 
211 
waitForCallback(nsecs_t reltime=0)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 
266 namespace android {
267 namespace hardware {
268 namespace broadcastradio {
269 namespace V1_0 {
270 
271 /**
272  * Compares two BandConfig objects for testing purposes.
273  */
operator ==(const BandConfig & l,const BandConfig & r)274 static 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 
getProperties()295 bool 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 
openTuner()322 bool 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 
checkAntenna()346 bool 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 
getBand(unsigned idx)363 const 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  */
TEST_P(BroadcastRadioHidlTest,GetProperties)387 TEST_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  */
TEST_P(BroadcastRadioHidlTest,OpenTuner)399 TEST_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  */
TEST_P(BroadcastRadioHidlTest,ReopenTuner)411 TEST_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  */
TEST_P(BroadcastRadioHidlTest,OpenTunerTwice)425 TEST_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  */
TEST_P(BroadcastRadioHidlTest,SetAndGetConfiguration)454 TEST_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  */
TEST_P(BroadcastRadioHidlTest,SetConfigurationFails)492 TEST_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  */
TEST_P(BroadcastRadioHidlTest,Scan)528 TEST_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  */
TEST_P(BroadcastRadioHidlTest,Step)559 TEST_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  */
TEST_P(BroadcastRadioHidlTest,TuneAndGetProgramInformationAndCancel)590 TEST_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  */
TEST_P(BroadcastRadioHidlTest,TuneFailsOutOfBounds)651 TEST_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  */
TEST_P(BroadcastRadioHidlTest,IbImagesOnly)690 TEST_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 
728 INSTANTIATE_TEST_CASE_P(
729     BroadcastRadioHidlTestCases,
730     BroadcastRadioHidlTest,
731     ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
732 
main(int argc,char ** argv)733 int 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