1 /*
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 "broadcastradio.vts"
18 
19 #include <android-base/logging.h>
20 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
21 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
22 #include <android/hardware/broadcastradio/1.1/ITuner.h>
23 #include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
24 #include <android/hardware/broadcastradio/1.1/types.h>
25 #include <broadcastradio-utils-1x/Utils.h>
26 #include <broadcastradio-vts-utils/call-barrier.h>
27 #include <broadcastradio-vts-utils/hal-1.x-enum-utils.h>
28 #include <broadcastradio-vts-utils/mock-timeout.h>
29 #include <broadcastradio-vts-utils/pointer-utils.h>
30 #include <cutils/native_handle.h>
31 #include <cutils/properties.h>
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 #include <hidl/GtestPrinter.h>
35 #include <hidl/HidlTransportSupport.h>
36 #include <hidl/ServiceManagement.h>
37 #include <utils/threads.h>
38 
39 #include <chrono>
40 
41 namespace android {
42 namespace hardware {
43 namespace broadcastradio {
44 namespace V1_1 {
45 namespace vts {
46 
47 using namespace std::chrono_literals;
48 
49 using testing::_;
50 using testing::AnyNumber;
51 using testing::ByMove;
52 using testing::DoAll;
53 using testing::Invoke;
54 using testing::SaveArg;
55 
56 using broadcastradio::V1_0::vts::RadioClassFromString;
57 using broadcastradio::vts::CallBarrier;
58 using V1_0::BandConfig;
59 using V1_0::Class;
60 using V1_0::MetaData;
61 using V1_0::MetadataKey;
62 using V1_0::MetadataType;
63 
64 using broadcastradio::vts::clearAndWait;
65 
66 static constexpr auto kConfigTimeout = 10s;
67 static constexpr auto kConnectModuleTimeout = 1s;
68 static constexpr auto kTuneTimeout = 30s;
69 static constexpr auto kEventPropagationTimeout = 1s;
70 static constexpr auto kFullScanTimeout = 1min;
71 
72 static constexpr ProgramType kStandardProgramTypes[] = {
73     ProgramType::AM,  ProgramType::FM,   ProgramType::AM_HD, ProgramType::FM_HD,
74     ProgramType::DAB, ProgramType::DRMO, ProgramType::SXM};
75 
76 struct TunerCallbackMock : public ITunerCallback {
TunerCallbackMockandroid::hardware::broadcastradio::V1_1::vts::TunerCallbackMock77     TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
78 
79     MOCK_METHOD0(hardwareFailure, Return<void>());
80     MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
81     MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
82     MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&));
83     MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
84     MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
85     MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
86     MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
87     MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
88     MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
89     MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
90     MOCK_METHOD0(programListChanged, Return<void>());
91     MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
92 };
93 
94 class BroadcastRadioHalTest
95     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
96   protected:
97     virtual void SetUp() override;
98     virtual void TearDown() override;
99 
100     bool openTuner();
101     bool nextBand();
102     bool getProgramList(std::function<void(const hidl_vec<ProgramInfo>& list)> cb);
103 
104     Class radioClass;
105 
106     sp<IBroadcastRadio> mRadioModule;
107     sp<ITuner> mTuner;
108     sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
109 
110    private:
111     const BandConfig& getBand(unsigned idx);
112 
113     unsigned currentBandIndex = 0;
114     hidl_vec<BandConfig> mBands;
115 };
116 
SetUp()117 void BroadcastRadioHalTest::SetUp() {
118     radioClass = RadioClassFromString(std::get<1>(GetParam()));
119 
120     // lookup HIDL service
121     auto factory = IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
122     ASSERT_NE(nullptr, factory.get());
123 
124     // connect radio module
125     Result connectResult;
126     CallBarrier onConnect;
127     factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
128         connectResult = ret;
129         if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
130         onConnect.call();
131     });
132     ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
133 
134     if (connectResult == Result::INVALID_ARGUMENTS) {
135         GTEST_SKIP() << "This device class is not supported.";
136     }
137     ASSERT_EQ(connectResult, Result::OK);
138     ASSERT_NE(nullptr, mRadioModule.get());
139 
140     // get module properties
141     Properties prop11;
142     auto& prop10 = prop11.base;
143     auto propResult =
144         mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
145 
146     ASSERT_TRUE(propResult.isOk());
147     EXPECT_EQ(radioClass, prop10.classId);
148     EXPECT_GT(prop10.numTuners, 0u);
149     EXPECT_GT(prop11.supportedProgramTypes.size(), 0u);
150     EXPECT_GT(prop11.supportedIdentifierTypes.size(), 0u);
151     if (radioClass == Class::AM_FM) {
152         EXPECT_GT(prop10.bands.size(), 0u);
153     }
154     mBands = prop10.bands;
155 }
156 
TearDown()157 void BroadcastRadioHalTest::TearDown() {
158     mTuner.clear();
159     mRadioModule.clear();
160     clearAndWait(mCallback, 1s);
161 }
162 
openTuner()163 bool BroadcastRadioHalTest::openTuner() {
164     EXPECT_EQ(nullptr, mTuner.get());
165 
166     if (radioClass == Class::AM_FM) {
167         EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
168     }
169 
170     Result halResult = Result::NOT_INITIALIZED;
171     auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
172         halResult = result;
173         if (result != Result::OK) return;
174         mTuner = ITuner::castFrom(tuner);
175     };
176     currentBandIndex = 0;
177     auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
178 
179     EXPECT_TRUE(hidlResult.isOk());
180     EXPECT_EQ(Result::OK, halResult);
181     EXPECT_NE(nullptr, mTuner.get());
182     if (radioClass == Class::AM_FM && mTuner != nullptr) {
183         EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
184 
185         BandConfig halConfig;
186         Result halResult = Result::NOT_INITIALIZED;
187         mTuner->getConfiguration([&](Result result, const BandConfig& config) {
188             halResult = result;
189             halConfig = config;
190         });
191         EXPECT_EQ(Result::OK, halResult);
192         EXPECT_TRUE(halConfig.antennaConnected);
193     }
194 
195     EXPECT_NE(nullptr, mTuner.get());
196     return nullptr != mTuner.get();
197 }
198 
getBand(unsigned idx)199 const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
200     static const BandConfig dummyBandConfig = {};
201 
202     if (radioClass != Class::AM_FM) {
203         ALOGD("Not AM/FM radio, returning dummy band config");
204         return dummyBandConfig;
205     }
206 
207     EXPECT_GT(mBands.size(), idx);
208     if (mBands.size() <= idx) {
209         ALOGD("Band index out of bound, returning dummy band config");
210         return dummyBandConfig;
211     }
212 
213     auto& band = mBands[idx];
214     ALOGD("Returning %s band", toString(band.type).c_str());
215     return band;
216 }
217 
nextBand()218 bool BroadcastRadioHalTest::nextBand() {
219     if (currentBandIndex + 1 >= mBands.size()) return false;
220     currentBandIndex++;
221 
222     BandConfig bandCb;
223     EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _)
224         .WillOnce(DoAll(SaveArg<1>(&bandCb), testing::Return(ByMove(Void()))));
225     auto hidlResult = mTuner->setConfiguration(getBand(currentBandIndex));
226     EXPECT_EQ(Result::OK, hidlResult);
227     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
228     EXPECT_EQ(getBand(currentBandIndex), bandCb);
229 
230     return true;
231 }
232 
getProgramList(std::function<void (const hidl_vec<ProgramInfo> & list)> cb)233 bool BroadcastRadioHalTest::getProgramList(
234     std::function<void(const hidl_vec<ProgramInfo>& list)> cb) {
235     ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
236     bool isListEmpty = true;
237     auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
238         ALOGD("getListCb(%s, ProgramInfo[%zu])", toString(result).c_str(), list.size());
239         getListResult = result;
240         if (result != ProgramListResult::OK) return;
241         isListEmpty = (list.size() == 0);
242         if (!isListEmpty) cb(list);
243     };
244 
245     // first try...
246     EXPECT_TIMEOUT_CALL(*mCallback, backgroundScanComplete, ProgramListResult::OK)
247         .Times(AnyNumber());
248     auto hidlResult = mTuner->getProgramList({}, getListCb);
249     EXPECT_TRUE(hidlResult.isOk());
250     if (!hidlResult.isOk()) return false;
251 
252     if (getListResult == ProgramListResult::NOT_STARTED) {
253         auto result = mTuner->startBackgroundScan();
254         EXPECT_EQ(ProgramListResult::OK, result);
255         getListResult = ProgramListResult::NOT_READY;  // continue as in NOT_READY case
256     }
257     if (getListResult == ProgramListResult::NOT_READY) {
258         EXPECT_TIMEOUT_CALL_WAIT(*mCallback, backgroundScanComplete, kFullScanTimeout);
259 
260         // second (last) try...
261         hidlResult = mTuner->getProgramList({}, getListCb);
262         EXPECT_TRUE(hidlResult.isOk());
263         if (!hidlResult.isOk()) return false;
264         EXPECT_EQ(ProgramListResult::OK, getListResult);
265     }
266 
267     return !isListEmpty;
268 }
269 
270 /**
271  * Test IBroadcastRadio::openTuner() method called twice.
272  *
273  * Verifies that:
274  *  - the openTuner method succeeds when called for the second time without
275  *    deleting previous ITuner instance.
276  *
277  * This is a more strict requirement than in 1.0, where a second openTuner
278  * might fail.
279  */
TEST_P(BroadcastRadioHalTest,OpenTunerTwice)280 TEST_P(BroadcastRadioHalTest, OpenTunerTwice) {
281     ASSERT_TRUE(openTuner());
282 
283     auto secondTuner = mTuner;
284     mTuner.clear();
285 
286     ASSERT_TRUE(openTuner());
287 }
288 
289 /**
290  * Test tuning to program list entry.
291  *
292  * Verifies that:
293  *  - getProgramList either succeeds or returns NOT_STARTED/NOT_READY status;
294  *  - if the program list is NOT_STARTED, startBackgroundScan makes it completed
295  *    within a full scan timeout and the next getProgramList call succeeds;
296  *  - if the program list is not empty, tuneByProgramSelector call succeeds;
297  *  - getProgramInformation_1_1 returns the same selector as returned in tuneComplete_1_1 call.
298  */
TEST_P(BroadcastRadioHalTest,TuneFromProgramList)299 TEST_P(BroadcastRadioHalTest, TuneFromProgramList) {
300     ASSERT_TRUE(openTuner());
301 
302     ProgramInfo firstProgram;
303     bool foundAny = false;
304     do {
305         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
306             // don't copy the whole list out, it might be heavy
307             firstProgram = list[0];
308         };
309         if (getProgramList(getCb)) foundAny = true;
310     } while (nextBand());
311     if (HasFailure()) return;
312     if (!foundAny) {
313         GTEST_SKIP() << "Program list is empty.";
314     }
315 
316     ProgramInfo infoCb;
317     ProgramSelector selCb;
318     EXPECT_CALL(*mCallback, tuneComplete(_, _)).Times(0);
319     EXPECT_TIMEOUT_CALL(*mCallback, tuneComplete_1_1, Result::OK, _)
320         .WillOnce(DoAll(SaveArg<1>(&selCb), testing::Return(ByMove(Void()))));
321     EXPECT_TIMEOUT_CALL(*mCallback, currentProgramInfoChanged, _)
322         .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
323     auto tuneResult = mTuner->tuneByProgramSelector(firstProgram.selector);
324     ASSERT_EQ(Result::OK, tuneResult);
325     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, tuneComplete_1_1, kTuneTimeout);
326     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, currentProgramInfoChanged, kEventPropagationTimeout);
327     EXPECT_EQ(firstProgram.selector.primaryId, selCb.primaryId);
328     EXPECT_EQ(infoCb.selector, selCb);
329 
330     bool called = false;
331     auto getResult = mTuner->getProgramInformation_1_1([&](Result result, ProgramInfo info) {
332         called = true;
333         EXPECT_EQ(Result::OK, result);
334         EXPECT_EQ(selCb, info.selector);
335     });
336     ASSERT_TRUE(getResult.isOk());
337     ASSERT_TRUE(called);
338 }
339 
340 /**
341  * Test that primary vendor identifier isn't used for standard program types.
342  *
343  * Verifies that:
344  *  - tuneByProgramSelector fails when VENDORn_PRIMARY is set as a primary
345  *    identifier for program types other than VENDORn.
346  */
TEST_P(BroadcastRadioHalTest,TuneFailsForPrimaryVendor)347 TEST_P(BroadcastRadioHalTest, TuneFailsForPrimaryVendor) {
348     ASSERT_TRUE(openTuner());
349 
350     for (auto ptype : kStandardProgramTypes) {
351         ALOGD("Checking %s...", toString(ptype).c_str());
352         ProgramSelector sel = {};
353         sel.programType = static_cast<uint32_t>(ptype);
354         sel.primaryId.type = static_cast<uint32_t>(IdentifierType::VENDOR_PRIMARY_START);
355 
356         auto tuneResult = mTuner->tuneByProgramSelector(sel);
357         ASSERT_NE(Result::OK, tuneResult);
358     }
359 }
360 
361 /**
362  * Test that tune with unknown program type fails.
363  *
364  * Verifies that:
365  *  - tuneByProgramSelector fails with INVALID_ARGUMENT when unknown program type is passed.
366  */
TEST_P(BroadcastRadioHalTest,TuneFailsForUnknownProgram)367 TEST_P(BroadcastRadioHalTest, TuneFailsForUnknownProgram) {
368     ASSERT_TRUE(openTuner());
369 
370     // Program type is 1-based, so 0 will be always invalid.
371     ProgramSelector sel = {};
372     auto tuneResult = mTuner->tuneByProgramSelector(sel);
373     ASSERT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
374 }
375 
376 /**
377  * Test cancelling announcement.
378  *
379  * Verifies that:
380  *  - cancelAnnouncement succeeds either when there is an announcement or there is none.
381  */
TEST_P(BroadcastRadioHalTest,CancelAnnouncement)382 TEST_P(BroadcastRadioHalTest, CancelAnnouncement) {
383     ASSERT_TRUE(openTuner());
384 
385     auto hidlResult = mTuner->cancelAnnouncement();
386     EXPECT_EQ(Result::OK, hidlResult);
387 }
388 
389 /**
390  * Test getImage call with invalid image ID.
391  *
392  * Verifies that:
393  * - getImage call handles argument 0 gracefully.
394  */
TEST_P(BroadcastRadioHalTest,GetNoImage)395 TEST_P(BroadcastRadioHalTest, GetNoImage) {
396     size_t len = 0;
397     auto hidlResult =
398         mRadioModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
399 
400     ASSERT_TRUE(hidlResult.isOk());
401     ASSERT_EQ(0u, len);
402 }
403 
404 /**
405  * Test proper image format in metadata.
406  *
407  * Verifies that:
408  * - all images in metadata are provided out-of-band (by id, not as a binary blob);
409  * - images are available for getImage call.
410  */
TEST_P(BroadcastRadioHalTest,OobImagesOnly)411 TEST_P(BroadcastRadioHalTest, OobImagesOnly) {
412     ASSERT_TRUE(openTuner());
413 
414     std::vector<int> imageIds;
415 
416     do {
417         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
418             for (auto&& program : list) {
419                 for (auto&& entry : program.base.metadata) {
420                     EXPECT_NE(MetadataType::RAW, entry.type);
421                     if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue;
422                     EXPECT_NE(0, entry.intValue);
423                     EXPECT_EQ(0u, entry.rawValue.size());
424                     if (entry.intValue != 0) imageIds.push_back(entry.intValue);
425                 }
426             }
427         };
428         getProgramList(getCb);
429     } while (nextBand());
430 
431     if (imageIds.size() == 0) {
432         GTEST_SKIP() << "No images found";
433     }
434 
435     for (auto id : imageIds) {
436         ALOGD("Checking image %d", id);
437 
438         size_t len = 0;
439         auto hidlResult =
440             mRadioModule->getImage(id, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
441 
442         ASSERT_TRUE(hidlResult.isOk());
443         ASSERT_GT(len, 0u);
444     }
445 }
446 
447 /**
448  * Test AnalogForced switch.
449  *
450  * Verifies that:
451  * - setAnalogForced results either with INVALID_STATE, or isAnalogForced replying the same.
452  */
TEST_P(BroadcastRadioHalTest,AnalogForcedSwitch)453 TEST_P(BroadcastRadioHalTest, AnalogForcedSwitch) {
454     ASSERT_TRUE(openTuner());
455 
456     bool forced;
457     Result halIsResult;
458     auto isCb = [&](Result result, bool isForced) {
459         halIsResult = result;
460         forced = isForced;
461     };
462 
463     // set analog mode
464     auto setResult = mTuner->setAnalogForced(true);
465     ASSERT_TRUE(setResult.isOk());
466     if (Result::INVALID_STATE == setResult) {
467         // if setter fails, getter should fail too - it means the switch is not supported at all
468         auto isResult = mTuner->isAnalogForced(isCb);
469         ASSERT_TRUE(isResult.isOk());
470         EXPECT_EQ(Result::INVALID_STATE, halIsResult);
471         return;
472     }
473     ASSERT_EQ(Result::OK, setResult);
474 
475     // check, if it's analog
476     auto isResult = mTuner->isAnalogForced(isCb);
477     ASSERT_TRUE(isResult.isOk());
478     EXPECT_EQ(Result::OK, halIsResult);
479     ASSERT_TRUE(forced);
480 
481     // set digital mode
482     setResult = mTuner->setAnalogForced(false);
483     ASSERT_EQ(Result::OK, setResult);
484 
485     // check, if it's digital
486     isResult = mTuner->isAnalogForced(isCb);
487     ASSERT_TRUE(isResult.isOk());
488     EXPECT_EQ(Result::OK, halIsResult);
489     ASSERT_FALSE(forced);
490 }
491 
verifyIdentifier(const ProgramIdentifier & id)492 static void verifyIdentifier(const ProgramIdentifier& id) {
493     EXPECT_NE(id.type, 0u);
494     auto val = id.value;
495 
496     switch (static_cast<IdentifierType>(id.type)) {
497         case IdentifierType::AMFM_FREQUENCY:
498         case IdentifierType::DAB_FREQUENCY:
499         case IdentifierType::DRMO_FREQUENCY:
500             EXPECT_GT(val, 100u) << "Expected f > 100kHz";
501             EXPECT_LT(val, 10000000u) << "Expected f < 10GHz";
502             break;
503         case IdentifierType::RDS_PI:
504             EXPECT_GT(val, 0u);
505             EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
506             break;
507         case IdentifierType::HD_STATION_ID_EXT: {
508             auto stationId = val & 0xFFFFFFFF;  // 32bit
509             val >>= 32;
510             auto subchannel = val & 0xF;  // 4bit
511             val >>= 4;
512             auto freq = val & 0x3FFFF;  // 18bit
513             EXPECT_GT(stationId, 0u);
514             EXPECT_LT(subchannel, 8u) << "Expected ch < 8";
515             EXPECT_GT(freq, 100u) << "Expected f > 100kHz";
516             EXPECT_LT(freq, 10000000u) << "Expected f < 10GHz";
517             break;
518         }
519         case IdentifierType::HD_SUBCHANNEL:
520             EXPECT_LT(val, 8u) << "Expected ch < 8";
521             break;
522         case IdentifierType::DAB_SIDECC: {
523             auto sid = val & 0xFFFF;  // 16bit
524             val >>= 16;
525             auto ecc = val & 0xFF;  // 8bit
526             EXPECT_NE(sid, 0u);
527             EXPECT_GE(ecc, 0xA0u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
528             EXPECT_LE(ecc, 0xF6u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
529             break;
530         }
531         case IdentifierType::DAB_ENSEMBLE:
532             EXPECT_GT(val, 0u);
533             EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
534             break;
535         case IdentifierType::DAB_SCID:
536             EXPECT_GT(val, 0xFu) << "Expected 12bit SCId (not 4bit SCIdS)";
537             EXPECT_LE(val, 0xFFFu) << "Expected 12bit id";
538             break;
539         case IdentifierType::DRMO_SERVICE_ID:
540             EXPECT_GT(val, 0u);
541             EXPECT_LE(val, 0xFFFFFFu) << "Expected 24bit id";
542             break;
543         case IdentifierType::DRMO_MODULATION:
544             EXPECT_GE(val, static_cast<uint32_t>(Modulation::AM));
545             EXPECT_LE(val, static_cast<uint32_t>(Modulation::FM));
546             break;
547         case IdentifierType::SXM_SERVICE_ID:
548             EXPECT_GT(val, 0u);
549             EXPECT_LE(val, 0xFFFFFFFFu) << "Expected 32bit id";
550             break;
551         case IdentifierType::SXM_CHANNEL:
552             EXPECT_LT(val, 1000u);
553             break;
554         case IdentifierType::VENDOR_PRIMARY_START:
555         case IdentifierType::VENDOR_PRIMARY_END:
556             // skip
557             break;
558     }
559 }
560 
561 /**
562  * Test ProgramIdentifier format.
563  *
564  * Verifies that:
565  * - values of ProgramIdentifier match their definitions at IdentifierType.
566  */
TEST_P(BroadcastRadioHalTest,VerifyIdentifiersFormat)567 TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) {
568     ASSERT_TRUE(openTuner());
569 
570     do {
571         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
572             for (auto&& program : list) {
573                 verifyIdentifier(program.selector.primaryId);
574                 for (auto&& id : program.selector.secondaryIds) {
575                     verifyIdentifier(id);
576                 }
577             }
578         };
579         getProgramList(getCb);
580     } while (nextBand());
581 }
582 
583 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
584 INSTANTIATE_TEST_CASE_P(
585         PerInstance, BroadcastRadioHalTest,
586         testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
587                                  IBroadcastRadioFactory::descriptor)),
588                          ::testing::Values("AM_FM", "SAT", "DT")),
589         android::hardware::PrintInstanceTupleNameToString<>);
590 
591 }  // namespace vts
592 }  // namespace V1_1
593 }  // namespace broadcastradio
594 }  // namespace hardware
595 }  // namespace android
596