~aleteoryx/muditaos

b069b7bc6be50968145fe4d1ec9d5922e78d981a — Marcin Zieliński 3 years ago d528cac
[MOS-793] Connect GUI and modem VoLTE steering

Additionally, fixed many covert bugs that emerged due to
modem restarting.
M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +0 -5
@@ 58,11 58,6 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
    endforeach()
endif()

option(ENABLE_VOLTE "Enable VoLTE" OFF)
if(${ENABLE_VOLTE})
    target_compile_definitions(${PROJECT_NAME} PUBLIC ENABLE_VOLTE=1)
endif()

option(DISABLED_SETTINGS_OPTIONS "Enable Disabled Settings Options" OFF)
if(${DISABLED_SETTINGS_OPTIONS})
    target_compile_definitions(${PROJECT_NAME} PUBLIC DISABLED_SETTINGS_OPTIONS=1)

M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +35 -0
@@ 61,6 61,7 @@
#include <application-settings/data/AutoLockData.hpp>
#include <application-settings/models/apps/SoundsModel.hpp>
#include <application-settings/models/display-keypad/DisplayModeModel.hpp>
#include <module-services/service-cellular/service-cellular/VolteState.hpp>
#include <service-evtmgr/EventManagerServiceAPI.hpp>
#include <service-audio/AudioServiceAPI.hpp>
#include <service-bluetooth/BluetoothMessage.hpp>


@@ 74,6 75,7 @@
#include <service-bluetooth/messages/Status.hpp>
#include <service-bluetooth/messages/Unpair.hpp>
#include <service-bluetooth/messages/Disconnect.hpp>
#include <service-cellular/Constans.hpp>
#include <service-db/Settings.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>
#include <module-services/service-appmgr/include/service-appmgr/Constants.hpp>


@@ 321,6 323,12 @@ namespace app
            return handleAudioStop(notification);
        });

        connect(typeid(cellular::GetVolteStateResponse),
                [&](sys::Message *msg) -> sys::MessagePointer { return handleVolteState(msg); });

        connect(typeid(cellular::VolteStateNotification),
                [&](sys::Message *msg) -> sys::MessagePointer { return handleVolteState(msg); });

        createUserInterface();

        settings->registerValueChange(settings::operators_on,


@@ 345,6 353,9 @@ namespace app

        bluetoothSettingsModel->requestBondedDevices();
        bluetoothSettingsModel->requestStatus();

        bus.sendUnicast(std::make_shared<cellular::GetVolteStateRequest>(), service::name::cellular);

        return ret;
    }



@@ 769,6 780,11 @@ namespace app
        return statusIndicators.phoneMode;
    }

    auto ApplicationSettings::getVolteState() const noexcept -> cellular::VolteState
    {
        return volteState;
    }

    void ApplicationSettings::setAutoLockTime(std::chrono::seconds lockTime)
    {
        bus.sendUnicast(std::make_shared<app::manager::SetAutoLockTimeoutRequest>(lockTime), service::name::appmgr);


@@ 805,4 821,23 @@ namespace app
        }
        return sys::MessageNone{};
    }

    auto ApplicationSettings::handleVolteState(sys::Message *msg) -> sys::MessagePointer
    {
        auto *volteStateMessage = static_cast<cellular::GetVolteStateResponse *>(msg);
        volteState              = volteStateMessage->volteState;

        if (isCurrentWindow(gui::window::name::network)) {
            // refreshWindow() would be insufficient because wouldn't trigger list rebuild
            switchWindow(gui::window::name::network);
        }

        return sys::MessageNone{};
    }

    void ApplicationSettings::sendVolteChangeRequest(bool enable)
    {
        auto message = std::make_shared<cellular::SwitchVolteOnOffRequest>(enable);
        bus.sendUnicast(std::move(message), service::name::cellular);
    };
} /* namespace app */

M module-apps/application-settings/include/application-settings/ApplicationSettings.hpp => module-apps/application-settings/include/application-settings/ApplicationSettings.hpp +6 -0
@@ 13,6 13,7 @@
#include <EventStore.hpp>
#include <application-settings/models/bluetooth/BluetoothSettingsModel.hpp>
#include <application-settings/data/WallpaperOption.hpp>
#include <module-services/service-cellular/service-cellular/VolteState.hpp>

class AudioStopNotification; // Forward declaration



