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

Commit 90884258 authored by Weilin Xu's avatar Weilin Xu Committed by Android (Google) Code Review
Browse files

Merge changes Ia4618232,Id0ba9b12 into main

* changes:
  Separate AM/FM band in default radio HAL
  Add mock HD programs to default AIDL bcradio HAL
parents abfd5064 4833896a
Loading
Loading
Loading
Loading
+244 −65
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ inline constexpr std::chrono::milliseconds kTuneDelayTimeMs = 150ms;
inline constexpr std::chrono::seconds kListDelayTimeS = 1s;

// clang-format off
const AmFmBandRange kFmFullBandRange = {65000, 108000, 10, 0};
const AmFmBandRange kAmFullBandRange = {150, 30000, 1, 0};
const AmFmRegionConfig kDefaultAmFmConfig = {
        {
                {87500, 108000, 100, 100},  // FM
@@ -77,14 +79,71 @@ Properties initProperties(const VirtualRadio& virtualRadio) {
    return prop;
}

bool isDigitalProgramAllowed(const ProgramSelector& sel, bool forceAnalogFm, bool forceAnalogAm) {
    if (sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
        return true;
    }
    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(sel));
    bool isFm = freq >= kFmFullBandRange.lowerBound && freq <= kFmFullBandRange.upperBound;
    return isFm ? !forceAnalogFm : !forceAnalogAm;
}

/**
 * Checks whether a program selector is in the current band.
 *
 * <p>For an AM/FM program, this method checks whether it is in the current AM/FM band. For a
 * program selector is also an HD program, it is also checked whether HD radio is enabled in the
 * current AM/FM band. For a non-AM/FM program, the method will returns {@code true} directly.
 * @param sel Program selector to be checked
 * @param currentAmFmBandRange the current AM/FM band
 * @param forceAnalogFm whether FM band is forced to be analog
 * @param forceAnalogAm  whether AM band is forced to be analog
 * @return whether the program selector is in the current band if it is an AM/FM (including HD)
 * selector, {@code true} otherwise
 */
bool isProgramInBand(const ProgramSelector& sel,
                     const std::optional<AmFmBandRange>& currentAmFmBandRange, bool forceAnalogFm,
                     bool forceAnalogAm) {
    if (!utils::hasAmFmFrequency(sel)) {
        return true;
    }
    if (!currentAmFmBandRange.has_value()) {
        return false;
    }
    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(sel));
    if (freq < currentAmFmBandRange->lowerBound || freq > currentAmFmBandRange->upperBound) {
        return false;
    }
    return isDigitalProgramAllowed(sel, forceAnalogFm, forceAnalogAm);
}

// Makes ProgramInfo that does not point to any particular program
ProgramInfo makeSampleProgramInfo(const ProgramSelector& selector) {
    ProgramInfo info = {};
    info.selector = selector;
    info.logicallyTunedTo =
            utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
    switch (info.selector.primaryId.type) {
        case IdentifierType::AMFM_FREQUENCY_KHZ:
            info.logicallyTunedTo = utils::makeIdentifier(
                    IdentifierType::AMFM_FREQUENCY_KHZ,
                    utils::getId(selector, IdentifierType::AMFM_FREQUENCY_KHZ));
            info.physicallyTunedTo = info.logicallyTunedTo;
            break;
        case IdentifierType::HD_STATION_ID_EXT:
            info.logicallyTunedTo = utils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
                                                          utils::getAmFmFrequency(info.selector));
            info.physicallyTunedTo = info.logicallyTunedTo;
            break;
        case IdentifierType::DAB_SID_EXT:
            info.logicallyTunedTo = info.selector.primaryId;
            info.physicallyTunedTo = utils::makeIdentifier(
                    IdentifierType::DAB_FREQUENCY_KHZ,
                    utils::getId(selector, IdentifierType::DAB_FREQUENCY_KHZ));
            break;
        default:
            info.logicallyTunedTo = info.selector.primaryId;
            info.physicallyTunedTo = info.logicallyTunedTo;
            break;
    }
    return info;
}

@@ -112,6 +171,7 @@ BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
        } else {
            mCurrentProgram = sel;
        }
        adjustAmFmRangeLocked();
    }
}

