blob: cac3dd0eaec2d109ae9491de47d68d1884c61daa [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
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070055#define RETURN_IF_SKIPPED \
56 if (skipped) { \
57 std::cout << "[ SKIPPED ] This device class is not supported. " << std::endl; \
58 return; \
59 }
60
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080061// The main test class for Broadcast Radio HIDL HAL.
Dan Shi170a4452020-04-04 00:59:41 -070062class BroadcastRadioHidlTest
63 : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
64 protected:
Eric Laurent566fcda2016-11-23 10:36:36 -080065 virtual void SetUp() override {
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070066 ASSERT_EQ(nullptr, mRadio.get());
67
Dan Shi170a4452020-04-04 00:59:41 -070068 radioClass = RadioClassFromString(std::get<1>(GetParam()));
69
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070070 skipped = false;
71
Eric Laurent566fcda2016-11-23 10:36:36 -080072 sp<IBroadcastRadioFactory> factory =
Dan Shi170a4452020-04-04 00:59:41 -070073 IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070074 ASSERT_NE(nullptr, factory.get());
75
76 Result connectResult;
77 factory->connectModule(radioClass, [&](Result ret, const sp<IBroadcastRadio>& radio) {
78 connectResult = ret;
79 mRadio = radio;
80 onCallback_l();
81 });
82 EXPECT_EQ(true, waitForCallback(kConnectCallbacktimeoutNs));
83 mCallbackCalled = false;
84
85 if (connectResult == Result::INVALID_ARGUMENTS) {
86 skipped = true;
87 return;
Eric Laurent566fcda2016-11-23 10:36:36 -080088 }
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070089 ASSERT_EQ(connectResult, Result::OK);
90
Eric Laurent566fcda2016-11-23 10:36:36 -080091 mTunerCallback = new MyCallback(this);
92 ASSERT_NE(nullptr, mRadio.get());
Eric Laurent566fcda2016-11-23 10:36:36 -080093 ASSERT_NE(nullptr, mTunerCallback.get());
94 }
95
96 virtual void TearDown() override {
97 mTuner.clear();
98 mRadio.clear();
99 }
100
101 class MyCallback : public ITunerCallback {
102 public:
103
104 // ITunerCallback methods (see doc in ITunerCallback.hal)
105 virtual Return<void> hardwareFailure() {
106 ALOGI("%s", __FUNCTION__);
107 mParentTest->onHwFailureCallback();
108 return Void();
109 }
110
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800111 virtual Return<void> configChange(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800112 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800113 mParentTest->onConfigChangeCallback(result, config);
Eric Laurent566fcda2016-11-23 10:36:36 -0800114 return Void();
115 }
116
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800117 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800118 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800119 mParentTest->onTuneCompleteCallback(result, info);
Eric Laurent566fcda2016-11-23 10:36:36 -0800120 return Void();
121 }
122
123 virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
124 return Void();
125 }
126
127 virtual Return<void> antennaStateChange(bool connected) {
128 ALOGI("%s connected %d", __FUNCTION__, connected);
129 return Void();
130 }
131
132 virtual Return<void> trafficAnnouncement(bool active) {
133 ALOGI("%s active %d", __FUNCTION__, active);
134 return Void();
135 }
136
137 virtual Return<void> emergencyAnnouncement(bool active) {
138 ALOGI("%s active %d", __FUNCTION__, active);
139 return Void();
140 }
141
142 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
143 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
144 ALOGI("%s", __FUNCTION__);
145 return Void();
146 }
147
148 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
149
150 private:
151 // BroadcastRadioHidlTest instance to which callbacks will be notified.
152 BroadcastRadioHidlTest *mParentTest;
153 };
154
155
156 /**
157 * Method called by MyCallback when a callback with no status or boolean value is received
158 */
159 void onCallback() {
160 Mutex::Autolock _l(mLock);
161 onCallback_l();
162 }
163
164 /**
165 * Method called by MyCallback when hardwareFailure() callback is received
166 */
167 void onHwFailureCallback() {
168 Mutex::Autolock _l(mLock);
169 mHwFailure = true;
170 onCallback_l();
171 }
172
173 /**
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800174 * Method called by MyCallback when configChange() callback is received.
Eric Laurent566fcda2016-11-23 10:36:36 -0800175 */
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800176 void onConfigChangeCallback(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800177 Mutex::Autolock _l(mLock);
178 mResultCallbackData = result;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800179 mBandConfigCallbackData = config;
180 onCallback_l();
181 }
182
183 /**
184 * Method called by MyCallback when tuneComplete() callback is received.
185 */
186 void onTuneCompleteCallback(Result result, const ProgramInfo& info) {
187 Mutex::Autolock _l(mLock);
188 mResultCallbackData = result;
189 mProgramInfoCallbackData = info;
Eric Laurent566fcda2016-11-23 10:36:36 -0800190 onCallback_l();
191 }
192
193 /**
194 * Method called by MyCallback when a boolean indication is received
195 */
196 void onBoolCallback(bool result) {
197 Mutex::Autolock _l(mLock);
198 mBoolCallbackData = result;
199 onCallback_l();
200 }
201
202
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700203 BroadcastRadioHidlTest()
204 : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK),
205 mHwFailure(false) {}
Eric Laurent566fcda2016-11-23 10:36:36 -0800206
207 void onCallback_l() {
208 if (!mCallbackCalled) {
209 mCallbackCalled = true;
210 mCallbackCond.broadcast();
211 }
212 }
213
214
215 bool waitForCallback(nsecs_t reltime = 0) {
216 Mutex::Autolock _l(mLock);
217 nsecs_t endTime = systemTime() + reltime;
218 while (!mCallbackCalled) {
219 if (reltime == 0) {
220 mCallbackCond.wait(mLock);
221 } else {
222 nsecs_t now = systemTime();
223 if (now > endTime) {
224 return false;
225 }
226 mCallbackCond.waitRelative(mLock, endTime - now);
227 }
228 }
229 return true;
230 }
231
232 bool getProperties();
233 bool openTuner();
234 bool checkAntenna();
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700235
236 /**
237 * Retrieves AM/FM band configuration from module properties.
238 *
239 * The configuration may not exist: if radio type is other than AM/FM
240 * or provided index is out of bounds.
241 * In such case, empty configuration is returned.
242 *
243 * @param idx Band index to retrieve.
244 * @return Band configuration reference.
245 */
246 const BandConfig& getBand(unsigned idx);
Eric Laurent566fcda2016-11-23 10:36:36 -0800247
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700248 static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1);
Eric Laurent566fcda2016-11-23 10:36:36 -0800249 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
250 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
251
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700252 Class radioClass;
253 bool skipped;
Eric Laurent566fcda2016-11-23 10:36:36 -0800254 sp<IBroadcastRadio> mRadio;
255 Properties mHalProperties;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700256 bool mHalPropertiesInitialized = false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800257 sp<ITuner> mTuner;
258 sp<MyCallback> mTunerCallback;
259 Mutex mLock;
260 Condition mCallbackCond;
261 bool mCallbackCalled;
262 bool mBoolCallbackData;
263 Result mResultCallbackData;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800264 ProgramInfo mProgramInfoCallbackData;
265 BandConfig mBandConfigCallbackData;
Eric Laurent566fcda2016-11-23 10:36:36 -0800266 bool mHwFailure;
267};
268
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800269namespace android {
270namespace hardware {
271namespace broadcastradio {
272namespace V1_0 {
273
274/**
275 * Compares two BandConfig objects for testing purposes.
276 */
277static bool operator==(const BandConfig& l, const BandConfig& r) {
278 if (l.type != r.type) return false;
279 if (l.antennaConnected != r.antennaConnected) return false;
280 if (l.lowerLimit != r.lowerLimit) return false;
281 if (l.upperLimit != r.upperLimit) return false;
282 if (l.spacings != r.spacings) return false;
283 if (l.type == Band::AM || l.type == Band::AM_HD) {
284 return l.ext.am == r.ext.am;
285 } else if (l.type == Band::FM || l.type == Band::FM_HD) {
286 return l.ext.fm == r.ext.fm;
287 } else {
288 // unsupported type
289 return false;
290 }
291}
292
293} // V1_0
294} // broadcastradio
295} // hardware
296} // android
297
Eric Laurent566fcda2016-11-23 10:36:36 -0800298bool BroadcastRadioHidlTest::getProperties()
299{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700300 if (mHalPropertiesInitialized) return true;
Eric Laurent566fcda2016-11-23 10:36:36 -0800301
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700302 Result halResult = Result::NOT_INITIALIZED;
303 auto hidlReturn = mRadio->getProperties([&](Result result, const Properties& properties) {
304 halResult = result;
305 if (result == Result::OK) {
306 mHalProperties = properties;
307 }
308 });
309
310 EXPECT_TRUE(hidlReturn.isOk());
311 EXPECT_EQ(Result::OK, halResult);
312 EXPECT_EQ(radioClass, mHalProperties.classId);
313 EXPECT_GT(mHalProperties.numTuners, 0u);
314 if (radioClass == Class::AM_FM) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800315 EXPECT_GT(mHalProperties.bands.size(), 0u);
316 }
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700317
318 if (hidlReturn.isOk() && halResult == Result::OK) {
319 mHalPropertiesInitialized = true;
320 return true;
321 }
322 return false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800323}
324
325bool BroadcastRadioHidlTest::openTuner()
326{
327 if (!getProperties()) {
328 return false;
329 }
330 if (mTuner.get() == nullptr) {
331 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700332 auto openCb = [&](Result result, const sp<ITuner>& tuner) {
333 halResult = result;
334 if (result == Result::OK) {
335 mTuner = tuner;
336 }
337 };
338 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
Steven Morelandb6438422017-01-03 17:06:57 -0800339 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800340 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700341 if (radioClass == Class::AM_FM) {
342 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
343 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800344 }
345 EXPECT_NE(nullptr, mTuner.get());
346 return nullptr != mTuner.get();
347}
348
349bool BroadcastRadioHidlTest::checkAntenna()
350{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700351 if (radioClass != Class::AM_FM) return true;
352
Eric Laurent566fcda2016-11-23 10:36:36 -0800353 BandConfig halConfig;
354 Result halResult = Result::NOT_INITIALIZED;
355 Return<void> hidlReturn =
356 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
357 halResult = result;
358 if (result == Result::OK) {
359 halConfig = config;
360 }
361 });
362
363 return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
364}
365
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700366const BandConfig& BroadcastRadioHidlTest::getBand(unsigned idx) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700367 static BandConfig dummyBandConfig = {};
368 if (radioClass == Class::AM_FM) {
369 EXPECT_GT(mHalProperties.bands.size(), idx);
370 if (mHalProperties.bands.size() > idx) {
371 return mHalProperties.bands[idx];
372 } else {
373 return dummyBandConfig;
374 }
375 } else {
376 return dummyBandConfig;
377 }
378}
Eric Laurent566fcda2016-11-23 10:36:36 -0800379
380/**
381 * Test IBroadcastRadio::getProperties() method
382 *
383 * Verifies that:
384 * - the HAL implements the method
385 * - the method returns 0 (no error)
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700386 * - the implementation class is radioClass
Eric Laurent566fcda2016-11-23 10:36:36 -0800387 * - the implementation supports at least one tuner
388 * - the implementation supports at one band
389 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700390TEST_P(BroadcastRadioHidlTest, GetProperties) {
391 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800392 EXPECT_EQ(true, getProperties());
393}
394
395/**
396 * Test IBroadcastRadio::openTuner() method
397 *
398 * Verifies that:
399 * - the HAL implements the method
400 * - the method returns 0 (no error) and a valid ITuner interface
401 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700402TEST_P(BroadcastRadioHidlTest, OpenTuner) {
403 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800404 EXPECT_EQ(true, openTuner());
405}
406
407/**
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800408 * Test IBroadcastRadio::openTuner() after ITuner disposal.
409 *
410 * Verifies that:
411 * - ITuner destruction gets propagated through HAL
412 * - the openTuner method works well when called for the second time
413 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700414TEST_P(BroadcastRadioHidlTest, ReopenTuner) {
415 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800416 EXPECT_TRUE(openTuner());
417 mTuner.clear();
418 EXPECT_TRUE(openTuner());
419}
420
421/**
422 * Test IBroadcastRadio::openTuner() method called twice.
423 *
424 * Verifies that:
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700425 * - the openTuner method fails with INVALID_STATE or succeeds when called for the second time
426 * without deleting previous ITuner instance
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800427 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700428TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) {
429 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800430 EXPECT_TRUE(openTuner());
431
432 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700433 auto openCb = [&](Result result, const sp<ITuner>&) { halResult = result; };
434 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800435 EXPECT_TRUE(hidlReturn.isOk());
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700436 if (halResult == Result::OK) {
437 if (radioClass == Class::AM_FM) {
438 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
439 }
440 } else {
441 EXPECT_EQ(Result::INVALID_STATE, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700442 }
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800443}
444
445/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800446 * Test ITuner::setConfiguration() and getConfiguration methods
447 *
448 * Verifies that:
449 * - the HAL implements both methods
450 * - the methods return 0 (no error)
451 * - the configuration callback is received within kConfigCallbacktimeoutNs ns
452 * - the configuration read back from HAl has the same class Id
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700453 *
454 * Skipped for other radio classes than AM/FM, because setConfiguration
455 * applies only for these bands.
Eric Laurent566fcda2016-11-23 10:36:36 -0800456 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700457TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700458 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700459 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800460 ASSERT_EQ(true, openTuner());
461 // test setConfiguration
462 mCallbackCalled = false;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700463 Return<Result> hidlResult = mTuner->setConfiguration(getBand(1));
Steven Morelandb6438422017-01-03 17:06:57 -0800464 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800465 EXPECT_EQ(Result::OK, hidlResult);
466 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
467 EXPECT_EQ(Result::OK, mResultCallbackData);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700468 EXPECT_EQ(getBand(1), mBandConfigCallbackData);
Eric Laurent566fcda2016-11-23 10:36:36 -0800469
470 // test getConfiguration
471 BandConfig halConfig;
472 Result halResult;
473 Return<void> hidlReturn =
474 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
475 halResult = result;
476 if (result == Result::OK) {
477 halConfig = config;
478 }
479 });
Steven Morelandb6438422017-01-03 17:06:57 -0800480 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800481 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700482 EXPECT_EQ(getBand(1), halConfig);
Eric Laurent566fcda2016-11-23 10:36:36 -0800483}
484
485/**
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800486 * Test ITuner::setConfiguration() with invalid arguments.
487 *
488 * Verifies that:
489 * - the methods returns INVALID_ARGUMENTS on invalid arguments
490 * - the method recovers and succeeds after passing correct arguments
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700491 *
492 * Skipped for other radio classes than AM/FM, because setConfiguration
493 * applies only for these bands.
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800494 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700495TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700496 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700497 RETURN_IF_SKIPPED;
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800498 ASSERT_EQ(true, openTuner());
499
500 // Let's define a config that's bad for sure.
501 BandConfig badConfig = {};
502 badConfig.type = Band::FM;
503 badConfig.lowerLimit = 0xFFFFFFFF;
504 badConfig.upperLimit = 0;
505 badConfig.spacings = (std::vector<uint32_t>){ 0 };
506
507 // Test setConfiguration failing on bad data.
508 mCallbackCalled = false;
509 auto setResult = mTuner->setConfiguration(badConfig);
510 EXPECT_TRUE(setResult.isOk());
511 EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult);
512
513 // Test setConfiguration recovering after passing good data.
514 mCallbackCalled = false;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700515 setResult = mTuner->setConfiguration(getBand(0));
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800516 EXPECT_TRUE(setResult.isOk());
517 EXPECT_EQ(Result::OK, setResult);
518 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
519 EXPECT_EQ(Result::OK, mResultCallbackData);
520}
521
522/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800523 * Test ITuner::scan
524 *
525 * Verifies that:
526 * - the HAL implements the method
527 * - the method returns 0 (no error)
528 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700529 * - skipping sub-channel or not does not fail the call
Eric Laurent566fcda2016-11-23 10:36:36 -0800530 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700531TEST_P(BroadcastRadioHidlTest, Scan) {
532 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800533 ASSERT_EQ(true, openTuner());
534 ASSERT_TRUE(checkAntenna());
535 // test scan UP
536 mCallbackCalled = false;
537 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800538 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800539 EXPECT_EQ(Result::OK, hidlResult);
540 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
541
542 // test scan DOWN
543 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700544 hidlResult = mTuner->scan(Direction::DOWN, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800545 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800546 EXPECT_EQ(Result::OK, hidlResult);
547 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
548}
549
550/**
551 * Test ITuner::step
552 *
553 * Verifies that:
554 * - the HAL implements the method
555 * - the method returns 0 (no error)
556 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700557 * - skipping sub-channel or not does not fail the call
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700558 *
559 * Skipped for other radio classes than AM/FM, because step is not possible
560 * on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800561 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700562TEST_P(BroadcastRadioHidlTest, Step) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700563 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700564 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800565 ASSERT_EQ(true, openTuner());
566 ASSERT_TRUE(checkAntenna());
567 // test step UP
568 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700569 Return<Result> hidlResult = mTuner->step(Direction::UP, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800570 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800571 EXPECT_EQ(Result::OK, hidlResult);
572 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
573
574 // test step DOWN
575 mCallbackCalled = false;
576 hidlResult = mTuner->step(Direction::DOWN, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800577 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800578 EXPECT_EQ(Result::OK, hidlResult);
579 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
580}
581
582/**
583 * Test ITuner::tune, getProgramInformation and cancel methods
584 *
585 * Verifies that:
586 * - the HAL implements the methods
587 * - the methods return 0 (no error)
588 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700589 *
590 * Skipped for other radio classes than AM/FM, because tune to frequency
591 * is not possible on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800592 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700593TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700594 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700595 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800596 ASSERT_EQ(true, openTuner());
597 ASSERT_TRUE(checkAntenna());
598
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700599 auto& band = getBand(0);
600
Eric Laurent566fcda2016-11-23 10:36:36 -0800601 // test tune
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700602 ASSERT_GT(band.spacings.size(), 0u);
603 ASSERT_GT(band.upperLimit, band.lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800604
605 // test scan UP
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700606 uint32_t lowerLimit = band.lowerLimit;
607 uint32_t upperLimit = band.upperLimit;
608 uint32_t spacing = band.spacings[0];
Eric Laurent566fcda2016-11-23 10:36:36 -0800609
610 uint32_t channel =
611 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
612 mCallbackCalled = false;
613 mResultCallbackData = Result::NOT_INITIALIZED;
614 Return<Result> hidlResult = mTuner->tune(channel, 0);
Steven Morelandb6438422017-01-03 17:06:57 -0800615 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800616 EXPECT_EQ(Result::OK, hidlResult);
617 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800618 EXPECT_EQ(channel, mProgramInfoCallbackData.channel);
Eric Laurent566fcda2016-11-23 10:36:36 -0800619
620 // test getProgramInformation
621 ProgramInfo halInfo;
622 Result halResult = Result::NOT_INITIALIZED;
623 Return<void> hidlReturn = mTuner->getProgramInformation(
Tomasz Wasilczyk5cc9d862017-01-06 14:19:11 -0800624 [&](Result result, const ProgramInfo& info) {
625 halResult = result;
626 if (result == Result::OK) {
627 halInfo = info;
628 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800629 });
Steven Morelandb6438422017-01-03 17:06:57 -0800630 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800631 EXPECT_EQ(Result::OK, halResult);
632 if (mResultCallbackData == Result::OK) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800633 EXPECT_LE(halInfo.channel, upperLimit);
634 EXPECT_GE(halInfo.channel, lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800635 }
636
637 // test cancel
638 mTuner->tune(lowerLimit, 0);
639 hidlResult = mTuner->cancel();
Steven Morelandb6438422017-01-03 17:06:57 -0800640 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800641 EXPECT_EQ(Result::OK, hidlResult);
642}
643
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800644/**
645 * Test ITuner::tune failing when channel out of the range is provided.
646 *
647 * Verifies that:
648 * - the method returns INVALID_ARGUMENTS when applicable
649 * - the method recovers and succeeds after passing correct arguments
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700650 *
651 * Skipped for other radio classes than AM/FM, because tune to frequency
652 * is not possible on DAB nor satellite.
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800653 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700654TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700655 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700656 RETURN_IF_SKIPPED;
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800657 ASSERT_TRUE(openTuner());
658 ASSERT_TRUE(checkAntenna());
659
660 // get current channel bounds
661 BandConfig halConfig;
662 Result halResult;
663 auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
664 halResult = result;
665 halConfig = config;
666 });
667 ASSERT_TRUE(configResult.isOk());
668 ASSERT_EQ(Result::OK, halResult);
669
670 // try to tune slightly above the limit and expect to fail
671 auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
672 auto tuneResult = mTuner->tune(badChannel, 0);
673 EXPECT_TRUE(tuneResult.isOk());
674 EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
675 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
676
677 // tuning exactly at the limit should succeed
678 auto goodChannel = halConfig.upperLimit;
679 tuneResult = mTuner->tune(goodChannel, 0);
680 EXPECT_TRUE(tuneResult.isOk());
681 EXPECT_EQ(Result::OK, tuneResult);
682 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
683}
684
Tomasz Wasilczykba3e2542017-07-17 13:59:21 -0700685/**
686 * Test proper image format in metadata.
687 *
688 * Verifies that:
689 * - all images in metadata are provided in-band (as a binary blob, not by id)
690 *
691 * This is a counter-test for OobImagesOnly from 1.1 VTS.
692 */
693TEST_P(BroadcastRadioHidlTest, IbImagesOnly) {
694 RETURN_IF_SKIPPED;
695 ASSERT_TRUE(openTuner());
696 ASSERT_TRUE(checkAntenna());
697
698 bool firstScan = true;
699 uint32_t firstChannel, prevChannel;
700 while (true) {
701 mCallbackCalled = false;
702 auto hidlResult = mTuner->scan(Direction::UP, true);
703 ASSERT_TRUE(hidlResult.isOk());
704 if (hidlResult == Result::TIMEOUT) {
705 ALOGI("Got timeout on scan operation");
706 break;
707 }
708 ASSERT_EQ(Result::OK, hidlResult);
709 ASSERT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
710
711 if (firstScan) {
712 firstScan = false;
713 firstChannel = mProgramInfoCallbackData.channel;
714 } else {
715 // scanned the whole band
716 if (mProgramInfoCallbackData.channel >= firstChannel && prevChannel <= firstChannel) {
717 break;
718 }
719 }
720 prevChannel = mProgramInfoCallbackData.channel;
721
722 for (auto&& entry : mProgramInfoCallbackData.metadata) {
723 if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue;
724 EXPECT_EQ(MetadataType::RAW, entry.type);
725 EXPECT_EQ(0, entry.intValue);
726 EXPECT_GT(entry.rawValue.size(), 0u);
727 }
728 }
729}
730
Dan Shiac9cf442020-09-08 10:42:38 -0700731GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHidlTest);
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700732INSTANTIATE_TEST_CASE_P(
Dan Shi170a4452020-04-04 00:59:41 -0700733 PerInstance, BroadcastRadioHidlTest,
734 testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
735 IBroadcastRadioFactory::descriptor)),
736 ::testing::Values("AM_FM", "SAT", "DT")),
737 android::hardware::PrintInstanceTupleNameToString<>);