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