@@ -124,8 +184,8 @@ ScopedAStatus BroadcastRadio::getAmFmRegionConfig(bool full, AmFmRegionConfig* r
    if (full) {
        *returnConfigs = {};
        returnConfigs->ranges = vector<AmFmBandRange>({
                {65000, 108000, 10, 0},  // FM
                {150, 30000, 1, 0},      // AM
                kFmFullBandRange,
                kAmFullBandRange,
        });
        returnConfigs->fmDeemphasis =
                AmFmRegionConfig::DEEMPHASIS_D50 | AmFmRegionConfig::DEEMPHASIS_D75;
@@ -171,14 +231,24 @@ ProgramInfo BroadcastRadio::tuneInternalLocked(const ProgramSelector& sel) {

    VirtualProgram virtualProgram = {};
    ProgramInfo programInfo;
    if (mVirtualRadio.getProgram(sel, &virtualProgram)) {
    bool isProgramAllowed =
            isDigitalProgramAllowed(sel, isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
                                    isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
    if (isProgramAllowed && mVirtualRadio.getProgram(sel, &virtualProgram)) {
        mCurrentProgram = virtualProgram.selector;
        programInfo = virtualProgram;
    } else {
        if (!isProgramAllowed) {
            mCurrentProgram = utils::makeSelectorAmfm(utils::getAmFmFrequency(sel));
        } else {
            mCurrentProgram = sel;
        }
        programInfo = makeSampleProgramInfo(sel);
    }
    mIsTuneCompleted = true;
    if (adjustAmFmRangeLocked()) {
        startProgramListUpdatesLocked({});
    }

    return programInfo;
}
@@ -246,6 +316,102 @@ ScopedAStatus BroadcastRadio::tune(const ProgramSelector& program) {
    return ScopedAStatus::ok();
}

bool BroadcastRadio::findNextLocked(const ProgramSelector& current, bool directionUp,
                                    bool skipSubChannel, VirtualProgram* nextProgram) const {
    if (mProgramList.empty()) {
        return false;
    }
    // The list is not sorted here since it has already stored in VirtualRadio.
    bool hasAmFmFrequency = utils::hasAmFmFrequency(current);
    uint32_t currentFreq = hasAmFmFrequency ? utils::getAmFmFrequency(current) : 0;
    auto found =
            std::lower_bound(mProgramList.begin(), mProgramList.end(), VirtualProgram({current}));
    if (directionUp) {
        if (found < mProgramList.end() - 1) {
            // When seeking up, tuner will jump to the first selector which is main program service
            // greater than and of the same band as the current program selector in the program
            // list (if not exist, jump to the first selector in the same band) for skipping
            // sub-channels case or AM/FM without HD radio enabled case. Otherwise, the tuner will
            // jump to the first selector which is greater than and of the same band as the current
            // program selector.
            if (utils::tunesTo(current, found->selector)) found++;
            if (skipSubChannel && hasAmFmFrequency) {
                auto firstFound = found;
                while (utils::getAmFmFrequency(found->selector) == currentFreq) {
                    if (found < mProgramList.end() - 1) {
                        found++;
                    } else {
                        found = mProgramList.begin();
                    }
                    if (found == firstFound) {
                        // Only one main channel exists in the program list, the tuner cannot skip
                        // sub-channel to the next program selector.
                        return false;
                    }
                }
            }
        } else {
            // If the selector of current program is no less than all selectors of the same band or
            // not found in the program list, seeking up should wrap the tuner to the first program
            // selector of the same band in the program list.
            found = mProgramList.begin();
        }
    } else {
        if (found > mProgramList.begin() && found != mProgramList.end()) {
            // When seeking down, tuner will jump to the first selector which is main program
            // service less than and of the same band as the current program selector in the
            // program list (if not exist, jump to the last main program service selector of the
            // same band) for skipping sub-channels case or AM/FM without HD radio enabled case.
            // Otherwise, the tuner will jump to the first selector less than and of the same band
            // as the current program selector.
            found--;
            if (hasAmFmFrequency && utils::hasAmFmFrequency(found->selector)) {
                uint32_t nextFreq = utils::getAmFmFrequency(found->selector);
                if (nextFreq != currentFreq) {
                    jumpToFirstSubChannelLocked(found);
                } else if (skipSubChannel) {
                    jumpToFirstSubChannelLocked(found);
                    auto firstFound = found;
                    if (found > mProgramList.begin()) {
                        found--;
                    } else {
                        found = mProgramList.end() - 1;
                    }
                    jumpToFirstSubChannelLocked(found);
                    if (found == firstFound) {
                        // Only one main channel exists in the program list, the tuner cannot skip
                        // sub-channel to the next program selector.
                        return false;
                    }
                }
            }
        } else {
            // If the selector of current program is no greater than all selectors of the same band
            // or not found in the program list, seeking down should wrap the tuner to the last
            // selector of the same band in the program list. If the last program selector in the
            // program list is sub-channel and skipping sub-channels is needed, the tuner will jump
            // to the last main program service of the same band in the program list.
            found = mProgramList.end() - 1;
            jumpToFirstSubChannelLocked(found);
        }
    }
    *nextProgram = *found;
    return true;
}

void BroadcastRadio::jumpToFirstSubChannelLocked(vector<VirtualProgram>::const_iterator& it) const {
    if (!utils::hasAmFmFrequency(it->selector) || it == mProgramList.begin()) {
        return;
    }
    uint32_t currentFrequency = utils::getAmFmFrequency(it->selector);
    it--;
    while (it != mProgramList.begin() && utils::hasAmFmFrequency(it->selector) &&
           utils::getAmFmFrequency(it->selector) == currentFrequency) {
        it--;
    }
    it++;
}

ScopedAStatus BroadcastRadio::seek(bool directionUp, bool skipSubChannel) {
    LOG(DEBUG) << __func__ << ": seek " << (directionUp ? "up" : "down") << " with skipSubChannel? "
               << (skipSubChannel ? "yes" : "no") << "...";
@@ -259,11 +425,21 @@ ScopedAStatus BroadcastRadio::seek(bool directionUp, bool skipSubChannel) {

    cancelLocked();

    auto filterCb = [this](const VirtualProgram& program) {
        return isProgramInBand(program.selector, mCurrentAmFmBandRange,
                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
    };
    const auto& list = mVirtualRadio.getProgramList();
    mProgramList.clear();
    std::copy_if(list.begin(), list.end(), std::back_inserter(mProgramList), filterCb);
    std::shared_ptr<ITunerCallback> callback = mCallback;
    auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
    if (list.empty()) {

    VirtualProgram nextProgram = {};
    bool foundNext = findNextLocked(mCurrentProgram, directionUp, skipSubChannel, &nextProgram);
    mIsTuneCompleted = false;
    if (!foundNext) {
        auto task = [callback]() {
            LOG(DEBUG) << "seek: program list is empty, seek couldn't stop";

@@ -274,31 +450,11 @@ ScopedAStatus BroadcastRadio::seek(bool directionUp, bool skipSubChannel) {
        return ScopedAStatus::ok();
    }

    // The list is not sorted here since it has already stored in VirtualRadio.
    // If the list is not sorted in advance, it should be sorted here.
    const auto& current = mCurrentProgram;
    auto found = std::lower_bound(list.begin(), list.end(), VirtualProgram({current}));
    if (directionUp) {
        if (found < list.end() - 1) {
            if (tunesTo(current, found->selector)) found++;
        } else {
            found = list.begin();
        }
    } else {
        if (found > list.begin() && found != list.end()) {
            found--;
        } else {
            found = list.end() - 1;
        }
    }
    const ProgramSelector tuneTo = found->selector;

    mIsTuneCompleted = false;
    auto task = [this, tuneTo, callback]() {
    auto task = [this, nextProgram, callback]() {
        ProgramInfo programInfo = {};
        {
            lock_guard<mutex> lk(mMutex);
            programInfo = tuneInternalLocked(tuneTo);
            programInfo = tuneInternalLocked(nextProgram.selector);
        }
        callback->onCurrentProgramInfoChanged(programInfo);
    };
@@ -319,31 +475,33 @@ ScopedAStatus BroadcastRadio::step(bool directionUp) {

    cancelLocked();

    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
    int64_t stepTo;
    if (utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
        stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
    } else if (mCurrentProgram.primaryId.type == IdentifierType::HD_STATION_ID_EXT) {
        stepTo = utils::getHdFrequency(mCurrentProgram);
    } else {
        LOG(WARNING) << __func__ << ": can't step in anything else than AM/FM";
        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
                resultToInt(Result::NOT_SUPPORTED), "cannot step in anything else than AM/FM");
    }

    int64_t stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
    std::optional<AmFmBandRange> range = getAmFmRangeLocked();
    if (!range) {
        LOG(ERROR) << __func__ << ": can't find current band or tune operation is in process";
    if (!mCurrentAmFmBandRange.has_value()) {
        LOG(ERROR) << __func__ << ": can't find current band";
        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
                resultToInt(Result::INTERNAL_ERROR),
                "can't find current band or tune operation is in process");
                resultToInt(Result::INTERNAL_ERROR), "can't find current band");
    }

    if (directionUp) {
        stepTo += range->spacing;
        stepTo += mCurrentAmFmBandRange->spacing;
    } else {
        stepTo -= range->spacing;
        stepTo -= mCurrentAmFmBandRange->spacing;
    }
    if (stepTo > range->upperBound) {
        stepTo = range->lowerBound;
    if (stepTo > mCurrentAmFmBandRange->upperBound) {
        stepTo = mCurrentAmFmBandRange->lowerBound;
    }
    if (stepTo < range->lowerBound) {
        stepTo = range->upperBound;
    if (stepTo < mCurrentAmFmBandRange->lowerBound) {
        stepTo = mCurrentAmFmBandRange->upperBound;
    }

    mIsTuneCompleted = false;
@@ -380,16 +538,14 @@ ScopedAStatus BroadcastRadio::cancel() {
    return ScopedAStatus::ok();
}

ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filter) {
    LOG(DEBUG) << __func__ << ": requested program list updates, filter = " << filter.toString()
               << "...";

    auto filterCb = [&filter](const VirtualProgram& program) {
        return utils::satisfies(filter, program.selector);
void BroadcastRadio::startProgramListUpdatesLocked(const ProgramFilter& filter) {
    auto filterCb = [&filter, this](const VirtualProgram& program) {
        return utils::satisfies(filter, program.selector) &&
               isProgramInBand(program.selector, mCurrentAmFmBandRange,
                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_FM),
                               isConfigFlagSetLocked(ConfigFlag::FORCE_ANALOG_AM));
    };

    lock_guard<mutex> lk(mMutex);

    cancelProgramListUpdateLocked();

    const auto& list = mVirtualRadio.getProgramList();
@@ -415,6 +571,15 @@ ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filte
        callback->onProgramListUpdated(chunk);
    };
    mProgramListThread->schedule(task, kListDelayTimeS);
}

ScopedAStatus BroadcastRadio::startProgramListUpdates(const ProgramFilter& filter) {
    LOG(DEBUG) << __func__ << ": requested program list updates, filter = " << filter.toString()
               << "...";

    lock_guard<mutex> lk(mMutex);

    startProgramListUpdatesLocked(filter);

    return ScopedAStatus::ok();
}
@@ -431,18 +596,28 @@ ScopedAStatus BroadcastRadio::stopProgramListUpdates() {
    return ScopedAStatus::ok();
}

bool BroadcastRadio::isConfigFlagSetLocked(ConfigFlag flag) const {
    int flagBit = static_cast<int>(flag);
    return ((mConfigFlagValues >> flagBit) & 1) == 1;
}

ScopedAStatus BroadcastRadio::isConfigFlagSet(ConfigFlag flag, bool* returnIsSet) {
    LOG(DEBUG) << __func__ << ": flag = " << toString(flag);

    int flagBit = static_cast<int>(flag);
    if (flag == ConfigFlag::FORCE_ANALOG) {
        flag = ConfigFlag::FORCE_ANALOG_FM;
    }
    lock_guard<mutex> lk(mMutex);
    *returnIsSet = ((mConfigFlagValues >> flagBit) & 1) == 1;
    *returnIsSet = isConfigFlagSetLocked(flag);
    return ScopedAStatus::ok();
}

ScopedAStatus BroadcastRadio::setConfigFlag(ConfigFlag flag, bool value) {
    LOG(DEBUG) << __func__ << ": flag = " << toString(flag) << ", value = " << value;

    if (flag == ConfigFlag::FORCE_ANALOG) {
        flag = ConfigFlag::FORCE_ANALOG_FM;
    }
    int flagBitMask = 1 << (static_cast<int>(flag));
    lock_guard<mutex> lk(mMutex);
    if (value) {
@@ -450,6 +625,9 @@ ScopedAStatus BroadcastRadio::setConfigFlag(ConfigFlag flag, bool value) {
    } else {
        mConfigFlagValues &= ~flagBitMask;
    }
    if (flag == ConfigFlag::FORCE_ANALOG_AM || flag == ConfigFlag::FORCE_ANALOG_FM) {
        startProgramListUpdatesLocked({});
    }
    return ScopedAStatus::ok();
}

@@ -468,24 +646,25 @@ ScopedAStatus BroadcastRadio::getParameters([[maybe_unused]] const vector<string
    return ScopedAStatus::ok();
}

std::optional<AmFmBandRange> BroadcastRadio::getAmFmRangeLocked() const {
    if (!mIsTuneCompleted) {
        LOG(WARNING) << __func__ << ": tune operation is in process";
        return {};
    }
    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ)) {
bool BroadcastRadio::adjustAmFmRangeLocked() {
    bool hasBandBefore = mCurrentAmFmBandRange.has_value();
    if (!utils::hasAmFmFrequency(mCurrentProgram)) {
        LOG(WARNING) << __func__ << ": current program does not has AMFM_FREQUENCY_KHZ identifier";
        return {};
        mCurrentAmFmBandRange.reset();
        return hasBandBefore;
    }

    int64_t freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY_KHZ);
    int32_t freq = static_cast<int32_t>(utils::getAmFmFrequency(mCurrentProgram));
    for (const auto& range : mAmFmConfig.ranges) {
        if (range.lowerBound <= freq && range.upperBound >= freq) {
            return range;
            bool isBandChanged = hasBandBefore ? *mCurrentAmFmBandRange != range : true;
            mCurrentAmFmBandRange = range;
            return isBandChanged;
        }
    }

    return {};
    mCurrentAmFmBandRange.reset();
    return !hasBandBefore;
}

ScopedAStatus BroadcastRadio::registerAnnouncementListener(
+30 −18
Original line number Diff line number Diff line
@@ -39,21 +39,25 @@ class BroadcastRadio final : public BnBroadcastRadio {
  public:
    explicit BroadcastRadio(const VirtualRadio& virtualRadio);
    ~BroadcastRadio();
    ndk::ScopedAStatus getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs) override;
    ndk::ScopedAStatus getAmFmRegionConfig(bool full, AmFmRegionConfig* returnConfigs)
            EXCLUDES(mMutex) override;
    ndk::ScopedAStatus getDabRegionConfig(std::vector<DabTableEntry>* returnConfigs) override;
    ndk::ScopedAStatus getImage(int32_t id, std::vector<uint8_t>* returnImage) override;
    ndk::ScopedAStatus getProperties(Properties* returnProperties) override;
    ndk::ScopedAStatus getProperties(Properties* returnProperties) EXCLUDES(mMutex) override;

    ndk::ScopedAStatus setTunerCallback(const std::shared_ptr<ITunerCallback>& callback) override;
    ndk::ScopedAStatus unsetTunerCallback() override;
    ndk::ScopedAStatus tune(const ProgramSelector& program) override;
    ndk::ScopedAStatus seek(bool directionUp, bool skipSubChannel) override;
    ndk::ScopedAStatus step(bool directionUp) override;
    ndk::ScopedAStatus cancel() override;
    ndk::ScopedAStatus startProgramListUpdates(const ProgramFilter& filter) override;
    ndk::ScopedAStatus stopProgramListUpdates() override;
    ndk::ScopedAStatus isConfigFlagSet(ConfigFlag flag, bool* returnIsSet) override;
    ndk::ScopedAStatus setConfigFlag(ConfigFlag flag, bool in_value) override;
    ndk::ScopedAStatus setTunerCallback(const std::shared_ptr<ITunerCallback>& callback)
            EXCLUDES(mMutex) override;
    ndk::ScopedAStatus unsetTunerCallback() EXCLUDES(mMutex) override;
    ndk::ScopedAStatus tune(const ProgramSelector& program) EXCLUDES(mMutex) override;
    ndk::ScopedAStatus seek(bool directionUp, bool skipSubChannel) EXCLUDES(mMutex) override;
    ndk::ScopedAStatus step(bool directionUp) EXCLUDES(mMutex) override;
    ndk::ScopedAStatus cancel() EXCLUDES(mMutex) override;
    ndk::ScopedAStatus startProgramListUpdates(const ProgramFilter& filter)
            EXCLUDES(mMutex) override;
    ndk::ScopedAStatus stopProgramListUpdates() EXCLUDES(mMutex) override;
    ndk::ScopedAStatus isConfigFlagSet(ConfigFlag flag, bool* returnIsSet)
            EXCLUDES(mMutex) override;
    ndk::ScopedAStatus setConfigFlag(ConfigFlag flag, bool in_value) EXCLUDES(mMutex) override;
    ndk::ScopedAStatus setParameters(const std::vector<VendorKeyValue>& parameters,
                                     std::vector<VendorKeyValue>* returnParameters) override;
    ndk::ScopedAStatus getParameters(const std::vector<std::string>& keys,
@@ -62,7 +66,7 @@ class BroadcastRadio final : public BnBroadcastRadio {
            const std::shared_ptr<IAnnouncementListener>& listener,
            const std::vector<AnnouncementType>& enabled,
            std::shared_ptr<ICloseHandle>* returnCloseHandle) override;
    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
    binder_status_t dump(int fd, const char** args, uint32_t numArgs) EXCLUDES(mMutex) override;

  private:
    const VirtualRadio& mVirtualRadio;
@@ -75,15 +79,23 @@ class BroadcastRadio final : public BnBroadcastRadio {
    bool mIsTuneCompleted GUARDED_BY(mMutex) = true;
    Properties mProperties GUARDED_BY(mMutex);
    ProgramSelector mCurrentProgram GUARDED_BY(mMutex) = {};
    std::vector<VirtualProgram> mProgramList GUARDED_BY(mMutex) = {};
    std::optional<AmFmBandRange> mCurrentAmFmBandRange GUARDED_BY(mMutex);
    std::shared_ptr<ITunerCallback> mCallback GUARDED_BY(mMutex);

    // Bitmap for all ConfigFlag values
    int mConfigFlagValues GUARDED_BY(mMutex) = 0;

    std::optional<AmFmBandRange> getAmFmRangeLocked() const;
    void cancelLocked();
    ProgramInfo tuneInternalLocked(const ProgramSelector& sel);
    void cancelProgramListUpdateLocked();
    bool adjustAmFmRangeLocked() REQUIRES(mMutex);
    void cancelLocked() REQUIRES(mMutex);
    ProgramInfo tuneInternalLocked(const ProgramSelector& sel) REQUIRES(mMutex);
    void startProgramListUpdatesLocked(const ProgramFilter& filter) REQUIRES(mMutex);
    void cancelProgramListUpdateLocked() REQUIRES(mMutex);
    bool findNextLocked(const ProgramSelector& current, bool directionUp, bool skipSubChannel,
                        VirtualProgram* nextProgram) const REQUIRES(mMutex);
    void jumpToFirstSubChannelLocked(std::vector<VirtualProgram>::const_iterator& it) const
            REQUIRES(mMutex);
    bool isConfigFlagSetLocked(ConfigFlag flag) const REQUIRES(mMutex);

    binder_status_t cmdHelp(int fd) const;
    binder_status_t cmdTune(int fd, const char** args, uint32_t numArgs);
@@ -93,7 +105,7 @@ class BroadcastRadio final : public BnBroadcastRadio {
    binder_status_t cmdStartProgramListUpdates(int fd, const char** args, uint32_t numArgs);
    binder_status_t cmdStopProgramListUpdates(int fd, uint32_t numArgs);

    binder_status_t dumpsys(int fd);
    binder_status_t dumpsys(int fd) EXCLUDES(mMutex);
};

}  // namespace aidl::android::hardware::broadcastradio
+33 −3

File changed.

Preview size limit exceeded, changes collapsed.

+35 −8

File changed.

Preview size limit exceeded, changes collapsed.

+9 −0
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
ProgramSelector makeSelectorAmfm(uint32_t frequency);
ProgramSelector makeSelectorDab(uint64_t sidExt);
ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq);
ProgramSelector makeSelectorHd(uint64_t stationId, uint64_t subChannel, uint64_t frequency);

bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);

@@ -158,6 +159,14 @@ std::optional<std::string> getMetadataString(const ProgramInfo& info, const Meta

ProgramIdentifier makeHdRadioStationName(const std::string& name);

uint32_t getHdFrequency(const ProgramSelector& sel);

int getHdSubchannel(const ProgramSelector& sel);

bool hasAmFmFrequency(const ProgramSelector& sel);

uint32_t getAmFmFrequency(const ProgramSelector& sel);

template <typename aidl_type>
inline std::string vectorToString(const std::vector<aidl_type>& in_values) {
    return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
Loading