@@ 183,12 184,16 @@ namespace app

        auto getCurrentPhoneMode() const noexcept -> sys::phone_modes::PhoneMode override;

        auto getVolteState() const noexcept -> cellular::VolteState;
        void sendVolteChangeRequest(bool enable);

      private:
        void attachQuotesWindows();
        void switchToAllDevicesViaBtErrorPrompt(std::shared_ptr<sys::DataMessage> msg, const std::string &errorMsg);

        auto handleSimNotification() -> sys::MessagePointer;
        auto handleAudioStop(AudioStopNotification *notification) -> sys::MessagePointer;
        auto handleVolteState(sys::Message *msg) -> sys::MessagePointer;

        std::shared_ptr<SoundsPlayer> soundsPlayer;
        Store::GSM::SelectedSIM selectedSim = Store::GSM::get()->selected;


@@ 200,6 205,7 @@ namespace app
        bool callsFromFavorites                                        = false;
        int connectionFrequency                                        = 0;
        bool flightModeOn                                              = true;
        cellular::VolteState volteState{cellular::VolteState::Undefined};
        std::shared_ptr<BluetoothSettingsModel> bluetoothSettingsModel = nullptr;
    };


M module-apps/application-settings/windows/network/NetworkWindow.cpp => module-apps/application-settings/windows/network/NetworkWindow.cpp +24 -17
@@ 37,23 37,21 @@ namespace gui
            gui::option::SettingRightItem::ArrowWhite,
            false));

#if ENABLE_VOLTE == 1
#pragma message "state switching not connected to the actual state yet - see MOS-793"
        auto getNextVolteState = []() {
            using namespace gui::option;

            static size_t volteStateIndex;
            static constexpr SettingRightItem volteStates[]{
                SettingRightItem::Transiting, SettingRightItem::On, SettingRightItem::Off};

            auto currentIndex = ++volteStateIndex % (sizeof(volteStates) / sizeof(volteStates[0]));
            return volteStates[currentIndex];
        };

        optList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::translate("app_settings_network_voice_over_lte"),
            [=](gui::Item &item) {
                refreshOptionsList();
            [&](gui::Item &item) {
                auto *settingsApp = static_cast<app::ApplicationSettings *>(application);
                switch (settingsApp->getVolteState()) {
                case cellular::VolteState::Off:
                    settingsApp->sendVolteChangeRequest(true);
                    break;
                case cellular::VolteState::On:
                    settingsApp->sendVolteChangeRequest(false);
                    break;
                default:
                    LOG_INFO("Skip request due unsettled VoLTE state");
                    break;
                }
                return true;
            },
            [&](Item &item) {


@@ 63,8 61,17 @@ namespace gui
                return true;
            },
            nullptr,
            getNextVolteState()));
#endif
            [&]() {
                auto const *settingsApp = static_cast<app::ApplicationSettings *>(application);
                switch (settingsApp->getVolteState()) {
                case cellular::VolteState::Off:
                    return option::SettingRightItem::Off;
                case cellular::VolteState::On:
                    return option::SettingRightItem::On;
                default:
                    return option::SettingRightItem::Transiting;
                }
            }()));

#if DISABLED_SETTINGS_OPTIONS == 1
        auto operatorsOn = operatorsSettings->getOperatorsOn();

