blob: dec1f1781d680a083ff6e35c35ed55719cd48c5b [file] [log] [blame]
Eric Laurent566fcda2016-11-23 10:36:36 -08001/*
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"
Eric Laurent566fcda2016-11-23 10:36:36 -080018#include <android-base/logging.h>
19#include <cutils/native_handle.h>
20#include <cutils/properties.h>
Dan Shi170a4452020-04-04 00:59:41 -070021#include <gtest/gtest.h>
22#include <hidl/GtestPrinter.h>
Martijn Coenen02822372016-12-29 14:03:41 +010023#include <hidl/HidlTransportSupport.h>
Dan Shi170a4452020-04-04 00:59:41 -070024#include <hidl/ServiceManagement.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080025#include <utils/threads.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080026
Eric Laurent566fcda2016-11-23 10:36:36 -080027#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080028#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080029#include <android/hardware/broadcastradio/1.0/ITuner.h>
30#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
31#include <android/hardware/broadcastradio/1.0/types.h>
Dan Shi170a4452020-04-04 00:59:41 -070032#include <broadcastradio-vts-utils/hal-1.x-enum-utils.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080033
Eric Laurent566fcda2016-11-23 10:36:36 -080034using ::android::Condition;
Dan Shi170a4452020-04-04 00:59:41 -070035using ::android::Mutex;
36using ::android::sp;
Eric Laurent566fcda2016-11-23 10:36:36 -080037using ::android::hardware::Return;
Eric Laurent566fcda2016-11-23 10:36:36 -080038using ::android::hardware::Void;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -080039using ::android::hardware::broadcastradio::V1_0::Band;
Eric Laurent566fcda2016-11-23 10:36:36 -080040using ::android::hardware::broadcastradio::V1_0::BandConfig;
Dan Shi170a4452020-04-04 00:59:41 -070041using ::android::hardware::broadcastradio::V1_0::Class;
Eric Laurent566fcda2016-11-23 10:36:36 -080042using ::android::hardware::broadcastradio::V1_0::Direction;
Dan Shi170a4452020-04-04 00:59:41 -070043using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
44using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
45using ::android::hardware::broadcastradio::V1_0::ITuner;
46using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
Eric Laurent566fcda2016-11-23 10:36:36 -080047using ::android::hardware::broadcastradio::V1_0::MetaData;
Tomasz Wasilczykba3e2542017-07-17 13:59:21 -070048using ::android::hardware::broadcastradio::V1_0::MetadataKey;
49using ::android::hardware::broadcastradio::V1_0::MetadataType;
Dan Shi170a4452020-04-04 00:59:41 -070050using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
51using ::android::hardware::broadcastradio::V1_0::Properties;
52using ::android::hardware::broadcastradio::V1_0::Result;
53using ::android::hardware::broadcastradio::V1_0::vts::RadioClassFromString;
Eric Laurent566fcda2016-11-23 10:36:36 -080054
V,Anilkumar86f31e72022-07-05 23:39:38 +053055#define RETURN_IF_SKIPPED \
56 if (skipped) { \
57 GTEST_SKIP() << "This device class is not supported."; \
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070058 }
59
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080060// The main test class for Broadcast Radio HIDL HAL.
Dan Shi170a4452020-04-04 00:59:41 -070061class BroadcastRadioHidlTest
62 : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
63 protected:
Eric Laurent566fcda2016-11-23 10:36:36 -080064 virtual void SetUp() override {
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070065 ASSERT_EQ(nullptr, mRadio.get());
66
Dan Shi170a4452020-04-04 00:59:41 -070067 radioClass = RadioClassFromString(std::get<1>(GetParam()));
68
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070069 skipped = false;
70
Eric Laurent566fcda2016-11-23 10:36:36 -080071 sp<IBroadcastRadioFactory> factory =
Dan Shi170a4452020-04-04 00:59:41 -070072 IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070073 ASSERT_NE(nullptr, factory.get());
74
75 Result connectResult;
76 factory->connectModule(radioClass, [&](Result ret, const sp<IBroadcastRadio>& radio) {
77 connectResult = ret;
78 mRadio = radio;
79 onCallback_l();
80 });
81 EXPECT_EQ(true, waitForCallback(kConnectCallbacktimeoutNs));
82 mCallbackCalled = false;
83
84 if (connectResult == Result::INVALID_ARGUMENTS) {
85 skipped = true;
86 return;
Eric Laurent566fcda2016-11-23 10:36:36 -080087 }
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070088 ASSERT_EQ(connectResult, Result::OK);
89
Eric Laurent566fcda2016-11-23 10:36:36 -080090 mTunerCallback = new MyCallback(this);
91 ASSERT_NE(nullptr, mRadio.get());
Eric Laurent566fcda2016-11-23 10:36:36 -080092 ASSERT_NE(nullptr, mTunerCallback.get());
93 }
94
95 virtual void TearDown() override {
96 mTuner.clear();
97 mRadio.clear();
98 }
99
100 class MyCallback : public ITunerCallback {
101 public:
102
103 // ITunerCallback methods (see doc in ITunerCallback.hal)
104 virtual Return<void> hardwareFailure() {
105 ALOGI("%s", __FUNCTION__);
106 mParentTest->onHwFailureCallback();
107 return Void();
108 }
109
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800110 virtual Return<void> configChange(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800111 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800112 mParentTest->onConfigChangeCallback(result, config);
Eric Laurent566fcda2016-11-23 10:36:36 -0800113 return Void();
114 }
115
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800116 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800117 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800118 mParentTest->onTuneCompleteCallback(result, info);
Eric Laurent566fcda2016-11-23 10:36:36 -0800119 return Void();
120 }
121
122 virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
123 return Void();
124 }
125
126 virtual Return<void> antennaStateChange(bool connected) {
127 ALOGI("%s connected %d", __FUNCTION__, connected);
128 return Void();
129 }
130
131 virtual Return<void> trafficAnnouncement(bool active) {
132 ALOGI("%s active %d", __FUNCTION__, active);
133 return Void();
134 }
135
136 virtual Return<void> emergencyAnnouncement(bool active) {
137 ALOGI("%s active %d", __FUNCTION__, active);
138 return Void();
139 }
140
141 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
142 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
143 ALOGI("%s", __FUNCTION__);
144 return Void();
145 }
146
147 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
148
149 private:
150 // BroadcastRadioHidlTest instance to which callbacks will be notified.
151 BroadcastRadioHidlTest *mParentTest;
152 };
153
154
155 /**
156 * Method called by MyCallback when a callback with no status or boolean value is received
157 */
158 void onCallback() {
159 Mutex::Autolock _l(mLock);
160 onCallback_l();
161 }
162
163 /**
164 * Method called by MyCallback when hardwareFailure() callback is received
165 */
166 void onHwFailureCallback() {
167 Mutex::Autolock _l(mLock);
168 mHwFailure = true;
169 onCallback_l();
170 }
171
172 /**
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800173 * Method called by MyCallback when configChange() callback is received.
Eric Laurent566fcda2016-11-23 10:36:36 -0800174 */
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800175 void onConfigChangeCallback(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800176 Mutex::Autolock _l(mLock);
177 mResultCallbackData = result;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800178 mBandConfigCallbackData = config;
179 onCallback_l();
180 }
181
182 /**
183 * Method called by MyCallback when tuneComplete() callback is received.
184 */
185 void onTuneCompleteCallback(Result result, const ProgramInfo& info) {
186 Mutex::Autolock _l(mLock);
187 mResultCallbackData = result;
188 mProgramInfoCallbackData = info;
Eric Laurent566fcda2016-11-23 10:36:36 -0800189 onCallback_l();
190 }
191
192 /**
193 * Method called by MyCallback when a boolean indication is received
194 */
195 void onBoolCallback(bool result) {
196 Mutex::Autolock _l(mLock);
197 mBoolCallbackData = result;
198 onCallback_l();
199 }
200
201
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700202 BroadcastRadioHidlTest()
203 : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK),
204 mHwFailure(false) {}
Eric Laurent566fcda2016-11-23 10:36:36 -0800205
206 void onCallback_l() {
207 if (!mCallbackCalled) {
208 mCallbackCalled = true;
209 mCallbackCond.broadcast();
210 }
211 }
212
213
214 bool waitForCallback(nsecs_t reltime = 0) {
215 Mutex::Autolock _l(mLock);
216 nsecs_t endTime = systemTime() + reltime;
217 while (!mCallbackCalled) {
218 if (reltime == 0) {
219 mCallbackCond.wait(mLock);
220 } else {
221 nsecs_t now = systemTime();
222 if (now > endTime) {
223 return false;
224 }
225 mCallbackCond.waitRelative(mLock, endTime - now);
226 }
227 }
228 return true;
229 }
230
231 bool getProperties();
232 bool openTuner();
233 bool checkAntenna();
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700234
235 /**
236 * Retrieves AM/FM band configuration from module properties.
237 *
238 * The configuration may not exist: if radio type is other than AM/FM
239 * or provided index is out of bounds.
240 * In such case, empty configuration is returned.
241 *
242 * @param idx Band index to retrieve.
243 * @return Band configuration reference.
244 */
245 const BandConfig& getBand(unsigned idx);
Eric Laurent566fcda2016-11-23 10:36:36 -0800246
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700247 static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1);
Eric Laurent566fcda2016-11-23 10:36:36 -0800248 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
249 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
250
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700251 Class radioClass;
252 bool skipped;
Eric Laurent566fcda2016-11-23 10:36:36 -0800253 sp<IBroadcastRadio> mRadio;
254 Properties mHalProperties;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700255 bool mHalPropertiesInitialized = false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800256 sp<ITuner> mTuner;
257 sp<MyCallback> mTunerCallback;
258 Mutex mLock;
259 Condition mCallbackCond;
260 bool mCallbackCalled;
261 bool mBoolCallbackData;
262 Result mResultCallbackData;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800263 ProgramInfo mProgramInfoCallbackData;
264 BandConfig mBandConfigCallbackData;
Eric Laurent566fcda2016-11-23 10:36:36 -0800265 bool mHwFailure;
266};
267
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800268namespace android {
269namespace hardware {
270namespace broadcastradio {
271namespace V1_0 {
272
273/**
274 * Compares two BandConfig objects for testing purposes.
275 */
276static bool operator==(const BandConfig& l, const BandConfig& r) {
277 if (l.type != r.type) return false;
278 if (l.antennaConnected != r.antennaConnected) return false;
279 if (l.lowerLimit != r.lowerLimit) return false;
280 if (l.upperLimit != r.upperLimit) return false;
281 if (l.spacings != r.spacings) return false;
282 if (l.type == Band::AM || l.type == Band::AM_HD) {
283 return l.ext.am == r.ext.am;
284 } else if (l.type == Band::FM || l.type == Band::FM_HD) {
285 return l.ext.fm == r.ext.fm;
286 } else {
287 // unsupported type
288 return false;
289 }
290}
291
292} // V1_0
293} // broadcastradio
294} // hardware
295} // android
296
Eric Laurent566fcda2016-11-23 10:36:36 -0800297bool BroadcastRadioHidlTest::getProperties()
298{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700299 if (mHalPropertiesInitialized) return true;
Eric Laurent566fcda2016-11-23 10:36:36 -0800300
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700301 Result halResult = Result::NOT_INITIALIZED;
302 auto hidlReturn = mRadio->getProperties([&](Result result, const Properties& properties) {
303 halResult = result;
304 if (result == Result::OK) {
305 mHalProperties = properties;
306 }
307 });
308
309 EXPECT_TRUE(hidlReturn.isOk());
310 EXPECT_EQ(Result::OK, halResult);
311 EXPECT_EQ(radioClass, mHalProperties.classId);
312 EXPECT_GT(mHalProperties.numTuners, 0u);
313 if (radioClass == Class::AM_FM) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800314 EXPECT_GT(mHalProperties.bands.size(), 0u);
315 }
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700316
317 if (hidlReturn.isOk() && halResult == Result::OK) {
318 mHalPropertiesInitialized = true;
319 return true;
320 }
321 return false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800322}
323
324bool BroadcastRadioHidlTest::openTuner()
325{
326 if (!getProperties()) {
327 return false;
328 }
329 if (mTuner.get() == nullptr) {
330 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700331 auto openCb = [&](Result result, const sp<ITuner>& tuner) {
332 halResult = result;
333 if (result == Result::OK) {
334 mTuner = tuner;
335 }
336 };
337 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
Steven Morelandb6438422017-01-03 17:06:57 -0800338 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800339 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700340 if (radioClass == Class::AM_FM) {
341 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
342 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800343 }
344 EXPECT_NE(nullptr, mTuner.get());
345 return nullptr != mTuner.get();
346}
347
348bool BroadcastRadioHidlTest::checkAntenna()
349{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700350 if (radioClass != Class::AM_FM) return true;
351
Eric Laurent566fcda2016-11-23 10:36:36 -0800352 BandConfig halConfig;
353 Result halResult = Result::NOT_INITIALIZED;
354 Return<void> hidlReturn =
355 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
356 halResult = result;
357 if (result == Result::OK) {
358 halConfig = config;
359 }
360 });
361
362 return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
363}
364
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700365const BandConfig& BroadcastRadioHidlTest::getBand(unsigned idx) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700366 static BandConfig dummyBandConfig = {};
367 if (radioClass == Class::AM_FM) {
368 EXPECT_GT(mHalProperties.bands.size(), idx);
369 if (mHalProperties.bands.size() > idx) {
370 return mHalProperties.bands[idx];
371 } else {
372 return dummyBandConfig;
373 }
374 } else {
375 return dummyBandConfig;
376 }
377}
Eric Laurent566fcda2016-11-23 10:36:36 -0800378
379/**
380 * Test IBroadcastRadio::getProperties() method
381 *
382 * Verifies that:
383 * - the HAL implements the method
384 * - the method returns 0 (no error)
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700385 * - the implementation class is radioClass
Eric Laurent566fcda2016-11-23 10:36:36 -0800386 * - the implementation supports at least one tuner
387 * - the implementation supports at one band
388 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700389TEST_P(BroadcastRadioHidlTest, GetProperties) {
390 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800391 EXPECT_EQ(true, getProperties());
392}
393
394/**
395 * Test IBroadcastRadio::openTuner() method
396 *
397 * Verifies that:
398 * - the HAL implements the method
399 * - the method returns 0 (no error) and a valid ITuner interface
400 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700401TEST_P(BroadcastRadioHidlTest, OpenTuner) {
402 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800403 EXPECT_EQ(true, openTuner());
404}
405
406/**
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800407 * Test IBroadcastRadio::openTuner() after ITuner disposal.
408 *
409 * Verifies that:
410 * - ITuner destruction gets propagated through HAL
411 * - the openTuner method works well when called for the second time
412 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700413TEST_P(BroadcastRadioHidlTest, ReopenTuner) {
414 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800415 EXPECT_TRUE(openTuner());
416 mTuner.clear();
417 EXPECT_TRUE(openTuner());
418}
419
420/**
421 * Test IBroadcastRadio::openTuner() method called twice.
422 *
423 * Verifies that:
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700424 * - the openTuner method fails with INVALID_STATE or succeeds when called for the second time
425 * without deleting previous ITuner instance
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800426 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700427TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) {
428 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800429 EXPECT_TRUE(openTuner());
430
431 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700432 auto openCb = [&](Result result, const sp<ITuner>&) { halResult = result; };
433 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800434 EXPECT_TRUE(hidlReturn.isOk());
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700435 if (halResult == Result::OK) {
436 if (radioClass == Class::AM_FM) {
437 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
438 }
439 } else {
440 EXPECT_EQ(Result::INVALID_STATE, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700441 }
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800442}
443
444/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800445 * Test ITuner::setConfiguration() and getConfiguration methods
446 *
447 * Verifies that:
448 * - the HAL implements both methods
449 * - the methods return 0 (no error)
450 * - the configuration callback is received within kConfigCallbacktimeoutNs ns
451 * - the configuration read back from HAl has the same class Id
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700452 *
453 * Skipped for other radio classes than AM/FM, because setConfiguration
454 * applies only for these bands.
Eric Laurent566fcda2016-11-23 10:36:36 -0800455 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700456TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700457 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700458 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800459 ASSERT_EQ(true, openTuner());
460 // test setConfiguration
461 mCallbackCalled = false;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700462 Return<Result> hidlResult = mTuner->setConfiguration(getBand(1));
Steven Morelandb6438422017-01-03 17:06:57 -0800463 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800464 EXPECT_EQ(Result::OK, hidlResult);
465 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
466 EXPECT_EQ(Result::OK, mResultCallbackData);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700467 EXPECT_EQ(getBand(1), mBandConfigCallbackData);
Eric Laurent566fcda2016-11-23 10:36:36 -0800468
469 // test getConfiguration
470 BandConfig halConfig;
471 Result halResult;
472 Return<void> hidlReturn =
473 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
474 halResult = result;
475 if (result == Result::OK) {
476 halConfig = config;
477 }
478 });
Steven Morelandb6438422017-01-03 17:06:57 -0800479 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800480 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700481 EXPECT_EQ(getBand(1), halConfig);
Eric Laurent566fcda2016-11-23 10:36:36 -0800482}
483
484/**
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800485 * Test ITuner::setConfiguration() with invalid arguments.
486 *
487 * Verifies that:
488 * - the methods returns INVALID_ARGUMENTS on invalid arguments
489 * - the method recovers and succeeds after passing correct arguments
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700490 *
491 * Skipped for other radio classes than AM/FM, because setConfiguration
492 * applies only for these bands.
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800493 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700494TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700495 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700496 RETURN_IF_SKIPPED;
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800497 ASSERT_EQ(true, openTuner());
498
499 // Let's define a config that's bad for sure.
500 BandConfig badConfig = {};
501 badConfig.type = Band::FM;
502 badConfig.lowerLimit = 0xFFFFFFFF;
503 badConfig.upperLimit = 0;
504 badConfig.spacings = (std::vector<uint32_t>){ 0 };
505
506 // Test setConfiguration failing on bad data.
507 mCallbackCalled = false;
508 auto setResult = mTuner->setConfiguration(badConfig);
509 EXPECT_TRUE(setResult.isOk());
510 EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult);
511
512 // Test setConfiguration recovering after passing good data.
513 mCallbackCalled = false;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700514 setResult = mTuner->setConfiguration(getBand(0));
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800515 EXPECT_TRUE(setResult.isOk());
516 EXPECT_EQ(Result::OK, setResult);
517 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
518 EXPECT_EQ(Result::OK, mResultCallbackData);
519}
520
521/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800522 * Test ITuner::scan
523 *
524 * Verifies that:
525 * - the HAL implements the method
526 * - the method returns 0 (no error)
527 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700528 * - skipping sub-channel or not does not fail the call
Eric Laurent566fcda2016-11-23 10:36:36 -0800529 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700530TEST_P(BroadcastRadioHidlTest, Scan) {
531 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800532 ASSERT_EQ(true, openTuner());
533 ASSERT_TRUE(checkAntenna());
534 // test scan UP
535 mCallbackCalled = false;
536 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800537 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800538 EXPECT_EQ(Result::OK, hidlResult);
539 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
540
541 // test scan DOWN
542 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700543 hidlResult = mTuner->scan(Direction::DOWN, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800544 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800545 EXPECT_EQ(Result::OK, hidlResult);
546 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
547}
548
549/**
550 * Test ITuner::step
551 *
552 * Verifies that:
553 * - the HAL implements the method
554 * - the method returns 0 (no error)
555 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700556 * - skipping sub-channel or not does not fail the call
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700557 *
558 * Skipped for other radio classes than AM/FM, because step is not possible
559 * on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800560 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700561TEST_P(BroadcastRadioHidlTest, Step) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700562 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700563 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800564 ASSERT_EQ(true, openTuner());
565 ASSERT_TRUE(checkAntenna());
566 // test step UP
567 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700568 Return<Result> hidlResult = mTuner->step(Direction::UP, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800569 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800570 EXPECT_EQ(Result::OK, hidlResult);
571 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
572
573 // test step DOWN
574 mCallbackCalled = false;
575 hidlResult = mTuner->step(Direction::DOWN, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800576 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800577 EXPECT_EQ(Result::OK, hidlResult);
578 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
579}
580
581/**
582 * Test ITuner::tune, getProgramInformation and cancel methods
583 *
584 * Verifies that:
585 * - the HAL implements the methods
586 * - the methods return 0 (no error)
587 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700588 *
589 * Skipped for other radio classes than AM/FM, because tune to frequency
590 * is not possible on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800591 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700592TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700593 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700594 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800595 ASSERT_EQ(true, openTuner());
596 ASSERT_TRUE(checkAntenna());
597
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700598 auto& band = getBand(0);
599
Eric Laurent566fcda2016-11-23 10:36:36 -0800600 // test tune
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700601 ASSERT_GT(band.spacings.size(), 0u);
602 ASSERT_GT(band.upperLimit, band.lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800603
604 // test scan UP
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700605 uint32_t lowerLimit = band.lowerLimit;
606 uint32_t upperLimit = band.upperLimit;
607 uint32_t spacing = band.spacings[0];
Eric Laurent566fcda2016-11-23 10:36:36 -0800608
609 uint32_t channel =
610 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
611 mCallbackCalled = false;
612 mResultCallbackData = Result::NOT_INITIALIZED;
613 Return<Result> hidlResult = mTuner->tune(channel, 0);
Steven Morelandb6438422017-01-03 17:06:57 -0800614 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800615 EXPECT_EQ(Result::OK, hidlResult);
616 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800617 EXPECT_EQ(channel, mProgramInfoCallbackData.channel);
Eric Laurent566fcda2016-11-23 10:36:36 -0800618
619 // test getProgramInformation
620 ProgramInfo halInfo;
621 Result halResult = Result::NOT_INITIALIZED;
622 Return<void> hidlReturn = mTuner->getProgramInformation(
Tomasz Wasilczyk5cc9d862017-01-06 14:19:11 -0800623 [&](Result result, const ProgramInfo& info) {
624 halResult = result;
625 if (result == Result::OK) {
626 halInfo = info;
627 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800628 });
Steven Morelandb6438422017-01-03 17:06:57 -0800629 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800630 EXPECT_EQ(Result::OK, halResult);
631 if (mResultCallbackData == Result::OK) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800632 EXPECT_LE(halInfo.channel, upperLimit);
633 EXPECT_GE(halInfo.channel, lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800634 }
635
636 // test cancel
637 mTuner->tune(lowerLimit, 0);
638 hidlResult = mTuner->cancel();
Steven Morelandb6438422017-01-03 17:06:57 -0800639 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800640 EXPECT_EQ(Result::OK, hidlResult);
641}
642
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800643/**
644 * Test ITuner::tune failing when channel out of the range is provided.
645 *
646 * Verifies that:
647 * - the method returns INVALID_ARGUMENTS when applicable
648 * - the method recovers and succeeds after passing correct arguments
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700649 *
650 * Skipped for other radio classes than AM/FM, because tune to frequency
651 * is not possible on DAB nor satellite.
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800652 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700653TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700654 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700655 RETURN_IF_SKIPPED;
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800656 ASSERT_TRUE(openTuner());
657 ASSERT_TRUE(checkAntenna());
658
659 // get current channel bounds
660 BandConfig halConfig;
661 Result halResult;
662 auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
663 halResult = result;
664 halConfig = config;
665 });
666 ASSERT_TRUE(configResult.isOk());
667 ASSERT_EQ(Result::OK, halResult);
668
669 // try to tune slightly above the limit and expect to fail
670 auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
671 auto tuneResult = mTuner->tune(badChannel, 0);
672 EXPECT_TRUE(tuneResult.isOk());
673 EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
674 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
675
676 // tuning exactly at the limit should succeed
677 auto goodChannel = halConfig.upperLimit;
678 tuneResult = mTuner->tune(goodChannel, 0);
679 EXPECT_TRUE(tuneResult.isOk());
680 EXPECT_EQ(Result::OK, tuneResult);
681 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
682}
683
Tomasz Wasilczykba3e2542017-07-17 13:59:21 -0700684/**
685 * Test proper image format in metadata.
686 *
687 * Verifies that:
688 * - all images in metadata are provided in-band (as a binary blob, not by id)
689 *
690 * This is a counter-test for OobImagesOnly from 1.1 VTS.
691 */
692TEST_P(BroadcastRadioHidlTest, IbImagesOnly) {
693 RETURN_IF_SKIPPED;
694 ASSERT_TRUE(openTuner());
695 ASSERT_TRUE(checkAntenna());
696
697 bool firstScan = true;
698 uint32_t firstChannel, prevChannel;
699 while (true) {
700 mCallbackCalled = false;
701 auto hidlResult = mTuner->scan(Direction::UP, true);
702 ASSERT_TRUE(hidlResult.isOk());
703 if (hidlResult == Result::TIMEOUT) {
704 ALOGI("Got timeout on scan operation");
705 break;
706 }
707 ASSERT_EQ(Result::OK, hidlResult);
708 ASSERT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
709
710 if (firstScan) {
711 firstScan = false;
712 firstChannel = mProgramInfoCallbackData.channel;
713 } else {
714 // scanned the whole band
715 if (mProgramInfoCallbackData.channel >= firstChannel && prevChannel <= firstChannel) {
716 break;
717 }
718 }
719 prevChannel = mProgramInfoCallbackData.channel;
720
721 for (auto&& entry : mProgramInfoCallbackData.metadata) {
722 if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue;
723 EXPECT_EQ(MetadataType::RAW, entry.type);
724 EXPECT_EQ(0, entry.intValue);
725 EXPECT_GT(entry.rawValue.size(), 0u);
726 }
727 }
728}
729
Dan Shiac9cf442020-09-08 10:42:38 -0700730GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHidlTest);
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700731INSTANTIATE_TEST_CASE_P(
Dan Shi170a4452020-04-04 00:59:41 -0700732 PerInstance, BroadcastRadioHidlTest,
733 testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
734 IBroadcastRadioFactory::descriptor)),
735 ::testing::Values("AM_FM", "SAT", "DT")),
V,Anilkumar86f31e72022-07-05 23:39:38 +0530736 android::hardware::PrintInstanceTupleNameToString<>);