xref: /aosp_15_r20/hardware/interfaces/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define EGMOCK_VERBOSE 1
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/Alert.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/BnAnnouncementListener.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>
27*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
28*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
29*4d7e907cSAndroid Build Coastguard Worker #include <android-base/thread_annotations.h>
30*4d7e907cSAndroid Build Coastguard Worker #include <android/binder_manager.h>
31*4d7e907cSAndroid Build Coastguard Worker #include <android/binder_process.h>
32*4d7e907cSAndroid Build Coastguard Worker 
33*4d7e907cSAndroid Build Coastguard Worker #include <aidl/Gtest.h>
34*4d7e907cSAndroid Build Coastguard Worker #include <aidl/Vintf.h>
35*4d7e907cSAndroid Build Coastguard Worker #include <broadcastradio-utils-aidl/Utils.h>
36*4d7e907cSAndroid Build Coastguard Worker #include <broadcastradio-utils-aidl/UtilsV2.h>
37*4d7e907cSAndroid Build Coastguard Worker #include <cutils/bitops.h>
38*4d7e907cSAndroid Build Coastguard Worker #include <gmock/gmock.h>
39*4d7e907cSAndroid Build Coastguard Worker #include <gtest/gtest.h>
40*4d7e907cSAndroid Build Coastguard Worker 
41*4d7e907cSAndroid Build Coastguard Worker #include <chrono>
42*4d7e907cSAndroid Build Coastguard Worker #include <condition_variable>
43*4d7e907cSAndroid Build Coastguard Worker #include <optional>
44*4d7e907cSAndroid Build Coastguard Worker #include <regex>
45*4d7e907cSAndroid Build Coastguard Worker 
46*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::broadcastradio::vts {
47*4d7e907cSAndroid Build Coastguard Worker 
48*4d7e907cSAndroid Build Coastguard Worker namespace {
49*4d7e907cSAndroid Build Coastguard Worker 
50*4d7e907cSAndroid Build Coastguard Worker using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
51*4d7e907cSAndroid Build Coastguard Worker using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
52*4d7e907cSAndroid Build Coastguard Worker using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
53*4d7e907cSAndroid Build Coastguard Worker using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
54*4d7e907cSAndroid Build Coastguard Worker using ::ndk::ScopedAStatus;
55*4d7e907cSAndroid Build Coastguard Worker using ::ndk::SharedRefBase;
56*4d7e907cSAndroid Build Coastguard Worker using ::std::vector;
57*4d7e907cSAndroid Build Coastguard Worker using ::testing::_;
58*4d7e907cSAndroid Build Coastguard Worker using ::testing::AnyNumber;
59*4d7e907cSAndroid Build Coastguard Worker using ::testing::ByMove;
60*4d7e907cSAndroid Build Coastguard Worker using ::testing::DoAll;
61*4d7e907cSAndroid Build Coastguard Worker using ::testing::Invoke;
62*4d7e907cSAndroid Build Coastguard Worker using ::testing::SaveArg;
63*4d7e907cSAndroid Build Coastguard Worker 
64*4d7e907cSAndroid Build Coastguard Worker namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
65*4d7e907cSAndroid Build Coastguard Worker 
66*4d7e907cSAndroid Build Coastguard Worker const ConfigFlag kConfigFlagValues[] = {
67*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::FORCE_MONO,
68*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::FORCE_ANALOG,
69*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::FORCE_DIGITAL,
70*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::RDS_AF,
71*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::RDS_REG,
72*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::DAB_DAB_LINKING,
73*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::DAB_FM_LINKING,
74*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::DAB_DAB_SOFT_LINKING,
75*4d7e907cSAndroid Build Coastguard Worker         ConfigFlag::DAB_FM_SOFT_LINKING,
76*4d7e907cSAndroid Build Coastguard Worker };
77*4d7e907cSAndroid Build Coastguard Worker 
78*4d7e907cSAndroid Build Coastguard Worker constexpr int32_t kAidlVersion1 = 1;
79*4d7e907cSAndroid Build Coastguard Worker constexpr int32_t kAidlVersion2 = 2;
80*4d7e907cSAndroid Build Coastguard Worker constexpr int32_t kAidlVersion3 = 3;
81*4d7e907cSAndroid Build Coastguard Worker 
isValidAmFmFreq(int64_t freq,int aidlVersion)82*4d7e907cSAndroid Build Coastguard Worker bool isValidAmFmFreq(int64_t freq, int aidlVersion) {
83*4d7e907cSAndroid Build Coastguard Worker     ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
84*4d7e907cSAndroid Build Coastguard Worker     if (aidlVersion == kAidlVersion1) {
85*4d7e907cSAndroid Build Coastguard Worker         return bcutils::isValid(id);
86*4d7e907cSAndroid Build Coastguard Worker     } else if (aidlVersion >= kAidlVersion2) {
87*4d7e907cSAndroid Build Coastguard Worker         return bcutils::isValidV2(id);
88*4d7e907cSAndroid Build Coastguard Worker     }
89*4d7e907cSAndroid Build Coastguard Worker     LOG(ERROR) << "Unknown AIDL version " << aidlVersion;
90*4d7e907cSAndroid Build Coastguard Worker     return false;
91*4d7e907cSAndroid Build Coastguard Worker }
92*4d7e907cSAndroid Build Coastguard Worker 
validateRange(const AmFmBandRange & range,int aidlVersion)93*4d7e907cSAndroid Build Coastguard Worker void validateRange(const AmFmBandRange& range, int aidlVersion) {
94*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(isValidAmFmFreq(range.lowerBound, aidlVersion));
95*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(isValidAmFmFreq(range.upperBound, aidlVersion));
96*4d7e907cSAndroid Build Coastguard Worker     EXPECT_LT(range.lowerBound, range.upperBound);
97*4d7e907cSAndroid Build Coastguard Worker     EXPECT_GT(range.spacing, 0u);
98*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ((range.upperBound - range.lowerBound) % range.spacing, 0u);
99*4d7e907cSAndroid Build Coastguard Worker }
100*4d7e907cSAndroid Build Coastguard Worker 
supportsFM(const AmFmRegionConfig & config)101*4d7e907cSAndroid Build Coastguard Worker bool supportsFM(const AmFmRegionConfig& config) {
102*4d7e907cSAndroid Build Coastguard Worker     for (const auto& range : config.ranges) {
103*4d7e907cSAndroid Build Coastguard Worker         if (bcutils::getBand(range.lowerBound) == bcutils::FrequencyBand::FM) {
104*4d7e907cSAndroid Build Coastguard Worker             return true;
105*4d7e907cSAndroid Build Coastguard Worker         }
106*4d7e907cSAndroid Build Coastguard Worker     }
107*4d7e907cSAndroid Build Coastguard Worker     return false;
108*4d7e907cSAndroid Build Coastguard Worker }
109*4d7e907cSAndroid Build Coastguard Worker 
validateMetadata(const ProgramInfo & info,int32_t aidlVersion)110*4d7e907cSAndroid Build Coastguard Worker void validateMetadata(const ProgramInfo& info, int32_t aidlVersion) {
111*4d7e907cSAndroid Build Coastguard Worker     for (const auto& metadataItem : info.metadata) {
112*4d7e907cSAndroid Build Coastguard Worker         bool validMetadata = false;
113*4d7e907cSAndroid Build Coastguard Worker         if (aidlVersion == kAidlVersion1) {
114*4d7e907cSAndroid Build Coastguard Worker             validMetadata = bcutils::isValidMetadata(metadataItem);
115*4d7e907cSAndroid Build Coastguard Worker         } else {
116*4d7e907cSAndroid Build Coastguard Worker             validMetadata = bcutils::isValidMetadataV2(metadataItem);
117*4d7e907cSAndroid Build Coastguard Worker         }
118*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
119*4d7e907cSAndroid Build Coastguard Worker     }
120*4d7e907cSAndroid Build Coastguard Worker }
121*4d7e907cSAndroid Build Coastguard Worker 
validateAlert(const ProgramInfo & info,int32_t aidlVersion)122*4d7e907cSAndroid Build Coastguard Worker void validateAlert(const ProgramInfo& info, int32_t aidlVersion) {
123*4d7e907cSAndroid Build Coastguard Worker     if (aidlVersion < kAidlVersion3 || !info.emergencyAlert.has_value()) {
124*4d7e907cSAndroid Build Coastguard Worker         return;
125*4d7e907cSAndroid Build Coastguard Worker     }
126*4d7e907cSAndroid Build Coastguard Worker     Alert alert = info.emergencyAlert.value();
127*4d7e907cSAndroid Build Coastguard Worker     ASSERT_FALSE(alert.infoArray.empty());
128*4d7e907cSAndroid Build Coastguard Worker     for (const auto& alertInfo : alert.infoArray) {
129*4d7e907cSAndroid Build Coastguard Worker         ASSERT_FALSE(alertInfo.categoryArray.empty());
130*4d7e907cSAndroid Build Coastguard Worker         if (alertInfo.areas.empty()) {
131*4d7e907cSAndroid Build Coastguard Worker             continue;
132*4d7e907cSAndroid Build Coastguard Worker         }
133*4d7e907cSAndroid Build Coastguard Worker         for (const auto& area : alertInfo.areas) {
134*4d7e907cSAndroid Build Coastguard Worker             if (area.polygons.empty()) {
135*4d7e907cSAndroid Build Coastguard Worker                 continue;
136*4d7e907cSAndroid Build Coastguard Worker             }
137*4d7e907cSAndroid Build Coastguard Worker             for (const auto& polygon : area.polygons) {
138*4d7e907cSAndroid Build Coastguard Worker                 ASSERT_GE(polygon.coordinates.size(), 4);
139*4d7e907cSAndroid Build Coastguard Worker                 EXPECT_EQ(polygon.coordinates.front(), polygon.coordinates.back());
140*4d7e907cSAndroid Build Coastguard Worker             }
141*4d7e907cSAndroid Build Coastguard Worker         }
142*4d7e907cSAndroid Build Coastguard Worker     }
143*4d7e907cSAndroid Build Coastguard Worker }
144*4d7e907cSAndroid Build Coastguard Worker 
145*4d7e907cSAndroid Build Coastguard Worker }  // namespace
146*4d7e907cSAndroid Build Coastguard Worker 
147*4d7e907cSAndroid Build Coastguard Worker class CallbackFlag final {
148*4d7e907cSAndroid Build Coastguard Worker   public:
CallbackFlag(int timeoutMs)149*4d7e907cSAndroid Build Coastguard Worker     CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
150*4d7e907cSAndroid Build Coastguard Worker     /**
151*4d7e907cSAndroid Build Coastguard Worker      * Notify that the callback is called.
152*4d7e907cSAndroid Build Coastguard Worker      */
notify()153*4d7e907cSAndroid Build Coastguard Worker     void notify() {
154*4d7e907cSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mMutex);
155*4d7e907cSAndroid Build Coastguard Worker         mCalled = true;
156*4d7e907cSAndroid Build Coastguard Worker         lock.unlock();
157*4d7e907cSAndroid Build Coastguard Worker         mCv.notify_all();
158*4d7e907cSAndroid Build Coastguard Worker     };
159*4d7e907cSAndroid Build Coastguard Worker 
160*4d7e907cSAndroid Build Coastguard Worker     /**
161*4d7e907cSAndroid Build Coastguard Worker      * Wait for the timeout passed into the constructor.
162*4d7e907cSAndroid Build Coastguard Worker      */
wait()163*4d7e907cSAndroid Build Coastguard Worker     bool wait() {
164*4d7e907cSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mMutex);
165*4d7e907cSAndroid Build Coastguard Worker         return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
166*4d7e907cSAndroid Build Coastguard Worker                             [this] { return mCalled; });
167*4d7e907cSAndroid Build Coastguard Worker     };
168*4d7e907cSAndroid Build Coastguard Worker 
169*4d7e907cSAndroid Build Coastguard Worker     /**
170*4d7e907cSAndroid Build Coastguard Worker      * Reset the callback to not called.
171*4d7e907cSAndroid Build Coastguard Worker      */
reset()172*4d7e907cSAndroid Build Coastguard Worker     void reset() {
173*4d7e907cSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mMutex);
174*4d7e907cSAndroid Build Coastguard Worker         mCalled = false;
175*4d7e907cSAndroid Build Coastguard Worker     }
176*4d7e907cSAndroid Build Coastguard Worker 
177*4d7e907cSAndroid Build Coastguard Worker   private:
178*4d7e907cSAndroid Build Coastguard Worker     std::mutex mMutex;
179*4d7e907cSAndroid Build Coastguard Worker     bool mCalled GUARDED_BY(mMutex) = false;
180*4d7e907cSAndroid Build Coastguard Worker     std::condition_variable mCv;
181*4d7e907cSAndroid Build Coastguard Worker     int mTimeoutMs;
182*4d7e907cSAndroid Build Coastguard Worker };
183*4d7e907cSAndroid Build Coastguard Worker 
184*4d7e907cSAndroid Build Coastguard Worker class TunerCallbackImpl final : public BnTunerCallback {
185*4d7e907cSAndroid Build Coastguard Worker   public:
186*4d7e907cSAndroid Build Coastguard Worker     explicit TunerCallbackImpl(int32_t aidlVersion);
187*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
188*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
189*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
190*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
191*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onAntennaStateChange(bool connected) override;
192*4d7e907cSAndroid Build Coastguard Worker     ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
193*4d7e907cSAndroid Build Coastguard Worker 
194*4d7e907cSAndroid Build Coastguard Worker     bool waitOnCurrentProgramInfoChangedCallback();
195*4d7e907cSAndroid Build Coastguard Worker     bool waitProgramReady();
196*4d7e907cSAndroid Build Coastguard Worker     void reset();
197*4d7e907cSAndroid Build Coastguard Worker 
198*4d7e907cSAndroid Build Coastguard Worker     bool getAntennaConnectionState();
199*4d7e907cSAndroid Build Coastguard Worker     ProgramInfo getCurrentProgramInfo();
200*4d7e907cSAndroid Build Coastguard Worker     bcutils::ProgramInfoSet getProgramList();
201*4d7e907cSAndroid Build Coastguard Worker 
202*4d7e907cSAndroid Build Coastguard Worker   private:
203*4d7e907cSAndroid Build Coastguard Worker     std::mutex mLock;
204*4d7e907cSAndroid Build Coastguard Worker     int32_t mCallbackAidlVersion;
205*4d7e907cSAndroid Build Coastguard Worker     bool mAntennaConnectionState GUARDED_BY(mLock);
206*4d7e907cSAndroid Build Coastguard Worker     ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
207*4d7e907cSAndroid Build Coastguard Worker     bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
208*4d7e907cSAndroid Build Coastguard Worker     CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
209*4d7e907cSAndroid Build Coastguard Worker     CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
210*4d7e907cSAndroid Build Coastguard Worker };
211*4d7e907cSAndroid Build Coastguard Worker 
212*4d7e907cSAndroid Build Coastguard Worker struct AnnouncementListenerMock : public BnAnnouncementListener {
213*4d7e907cSAndroid Build Coastguard Worker     MOCK_METHOD1(onListUpdated, ScopedAStatus(const vector<Announcement>&));
214*4d7e907cSAndroid Build Coastguard Worker };
215*4d7e907cSAndroid Build Coastguard Worker 
216*4d7e907cSAndroid Build Coastguard Worker class BroadcastRadioHalTest : public testing::TestWithParam<std::string> {
217*4d7e907cSAndroid Build Coastguard Worker   protected:
218*4d7e907cSAndroid Build Coastguard Worker     void SetUp() override;
219*4d7e907cSAndroid Build Coastguard Worker     void TearDown() override;
220*4d7e907cSAndroid Build Coastguard Worker 
221*4d7e907cSAndroid Build Coastguard Worker     bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
222*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> getProgramList();
223*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> getProgramList(const ProgramFilter& filter);
224*4d7e907cSAndroid Build Coastguard Worker 
225*4d7e907cSAndroid Build Coastguard Worker     std::shared_ptr<IBroadcastRadio> mModule;
226*4d7e907cSAndroid Build Coastguard Worker     Properties mProperties;
227*4d7e907cSAndroid Build Coastguard Worker     std::shared_ptr<TunerCallbackImpl> mCallback;
228*4d7e907cSAndroid Build Coastguard Worker     int32_t mAidlVersion;
229*4d7e907cSAndroid Build Coastguard Worker };
230*4d7e907cSAndroid Build Coastguard Worker 
231*4d7e907cSAndroid Build Coastguard Worker MATCHER_P(InfoHasId, id,
232*4d7e907cSAndroid Build Coastguard Worker           std::string(negation ? "does not contain" : "contains") + " " + id.toString()) {
233*4d7e907cSAndroid Build Coastguard Worker     vector<int64_t> ids = bcutils::getAllIds(arg.selector, id.type);
234*4d7e907cSAndroid Build Coastguard Worker     return ids.end() != find(ids.begin(), ids.end(), id.value);
235*4d7e907cSAndroid Build Coastguard Worker }
236*4d7e907cSAndroid Build Coastguard Worker 
TunerCallbackImpl(int32_t aidlVersion)237*4d7e907cSAndroid Build Coastguard Worker TunerCallbackImpl::TunerCallbackImpl(int32_t aidlVersion) {
238*4d7e907cSAndroid Build Coastguard Worker     mCallbackAidlVersion = aidlVersion;
239*4d7e907cSAndroid Build Coastguard Worker     mAntennaConnectionState = true;
240*4d7e907cSAndroid Build Coastguard Worker }
241*4d7e907cSAndroid Build Coastguard Worker 
onTuneFailed(Result result,const ProgramSelector & selector)242*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
243*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Tune failed for selector" << selector.toString();
244*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result == Result::CANCELED);
245*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
246*4d7e907cSAndroid Build Coastguard Worker }
247*4d7e907cSAndroid Build Coastguard Worker 
onCurrentProgramInfoChanged(const ProgramInfo & info)248*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
249*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "onCurrentProgramInfoChanged called";
250*4d7e907cSAndroid Build Coastguard Worker     for (const auto& id : info.selector) {
251*4d7e907cSAndroid Build Coastguard Worker         EXPECT_NE(id.type, IdentifierType::INVALID);
252*4d7e907cSAndroid Build Coastguard Worker     }
253*4d7e907cSAndroid Build Coastguard Worker 
254*4d7e907cSAndroid Build Coastguard Worker     IdentifierType logically = info.logicallyTunedTo.type;
255*4d7e907cSAndroid Build Coastguard Worker     // This field is required for currently tuned program and should be INVALID
256*4d7e907cSAndroid Build Coastguard Worker     // for entries from the program list.
257*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(logically == IdentifierType::AMFM_FREQUENCY_KHZ ||
258*4d7e907cSAndroid Build Coastguard Worker                 logically == IdentifierType::RDS_PI ||
259*4d7e907cSAndroid Build Coastguard Worker                 logically == IdentifierType::HD_STATION_ID_EXT ||
260*4d7e907cSAndroid Build Coastguard Worker                 logically == IdentifierType::DAB_SID_EXT ||
261*4d7e907cSAndroid Build Coastguard Worker                 logically == IdentifierType::DRMO_SERVICE_ID ||
262*4d7e907cSAndroid Build Coastguard Worker                 logically == IdentifierType::SXM_SERVICE_ID ||
263*4d7e907cSAndroid Build Coastguard Worker                 (logically >= IdentifierType::VENDOR_START &&
264*4d7e907cSAndroid Build Coastguard Worker                  logically <= IdentifierType::VENDOR_END) ||
265*4d7e907cSAndroid Build Coastguard Worker                 logically > IdentifierType::SXM_CHANNEL);
266*4d7e907cSAndroid Build Coastguard Worker 
267*4d7e907cSAndroid Build Coastguard Worker     IdentifierType physically = info.physicallyTunedTo.type;
268*4d7e907cSAndroid Build Coastguard Worker     // ditto (see "logically" above)
269*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
270*4d7e907cSAndroid Build Coastguard Worker                 physically == IdentifierType::DAB_FREQUENCY_KHZ ||
271*4d7e907cSAndroid Build Coastguard Worker                 physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
272*4d7e907cSAndroid Build Coastguard Worker                 physically == IdentifierType::SXM_CHANNEL ||
273*4d7e907cSAndroid Build Coastguard Worker                 (physically >= IdentifierType::VENDOR_START &&
274*4d7e907cSAndroid Build Coastguard Worker                  physically <= IdentifierType::VENDOR_END) ||
275*4d7e907cSAndroid Build Coastguard Worker                 physically > IdentifierType::SXM_CHANNEL);
276*4d7e907cSAndroid Build Coastguard Worker 
277*4d7e907cSAndroid Build Coastguard Worker     if (logically == IdentifierType::AMFM_FREQUENCY_KHZ) {
278*4d7e907cSAndroid Build Coastguard Worker         std::optional<std::string> ps;
279*4d7e907cSAndroid Build Coastguard Worker         if (mCallbackAidlVersion == kAidlVersion1) {
280*4d7e907cSAndroid Build Coastguard Worker             ps = bcutils::getMetadataString(info, Metadata::rdsPs);
281*4d7e907cSAndroid Build Coastguard Worker         } else {
282*4d7e907cSAndroid Build Coastguard Worker             ps = bcutils::getMetadataStringV2(info, Metadata::rdsPs);
283*4d7e907cSAndroid Build Coastguard Worker         }
284*4d7e907cSAndroid Build Coastguard Worker         if (ps.has_value()) {
285*4d7e907cSAndroid Build Coastguard Worker             EXPECT_NE(::android::base::Trim(*ps), "")
286*4d7e907cSAndroid Build Coastguard Worker                     << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
287*4d7e907cSAndroid Build Coastguard Worker         }
288*4d7e907cSAndroid Build Coastguard Worker     }
289*4d7e907cSAndroid Build Coastguard Worker 
290*4d7e907cSAndroid Build Coastguard Worker     validateMetadata(info, mCallbackAidlVersion);
291*4d7e907cSAndroid Build Coastguard Worker 
292*4d7e907cSAndroid Build Coastguard Worker     validateAlert(info, mCallbackAidlVersion);
293*4d7e907cSAndroid Build Coastguard Worker 
294*4d7e907cSAndroid Build Coastguard Worker     {
295*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lk(mLock);
296*4d7e907cSAndroid Build Coastguard Worker         mCurrentProgramInfo = info;
297*4d7e907cSAndroid Build Coastguard Worker     }
298*4d7e907cSAndroid Build Coastguard Worker 
299*4d7e907cSAndroid Build Coastguard Worker     mOnCurrentProgramInfoChangedFlag.notify();
300*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
301*4d7e907cSAndroid Build Coastguard Worker }
302*4d7e907cSAndroid Build Coastguard Worker 
onProgramListUpdated(const ProgramListChunk & chunk)303*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
304*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "onProgramListUpdated called";
305*4d7e907cSAndroid Build Coastguard Worker     {
306*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lk(mLock);
307*4d7e907cSAndroid Build Coastguard Worker         updateProgramList(chunk, &mProgramList);
308*4d7e907cSAndroid Build Coastguard Worker     }
309*4d7e907cSAndroid Build Coastguard Worker 
310*4d7e907cSAndroid Build Coastguard Worker     if (chunk.complete) {
311*4d7e907cSAndroid Build Coastguard Worker         mOnProgramListReadyFlag.notify();
312*4d7e907cSAndroid Build Coastguard Worker     }
313*4d7e907cSAndroid Build Coastguard Worker 
314*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
315*4d7e907cSAndroid Build Coastguard Worker }
316*4d7e907cSAndroid Build Coastguard Worker 
onParametersUpdated(const vector<VendorKeyValue> & parameters)317*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onParametersUpdated(
318*4d7e907cSAndroid Build Coastguard Worker         [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
319*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
320*4d7e907cSAndroid Build Coastguard Worker }
321*4d7e907cSAndroid Build Coastguard Worker 
onAntennaStateChange(bool connected)322*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
323*4d7e907cSAndroid Build Coastguard Worker     if (!connected) {
324*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard<std::mutex> lk(mLock);
325*4d7e907cSAndroid Build Coastguard Worker         mAntennaConnectionState = false;
326*4d7e907cSAndroid Build Coastguard Worker     }
327*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
328*4d7e907cSAndroid Build Coastguard Worker }
329*4d7e907cSAndroid Build Coastguard Worker 
onConfigFlagUpdated(ConfigFlag in_flag,bool in_value)330*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
331*4d7e907cSAndroid Build Coastguard Worker                                                      [[maybe_unused]] bool in_value) {
332*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
333*4d7e907cSAndroid Build Coastguard Worker }
334*4d7e907cSAndroid Build Coastguard Worker 
waitOnCurrentProgramInfoChangedCallback()335*4d7e907cSAndroid Build Coastguard Worker bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
336*4d7e907cSAndroid Build Coastguard Worker     return mOnCurrentProgramInfoChangedFlag.wait();
337*4d7e907cSAndroid Build Coastguard Worker }
338*4d7e907cSAndroid Build Coastguard Worker 
waitProgramReady()339*4d7e907cSAndroid Build Coastguard Worker bool TunerCallbackImpl::waitProgramReady() {
340*4d7e907cSAndroid Build Coastguard Worker     return mOnProgramListReadyFlag.wait();
341*4d7e907cSAndroid Build Coastguard Worker }
342*4d7e907cSAndroid Build Coastguard Worker 
reset()343*4d7e907cSAndroid Build Coastguard Worker void TunerCallbackImpl::reset() {
344*4d7e907cSAndroid Build Coastguard Worker     mOnCurrentProgramInfoChangedFlag.reset();
345*4d7e907cSAndroid Build Coastguard Worker     mOnProgramListReadyFlag.reset();
346*4d7e907cSAndroid Build Coastguard Worker }
347*4d7e907cSAndroid Build Coastguard Worker 
getAntennaConnectionState()348*4d7e907cSAndroid Build Coastguard Worker bool TunerCallbackImpl::getAntennaConnectionState() {
349*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lk(mLock);
350*4d7e907cSAndroid Build Coastguard Worker     return mAntennaConnectionState;
351*4d7e907cSAndroid Build Coastguard Worker }
352*4d7e907cSAndroid Build Coastguard Worker 
getCurrentProgramInfo()353*4d7e907cSAndroid Build Coastguard Worker ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
354*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lk(mLock);
355*4d7e907cSAndroid Build Coastguard Worker     return mCurrentProgramInfo;
356*4d7e907cSAndroid Build Coastguard Worker }
357*4d7e907cSAndroid Build Coastguard Worker 
getProgramList()358*4d7e907cSAndroid Build Coastguard Worker bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
359*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lk(mLock);
360*4d7e907cSAndroid Build Coastguard Worker     return mProgramList;
361*4d7e907cSAndroid Build Coastguard Worker }
362*4d7e907cSAndroid Build Coastguard Worker 
SetUp()363*4d7e907cSAndroid Build Coastguard Worker void BroadcastRadioHalTest::SetUp() {
364*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
365*4d7e907cSAndroid Build Coastguard Worker 
366*4d7e907cSAndroid Build Coastguard Worker     // lookup AIDL service (radio module)
367*4d7e907cSAndroid Build Coastguard Worker     AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
368*4d7e907cSAndroid Build Coastguard Worker     ASSERT_NE(binder, nullptr);
369*4d7e907cSAndroid Build Coastguard Worker     mModule = IBroadcastRadio::fromBinder(ndk::SpAIBinder(binder));
370*4d7e907cSAndroid Build Coastguard Worker     ASSERT_NE(mModule, nullptr) << "Couldn't find broadcast radio HAL implementation";
371*4d7e907cSAndroid Build Coastguard Worker 
372*4d7e907cSAndroid Build Coastguard Worker     // get module properties
373*4d7e907cSAndroid Build Coastguard Worker     auto propResult = mModule->getProperties(&mProperties);
374*4d7e907cSAndroid Build Coastguard Worker 
375*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(propResult.isOk());
376*4d7e907cSAndroid Build Coastguard Worker     EXPECT_FALSE(mProperties.maker.empty());
377*4d7e907cSAndroid Build Coastguard Worker     EXPECT_FALSE(mProperties.product.empty());
378*4d7e907cSAndroid Build Coastguard Worker     EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
379*4d7e907cSAndroid Build Coastguard Worker 
380*4d7e907cSAndroid Build Coastguard Worker     // get AIDL HAL version
381*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(mModule->getInterfaceVersion(&mAidlVersion).isOk());
382*4d7e907cSAndroid Build Coastguard Worker     EXPECT_GE(mAidlVersion, kAidlVersion1);
383*4d7e907cSAndroid Build Coastguard Worker     EXPECT_LE(mAidlVersion, kAidlVersion3);
384*4d7e907cSAndroid Build Coastguard Worker 
385*4d7e907cSAndroid Build Coastguard Worker     // set callback
386*4d7e907cSAndroid Build Coastguard Worker     mCallback = SharedRefBase::make<TunerCallbackImpl>(mAidlVersion);
387*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
388*4d7e907cSAndroid Build Coastguard Worker }
389*4d7e907cSAndroid Build Coastguard Worker 
TearDown()390*4d7e907cSAndroid Build Coastguard Worker void BroadcastRadioHalTest::TearDown() {
391*4d7e907cSAndroid Build Coastguard Worker     if (mModule) {
392*4d7e907cSAndroid Build Coastguard Worker         ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
393*4d7e907cSAndroid Build Coastguard Worker     }
394*4d7e907cSAndroid Build Coastguard Worker     if (mCallback) {
395*4d7e907cSAndroid Build Coastguard Worker         // we expect the antenna is connected through the whole test
396*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(mCallback->getAntennaConnectionState());
397*4d7e907cSAndroid Build Coastguard Worker         mCallback = nullptr;
398*4d7e907cSAndroid Build Coastguard Worker     }
399*4d7e907cSAndroid Build Coastguard Worker }
400*4d7e907cSAndroid Build Coastguard Worker 
getAmFmRegionConfig(bool full,AmFmRegionConfig * config)401*4d7e907cSAndroid Build Coastguard Worker bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
402*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->getAmFmRegionConfig(full, config);
403*4d7e907cSAndroid Build Coastguard Worker 
404*4d7e907cSAndroid Build Coastguard Worker     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
405*4d7e907cSAndroid Build Coastguard Worker         return false;
406*4d7e907cSAndroid Build Coastguard Worker     }
407*4d7e907cSAndroid Build Coastguard Worker 
408*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(halResult.isOk());
409*4d7e907cSAndroid Build Coastguard Worker     return halResult.isOk();
410*4d7e907cSAndroid Build Coastguard Worker }
411*4d7e907cSAndroid Build Coastguard Worker 
getProgramList()412*4d7e907cSAndroid Build Coastguard Worker std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
413*4d7e907cSAndroid Build Coastguard Worker     ProgramFilter emptyFilter = {};
414*4d7e907cSAndroid Build Coastguard Worker     return getProgramList(emptyFilter);
415*4d7e907cSAndroid Build Coastguard Worker }
416*4d7e907cSAndroid Build Coastguard Worker 
getProgramList(const ProgramFilter & filter)417*4d7e907cSAndroid Build Coastguard Worker std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
418*4d7e907cSAndroid Build Coastguard Worker         const ProgramFilter& filter) {
419*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
420*4d7e907cSAndroid Build Coastguard Worker 
421*4d7e907cSAndroid Build Coastguard Worker     auto startResult = mModule->startProgramListUpdates(filter);
422*4d7e907cSAndroid Build Coastguard Worker 
423*4d7e907cSAndroid Build Coastguard Worker     if (startResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
424*4d7e907cSAndroid Build Coastguard Worker         LOG(WARNING) << "Program list not supported";
425*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
426*4d7e907cSAndroid Build Coastguard Worker     }
427*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(startResult.isOk());
428*4d7e907cSAndroid Build Coastguard Worker     if (!startResult.isOk()) {
429*4d7e907cSAndroid Build Coastguard Worker         return std::nullopt;
430*4d7e907cSAndroid Build Coastguard Worker     }
431*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitProgramReady());
432*4d7e907cSAndroid Build Coastguard Worker 
433*4d7e907cSAndroid Build Coastguard Worker     auto stopResult = mModule->stopProgramListUpdates();
434*4d7e907cSAndroid Build Coastguard Worker 
435*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(stopResult.isOk());
436*4d7e907cSAndroid Build Coastguard Worker 
437*4d7e907cSAndroid Build Coastguard Worker     return mCallback->getProgramList();
438*4d7e907cSAndroid Build Coastguard Worker }
439*4d7e907cSAndroid Build Coastguard Worker 
440*4d7e907cSAndroid Build Coastguard Worker /**
441*4d7e907cSAndroid Build Coastguard Worker  * Test setting tuner callback to null.
442*4d7e907cSAndroid Build Coastguard Worker  *
443*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
444*4d7e907cSAndroid Build Coastguard Worker  *  - Setting to a null tuner callback results with INVALID_ARGUMENTS.
445*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,TunerCallbackFailsWithNull)446*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, TunerCallbackFailsWithNull) {
447*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "TunerCallbackFailsWithNull Test";
448*4d7e907cSAndroid Build Coastguard Worker 
449*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->setTunerCallback(nullptr);
450*4d7e907cSAndroid Build Coastguard Worker 
451*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(halResult.getServiceSpecificError(), resultToInt(Result::INVALID_ARGUMENTS));
452*4d7e907cSAndroid Build Coastguard Worker }
453*4d7e907cSAndroid Build Coastguard Worker 
454*4d7e907cSAndroid Build Coastguard Worker /**
455*4d7e907cSAndroid Build Coastguard Worker  * Test fetching AM/FM regional configuration.
456*4d7e907cSAndroid Build Coastguard Worker  *
457*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
458*4d7e907cSAndroid Build Coastguard Worker  *  - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
459*4d7e907cSAndroid Build Coastguard Worker  *  - FM Deemphasis and RDS are correctly configured for FM-capable radio;
460*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfig)461*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
462*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetAmFmRegionConfig Test";
463*4d7e907cSAndroid Build Coastguard Worker 
464*4d7e907cSAndroid Build Coastguard Worker     AmFmRegionConfig config;
465*4d7e907cSAndroid Build Coastguard Worker 
466*4d7e907cSAndroid Build Coastguard Worker     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
467*4d7e907cSAndroid Build Coastguard Worker 
468*4d7e907cSAndroid Build Coastguard Worker     if (!supported) {
469*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "AM/FM not supported";
470*4d7e907cSAndroid Build Coastguard Worker     }
471*4d7e907cSAndroid Build Coastguard Worker 
472*4d7e907cSAndroid Build Coastguard Worker     EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
473*4d7e907cSAndroid Build Coastguard Worker     EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmRds)), 1);
474*4d7e907cSAndroid Build Coastguard Worker 
475*4d7e907cSAndroid Build Coastguard Worker     if (supportsFM(config)) {
476*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
477*4d7e907cSAndroid Build Coastguard Worker     }
478*4d7e907cSAndroid Build Coastguard Worker }
479*4d7e907cSAndroid Build Coastguard Worker 
480*4d7e907cSAndroid Build Coastguard Worker /**
481*4d7e907cSAndroid Build Coastguard Worker  * Test fetching ranges of AM/FM regional configuration.
482*4d7e907cSAndroid Build Coastguard Worker  *
483*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
484*4d7e907cSAndroid Build Coastguard Worker  *  - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
485*4d7e907cSAndroid Build Coastguard Worker  *  - there is at least one AM/FM band configured;
486*4d7e907cSAndroid Build Coastguard Worker  *  - all channel grids (frequency ranges and spacings) are valid;
487*4d7e907cSAndroid Build Coastguard Worker  *  - seek spacing is a multiple of the manual spacing value.
488*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigRanges)489*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigRanges) {
490*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetAmFmRegionConfigRanges Test";
491*4d7e907cSAndroid Build Coastguard Worker 
492*4d7e907cSAndroid Build Coastguard Worker     AmFmRegionConfig config;
493*4d7e907cSAndroid Build Coastguard Worker 
494*4d7e907cSAndroid Build Coastguard Worker     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
495*4d7e907cSAndroid Build Coastguard Worker 
496*4d7e907cSAndroid Build Coastguard Worker     if (!supported) {
497*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "AM/FM not supported";
498*4d7e907cSAndroid Build Coastguard Worker     }
499*4d7e907cSAndroid Build Coastguard Worker 
500*4d7e907cSAndroid Build Coastguard Worker     EXPECT_GT(config.ranges.size(), 0u);
501*4d7e907cSAndroid Build Coastguard Worker     for (const auto& range : config.ranges) {
502*4d7e907cSAndroid Build Coastguard Worker         validateRange(range, mAidlVersion);
503*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(range.seekSpacing % range.spacing, 0u);
504*4d7e907cSAndroid Build Coastguard Worker         EXPECT_GE(range.seekSpacing, range.spacing);
505*4d7e907cSAndroid Build Coastguard Worker     }
506*4d7e907cSAndroid Build Coastguard Worker }
507*4d7e907cSAndroid Build Coastguard Worker 
508*4d7e907cSAndroid Build Coastguard Worker /**
509*4d7e907cSAndroid Build Coastguard Worker  * Test fetching FM regional capabilities.
510*4d7e907cSAndroid Build Coastguard Worker  *
511*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
512*4d7e907cSAndroid Build Coastguard Worker  *  - AM/FM regional capabilities are either available or not supported at all by the hardware;
513*4d7e907cSAndroid Build Coastguard Worker  *  - there is at least one de-emphasis filter mode supported for FM-capable radio;
514*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigCapabilitiesForFM)515*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesForFM) {
516*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesForFM Test";
517*4d7e907cSAndroid Build Coastguard Worker 
518*4d7e907cSAndroid Build Coastguard Worker     AmFmRegionConfig config;
519*4d7e907cSAndroid Build Coastguard Worker 
520*4d7e907cSAndroid Build Coastguard Worker     bool supported = getAmFmRegionConfig(/* full= */ true, &config);
521*4d7e907cSAndroid Build Coastguard Worker 
522*4d7e907cSAndroid Build Coastguard Worker     if (supported && supportsFM(config)) {
523*4d7e907cSAndroid Build Coastguard Worker         EXPECT_GE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
524*4d7e907cSAndroid Build Coastguard Worker     } else {
525*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "FM not supported";
526*4d7e907cSAndroid Build Coastguard Worker     }
527*4d7e907cSAndroid Build Coastguard Worker }
528*4d7e907cSAndroid Build Coastguard Worker 
529*4d7e907cSAndroid Build Coastguard Worker /**
530*4d7e907cSAndroid Build Coastguard Worker  * Test fetching the ranges of AM/FM regional capabilities.
531*4d7e907cSAndroid Build Coastguard Worker  *
532*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
533*4d7e907cSAndroid Build Coastguard Worker  *  - AM/FM regional capabilities are either available or not supported at all by the hardware;
534*4d7e907cSAndroid Build Coastguard Worker  *  - there is at least one AM/FM range supported;
535*4d7e907cSAndroid Build Coastguard Worker  *  - all channel grids (frequency ranges and spacings) are valid;
536*4d7e907cSAndroid Build Coastguard Worker  *  - seek spacing is not set.
537*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigCapabilitiesRanges)538*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesRanges) {
539*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesRanges Test";
540*4d7e907cSAndroid Build Coastguard Worker 
541*4d7e907cSAndroid Build Coastguard Worker     AmFmRegionConfig config;
542*4d7e907cSAndroid Build Coastguard Worker 
543*4d7e907cSAndroid Build Coastguard Worker     bool supported = getAmFmRegionConfig(/* full= */ true, &config);
544*4d7e907cSAndroid Build Coastguard Worker 
545*4d7e907cSAndroid Build Coastguard Worker     if (!supported) {
546*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "AM/FM not supported";
547*4d7e907cSAndroid Build Coastguard Worker     }
548*4d7e907cSAndroid Build Coastguard Worker 
549*4d7e907cSAndroid Build Coastguard Worker     EXPECT_GT(config.ranges.size(), 0u);
550*4d7e907cSAndroid Build Coastguard Worker 
551*4d7e907cSAndroid Build Coastguard Worker     for (const auto& range : config.ranges) {
552*4d7e907cSAndroid Build Coastguard Worker         validateRange(range, mAidlVersion);
553*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(range.seekSpacing, 0u);
554*4d7e907cSAndroid Build Coastguard Worker     }
555*4d7e907cSAndroid Build Coastguard Worker }
556*4d7e907cSAndroid Build Coastguard Worker 
557*4d7e907cSAndroid Build Coastguard Worker /**
558*4d7e907cSAndroid Build Coastguard Worker  * Test fetching DAB regional configuration.
559*4d7e907cSAndroid Build Coastguard Worker  *
560*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
561*4d7e907cSAndroid Build Coastguard Worker  *  - DAB regional configuration is either set at startup or not supported at all by the hardware;
562*4d7e907cSAndroid Build Coastguard Worker  *  - all channel labels match correct format;
563*4d7e907cSAndroid Build Coastguard Worker  *  - all channel frequencies are in correct range.
564*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetDabRegionConfig)565*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
566*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetDabRegionConfig Test";
567*4d7e907cSAndroid Build Coastguard Worker     vector<DabTableEntry> config;
568*4d7e907cSAndroid Build Coastguard Worker 
569*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->getDabRegionConfig(&config);
570*4d7e907cSAndroid Build Coastguard Worker 
571*4d7e907cSAndroid Build Coastguard Worker     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
572*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "DAB not supported";
573*4d7e907cSAndroid Build Coastguard Worker     }
574*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
575*4d7e907cSAndroid Build Coastguard Worker 
576*4d7e907cSAndroid Build Coastguard Worker     std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
577*4d7e907cSAndroid Build Coastguard Worker 
578*4d7e907cSAndroid Build Coastguard Worker     for (const auto& entry : config) {
579*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
580*4d7e907cSAndroid Build Coastguard Worker 
581*4d7e907cSAndroid Build Coastguard Worker         ProgramIdentifier id =
582*4d7e907cSAndroid Build Coastguard Worker                 bcutils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, entry.frequencyKhz);
583*4d7e907cSAndroid Build Coastguard Worker         if (mAidlVersion == kAidlVersion1) {
584*4d7e907cSAndroid Build Coastguard Worker             EXPECT_TRUE(bcutils::isValid(id));
585*4d7e907cSAndroid Build Coastguard Worker         } else if (mAidlVersion == kAidlVersion2) {
586*4d7e907cSAndroid Build Coastguard Worker             EXPECT_TRUE(bcutils::isValidV2(id));
587*4d7e907cSAndroid Build Coastguard Worker         } else {
588*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Unknown callback AIDL version " << mAidlVersion;
589*4d7e907cSAndroid Build Coastguard Worker         }
590*4d7e907cSAndroid Build Coastguard Worker     }
591*4d7e907cSAndroid Build Coastguard Worker }
592*4d7e907cSAndroid Build Coastguard Worker 
593*4d7e907cSAndroid Build Coastguard Worker /**
594*4d7e907cSAndroid Build Coastguard Worker  * Test tuning without tuner callback set.
595*4d7e907cSAndroid Build Coastguard Worker  *
596*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
597*4d7e907cSAndroid Build Coastguard Worker  *  - No tuner callback set results in INVALID_STATE, regardless of whether the selector is
598*4d7e907cSAndroid Build Coastguard Worker  * supported.
599*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithoutTunerCallback)600*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) {
601*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "TuneFailsWithoutTunerCallback Test";
602*4d7e907cSAndroid Build Coastguard Worker 
603*4d7e907cSAndroid Build Coastguard Worker     mModule->unsetTunerCallback();
604*4d7e907cSAndroid Build Coastguard Worker     int64_t freq = 90900;  // 90.9 FM
605*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector sel = makeSelectorAmfm(freq);
606*4d7e907cSAndroid Build Coastguard Worker 
607*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->tune(sel);
608*4d7e907cSAndroid Build Coastguard Worker 
609*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
610*4d7e907cSAndroid Build Coastguard Worker }
611*4d7e907cSAndroid Build Coastguard Worker 
612*4d7e907cSAndroid Build Coastguard Worker /**
613*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with selectors that can be not supported.
614*4d7e907cSAndroid Build Coastguard Worker  *
615*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
616*4d7e907cSAndroid Build Coastguard Worker  *  - if the selector is not supported, an invalid value results with NOT_SUPPORTED, regardless of
617*4d7e907cSAndroid Build Coastguard Worker  *    whether it is valid;
618*4d7e907cSAndroid Build Coastguard Worker  *  - if it is supported, the test is ignored;
619*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithNotSupported)620*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
621*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "TuneFailsWithNotSupported Test";
622*4d7e907cSAndroid Build Coastguard Worker 
623*4d7e907cSAndroid Build Coastguard Worker     vector<ProgramIdentifier> supportTestId = {
624*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),           // invalid
625*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 94900),       // valid
626*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::RDS_PI, 0x10000),                 // invalid
627*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::RDS_PI, 0x1001),                  // valid
628*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),  // invalid
629*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x10000001),   // valid
630*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DAB_SID_EXT, 0),                  // invalid
631*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DAB_SID_EXT, 0xA00001),           // valid
632*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),    // invalid
633*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x10000001),     // valid
634*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),     // invalid
635*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x10000001),      // valid
636*4d7e907cSAndroid Build Coastguard Worker     };
637*4d7e907cSAndroid Build Coastguard Worker 
638*4d7e907cSAndroid Build Coastguard Worker     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
639*4d7e907cSAndroid Build Coastguard Worker     for (const auto& id : supportTestId) {
640*4d7e907cSAndroid Build Coastguard Worker         ProgramSelector sel{id, {}};
641*4d7e907cSAndroid Build Coastguard Worker 
642*4d7e907cSAndroid Build Coastguard Worker         if (!bcutils::isSupported(mProperties, sel)) {
643*4d7e907cSAndroid Build Coastguard Worker             auto result = mModule->tune(sel);
644*4d7e907cSAndroid Build Coastguard Worker 
645*4d7e907cSAndroid Build Coastguard Worker             EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
646*4d7e907cSAndroid Build Coastguard Worker         }
647*4d7e907cSAndroid Build Coastguard Worker     }
648*4d7e907cSAndroid Build Coastguard Worker }
649*4d7e907cSAndroid Build Coastguard Worker 
650*4d7e907cSAndroid Build Coastguard Worker /**
651*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with invalid selectors.
652*4d7e907cSAndroid Build Coastguard Worker  *
653*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
654*4d7e907cSAndroid Build Coastguard Worker  *  - if the selector is not supported, it's ignored;
655*4d7e907cSAndroid Build Coastguard Worker  *  - if it is supported, an invalid value results with INVALID_ARGUMENTS;
656*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithInvalid)657*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
658*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "TuneFailsWithInvalid Test";
659*4d7e907cSAndroid Build Coastguard Worker 
660*4d7e907cSAndroid Build Coastguard Worker     vector<ProgramIdentifier> invalidId = {
661*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),
662*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::RDS_PI, 0x10000),
663*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
664*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DAB_SID_EXT, 0),
665*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
666*4d7e907cSAndroid Build Coastguard Worker             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
667*4d7e907cSAndroid Build Coastguard Worker     };
668*4d7e907cSAndroid Build Coastguard Worker 
669*4d7e907cSAndroid Build Coastguard Worker     auto invalidArgumentsError = resultToInt(Result::INVALID_ARGUMENTS);
670*4d7e907cSAndroid Build Coastguard Worker     for (const auto& id : invalidId) {
671*4d7e907cSAndroid Build Coastguard Worker         ProgramSelector sel{id, {}};
672*4d7e907cSAndroid Build Coastguard Worker 
673*4d7e907cSAndroid Build Coastguard Worker         if (bcutils::isSupported(mProperties, sel)) {
674*4d7e907cSAndroid Build Coastguard Worker             auto result = mModule->tune(sel);
675*4d7e907cSAndroid Build Coastguard Worker 
676*4d7e907cSAndroid Build Coastguard Worker             EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
677*4d7e907cSAndroid Build Coastguard Worker         }
678*4d7e907cSAndroid Build Coastguard Worker     }
679*4d7e907cSAndroid Build Coastguard Worker }
680*4d7e907cSAndroid Build Coastguard Worker 
681*4d7e907cSAndroid Build Coastguard Worker /**
682*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with empty program selector.
683*4d7e907cSAndroid Build Coastguard Worker  *
684*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
685*4d7e907cSAndroid Build Coastguard Worker  *  - tune fails with NOT_SUPPORTED when program selector is not initialized.
686*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithEmpty)687*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
688*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "TuneFailsWithEmpty Test";
689*4d7e907cSAndroid Build Coastguard Worker 
690*4d7e907cSAndroid Build Coastguard Worker     // Program type is 1-based, so 0 will always be invalid.
691*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector sel = {};
692*4d7e907cSAndroid Build Coastguard Worker 
693*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->tune(sel);
694*4d7e907cSAndroid Build Coastguard Worker 
695*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
696*4d7e907cSAndroid Build Coastguard Worker }
697*4d7e907cSAndroid Build Coastguard Worker 
698*4d7e907cSAndroid Build Coastguard Worker /**
699*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with FM selector.
700*4d7e907cSAndroid Build Coastguard Worker  *
701*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
702*4d7e907cSAndroid Build Coastguard Worker  *  - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
703*4d7e907cSAndroid Build Coastguard Worker  *  - if it is supported, the method succeeds;
704*4d7e907cSAndroid Build Coastguard Worker  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
705*4d7e907cSAndroid Build Coastguard Worker  *    invoked carrying a proper selector;
706*4d7e907cSAndroid Build Coastguard Worker  *  - program changes to a program info with the program selector requested.
707*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,FmTune)708*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, FmTune) {
709*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "FmTune Test";
710*4d7e907cSAndroid Build Coastguard Worker 
711*4d7e907cSAndroid Build Coastguard Worker     int64_t freq = 90900;  // 90.9 FM
712*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector sel = makeSelectorAmfm(freq);
713*4d7e907cSAndroid Build Coastguard Worker     // try tuning
714*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
715*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->tune(sel);
716*4d7e907cSAndroid Build Coastguard Worker 
717*4d7e907cSAndroid Build Coastguard Worker     // expect a failure if it's not supported
718*4d7e907cSAndroid Build Coastguard Worker     if (!bcutils::isSupported(mProperties, sel)) {
719*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
720*4d7e907cSAndroid Build Coastguard Worker         return;
721*4d7e907cSAndroid Build Coastguard Worker     }
722*4d7e907cSAndroid Build Coastguard Worker 
723*4d7e907cSAndroid Build Coastguard Worker     // expect a callback if it succeeds
724*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
725*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
726*4d7e907cSAndroid Build Coastguard Worker     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
727*4d7e907cSAndroid Build Coastguard Worker 
728*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Current program info: " << infoCb.toString();
729*4d7e907cSAndroid Build Coastguard Worker 
730*4d7e907cSAndroid Build Coastguard Worker     // it should tune exactly to what was requested
731*4d7e907cSAndroid Build Coastguard Worker     vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
732*4d7e907cSAndroid Build Coastguard Worker     EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
733*4d7e907cSAndroid Build Coastguard Worker             << "FM freq " << freq << " kHz is not sent back by callback.";
734*4d7e907cSAndroid Build Coastguard Worker }
735*4d7e907cSAndroid Build Coastguard Worker 
736*4d7e907cSAndroid Build Coastguard Worker /**
737*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with HD selector.
738*4d7e907cSAndroid Build Coastguard Worker  *
739*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
740*4d7e907cSAndroid Build Coastguard Worker  *  - if AM/FM HD selector is not supported, the method returns NOT_SUPPORTED;
741*4d7e907cSAndroid Build Coastguard Worker  *  - if it is supported, the method succeeds;
742*4d7e907cSAndroid Build Coastguard Worker  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
743*4d7e907cSAndroid Build Coastguard Worker  *    invoked carrying a proper selector;
744*4d7e907cSAndroid Build Coastguard Worker  *  - program changes to a program info with the program selector requested.
745*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,HdTune)746*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, HdTune) {
747*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "HdTune Test";
748*4d7e907cSAndroid Build Coastguard Worker     auto programList = getProgramList();
749*4d7e907cSAndroid Build Coastguard Worker     if (!programList) {
750*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "Empty station list, tune cannot be performed";
751*4d7e907cSAndroid Build Coastguard Worker     }
752*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector hdSel = {};
753*4d7e907cSAndroid Build Coastguard Worker     ProgramIdentifier physicallyTunedToExpected = {};
754*4d7e907cSAndroid Build Coastguard Worker     bool hdStationPresent = false;
755*4d7e907cSAndroid Build Coastguard Worker     for (auto&& programInfo : *programList) {
756*4d7e907cSAndroid Build Coastguard Worker         if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
757*4d7e907cSAndroid Build Coastguard Worker             continue;
758*4d7e907cSAndroid Build Coastguard Worker         }
759*4d7e907cSAndroid Build Coastguard Worker         hdSel = programInfo.selector;
760*4d7e907cSAndroid Build Coastguard Worker         hdStationPresent = true;
761*4d7e907cSAndroid Build Coastguard Worker         physicallyTunedToExpected = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
762*4d7e907cSAndroid Build Coastguard Worker                                                             bcutils::getAmFmFrequency(hdSel));
763*4d7e907cSAndroid Build Coastguard Worker         break;
764*4d7e907cSAndroid Build Coastguard Worker     }
765*4d7e907cSAndroid Build Coastguard Worker     if (!hdStationPresent) {
766*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No HD stations in the list, tune cannot be performed";
767*4d7e907cSAndroid Build Coastguard Worker     }
768*4d7e907cSAndroid Build Coastguard Worker 
769*4d7e907cSAndroid Build Coastguard Worker     // try tuning
770*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->tune(hdSel);
771*4d7e907cSAndroid Build Coastguard Worker 
772*4d7e907cSAndroid Build Coastguard Worker     // expect a failure if it's not supported
773*4d7e907cSAndroid Build Coastguard Worker     if (!bcutils::isSupported(mProperties, hdSel)) {
774*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
775*4d7e907cSAndroid Build Coastguard Worker         return;
776*4d7e907cSAndroid Build Coastguard Worker     }
777*4d7e907cSAndroid Build Coastguard Worker     // expect a callback if it succeeds
778*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
779*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
780*4d7e907cSAndroid Build Coastguard Worker     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
781*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Current program info: " << infoCb.toString();
782*4d7e907cSAndroid Build Coastguard Worker     // it should tune exactly to what was requested
783*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(infoCb.selector.primaryId, hdSel.primaryId);
784*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
785*4d7e907cSAndroid Build Coastguard Worker }
786*4d7e907cSAndroid Build Coastguard Worker 
787*4d7e907cSAndroid Build Coastguard Worker /**
788*4d7e907cSAndroid Build Coastguard Worker  * Test tuning with DAB selector.
789*4d7e907cSAndroid Build Coastguard Worker  *
790*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
791*4d7e907cSAndroid Build Coastguard Worker  *  - if DAB selector is not supported, the method returns NOT_SUPPORTED;
792*4d7e907cSAndroid Build Coastguard Worker  *  - if it is supported, the method succeeds;
793*4d7e907cSAndroid Build Coastguard Worker  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
794*4d7e907cSAndroid Build Coastguard Worker  *    invoked carrying a proper selector;
795*4d7e907cSAndroid Build Coastguard Worker  *  - program changes to a program info with the program selector requested.
796*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,DabTune)797*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, DabTune) {
798*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "DabTune Test";
799*4d7e907cSAndroid Build Coastguard Worker     vector<DabTableEntry> config;
800*4d7e907cSAndroid Build Coastguard Worker 
801*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->getDabRegionConfig(&config);
802*4d7e907cSAndroid Build Coastguard Worker 
803*4d7e907cSAndroid Build Coastguard Worker     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
804*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "DAB not supported";
805*4d7e907cSAndroid Build Coastguard Worker     }
806*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
807*4d7e907cSAndroid Build Coastguard Worker     ASSERT_NE(config.size(), 0U);
808*4d7e907cSAndroid Build Coastguard Worker 
809*4d7e907cSAndroid Build Coastguard Worker     auto programList = getProgramList();
810*4d7e907cSAndroid Build Coastguard Worker 
811*4d7e907cSAndroid Build Coastguard Worker     if (!programList) {
812*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "Empty DAB station list, tune cannot be performed";
813*4d7e907cSAndroid Build Coastguard Worker     }
814*4d7e907cSAndroid Build Coastguard Worker 
815*4d7e907cSAndroid Build Coastguard Worker     ProgramSelector sel = {};
816*4d7e907cSAndroid Build Coastguard Worker     uint64_t freq = 0;
817*4d7e907cSAndroid Build Coastguard Worker     bool dabStationPresent = false;
818*4d7e907cSAndroid Build Coastguard Worker     for (auto&& programInfo : *programList) {
819*4d7e907cSAndroid Build Coastguard Worker         if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
820*4d7e907cSAndroid Build Coastguard Worker             continue;
821*4d7e907cSAndroid Build Coastguard Worker         }
822*4d7e907cSAndroid Build Coastguard Worker         for (auto&& config_entry : config) {
823*4d7e907cSAndroid Build Coastguard Worker             if (config_entry.frequencyKhz ==
824*4d7e907cSAndroid Build Coastguard Worker                 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
825*4d7e907cSAndroid Build Coastguard Worker                 freq = config_entry.frequencyKhz;
826*4d7e907cSAndroid Build Coastguard Worker                 break;
827*4d7e907cSAndroid Build Coastguard Worker             }
828*4d7e907cSAndroid Build Coastguard Worker         }
829*4d7e907cSAndroid Build Coastguard Worker         // Do not trigger a tune request if the programList entry does not contain
830*4d7e907cSAndroid Build Coastguard Worker         // a valid DAB frequency.
831*4d7e907cSAndroid Build Coastguard Worker         if (freq == 0) {
832*4d7e907cSAndroid Build Coastguard Worker             continue;
833*4d7e907cSAndroid Build Coastguard Worker         }
834*4d7e907cSAndroid Build Coastguard Worker         int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
835*4d7e907cSAndroid Build Coastguard Worker         int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
836*4d7e907cSAndroid Build Coastguard Worker         sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
837*4d7e907cSAndroid Build Coastguard Worker         dabStationPresent = true;
838*4d7e907cSAndroid Build Coastguard Worker         break;
839*4d7e907cSAndroid Build Coastguard Worker     }
840*4d7e907cSAndroid Build Coastguard Worker 
841*4d7e907cSAndroid Build Coastguard Worker     if (!dabStationPresent) {
842*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No DAB stations in the list, tune cannot be performed";
843*4d7e907cSAndroid Build Coastguard Worker     }
844*4d7e907cSAndroid Build Coastguard Worker 
845*4d7e907cSAndroid Build Coastguard Worker     // try tuning
846*4d7e907cSAndroid Build Coastguard Worker 
847*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->tune(sel);
848*4d7e907cSAndroid Build Coastguard Worker 
849*4d7e907cSAndroid Build Coastguard Worker     // expect a failure if it's not supported
850*4d7e907cSAndroid Build Coastguard Worker     if (!bcutils::isSupported(mProperties, sel)) {
851*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
852*4d7e907cSAndroid Build Coastguard Worker         return;
853*4d7e907cSAndroid Build Coastguard Worker     }
854*4d7e907cSAndroid Build Coastguard Worker 
855*4d7e907cSAndroid Build Coastguard Worker     // expect a callback if it succeeds
856*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
857*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
858*4d7e907cSAndroid Build Coastguard Worker     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
859*4d7e907cSAndroid Build Coastguard Worker 
860*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Current program info: " << infoCb.toString();
861*4d7e907cSAndroid Build Coastguard Worker 
862*4d7e907cSAndroid Build Coastguard Worker     // it should tune exactly to what was requested
863*4d7e907cSAndroid Build Coastguard Worker     vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
864*4d7e907cSAndroid Build Coastguard Worker     EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
865*4d7e907cSAndroid Build Coastguard Worker             << "DAB freq " << freq << " kHz is not sent back by callback.";
866*4d7e907cSAndroid Build Coastguard Worker }
867*4d7e907cSAndroid Build Coastguard Worker 
868*4d7e907cSAndroid Build Coastguard Worker /**
869*4d7e907cSAndroid Build Coastguard Worker  * Test seeking to next/prev station via IBroadcastRadio::seek().
870*4d7e907cSAndroid Build Coastguard Worker  *
871*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
872*4d7e907cSAndroid Build Coastguard Worker  *  - the method succeeds;
873*4d7e907cSAndroid Build Coastguard Worker  *  - the program info is changed within kTuneTimeoutMs;
874*4d7e907cSAndroid Build Coastguard Worker  *  - works both directions and with or without ing sub-channel.
875*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,Seek)876*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, Seek) {
877*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Seek Test";
878*4d7e907cSAndroid Build Coastguard Worker 
879*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
880*4d7e907cSAndroid Build Coastguard Worker 
881*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
882*4d7e907cSAndroid Build Coastguard Worker 
883*4d7e907cSAndroid Build Coastguard Worker     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
884*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "Seek not supported";
885*4d7e907cSAndroid Build Coastguard Worker     }
886*4d7e907cSAndroid Build Coastguard Worker 
887*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
888*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
889*4d7e907cSAndroid Build Coastguard Worker 
890*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
891*4d7e907cSAndroid Build Coastguard Worker 
892*4d7e907cSAndroid Build Coastguard Worker     result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
893*4d7e907cSAndroid Build Coastguard Worker 
894*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
895*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
896*4d7e907cSAndroid Build Coastguard Worker }
897*4d7e907cSAndroid Build Coastguard Worker 
898*4d7e907cSAndroid Build Coastguard Worker /**
899*4d7e907cSAndroid Build Coastguard Worker  * Test seeking without tuner callback set.
900*4d7e907cSAndroid Build Coastguard Worker  *
901*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
902*4d7e907cSAndroid Build Coastguard Worker  *  - No tuner callback set results in INVALID_STATE.
903*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,SeekFailsWithoutTunerCallback)904*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
905*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "SeekFailsWithoutTunerCallback Test";
906*4d7e907cSAndroid Build Coastguard Worker 
907*4d7e907cSAndroid Build Coastguard Worker     mModule->unsetTunerCallback();
908*4d7e907cSAndroid Build Coastguard Worker 
909*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
910*4d7e907cSAndroid Build Coastguard Worker 
911*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
912*4d7e907cSAndroid Build Coastguard Worker 
913*4d7e907cSAndroid Build Coastguard Worker     result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
914*4d7e907cSAndroid Build Coastguard Worker 
915*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
916*4d7e907cSAndroid Build Coastguard Worker }
917*4d7e907cSAndroid Build Coastguard Worker 
918*4d7e907cSAndroid Build Coastguard Worker /**
919*4d7e907cSAndroid Build Coastguard Worker  * Test step operation.
920*4d7e907cSAndroid Build Coastguard Worker  *
921*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
922*4d7e907cSAndroid Build Coastguard Worker  *  - the method succeeds or returns NOT_SUPPORTED;
923*4d7e907cSAndroid Build Coastguard Worker  *  - the program info is changed within kTuneTimeoutMs if the method succeeded;
924*4d7e907cSAndroid Build Coastguard Worker  *  - works both directions.
925*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,Step)926*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, Step) {
927*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Step Test";
928*4d7e907cSAndroid Build Coastguard Worker 
929*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
930*4d7e907cSAndroid Build Coastguard Worker 
931*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->step(/* in_directionUp= */ true);
932*4d7e907cSAndroid Build Coastguard Worker 
933*4d7e907cSAndroid Build Coastguard Worker     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
934*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "Step not supported";
935*4d7e907cSAndroid Build Coastguard Worker     }
936*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
937*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
938*4d7e907cSAndroid Build Coastguard Worker 
939*4d7e907cSAndroid Build Coastguard Worker     mCallback->reset();
940*4d7e907cSAndroid Build Coastguard Worker 
941*4d7e907cSAndroid Build Coastguard Worker     result = mModule->step(/* in_directionUp= */ false);
942*4d7e907cSAndroid Build Coastguard Worker 
943*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(result.isOk());
944*4d7e907cSAndroid Build Coastguard Worker     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
945*4d7e907cSAndroid Build Coastguard Worker }
946*4d7e907cSAndroid Build Coastguard Worker 
947*4d7e907cSAndroid Build Coastguard Worker /**
948*4d7e907cSAndroid Build Coastguard Worker  * Test step operation without tuner callback set.
949*4d7e907cSAndroid Build Coastguard Worker  *
950*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
951*4d7e907cSAndroid Build Coastguard Worker  *  - No tuner callback set results in INVALID_STATE.
952*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,StepFailsWithoutTunerCallback)953*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, StepFailsWithoutTunerCallback) {
954*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "StepFailsWithoutTunerCallback Test";
955*4d7e907cSAndroid Build Coastguard Worker 
956*4d7e907cSAndroid Build Coastguard Worker     mModule->unsetTunerCallback();
957*4d7e907cSAndroid Build Coastguard Worker 
958*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->step(/* in_directionUp= */ true);
959*4d7e907cSAndroid Build Coastguard Worker 
960*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
961*4d7e907cSAndroid Build Coastguard Worker 
962*4d7e907cSAndroid Build Coastguard Worker     result = mModule->step(/* in_directionUp= */ false);
963*4d7e907cSAndroid Build Coastguard Worker 
964*4d7e907cSAndroid Build Coastguard Worker     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
965*4d7e907cSAndroid Build Coastguard Worker }
966*4d7e907cSAndroid Build Coastguard Worker 
967*4d7e907cSAndroid Build Coastguard Worker /**
968*4d7e907cSAndroid Build Coastguard Worker  * Test tune cancellation.
969*4d7e907cSAndroid Build Coastguard Worker  *
970*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
971*4d7e907cSAndroid Build Coastguard Worker  *  - the method does not crash after being invoked multiple times.
972*4d7e907cSAndroid Build Coastguard Worker  *
973*4d7e907cSAndroid Build Coastguard Worker  * Since cancel() might be called after the HAL completes an operation (tune, seek, and step)
974*4d7e907cSAndroid Build Coastguard Worker  * and before the callback completions, the operation might not be actually canceled and the
975*4d7e907cSAndroid Build Coastguard Worker  * effect of cancel() is not deterministic to be tested here.
976*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,Cancel)977*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, Cancel) {
978*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "Cancel Test";
979*4d7e907cSAndroid Build Coastguard Worker 
980*4d7e907cSAndroid Build Coastguard Worker     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
981*4d7e907cSAndroid Build Coastguard Worker     for (int i = 0; i < 10; i++) {
982*4d7e907cSAndroid Build Coastguard Worker         auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
983*4d7e907cSAndroid Build Coastguard Worker 
984*4d7e907cSAndroid Build Coastguard Worker         if (result.getServiceSpecificError() == notSupportedError) {
985*4d7e907cSAndroid Build Coastguard Worker             GTEST_SKIP() << "Cancel is skipped because of seek not supported";
986*4d7e907cSAndroid Build Coastguard Worker         }
987*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(result.isOk());
988*4d7e907cSAndroid Build Coastguard Worker 
989*4d7e907cSAndroid Build Coastguard Worker         auto cancelResult = mModule->cancel();
990*4d7e907cSAndroid Build Coastguard Worker 
991*4d7e907cSAndroid Build Coastguard Worker         ASSERT_TRUE(cancelResult.isOk());
992*4d7e907cSAndroid Build Coastguard Worker     }
993*4d7e907cSAndroid Build Coastguard Worker }
994*4d7e907cSAndroid Build Coastguard Worker 
995*4d7e907cSAndroid Build Coastguard Worker /**
996*4d7e907cSAndroid Build Coastguard Worker  * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
997*4d7e907cSAndroid Build Coastguard Worker  *
998*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
999*4d7e907cSAndroid Build Coastguard Worker  *  - callback is called for empty parameters set.
1000*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,NoParameters)1001*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, NoParameters) {
1002*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "NoParameters Test";
1003*4d7e907cSAndroid Build Coastguard Worker 
1004*4d7e907cSAndroid Build Coastguard Worker     vector<VendorKeyValue> parametersResults = {};
1005*4d7e907cSAndroid Build Coastguard Worker 
1006*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->setParameters({}, &parametersResults);
1007*4d7e907cSAndroid Build Coastguard Worker 
1008*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
1009*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(parametersResults.size(), 0u);
1010*4d7e907cSAndroid Build Coastguard Worker 
1011*4d7e907cSAndroid Build Coastguard Worker     parametersResults.clear();
1012*4d7e907cSAndroid Build Coastguard Worker 
1013*4d7e907cSAndroid Build Coastguard Worker     halResult = mModule->getParameters({}, &parametersResults);
1014*4d7e907cSAndroid Build Coastguard Worker 
1015*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
1016*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(parametersResults.size(), 0u);
1017*4d7e907cSAndroid Build Coastguard Worker }
1018*4d7e907cSAndroid Build Coastguard Worker 
1019*4d7e907cSAndroid Build Coastguard Worker /**
1020*4d7e907cSAndroid Build Coastguard Worker  * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
1021*4d7e907cSAndroid Build Coastguard Worker  *
1022*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1023*4d7e907cSAndroid Build Coastguard Worker  *  - unknown parameters are ignored;
1024*4d7e907cSAndroid Build Coastguard Worker  *  - callback is called also for empty results set.
1025*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,UnknownParameters)1026*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, UnknownParameters) {
1027*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "UnknownParameters Test";
1028*4d7e907cSAndroid Build Coastguard Worker 
1029*4d7e907cSAndroid Build Coastguard Worker     vector<VendorKeyValue> parametersResults = {};
1030*4d7e907cSAndroid Build Coastguard Worker 
1031*4d7e907cSAndroid Build Coastguard Worker     auto halResult =
1032*4d7e907cSAndroid Build Coastguard Worker             mModule->setParameters({{"com.android.unknown", "sample"}}, &parametersResults);
1033*4d7e907cSAndroid Build Coastguard Worker 
1034*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
1035*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(parametersResults.size(), 0u);
1036*4d7e907cSAndroid Build Coastguard Worker 
1037*4d7e907cSAndroid Build Coastguard Worker     parametersResults.clear();
1038*4d7e907cSAndroid Build Coastguard Worker 
1039*4d7e907cSAndroid Build Coastguard Worker     halResult = mModule->getParameters({"com.android.unknown*", "sample"}, &parametersResults);
1040*4d7e907cSAndroid Build Coastguard Worker 
1041*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
1042*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(parametersResults.size(), 0u);
1043*4d7e907cSAndroid Build Coastguard Worker }
1044*4d7e907cSAndroid Build Coastguard Worker 
1045*4d7e907cSAndroid Build Coastguard Worker /**
1046*4d7e907cSAndroid Build Coastguard Worker  * Test geting image of invalid ID.
1047*4d7e907cSAndroid Build Coastguard Worker  *
1048*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1049*4d7e907cSAndroid Build Coastguard Worker  * - getImage call handles argument 0 gracefully.
1050*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetNoImage)1051*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetNoImage) {
1052*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetNoImage Test";
1053*4d7e907cSAndroid Build Coastguard Worker     vector<uint8_t> rawImage;
1054*4d7e907cSAndroid Build Coastguard Worker 
1055*4d7e907cSAndroid Build Coastguard Worker     auto result = mModule->getImage(IBroadcastRadio::INVALID_IMAGE, &rawImage);
1056*4d7e907cSAndroid Build Coastguard Worker 
1057*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(result.isOk());
1058*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(rawImage.size(), 0u);
1059*4d7e907cSAndroid Build Coastguard Worker }
1060*4d7e907cSAndroid Build Coastguard Worker 
1061*4d7e907cSAndroid Build Coastguard Worker /**
1062*4d7e907cSAndroid Build Coastguard Worker  * Test getting config flags.
1063*4d7e907cSAndroid Build Coastguard Worker  *
1064*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1065*4d7e907cSAndroid Build Coastguard Worker  * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1066*4d7e907cSAndroid Build Coastguard Worker  * - call success or failure is consistent with setConfigFlag.
1067*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,FetchConfigFlags)1068*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
1069*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "FetchConfigFlags Test";
1070*4d7e907cSAndroid Build Coastguard Worker 
1071*4d7e907cSAndroid Build Coastguard Worker     for (const auto& flag : kConfigFlagValues) {
1072*4d7e907cSAndroid Build Coastguard Worker         bool gotValue = false;
1073*4d7e907cSAndroid Build Coastguard Worker 
1074*4d7e907cSAndroid Build Coastguard Worker         auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1075*4d7e907cSAndroid Build Coastguard Worker 
1076*4d7e907cSAndroid Build Coastguard Worker         if (halResult.getServiceSpecificError() != resultToInt(Result::NOT_SUPPORTED) &&
1077*4d7e907cSAndroid Build Coastguard Worker             halResult.getServiceSpecificError() != resultToInt(Result::INVALID_STATE)) {
1078*4d7e907cSAndroid Build Coastguard Worker             ASSERT_TRUE(halResult.isOk());
1079*4d7e907cSAndroid Build Coastguard Worker         }
1080*4d7e907cSAndroid Build Coastguard Worker 
1081*4d7e907cSAndroid Build Coastguard Worker         // set must fail or succeed the same way as get
1082*4d7e907cSAndroid Build Coastguard Worker         auto setResult = mModule->setConfigFlag(flag, /* value= */ false);
1083*4d7e907cSAndroid Build Coastguard Worker 
1084*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1085*4d7e907cSAndroid Build Coastguard Worker                     (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1086*4d7e907cSAndroid Build Coastguard Worker 
1087*4d7e907cSAndroid Build Coastguard Worker         setResult = mModule->setConfigFlag(flag, /* value= */ true);
1088*4d7e907cSAndroid Build Coastguard Worker 
1089*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1090*4d7e907cSAndroid Build Coastguard Worker                     (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1091*4d7e907cSAndroid Build Coastguard Worker     }
1092*4d7e907cSAndroid Build Coastguard Worker }
1093*4d7e907cSAndroid Build Coastguard Worker 
1094*4d7e907cSAndroid Build Coastguard Worker /**
1095*4d7e907cSAndroid Build Coastguard Worker  * Test setting config flags.
1096*4d7e907cSAndroid Build Coastguard Worker  *
1097*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1098*4d7e907cSAndroid Build Coastguard Worker  * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1099*4d7e907cSAndroid Build Coastguard Worker  * - isConfigFlagSet reflects the state requested immediately after the set call.
1100*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,SetConfigFlags)1101*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
1102*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "SetConfigFlags Test";
1103*4d7e907cSAndroid Build Coastguard Worker 
1104*4d7e907cSAndroid Build Coastguard Worker     auto get = [&](ConfigFlag flag) -> bool {
1105*4d7e907cSAndroid Build Coastguard Worker         bool gotValue;
1106*4d7e907cSAndroid Build Coastguard Worker 
1107*4d7e907cSAndroid Build Coastguard Worker         auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1108*4d7e907cSAndroid Build Coastguard Worker 
1109*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(halResult.isOk());
1110*4d7e907cSAndroid Build Coastguard Worker         return gotValue;
1111*4d7e907cSAndroid Build Coastguard Worker     };
1112*4d7e907cSAndroid Build Coastguard Worker 
1113*4d7e907cSAndroid Build Coastguard Worker     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
1114*4d7e907cSAndroid Build Coastguard Worker     auto invalidStateError = resultToInt(Result::INVALID_STATE);
1115*4d7e907cSAndroid Build Coastguard Worker     for (const auto& flag : kConfigFlagValues) {
1116*4d7e907cSAndroid Build Coastguard Worker         auto result = mModule->setConfigFlag(flag, /* value= */ false);
1117*4d7e907cSAndroid Build Coastguard Worker 
1118*4d7e907cSAndroid Build Coastguard Worker         if (result.getServiceSpecificError() == notSupportedError ||
1119*4d7e907cSAndroid Build Coastguard Worker             result.getServiceSpecificError() == invalidStateError) {
1120*4d7e907cSAndroid Build Coastguard Worker             // setting to true must result in the same error as false
1121*4d7e907cSAndroid Build Coastguard Worker             auto secondResult = mModule->setConfigFlag(flag, /* value= */ true);
1122*4d7e907cSAndroid Build Coastguard Worker 
1123*4d7e907cSAndroid Build Coastguard Worker             EXPECT_TRUE((result.isOk() && secondResult.isOk()) ||
1124*4d7e907cSAndroid Build Coastguard Worker                         result.getServiceSpecificError() == secondResult.getServiceSpecificError());
1125*4d7e907cSAndroid Build Coastguard Worker             continue;
1126*4d7e907cSAndroid Build Coastguard Worker         } else {
1127*4d7e907cSAndroid Build Coastguard Worker             ASSERT_TRUE(result.isOk());
1128*4d7e907cSAndroid Build Coastguard Worker         }
1129*4d7e907cSAndroid Build Coastguard Worker 
1130*4d7e907cSAndroid Build Coastguard Worker         // verify false is set
1131*4d7e907cSAndroid Build Coastguard Worker         bool value = get(flag);
1132*4d7e907cSAndroid Build Coastguard Worker         EXPECT_FALSE(value);
1133*4d7e907cSAndroid Build Coastguard Worker 
1134*4d7e907cSAndroid Build Coastguard Worker         // try setting true this time
1135*4d7e907cSAndroid Build Coastguard Worker         result = mModule->setConfigFlag(flag, /* value= */ true);
1136*4d7e907cSAndroid Build Coastguard Worker 
1137*4d7e907cSAndroid Build Coastguard Worker         ASSERT_TRUE(result.isOk());
1138*4d7e907cSAndroid Build Coastguard Worker         value = get(flag);
1139*4d7e907cSAndroid Build Coastguard Worker         EXPECT_TRUE(value);
1140*4d7e907cSAndroid Build Coastguard Worker 
1141*4d7e907cSAndroid Build Coastguard Worker         // false again
1142*4d7e907cSAndroid Build Coastguard Worker         result = mModule->setConfigFlag(flag, /* value= */ false);
1143*4d7e907cSAndroid Build Coastguard Worker 
1144*4d7e907cSAndroid Build Coastguard Worker         ASSERT_TRUE(result.isOk());
1145*4d7e907cSAndroid Build Coastguard Worker         value = get(flag);
1146*4d7e907cSAndroid Build Coastguard Worker         EXPECT_FALSE(value);
1147*4d7e907cSAndroid Build Coastguard Worker     }
1148*4d7e907cSAndroid Build Coastguard Worker }
1149*4d7e907cSAndroid Build Coastguard Worker 
1150*4d7e907cSAndroid Build Coastguard Worker /**
1151*4d7e907cSAndroid Build Coastguard Worker  * Test getting program list using empty program filter.
1152*4d7e907cSAndroid Build Coastguard Worker  *
1153*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1154*4d7e907cSAndroid Build Coastguard Worker  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1155*4d7e907cSAndroid Build Coastguard Worker  * - the complete list is fetched within kProgramListScanTimeoutMs;
1156*4d7e907cSAndroid Build Coastguard Worker  * - stopProgramListUpdates does not crash;
1157*4d7e907cSAndroid Build Coastguard Worker  * - metadata of program info in the program list is valid;
1158*4d7e907cSAndroid Build Coastguard Worker  * - alert message is valid if it exists in the program list.
1159*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromEmptyFilter)1160*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
1161*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
1162*4d7e907cSAndroid Build Coastguard Worker 
1163*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1164*4d7e907cSAndroid Build Coastguard Worker 
1165*4d7e907cSAndroid Build Coastguard Worker     if (!completeList || mAidlVersion < kAidlVersion3) {
1166*4d7e907cSAndroid Build Coastguard Worker         return;
1167*4d7e907cSAndroid Build Coastguard Worker     }
1168*4d7e907cSAndroid Build Coastguard Worker     for (const auto& program : *completeList) {
1169*4d7e907cSAndroid Build Coastguard Worker         validateMetadata(program, mAidlVersion);
1170*4d7e907cSAndroid Build Coastguard Worker         validateAlert(program, mAidlVersion);
1171*4d7e907cSAndroid Build Coastguard Worker     }
1172*4d7e907cSAndroid Build Coastguard Worker }
1173*4d7e907cSAndroid Build Coastguard Worker 
1174*4d7e907cSAndroid Build Coastguard Worker /**
1175*4d7e907cSAndroid Build Coastguard Worker  * Test getting program list using AMFM frequency program filter.
1176*4d7e907cSAndroid Build Coastguard Worker  *
1177*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1178*4d7e907cSAndroid Build Coastguard Worker  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1179*4d7e907cSAndroid Build Coastguard Worker  * - the complete list is fetched within kProgramListScanTimeoutMs;
1180*4d7e907cSAndroid Build Coastguard Worker  * - stopProgramListUpdates does not crash;
1181*4d7e907cSAndroid Build Coastguard Worker  * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
1182*4d7e907cSAndroid Build Coastguard Worker  *   AMFM program matches the expected result.
1183*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromAmFmFilter)1184*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
1185*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetProgramListFromAmFmFilter Test";
1186*4d7e907cSAndroid Build Coastguard Worker 
1187*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1188*4d7e907cSAndroid Build Coastguard Worker     if (!completeList) {
1189*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No program list available";
1190*4d7e907cSAndroid Build Coastguard Worker     }
1191*4d7e907cSAndroid Build Coastguard Worker 
1192*4d7e907cSAndroid Build Coastguard Worker     ProgramFilter amfmFilter = {};
1193*4d7e907cSAndroid Build Coastguard Worker     int expectedResultSize = 0;
1194*4d7e907cSAndroid Build Coastguard Worker     uint64_t expectedFreq = 0;
1195*4d7e907cSAndroid Build Coastguard Worker     for (const auto& program : *completeList) {
1196*4d7e907cSAndroid Build Coastguard Worker         vector<int64_t> amfmIds =
1197*4d7e907cSAndroid Build Coastguard Worker                 bcutils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
1198*4d7e907cSAndroid Build Coastguard Worker         EXPECT_LE(amfmIds.size(), 1u);
1199*4d7e907cSAndroid Build Coastguard Worker         if (amfmIds.size() == 0) {
1200*4d7e907cSAndroid Build Coastguard Worker             continue;
1201*4d7e907cSAndroid Build Coastguard Worker         }
1202*4d7e907cSAndroid Build Coastguard Worker 
1203*4d7e907cSAndroid Build Coastguard Worker         if (expectedResultSize == 0) {
1204*4d7e907cSAndroid Build Coastguard Worker             expectedFreq = amfmIds[0];
1205*4d7e907cSAndroid Build Coastguard Worker             amfmFilter.identifiers = {
1206*4d7e907cSAndroid Build Coastguard Worker                     makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, expectedFreq)};
1207*4d7e907cSAndroid Build Coastguard Worker             expectedResultSize = 1;
1208*4d7e907cSAndroid Build Coastguard Worker         } else if (amfmIds[0] == expectedFreq) {
1209*4d7e907cSAndroid Build Coastguard Worker             expectedResultSize++;
1210*4d7e907cSAndroid Build Coastguard Worker         }
1211*4d7e907cSAndroid Build Coastguard Worker     }
1212*4d7e907cSAndroid Build Coastguard Worker 
1213*4d7e907cSAndroid Build Coastguard Worker     if (expectedResultSize == 0) {
1214*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No Am/FM programs available";
1215*4d7e907cSAndroid Build Coastguard Worker     }
1216*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
1217*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
1218*4d7e907cSAndroid Build Coastguard Worker }
1219*4d7e907cSAndroid Build Coastguard Worker 
1220*4d7e907cSAndroid Build Coastguard Worker /**
1221*4d7e907cSAndroid Build Coastguard Worker  * Test getting program list using DAB ensemble program filter.
1222*4d7e907cSAndroid Build Coastguard Worker  *
1223*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1224*4d7e907cSAndroid Build Coastguard Worker  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1225*4d7e907cSAndroid Build Coastguard Worker  * - the complete list is fetched within kProgramListScanTimeoutMs;
1226*4d7e907cSAndroid Build Coastguard Worker  * - stopProgramListUpdates does not crash;
1227*4d7e907cSAndroid Build Coastguard Worker  * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
1228*4d7e907cSAndroid Build Coastguard Worker  *   program matches the expected result.
1229*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromDabFilter)1230*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
1231*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "GetProgramListFromDabFilter Test";
1232*4d7e907cSAndroid Build Coastguard Worker 
1233*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1234*4d7e907cSAndroid Build Coastguard Worker     if (!completeList) {
1235*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No program list available";
1236*4d7e907cSAndroid Build Coastguard Worker     }
1237*4d7e907cSAndroid Build Coastguard Worker 
1238*4d7e907cSAndroid Build Coastguard Worker     ProgramFilter dabFilter = {};
1239*4d7e907cSAndroid Build Coastguard Worker     int expectedResultSize = 0;
1240*4d7e907cSAndroid Build Coastguard Worker     uint64_t expectedEnsemble = 0;
1241*4d7e907cSAndroid Build Coastguard Worker     for (const auto& program : *completeList) {
1242*4d7e907cSAndroid Build Coastguard Worker         auto dabEnsembles = bcutils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
1243*4d7e907cSAndroid Build Coastguard Worker         EXPECT_LE(dabEnsembles.size(), 1u);
1244*4d7e907cSAndroid Build Coastguard Worker         if (dabEnsembles.size() == 0) {
1245*4d7e907cSAndroid Build Coastguard Worker             continue;
1246*4d7e907cSAndroid Build Coastguard Worker         }
1247*4d7e907cSAndroid Build Coastguard Worker 
1248*4d7e907cSAndroid Build Coastguard Worker         if (expectedResultSize == 0) {
1249*4d7e907cSAndroid Build Coastguard Worker             expectedEnsemble = dabEnsembles[0];
1250*4d7e907cSAndroid Build Coastguard Worker             dabFilter.identifiers = {
1251*4d7e907cSAndroid Build Coastguard Worker                     makeIdentifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
1252*4d7e907cSAndroid Build Coastguard Worker             expectedResultSize = 1;
1253*4d7e907cSAndroid Build Coastguard Worker         } else if (dabEnsembles[0] == expectedEnsemble) {
1254*4d7e907cSAndroid Build Coastguard Worker             expectedResultSize++;
1255*4d7e907cSAndroid Build Coastguard Worker         }
1256*4d7e907cSAndroid Build Coastguard Worker     }
1257*4d7e907cSAndroid Build Coastguard Worker 
1258*4d7e907cSAndroid Build Coastguard Worker     if (expectedResultSize == 0) {
1259*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No DAB programs available";
1260*4d7e907cSAndroid Build Coastguard Worker     }
1261*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
1262*4d7e907cSAndroid Build Coastguard Worker     ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
1263*4d7e907cSAndroid Build Coastguard Worker }
1264*4d7e907cSAndroid Build Coastguard Worker 
1265*4d7e907cSAndroid Build Coastguard Worker /**
1266*4d7e907cSAndroid Build Coastguard Worker  * Test HD_STATION_NAME correctness.
1267*4d7e907cSAndroid Build Coastguard Worker  *
1268*4d7e907cSAndroid Build Coastguard Worker  * Verifies that if a program on the list contains HD_STATION_NAME identifier:
1269*4d7e907cSAndroid Build Coastguard Worker  *  - the program provides station name in its metadata;
1270*4d7e907cSAndroid Build Coastguard Worker  *  - the identifier matches the name;
1271*4d7e907cSAndroid Build Coastguard Worker  *  - there is only one identifier of that type.
1272*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,HdRadioStationNameId)1273*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
1274*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "HdRadioStationNameId Test";
1275*4d7e907cSAndroid Build Coastguard Worker 
1276*4d7e907cSAndroid Build Coastguard Worker     std::optional<bcutils::ProgramInfoSet> list = getProgramList();
1277*4d7e907cSAndroid Build Coastguard Worker     if (!list) {
1278*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "No program list";
1279*4d7e907cSAndroid Build Coastguard Worker     }
1280*4d7e907cSAndroid Build Coastguard Worker 
1281*4d7e907cSAndroid Build Coastguard Worker     for (const auto& program : *list) {
1282*4d7e907cSAndroid Build Coastguard Worker         vector<int64_t> nameIds =
1283*4d7e907cSAndroid Build Coastguard Worker                 bcutils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
1284*4d7e907cSAndroid Build Coastguard Worker         EXPECT_LE(nameIds.size(), 1u);
1285*4d7e907cSAndroid Build Coastguard Worker         if (nameIds.size() == 0) {
1286*4d7e907cSAndroid Build Coastguard Worker             continue;
1287*4d7e907cSAndroid Build Coastguard Worker         }
1288*4d7e907cSAndroid Build Coastguard Worker 
1289*4d7e907cSAndroid Build Coastguard Worker         std::optional<std::string> name;
1290*4d7e907cSAndroid Build Coastguard Worker         if (mAidlVersion == kAidlVersion1) {
1291*4d7e907cSAndroid Build Coastguard Worker             name = bcutils::getMetadataString(program, Metadata::programName);
1292*4d7e907cSAndroid Build Coastguard Worker             if (!name) {
1293*4d7e907cSAndroid Build Coastguard Worker                 name = bcutils::getMetadataString(program, Metadata::rdsPs);
1294*4d7e907cSAndroid Build Coastguard Worker             }
1295*4d7e907cSAndroid Build Coastguard Worker         } else if (mAidlVersion == kAidlVersion2) {
1296*4d7e907cSAndroid Build Coastguard Worker             name = bcutils::getMetadataStringV2(program, Metadata::programName);
1297*4d7e907cSAndroid Build Coastguard Worker             if (!name) {
1298*4d7e907cSAndroid Build Coastguard Worker                 name = bcutils::getMetadataStringV2(program, Metadata::rdsPs);
1299*4d7e907cSAndroid Build Coastguard Worker             }
1300*4d7e907cSAndroid Build Coastguard Worker         } else {
1301*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Unknown HAL AIDL version " << mAidlVersion;
1302*4d7e907cSAndroid Build Coastguard Worker         }
1303*4d7e907cSAndroid Build Coastguard Worker 
1304*4d7e907cSAndroid Build Coastguard Worker         ASSERT_TRUE(name.has_value());
1305*4d7e907cSAndroid Build Coastguard Worker 
1306*4d7e907cSAndroid Build Coastguard Worker         ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
1307*4d7e907cSAndroid Build Coastguard Worker         EXPECT_EQ(nameIds[0], expectedId.value);
1308*4d7e907cSAndroid Build Coastguard Worker     }
1309*4d7e907cSAndroid Build Coastguard Worker }
1310*4d7e907cSAndroid Build Coastguard Worker 
1311*4d7e907cSAndroid Build Coastguard Worker /**
1312*4d7e907cSAndroid Build Coastguard Worker  * Test announcement listener registration.
1313*4d7e907cSAndroid Build Coastguard Worker  *
1314*4d7e907cSAndroid Build Coastguard Worker  * Verifies that:
1315*4d7e907cSAndroid Build Coastguard Worker  *  - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
1316*4d7e907cSAndroid Build Coastguard Worker  *  - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
1317*4d7e907cSAndroid Build Coastguard Worker  *  - closing handle does not crash.
1318*4d7e907cSAndroid Build Coastguard Worker  */
TEST_P(BroadcastRadioHalTest,AnnouncementListenerRegistration)1319*4d7e907cSAndroid Build Coastguard Worker TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
1320*4d7e907cSAndroid Build Coastguard Worker     LOG(DEBUG) << "AnnouncementListenerRegistration Test";
1321*4d7e907cSAndroid Build Coastguard Worker     std::shared_ptr<AnnouncementListenerMock> listener =
1322*4d7e907cSAndroid Build Coastguard Worker             SharedRefBase::make<AnnouncementListenerMock>();
1323*4d7e907cSAndroid Build Coastguard Worker     std::shared_ptr<ICloseHandle> closeHandle = nullptr;
1324*4d7e907cSAndroid Build Coastguard Worker 
1325*4d7e907cSAndroid Build Coastguard Worker     auto halResult = mModule->registerAnnouncementListener(listener, {AnnouncementType::EMERGENCY},
1326*4d7e907cSAndroid Build Coastguard Worker                                                            &closeHandle);
1327*4d7e907cSAndroid Build Coastguard Worker 
1328*4d7e907cSAndroid Build Coastguard Worker     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
1329*4d7e907cSAndroid Build Coastguard Worker         ASSERT_EQ(closeHandle.get(), nullptr);
1330*4d7e907cSAndroid Build Coastguard Worker         GTEST_SKIP() << "Announcements not supported";
1331*4d7e907cSAndroid Build Coastguard Worker     }
1332*4d7e907cSAndroid Build Coastguard Worker 
1333*4d7e907cSAndroid Build Coastguard Worker     ASSERT_TRUE(halResult.isOk());
1334*4d7e907cSAndroid Build Coastguard Worker     ASSERT_NE(closeHandle.get(), nullptr);
1335*4d7e907cSAndroid Build Coastguard Worker 
1336*4d7e907cSAndroid Build Coastguard Worker     closeHandle->close();
1337*4d7e907cSAndroid Build Coastguard Worker }
1338*4d7e907cSAndroid Build Coastguard Worker 
1339*4d7e907cSAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
1340*4d7e907cSAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(
1341*4d7e907cSAndroid Build Coastguard Worker         PerInstance, BroadcastRadioHalTest,
1342*4d7e907cSAndroid Build Coastguard Worker         testing::ValuesIn(::android::getAidlHalInstanceNames(IBroadcastRadio::descriptor)),
1343*4d7e907cSAndroid Build Coastguard Worker         ::android::PrintInstanceNameToString);
1344*4d7e907cSAndroid Build Coastguard Worker 
1345*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl::android::hardware::broadcastradio::vts
1346*4d7e907cSAndroid Build Coastguard Worker 
main(int argc,char ** argv)1347*4d7e907cSAndroid Build Coastguard Worker int main(int argc, char** argv) {
1348*4d7e907cSAndroid Build Coastguard Worker     android::base::SetDefaultTag("BcRadio.vts");
1349*4d7e907cSAndroid Build Coastguard Worker     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1350*4d7e907cSAndroid Build Coastguard Worker     ::testing::InitGoogleTest(&argc, argv);
1351*4d7e907cSAndroid Build Coastguard Worker     ABinderProcess_setThreadPoolMaxThreadCount(4);
1352*4d7e907cSAndroid Build Coastguard Worker     ABinderProcess_startThreadPool();
1353*4d7e907cSAndroid Build Coastguard Worker     return RUN_ALL_TESTS();
1354*4d7e907cSAndroid Build Coastguard Worker }
1355