M module-cellular/modem/ATCommon.hpp => module-cellular/modem/ATCommon.hpp +2 -0
@@ 77,6 77,8 @@ namespace at

              };

        virtual ~Channel() = default;

        /// waits till ok or timeout
        virtual auto cmd(const std::string &cmd,
                         std::chrono::milliseconds timeout = at::default_timeout,

M module-cellular/modem/mux/DLCChannel.h => module-cellular/modem/mux/DLCChannel.h +2 -0
@@ 33,6 33,8 @@ class DLCChannel : public at::Channel
    DLCChannel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback = nullptr);
    DLCChannel() : Channel{nullptr}, name{"none"}, DLCI{-1} {};

    virtual ~DLCChannel() = default;

    bool init();
    bool establish();
    void sendData(std::vector<uint8_t> &data);

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +71 -21
@@ 405,11 405,7 @@ void ServiceCellular::registerMessageHandlers()
    connect(typeid(sdesktop::developerMode::DeveloperModeRequest), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<sdesktop::developerMode::DeveloperModeRequest *>(request);
        if (typeid(*msg->event.get()) == typeid(sdesktop::developerMode::CellularHotStartEvent)) {
            priv->simCard->setChannel(nullptr);
            priv->networkTime->setChannel(nullptr);
            priv->simContacts->setChannel(nullptr);
            priv->imeiGetHandler->setChannel(nullptr);

            priv->privDeinit();
            cmux->closeChannels();
            ///> change state - simulate hot start
            handle_power_up_request();


@@ 602,7 598,9 @@ void ServiceCellular::registerMessageHandlers()
    });

    connect(typeid(cellular::GetVolteStateRequest), [&](sys::Message *request) -> sys::MessagePointer {
        return std::make_shared<cellular::GetVolteStateResponse>(priv->volteHandler->getVolteState());
        bus.sendUnicast(std::make_shared<cellular::GetVolteStateResponse>(priv->volteHandler->getVolteState()),
                        request->sender);
        return sys::MessageNone{};
    });

    connect(typeid(cellular::SwitchVolteOnOffRequest), [&](sys::Message *request) -> sys::MessagePointer {


@@ 614,14 612,29 @@ void ServiceCellular::registerMessageHandlers()
        }
        settings->setValue(
            settings::Cellular::volteEnabled, message->enable ? "1" : "0", settings::SettingsScope::Global);
        if (not priv->volteHandler->switchVolte(*channel, message->enable)) {
            auto notification = std::make_shared<cellular::VolteStateNotification>(priv->volteHandler->getVolteState());
            bus.sendMulticast(std::move(notification), sys::BusChannel::ServiceCellularNotifications);
        try {
            if (not priv->volteHandler->switchVolte(*channel, message->enable)) {
                auto notification =
                    std::make_shared<cellular::VolteStateNotification>(priv->volteHandler->getVolteState());
                bus.sendMulticast(std::move(notification), sys::BusChannel::ServiceCellularNotifications);
                priv->modemResetHandler->performHardReset();
            }
        }
        catch (std::runtime_error const &exc) {
            LOG_ERROR("%s", exc.what());
            priv->modemResetHandler->performHardReset();
        }
        return sys::MessageNone{};
    });

    connect(typeid(cellular::msg::notification::SimReady), [&](sys::Message *) {
        if (priv->volteHandler->isFunctionalityResetNeeded()) {
            LOG_INFO("First run after VoLTE switch, functionality reset needed");
            priv->modemResetHandler->performFunctionalityReset();
        }
        return sys::MessageNone{};
    });

    handle_CellularGetChannelMessage();
}



