blob: 90c846375575b4f1186cd24456dcbf30be8e78a9 [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"
Yuexi Maed2bb4e2017-03-10 00:44:45 -080018#include <VtsHalHidlTargetTestBase.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080019#include <android-base/logging.h>
20#include <cutils/native_handle.h>
21#include <cutils/properties.h>
Martijn Coenen02822372016-12-29 14:03:41 +010022#include <hidl/HidlTransportSupport.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080023#include <utils/threads.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080024
Eric Laurent566fcda2016-11-23 10:36:36 -080025#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080026#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080027#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>
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080030#include <broadcastradio-vts-utils/environment-utils.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080031
32using ::android::sp;
33using ::android::Mutex;
34using ::android::Condition;
Eric Laurent566fcda2016-11-23 10:36:36 -080035using ::android::hardware::Return;
Eric Laurent566fcda2016-11-23 10:36:36 -080036using ::android::hardware::Void;
37using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
38using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
39using ::android::hardware::broadcastradio::V1_0::ITuner;
40using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
41using ::android::hardware::broadcastradio::V1_0::Result;
42using ::android::hardware::broadcastradio::V1_0::Class;
43using ::android::hardware::broadcastradio::V1_0::Properties;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -080044using ::android::hardware::broadcastradio::V1_0::Band;
Eric Laurent566fcda2016-11-23 10:36:36 -080045using ::android::hardware::broadcastradio::V1_0::BandConfig;
46using ::android::hardware::broadcastradio::V1_0::Direction;
47using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
48using ::android::hardware::broadcastradio::V1_0::MetaData;
Tomasz Wasilczykba3e2542017-07-17 13:59:21 -070049using ::android::hardware::broadcastradio::V1_0::MetadataKey;
50using ::android::hardware::broadcastradio::V1_0::MetadataType;
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080051using ::android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
Eric Laurent566fcda2016-11-23 10:36:36 -080052
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070053#define RETURN_IF_SKIPPED \
54 if (skipped) { \
55 std::cout << "[ SKIPPED ] This device class is not supported. " << std::endl; \
56 return; \
57 }
58
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080059static BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>* gEnv = nullptr;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080060// The main test class for Broadcast Radio HIDL HAL.
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070061class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase,
62 public ::testing::WithParamInterface<Class> {
Eric Laurent566fcda2016-11-23 10:36:36 -080063 protected:
64 virtual void SetUp() override {
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070065 ASSERT_EQ(nullptr, mRadio.get());
66
67 radioClass = GetParam();
68 skipped = false;
69
Eric Laurent566fcda2016-11-23 10:36:36 -080070 sp<IBroadcastRadioFactory> factory =
Zhuoyao Zhang190548f2018-02-08 20:40:23 -080071 getService<IBroadcastRadioFactory>(gEnv->getServiceName<IBroadcastRadioFactory>());
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070072 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;
Eric Laurent566fcda2016-11-23 10:36:36 -080086 }
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -070087 ASSERT_EQ(connectResult, Result::OK);
88
Eric Laurent566fcda2016-11-23 10:36:36 -080089 mTunerCallback = new MyCallback(this);
90 ASSERT_NE(nullptr, mRadio.get());
Eric Laurent566fcda2016-11-23 10:36:36 -080091 ASSERT_NE(nullptr, mTunerCallback.get());
92 }
93
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)
103 virtual Return<void> hardwareFailure() {
104 ALOGI("%s", __FUNCTION__);
105 mParentTest->onHwFailureCallback();
106 return Void();
107 }
108
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800109 virtual Return<void> configChange(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800110 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800111 mParentTest->onConfigChangeCallback(result, config);
Eric Laurent566fcda2016-11-23 10:36:36 -0800112 return Void();
113 }
114
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800115 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800116 ALOGI("%s result %d", __FUNCTION__, result);
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800117 mParentTest->onTuneCompleteCallback(result, info);
Eric Laurent566fcda2016-11-23 10:36:36 -0800118 return Void();
119 }
120
121 virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
122 return Void();
123 }
124
125 virtual Return<void> antennaStateChange(bool connected) {
126 ALOGI("%s connected %d", __FUNCTION__, connected);
127 return Void();
128 }
129
130 virtual Return<void> trafficAnnouncement(bool active) {
131 ALOGI("%s active %d", __FUNCTION__, active);
132 return Void();
133 }
134
135 virtual Return<void> emergencyAnnouncement(bool active) {
136 ALOGI("%s active %d", __FUNCTION__, active);
137 return Void();
138 }
139
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
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 */
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 */
165 void onHwFailureCallback() {
166 Mutex::Autolock _l(mLock);
167 mHwFailure = true;
168 onCallback_l();
169 }
170
171 /**
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800172 * Method called by MyCallback when configChange() callback is received.
Eric Laurent566fcda2016-11-23 10:36:36 -0800173 */
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800174 void onConfigChangeCallback(Result result, const BandConfig& config) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800175 Mutex::Autolock _l(mLock);
176 mResultCallbackData = result;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800177 mBandConfigCallbackData = config;
178 onCallback_l();
179 }
180
181 /**
182 * Method called by MyCallback when tuneComplete() callback is received.
183 */
184 void onTuneCompleteCallback(Result result, const ProgramInfo& info) {
185 Mutex::Autolock _l(mLock);
186 mResultCallbackData = result;
187 mProgramInfoCallbackData = info;
Eric Laurent566fcda2016-11-23 10:36:36 -0800188 onCallback_l();
189 }
190
191 /**
192 * Method called by MyCallback when a boolean indication is received
193 */
194 void onBoolCallback(bool result) {
195 Mutex::Autolock _l(mLock);
196 mBoolCallbackData = result;
197 onCallback_l();
198 }
199
200
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700201 BroadcastRadioHidlTest()
202 : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK),
203 mHwFailure(false) {}
Eric Laurent566fcda2016-11-23 10:36:36 -0800204
205 void onCallback_l() {
206 if (!mCallbackCalled) {
207 mCallbackCalled = true;
208 mCallbackCond.broadcast();
209 }
210 }
211
212
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();
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700233
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);
Eric Laurent566fcda2016-11-23 10:36:36 -0800245
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700246 static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1);
Eric Laurent566fcda2016-11-23 10:36:36 -0800247 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
248 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
249
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700250 Class radioClass;
251 bool skipped;
Eric Laurent566fcda2016-11-23 10:36:36 -0800252 sp<IBroadcastRadio> mRadio;
253 Properties mHalProperties;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700254 bool mHalPropertiesInitialized = false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800255 sp<ITuner> mTuner;
256 sp<MyCallback> mTunerCallback;
257 Mutex mLock;
258 Condition mCallbackCond;
259 bool mCallbackCalled;
260 bool mBoolCallbackData;
261 Result mResultCallbackData;
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800262 ProgramInfo mProgramInfoCallbackData;
263 BandConfig mBandConfigCallbackData;
Eric Laurent566fcda2016-11-23 10:36:36 -0800264 bool mHwFailure;
265};
266
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800267namespace android {
268namespace hardware {
269namespace broadcastradio {
270namespace V1_0 {
271
272/**
273 * Compares two BandConfig objects for testing purposes.
274 */
275static 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
Eric Laurent566fcda2016-11-23 10:36:36 -0800296bool BroadcastRadioHidlTest::getProperties()
297{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700298 if (mHalPropertiesInitialized) return true;
Eric Laurent566fcda2016-11-23 10:36:36 -0800299
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700300 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) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800313 EXPECT_GT(mHalProperties.bands.size(), 0u);
314 }
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700315
316 if (hidlReturn.isOk() && halResult == Result::OK) {
317 mHalPropertiesInitialized = true;
318 return true;
319 }
320 return false;
Eric Laurent566fcda2016-11-23 10:36:36 -0800321}
322
323bool BroadcastRadioHidlTest::openTuner()
324{
325 if (!getProperties()) {
326 return false;
327 }
328 if (mTuner.get() == nullptr) {
329 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700330 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);
Steven Morelandb6438422017-01-03 17:06:57 -0800337 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800338 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700339 if (radioClass == Class::AM_FM) {
340 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
341 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800342 }
343 EXPECT_NE(nullptr, mTuner.get());
344 return nullptr != mTuner.get();
345}
346
347bool BroadcastRadioHidlTest::checkAntenna()
348{
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700349 if (radioClass != Class::AM_FM) return true;
350
Eric Laurent566fcda2016-11-23 10:36:36 -0800351 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
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700364const BandConfig& BroadcastRadioHidlTest::getBand(unsigned idx) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700365 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}
Eric Laurent566fcda2016-11-23 10:36:36 -0800377
378/**
379 * Test IBroadcastRadio::getProperties() method
380 *
381 * Verifies that:
382 * - the HAL implements the method
383 * - the method returns 0 (no error)
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700384 * - the implementation class is radioClass
Eric Laurent566fcda2016-11-23 10:36:36 -0800385 * - the implementation supports at least one tuner
386 * - the implementation supports at one band
387 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700388TEST_P(BroadcastRadioHidlTest, GetProperties) {
389 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800390 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 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700400TEST_P(BroadcastRadioHidlTest, OpenTuner) {
401 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800402 EXPECT_EQ(true, openTuner());
403}
404
405/**
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800406 * 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 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700412TEST_P(BroadcastRadioHidlTest, ReopenTuner) {
413 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800414 EXPECT_TRUE(openTuner());
415 mTuner.clear();
416 EXPECT_TRUE(openTuner());
417}
418
419/**
420 * Test IBroadcastRadio::openTuner() method called twice.
421 *
422 * Verifies that:
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700423 * - the openTuner method fails with INVALID_STATE or succeeds when called for the second time
424 * without deleting previous ITuner instance
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800425 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700426TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) {
427 RETURN_IF_SKIPPED;
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800428 EXPECT_TRUE(openTuner());
429
430 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700431 auto openCb = [&](Result result, const sp<ITuner>&) { halResult = result; };
432 auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800433 EXPECT_TRUE(hidlReturn.isOk());
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700434 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);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700440 }
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800441}
442
443/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800444 * 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
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700451 *
452 * Skipped for other radio classes than AM/FM, because setConfiguration
453 * applies only for these bands.
Eric Laurent566fcda2016-11-23 10:36:36 -0800454 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700455TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700456 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700457 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800458 ASSERT_EQ(true, openTuner());
459 // test setConfiguration
460 mCallbackCalled = false;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700461 Return<Result> hidlResult = mTuner->setConfiguration(getBand(1));
Steven Morelandb6438422017-01-03 17:06:57 -0800462 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800463 EXPECT_EQ(Result::OK, hidlResult);
464 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
465 EXPECT_EQ(Result::OK, mResultCallbackData);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700466 EXPECT_EQ(getBand(1), mBandConfigCallbackData);
Eric Laurent566fcda2016-11-23 10:36:36 -0800467
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 });
Steven Morelandb6438422017-01-03 17:06:57 -0800478 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800479 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700480 EXPECT_EQ(getBand(1), halConfig);
Eric Laurent566fcda2016-11-23 10:36:36 -0800481}
482
483/**
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800484 * 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
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700489 *
490 * Skipped for other radio classes than AM/FM, because setConfiguration
491 * applies only for these bands.
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800492 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700493TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700494 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700495 RETURN_IF_SKIPPED;
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800496 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;
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700513 setResult = mTuner->setConfiguration(getBand(0));
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800514 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/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800521 * 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
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700527 * - skipping sub-channel or not does not fail the call
Eric Laurent566fcda2016-11-23 10:36:36 -0800528 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700529TEST_P(BroadcastRadioHidlTest, Scan) {
530 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800531 ASSERT_EQ(true, openTuner());
532 ASSERT_TRUE(checkAntenna());
533 // test scan UP
534 mCallbackCalled = false;
535 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800536 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800537 EXPECT_EQ(Result::OK, hidlResult);
538 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
539
540 // test scan DOWN
541 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700542 hidlResult = mTuner->scan(Direction::DOWN, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800543 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800544 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
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700555 * - skipping sub-channel or not does not fail the call
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700556 *
557 * Skipped for other radio classes than AM/FM, because step is not possible
558 * on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800559 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700560TEST_P(BroadcastRadioHidlTest, Step) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700561 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700562 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800563 ASSERT_EQ(true, openTuner());
564 ASSERT_TRUE(checkAntenna());
565 // test step UP
566 mCallbackCalled = false;
Tomasz Wasilczyka8dec0f2017-03-14 10:20:53 -0700567 Return<Result> hidlResult = mTuner->step(Direction::UP, false);
Steven Morelandb6438422017-01-03 17:06:57 -0800568 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800569 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);
Steven Morelandb6438422017-01-03 17:06:57 -0800575 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800576 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()
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700587 *
588 * Skipped for other radio classes than AM/FM, because tune to frequency
589 * is not possible on DAB nor satellite.
Eric Laurent566fcda2016-11-23 10:36:36 -0800590 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700591TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700592 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700593 RETURN_IF_SKIPPED;
Eric Laurent566fcda2016-11-23 10:36:36 -0800594 ASSERT_EQ(true, openTuner());
595 ASSERT_TRUE(checkAntenna());
596
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700597 auto& band = getBand(0);
598
Eric Laurent566fcda2016-11-23 10:36:36 -0800599 // test tune
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700600 ASSERT_GT(band.spacings.size(), 0u);
601 ASSERT_GT(band.upperLimit, band.lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800602
603 // test scan UP
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700604 uint32_t lowerLimit = band.lowerLimit;
605 uint32_t upperLimit = band.upperLimit;
606 uint32_t spacing = band.spacings[0];
Eric Laurent566fcda2016-11-23 10:36:36 -0800607
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);
Steven Morelandb6438422017-01-03 17:06:57 -0800613 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800614 EXPECT_EQ(Result::OK, hidlResult);
615 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
Tomasz Wasilczykf3c036d2017-03-03 15:07:50 -0800616 EXPECT_EQ(channel, mProgramInfoCallbackData.channel);
Eric Laurent566fcda2016-11-23 10:36:36 -0800617
618 // test getProgramInformation
619 ProgramInfo halInfo;
620 Result halResult = Result::NOT_INITIALIZED;
621 Return<void> hidlReturn = mTuner->getProgramInformation(
Tomasz Wasilczyk5cc9d862017-01-06 14:19:11 -0800622 [&](Result result, const ProgramInfo& info) {
623 halResult = result;
624 if (result == Result::OK) {
625 halInfo = info;
626 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800627 });
Steven Morelandb6438422017-01-03 17:06:57 -0800628 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800629 EXPECT_EQ(Result::OK, halResult);
630 if (mResultCallbackData == Result::OK) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800631 EXPECT_LE(halInfo.channel, upperLimit);
632 EXPECT_GE(halInfo.channel, lowerLimit);
Eric Laurent566fcda2016-11-23 10:36:36 -0800633 }
634
635 // test cancel
636 mTuner->tune(lowerLimit, 0);
637 hidlResult = mTuner->cancel();
Steven Morelandb6438422017-01-03 17:06:57 -0800638 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800639 EXPECT_EQ(Result::OK, hidlResult);
640}
641
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800642/**
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
Tomasz Wasilczyk394b3432017-08-07 18:00:28 -0700648 *
649 * Skipped for other radio classes than AM/FM, because tune to frequency
650 * is not possible on DAB nor satellite.
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800651 */
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700652TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
Tomasz Wasilczykda72d372017-06-26 16:08:51 -0700653 if (radioClass != Class::AM_FM) skipped = true;
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700654 RETURN_IF_SKIPPED;
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800655 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
Tomasz Wasilczykba3e2542017-07-17 13:59:21 -0700683/**
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 */
691TEST_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
Tomasz Wasilczyk2f461012017-03-14 11:19:15 -0700729INSTANTIATE_TEST_CASE_P(
730 BroadcastRadioHidlTestCases,
731 BroadcastRadioHidlTest,
732 ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
Eric Laurent566fcda2016-11-23 10:36:36 -0800733
734int main(int argc, char** argv) {
Zhuoyao Zhang190548f2018-02-08 20:40:23 -0800735 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;
Eric Laurent566fcda2016-11-23 10:36:36 -0800742}