Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b61ee9eb authored by Weilin Xu's avatar Weilin Xu
Browse files

Add tuner callback for default bcradio HAL

Implemented mocked tuner callback and added unit test for getting
and setting the default broadcast radio HAL implementation.

Bug: 316630344
Test: atest DefaultBroadcastRadioHalTestCase
Change-Id: I4d41746f7725a79a8d398a1fb798fbc7cab94e09
parent 7b1e7ce8
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -14,10 +14,13 @@
 * limitations under the License.
 */

#include "MockBroadcastRadioCallback.h"

#include <BroadcastRadio.h>
#include <VirtualRadio.h>
#include <broadcastradio-utils-aidl/Utils.h>

#include <android-base/logging.h>
#include <gtest/gtest.h>

namespace aidl::android::hardware::broadcastradio {
@@ -74,10 +77,19 @@ const VirtualRadio& getAmFmMockTestRadio() {
class DefaultBroadcastRadioHalTest : public testing::Test {
  public:
    void SetUp() override {
        ::android::base::SetDefaultTag("BcRadioAidlDef.test");
        const VirtualRadio& amFmRadioMockTest = getAmFmMockTestRadio();
        mBroadcastRadioHal = ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMockTest);
        mTunerCallback = ndk::SharedRefBase::make<MockBroadcastRadioCallback>();
    }

    void TearDown() override {
        mBroadcastRadioHal->unsetTunerCallback();
        EXPECT_FALSE(mTunerCallback->isTunerFailed());
    }

    std::shared_ptr<BroadcastRadio> mBroadcastRadioHal;
    std::shared_ptr<MockBroadcastRadioCallback> mTunerCallback;
};

TEST_F(DefaultBroadcastRadioHalTest, GetAmFmRegionConfig) {
@@ -136,4 +148,24 @@ TEST_F(DefaultBroadcastRadioHalTest, GetProperties) {
    }
}

TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallback) {
    auto halResult = mBroadcastRadioHal->setTunerCallback(mTunerCallback);

    ASSERT_TRUE(halResult.isOk());
}

TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallbackWithNull) {
    auto halResult = mBroadcastRadioHal->setTunerCallback(nullptr);

    ASSERT_EQ(halResult.getServiceSpecificError(), utils::resultToInt(Result::INVALID_ARGUMENTS));
}

TEST_F(DefaultBroadcastRadioHalTest, UnsetTunerCallbackWithNull) {
    ASSERT_TRUE(mBroadcastRadioHal->setTunerCallback(mTunerCallback).isOk());

    auto halResult = mBroadcastRadioHal->unsetTunerCallback();

    ASSERT_TRUE(halResult.isOk());
}

}  // namespace aidl::android::hardware::broadcastradio
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "MockBroadcastRadioCallback.h"

#include <android-base/logging.h>

namespace aidl::android::hardware::broadcastradio {

namespace {
using std::vector;
}

MockBroadcastRadioCallback::MockBroadcastRadioCallback() {
    mAntennaConnectionState = true;
}

ScopedAStatus MockBroadcastRadioCallback::onTuneFailed(Result result,
                                                       const ProgramSelector& selector) {
    LOG(DEBUG) << "onTuneFailed with result with " << selector.toString().c_str();
    if (result != Result::CANCELED) {
        std::lock_guard<std::mutex> lk(mLock);
        tunerFailed = true;
    }
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onCurrentProgramInfoChanged(const ProgramInfo& info) {
    LOG(DEBUG) << "onCurrentProgramInfoChanged with " << info.toString().c_str();
    {
        std::lock_guard<std::mutex> lk(mLock);
        mCurrentProgramInfo = info;
    }

    mOnCurrentProgramInfoChangedFlag.notify();
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onProgramListUpdated(
        [[maybe_unused]] const ProgramListChunk& chunk) {
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onParametersUpdated(
        [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onAntennaStateChange(bool connected) {
    if (!connected) {
        std::lock_guard<std::mutex> lk(mLock);
        mAntennaConnectionState = false;
    }
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
                                                              [[maybe_unused]] bool in_value) {
    return ndk::ScopedAStatus::ok();
}

bool MockBroadcastRadioCallback::waitOnCurrentProgramInfoChangedCallback() {
    return mOnCurrentProgramInfoChangedFlag.wait();
}

void MockBroadcastRadioCallback::reset() {
    mOnCurrentProgramInfoChangedFlag.reset();
}

bool MockBroadcastRadioCallback::isTunerFailed() {
    std::lock_guard<std::mutex> lk(mLock);
    return tunerFailed;
}

ProgramInfo MockBroadcastRadioCallback::getCurrentProgramInfo() {
    std::lock_guard<std::mutex> lk(mLock);
    return mCurrentProgramInfo;
}

}  // namespace aidl::android::hardware::broadcastradio
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
#include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
#include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
#include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
#include <aidl/android/hardware/broadcastradio/Result.h>
#include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>

#include <android-base/thread_annotations.h>

#include <broadcastradio-utils-aidl/Utils.h>

#include <condition_variable>

namespace aidl::android::hardware::broadcastradio {

namespace {
using ::ndk::ScopedAStatus;

}  // namespace

class MockBroadcastRadioCallback final : public BnTunerCallback {
  public:
    explicit MockBroadcastRadioCallback();
    ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
    ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
    ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
    ScopedAStatus onParametersUpdated(const std::vector<VendorKeyValue>& parameters) override;
    ScopedAStatus onAntennaStateChange(bool connected) override;
    ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;

    bool waitOnCurrentProgramInfoChangedCallback();
    bool isTunerFailed();
    void reset();

    ProgramInfo getCurrentProgramInfo();

  private:
    class CallbackFlag final {
      public:
        CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
        /**
         * Notify that the callback is called.
         */
        void notify() {
            std::unique_lock<std::mutex> lock(mMutex);
            mCalled = true;
            lock.unlock();
            mCv.notify_all();
        };

        /**
         * Wait for the timeout passed into the constructor.
         */
        bool wait() {
            std::unique_lock<std::mutex> lock(mMutex);
            return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
                                [this] { return mCalled; });
        };

        /**
         * Reset the callback to not called.
         */
        void reset() {
            std::unique_lock<std::mutex> lock(mMutex);
            mCalled = false;
        }

      private:
        std::mutex mMutex;
        bool mCalled GUARDED_BY(mMutex) = false;
        std::condition_variable mCv;
        int mTimeoutMs;
    };

    std::mutex mLock;
    bool mAntennaConnectionState GUARDED_BY(mLock);
    bool tunerFailed GUARDED_BY(mLock) = false;
    ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
    utils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
    CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
};

}  // namespace aidl::android::hardware::broadcastradio