@@ 821,6 834,7 @@ bool ServiceCellular::handle_power_down_waiting()
bool ServiceCellular::handle_power_down()
{
    LOG_DEBUG("Powered Down");
    priv->privDeinit();
    cmux->closeChannels();
    cmux.reset();
    cmux = std::make_unique<CellularMux>(PortSpeed_e::PS460800, this);


@@ 892,23 906,28 @@ bool ServiceCellular::handle_audio_conf_procedure()
bool ServiceCellular::handle_cellular_priv_init()
{
    auto channel = cmux->get(CellularMux::Channel::Commands);
    priv->simCard->setChannel(channel);
    priv->networkTime->setChannel(channel);
    priv->simContacts->setChannel(channel);
    priv->imeiGetHandler->setChannel(channel);
    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        priv->modemResetHandler->performHardReset();
        return true;
    }

    bool needReset = false;
    priv->privInit(channel);

    auto enableVolte =
        settings->getValue(settings::Cellular::volteEnabled, settings::SettingsScope::Global) == "1" ? true : false;

    bool volteNeedReset = false;
    try {
        needReset = !priv->tetheringHandler->configure() || !priv->volteHandler->switchVolte(*channel, enableVolte);
        volteNeedReset    = !priv->volteHandler->switchVolte(*channel, enableVolte);
        auto notification = std::make_shared<cellular::VolteStateNotification>(priv->volteHandler->getVolteState());
        bus.sendMulticast(std::move(notification), sys::BusChannel::ServiceCellularNotifications);
    }
    catch (std::runtime_error const &exc) {
        LOG_ERROR("%s", exc.what());
    }
    if (needReset) {

    auto tetheringNeedReset = !priv->tetheringHandler->configure();
    if (tetheringNeedReset || volteNeedReset) {
        priv->modemResetHandler->performHardReset();
        return true;
    }


@@ 1086,7 1105,12 @@ auto ServiceCellular::receiveSMS(std::string messageNumber) -> bool

bool ServiceCellular::getOwnNumber(std::string &destination)
{
    auto ret = cmux->get(CellularMux::Channel::Commands)->cmd(at::AT::CNUM);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (not channel) {
        LOG_ERROR("ServiceCellular::getOwnNumber failed because no cmux channel provided");
        return false;
    }
    auto ret = channel->cmd(at::AT::CNUM);

    if (ret) {
        auto begin = ret.response[0].find(',');


@@ 1113,8 1137,13 @@ bool ServiceCellular::getOwnNumber(std::string &destination)

bool ServiceCellular::getIMSI(std::string &destination, bool fullNumber)
{
    auto ret = cmux->get(CellularMux::Channel::Commands)->cmd(at::AT::CIMI);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        return false;
    }

    auto ret = channel->cmd(at::AT::CIMI);
    if (ret) {
        if (fullNumber) {
            destination = ret.response[0];


@@ 1253,9 1282,13 @@ void save_SIM_detection_status(DLCChannel *channel)

bool sim_check_hot_swap(DLCChannel *channel)
{
    assert(channel);
    bool reboot_needed = false;

    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        return reboot_needed;
    }

    if (!is_SIM_detection_enabled(channel)) {
        reboot_needed = true;
    }


@@ 1287,6 1320,11 @@ bool ServiceCellular::handle_sim_sanity_check()
bool ServiceCellular::handle_modem_on()
{
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        return false;
    }

    channel->cmd("AT+CCLK?");
    // inform host ap ready
    cmux->informModemHostWakeup();


@@ 1299,6 1337,11 @@ bool ServiceCellular::handle_modem_on()
bool ServiceCellular::handle_URCReady()
{
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        return false;
    }

    bool ret     = true;

    ret = ret && channel->cmd(at::AT::ENABLE_NETWORK_REGISTRATION_URC);


@@ 1476,6 1519,7 @@ void ServiceCellular::handle_CellularGetChannelMessage()
        auto getChannelMsg = static_cast<cellular::GetChannelMessage *>(req);
        LOG_DEBUG("Handle request for channel: %s", CellularMux::name(getChannelMsg->dataChannel).c_str());
        std::shared_ptr<cellular::GetChannelResponseMessage> channelResponsMessage =
            // MOS-809: find out if there's a need here for checking 'cmux' against nullptr
            std::make_shared<cellular::GetChannelResponseMessage>(cmux->get(getChannelMsg->dataChannel));
        LOG_DEBUG("channel ptr: %p", channelResponsMessage->dataChannelPtr);
        bus.sendUnicast(std::move(channelResponsMessage), req->sender);


@@ 1869,7 1913,13 @@ auto ServiceCellular::handleDBQueryResponseMessage(db::QueryResponse *msg) -> st
auto ServiceCellular::handleCellularListCallsMessage(CellularMessage *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    at::cmd::CLCC cmd;
    auto base = cmux->get(CellularMux::Channel::Commands)->cmd(cmd);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        LOG_ERROR("no cmux channel provided");
        return std::make_shared<cellular::ResponseMessage>(false);
    }

    auto base = channel->cmd(cmd);
    if (auto response = cmd.parseCLCC(base); response) {
        const auto &data = response.getData();
        auto it          = std::find_if(std::begin(data), std::end(data), [&](const auto &entry) {

M module-services/service-cellular/call/api/ModemCallApi.cpp => module-services/service-cellular/call/api/ModemCallApi.cpp +16 -4
@@ 30,19 30,31 @@ namespace cellular
    bool Api::hangupCall()
    {
        if (cmux == nullptr) {
            throw std::runtime_error("call api not initialized");
            return false;
        }
        auto channel = cmux->get(CellularMux::Channel::Commands);
        return channel != nullptr && channel->cmd(at::AT::ATH);
        if (channel != nullptr) {
            auto response = channel->cmd(at::AT::ATH);
            if (response) {
                return true;
            }
        }
        return false;
    }

    bool Api::rejectCall()
    {
        if (cmux == nullptr) {
            throw std::runtime_error("call api not initialized");
            return false;
        }
        auto channel = cmux->get(CellularMux::Channel::Commands);
        return channel != nullptr && channel->cmd(at::AT::CHUP);
        if (channel != nullptr) {
            auto response = channel->cmd(at::AT::CHUP);
            if (response) {
                return true;
            }
        }
        return false;
    }

    bool Api::areCallsFromFavouritesEnabled()

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +1 -1
@@ 1059,7 1059,7 @@ namespace cellular
    class GetVolteStateRequest : public sys::DataMessage
    {};

    struct GetVolteStateResponse : public sys::ResponseMessage
    struct GetVolteStateResponse : public sys::DataMessage
    {
        VolteState volteState;
        explicit GetVolteStateResponse(VolteState volteState) : volteState(volteState)

M module-services/service-cellular/src/ModemResetHandler.cpp => module-services/service-cellular/src/ModemResetHandler.cpp +8 -0
@@ 87,4 87,12 @@ namespace cellular::service
        onCellularStateSet(State::ST::StatusCheck);
        return true;
    }

    auto ModemResetHandler::performFunctionalityReset() -> bool
    {
        if (onFunctionalityReset) {
            return onFunctionalityReset();
        }
        return false;
    }
} // namespace cellular::service

M module-services/service-cellular/src/ModemResetHandler.hpp => module-services/service-cellular/src/ModemResetHandler.hpp +6 -0
@@ 30,6 30,11 @@ namespace cellular::service
         */
        auto performReboot() -> bool;
        /**
         * It performs functionality reset via AT command. It does not require cellular reinitialisation.
         * @return true on success
         */
        auto performFunctionalityReset() -> bool;
        /**
         * It handles STATUS pin changed event when any reset procedure is in progress, other case it's doing nothing.
         * @param isActive STATUS pin value. True when STATUS is active, false when it's inactive
         * @return true when event is handled, false when not


@@ 48,6 53,7 @@ namespace cellular::service
        std::function<void()> onTurnModemOff;
        std::function<bool()> onSoftReset;
        std::function<void()> onHardReset;
        std::function<bool()> onFunctionalityReset;

      private:
        enum class ProcedureInProgress

M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +40 -2
@@ 91,7 91,11 @@ namespace cellular::internal
                owner->bus.sendMulticast<notification::SimNotInserted>();
                return sys::MessageNone{};
            }
            return std::make_shared<request::sim::GetPinSettings::Response>(simCard->handleIsPinNeeded());
            auto simLockState = simCard->handleIsPinNeeded();
            if (!simLockState.has_value()) {
                return sys::MessageNone{};
            }
            return std::make_shared<request::sim::GetPinSettings::Response>(simLockState.value());
        });
        owner->connect(typeid(request::sim::ChangePin), [&](sys::Message *request) -> sys::MessagePointer {
            auto msg = static_cast<request::sim::ChangePin *>(request);


@@ 255,7 259,6 @@ namespace cellular::internal
                    result = false;
                }
                else {
                    auto channel = owner->cmux->get(CellularMux::Channel::Commands);
                    saveNewMultiPartSMSUIDCallback(multiPartSMSUID);

                    for (unsigned i = 0; i < partHandler.getPartsCount(); i++) {


@@ 400,6 403,25 @@ namespace cellular::internal
            }
            return false;
        };

        modemResetHandler->onFunctionalityReset = [this]() -> bool {
            auto channel = owner->cmux->get(CellularMux::Channel::Commands);
            if (channel == nullptr) {
                return false;
            }
            auto succeed  = false;
            auto response = channel->cmd(at::AT::CFUN_DISABLE_TRANSMITTING);
            if (response) {
                succeed = true;
            }
            constexpr auto delay = 200;
            vTaskDelay(pdMS_TO_TICKS(delay));
            response = channel->cmd(at::AT::CFUN_FULL_FUNCTIONALITY);
            if (response) {
                succeed |= true;
            }
            return succeed;
        };
    }

    void ServiceCellularPriv::initCSQHandler()


@@ 552,4 574,20 @@ namespace cellular::internal
            return sys::MessageNone{};
        });
    }

    void ServiceCellularPriv::privInit(at::BaseChannel *channel)
    {
        simCard->setChannel(channel);
        networkTime->setChannel(channel);
        simContacts->setChannel(channel);
        imeiGetHandler->setChannel(channel);
    }

    void ServiceCellularPriv::privDeinit()
    {
        simCard->setChannel(nullptr);
        networkTime->setChannel(nullptr);
        simContacts->setChannel(nullptr);
        imeiGetHandler->setChannel(nullptr);
    }
} // namespace cellular::internal

M module-services/service-cellular/src/ServiceCellularPriv.hpp => module-services/service-cellular/src/ServiceCellularPriv.hpp +3 -0
@@ 59,6 59,9 @@ namespace cellular::internal
        void setInitialMultiPartSMSUID(std::uint8_t uid);
        std::function<void(std::uint8_t uid)> saveNewMultiPartSMSUIDCallback;

        void privInit(at::BaseChannel *channel);
        void privDeinit();

      private:
        void initSimCard();
        void initSMSSendHandler();

M module-services/service-cellular/src/SimCard.cpp => module-services/service-cellular/src/SimCard.cpp +10 -2
@@ 70,7 70,7 @@ namespace cellular
            return true;
        }

        bool SimCard::handleIsPinNeeded() const
        std::optional<bool> SimCard::handleIsPinNeeded() const
        {
            return isPinNeeded();
        }


@@ 276,8 276,12 @@ namespace cellular
                               at::factory(at::AT::CLCK) + "\"SC\"," + (lock ? "1" : "0") + ",\"" + pin + "\"");
        }

        bool SimCard::isPinNeeded() const
        std::optional<bool> SimCard::isPinNeeded() const
        {
            if (not ready()) {
                return std::nullopt;
            }

            auto resp = channel->cmd(at::factory(at::AT::CLCK) + "\"SC\",2\r");
            int val   = 0;
            if (at::response::parseCLCK(resp, val)) {


@@ 288,6 292,10 @@ namespace cellular

        std::optional<at::SimState> SimCard::simState() const
        {
            if (not ready()) {
                return at::SimState::Unknown;
            }

            auto resp = channel->cmd(at::factory(at::AT::GET_CPIN));
            if (resp.code == at::Result::Code::OK) {
                if (resp.response.size()) {

M module-services/service-cellular/src/SimCard.hpp => module-services/service-cellular/src/SimCard.hpp +5 -4
@@ 84,7 84,7 @@ namespace cellular::service
         * Request message handlers
         */
        bool handleSetActiveSim(api::SimSlot sim);
        bool handleIsPinNeeded() const;
        std::optional<bool> handleIsPinNeeded() const;
        bool handleChangePin(const api::SimCode &old_pin, const api::SimCode &pin);
        bool handleUnblockWithPuk(const api::SimCode &puk, const api::SimCode &pin);
        bool handleSetPinLock(const api::SimCode &pin, api::SimPinState pinLock);


@@ 231,10 231,11 @@ namespace cellular::service
         */
        sim::Result changePin(const std::string &oldPin, const std::string &newPin) const;

        /** Check whether the pin needs to be provided, only for standard pin.
         * \return true if need pin to unlock SIM card functionality
        /** Check whether the PIN needs to be provided, only for standard PIN.
         * \return true if need PIN to unlock SIM card functionality, false if don't need, std::nullopt if SIM card
         * not ready
         */
        bool isPinNeeded() const;
        std::optional<bool> isPinNeeded() const;

        /** Process sim::Result from PIN lock/unlock operations
         * \param result result from operation (`sendCommand()`)

M module-services/service-cellular/src/VolteHandler.hpp => module-services/service-cellular/src/VolteHandler.hpp +13 -0
@@ 78,9 78,15 @@ namespace cellular::service
                    throw std::runtime_error("[VoLTE] failed to " + std::string(enable ? "enable" : "disable") +
                                             " IMS");
                }

                volteState = enable ? cellular::VolteState::SwitchingToOn : cellular::VolteState::SwitchingToOff;
                isFirstRunAfterSwitch = false;
            }
            else {
                if (volteState == cellular::VolteState::SwitchingToOn ||
                    volteState == cellular::VolteState::SwitchingToOff) {
                    isFirstRunAfterSwitch = true;
                }
                volteState = enable ? cellular::VolteState::On : cellular::VolteState::Off;
            }



@@ 92,11 98,18 @@ namespace cellular::service
            return volteState;
        }

        auto isFunctionalityResetNeeded() -> bool
        {
            return isFirstRunAfterSwitch;
        }

      private:
        std::string imsStateToString(response::qcfg_ims::IMSState imsState) const
        {
            return std::to_string(magic_enum::enum_integer(imsState));
        }

        cellular::VolteState volteState = cellular::VolteState::Undefined;
        bool isFirstRunAfterSwitch      = false;
    };
} // namespace cellular::service

M pure_changelog.md => pure_changelog.md +1 -1
@@ 42,7 42,7 @@
* Added tethering information on the status bar
* Added basic MMS handling
* Added run-time statistics for tasks
* Added VoLTE state in settings database
* Added VoLTE support

## [1.3.0 2022-08-04]