~aleteoryx/muditaos

c514fc53bbc54172d1f05d001029e227f22d06b3 — Kuba Kleczkowski 2 years ago 04922b9
[MOS-47] Fixed non closed USSD session

USSD pull session was not closed when USSD popup
was closed by back button. Also USSD code was slightly
refactored.
M module-apps/application-desktop/windows/MmiPullWindow.cpp => module-apps/application-desktop/windows/MmiPullWindow.cpp +13 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DesktopInputWidget.hpp"


@@ 7,6 7,7 @@

#include <i18n/i18n.hpp>
#include <service-appmgr/data/MmiActionsParams.hpp>
#include <service-cellular/CellularServiceAPI.hpp>

#include <string>



@@ 76,6 77,17 @@ void MmiPullWindow::onBeforeShow(ShowMode mode, SwitchData *data)

bool MmiPullWindow::onInput(const InputEvent &inputEvent)
{
    if (inputEvent.isShortRelease()) {
        switch (inputEvent.getKeyCode()) {
        case KeyCode::KEY_RF: {
            CellularServiceAPI::USSDRequest(this->application, cellular::USSDMessage::RequestType::abortSession, "");
            application->returnToPreviousWindow();
            return true;
        }
        default:
            break;
        }
    }
    return AppWindow::onInput(inputEvent);
}


M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +2 -0
@@ 21,6 21,8 @@ set(SOURCES
    src/volte/VolteAllowedUSList.cpp
    src/volte/VolteCapabilityHandlerCellular.cpp

    src/ussd/USSDHandler.cpp

    DTMFCode.cpp

    CellularServiceAPI.cpp

M module-services/service-cellular/CellularRequestHandler.cpp => module-services/service-cellular/CellularRequestHandler.cpp +5 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "service-cellular/CellularRequestHandler.hpp"


@@ 22,6 22,9 @@
#include "service-cellular/requests/CallWaitingRequest.hpp"
#include "service-cellular/requests/RejectRequest.hpp"

#include <service-cellular/src/ServiceCellularPriv.hpp>
#include <service-cellular/src/ussd/USSDHandler.hpp>

#include <service-appmgr/Constants.hpp>

#include <service-audio/AudioServiceAPI.hpp>


@@ 53,8 56,7 @@ void CellularRequestHandler::handle(cellular::UssdRequest &request, at::Result &
    auto requestHandled = request.checkModemResponse(result);

    if (requestHandled) {
        cellular.ussdState = ussd::State::pullRequestSent;
        cellular.setUSSDTimer();
        cellular.externalUSSDRequestHandled();
    }
    else {
        sendMmiResult(requestHandled);

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +5 -13
@@ 1,9 1,12 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CellularUrcHandler.hpp"
#include "messages.hpp"

#include "service-cellular/src/ServiceCellularPriv.hpp"
#include "service-cellular/src/ussd/USSDHandler.hpp"

#include <service-antenna/AntennaServiceAPI.hpp>
#include <service-appmgr/Constants.hpp>
#include <service-time/Constants.hpp>


@@ 90,25 93,14 @@ void CellularUrcHandler::Handle(Cusd &urc)
    urc.setHandled(true);

    if (urc.isActionNeeded()) {
        switch (cellularService.ussdState) {
        case ussd::State::pullRequestSent:
            cellularService.ussdState = ussd::State::pullResponseReceived;
            [[fallthrough]];
        case ussd::State::pushSession: {
            cellularService.setUSSDTimer();
        if (cellularService.handleUSSDURC()) {
            auto msg = std::make_shared<cellular::MMIResponseMessage>(*message);
            cellularService.bus.sendUnicast(msg, service::name::appmgr);
            return;
        }
        default:
            LOG_WARN("unexpected URC handling state: %s", magic_enum::enum_name(cellularService.ussdState).data());
            return;
        }
    }

    CellularServiceAPI::USSDRequest(&cellularService, cellular::USSDMessage::RequestType::abortSession);
    cellularService.ussdState = ussd::State::sessionAborted;
    cellularService.setUSSDTimer();
    auto msg = std::make_shared<cellular::MMIPushMessage>(*message);
    cellularService.bus.sendUnicast(msg, service::name::appmgr);
}

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +16 -72
@@ 143,7 143,7 @@ ServiceCellular::ServiceCellular()
    stateTimer = sys::TimerFactory::createPeriodicTimer(
        this, "state", std::chrono::milliseconds{1000}, [&](sys::Timer &) { handleStateTimer(); });
    ussdTimer = sys::TimerFactory::createPeriodicTimer(
        this, "ussd", std::chrono::milliseconds{1000}, [this](sys::Timer &) { handleUSSDTimer(); });
        this, "ussd", std::chrono::milliseconds{1000}, [this](sys::Timer &) { priv->ussdHandler->handleUSSDTimer(); });
    sleepTimer = sys::TimerFactory::createSingleShotTimer(
        this, "sleep", constants::sleepTimerInterval, [this](sys::Timer &) { SleepTimerHandler(); });
    connectionTimer =


@@ 163,6 163,9 @@ ServiceCellular::ServiceCellular()
        csqCounter.clearCounter();
    });

    priv->ussdHandler->setTimerStartCallback([this]() { ussdTimer.start(); });
    priv->ussdHandler->setTimerStopCallback([this]() { ussdTimer.stop(); });

    notificationCallback = [this](std::string &data) {
        LOG_DEBUG("Notifications callback called with %u data bytes", static_cast<unsigned int>(data.size()));



@@ 1208,6 1211,16 @@ std::vector<std::string> ServiceCellular::getNetworkInfo()
    return data;
}

void ServiceCellular::externalUSSDRequestHandled()
{
    priv->ussdHandler->externalRequestHandled();
}

bool ServiceCellular::handleUSSDURC()
{
    return priv->ussdHandler->handleURC();
}

std::vector<std::string> get_last_AT_error(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::CEER);


@@ 1601,76 1614,6 @@ void ServiceCellular::handle_power_state_change()
    }
}

bool ServiceCellular::handleUSSDRequest(cellular::USSDMessage::RequestType requestType, const std::string &request)
{
    constexpr uint32_t commandTimeout = 120000;

    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel != nullptr) {
        if (requestType == cellular::USSDMessage::RequestType::pullSessionRequest) {
            channel->cmd(at::AT::SMS_GSM);
            std::string command = at::factory(at::AT::CUSD_SEND) + request + ",15";
            auto result         = channel->cmd(command, std::chrono::milliseconds(commandTimeout));
            if (result.code == at::Result::Code::OK) {
                ussdState = ussd::State::pullRequestSent;
                setUSSDTimer();
            }
        }
        else if (requestType == cellular::USSDMessage::RequestType::abortSession) {

            ussdState   = ussd::State::sessionAborted;
            auto result = channel->cmd(at::AT::CUSD_CLOSE_SESSION);
            if (result.code == at::Result::Code::OK) {
                CellularServiceAPI::USSDRequest(this, cellular::USSDMessage::RequestType::pushSessionRequest);
            }
            else {
                CellularServiceAPI::USSDRequest(this, cellular::USSDMessage::RequestType::abortSession);
            }
        }
        else if (requestType == cellular::USSDMessage::RequestType::pushSessionRequest) {

            ussdState   = ussd::State::pushSession;
            auto result = channel->cmd(at::AT::CUSD_OPEN_SESSION);
            if (result.code == at::Result::Code::OK) {}
        }
        return true;
    }
    return false;
}

void ServiceCellular::handleUSSDTimer(void)
{
    if (ussdTimeout > 0) {
        ussdTimeout -= 1;
    }
    else {
        LOG_WARN("USSD timeout occurred, aborting current session");
        ussdTimer.stop();
        CellularServiceAPI::USSDRequest(this, cellular::USSDMessage::RequestType::abortSession);
    }
}
void ServiceCellular::setUSSDTimer(void)
{
    switch (ussdState) {
    case ussd::State::pullRequestSent:
        ussdTimeout = ussd::pullResponseTimeout;
        break;
    case ussd::State::pullResponseReceived:
        ussdTimeout = ussd::pullSesionTimeout;
        break;
    case ussd::State::pushSession:
    case ussd::State::sessionAborted:
    case ussd::State::none:
        ussdTimeout = ussd::noTimeout;
        break;
    }
    if (ussdTimeout == ussd::noTimeout) {
        ussdTimer.stop();
        return;
    }
    ussdTimer.start();
}

std::shared_ptr<cellular::RawCommandRespAsync> ServiceCellular::handleCellularStartOperatorsScan(
    cellular::StartOperatorsScanMessage *msg)
{


@@ 2091,7 2034,8 @@ auto ServiceCellular::handleCellularDtmfRequestMessage(sys::Message *msg) -> std
auto ServiceCellular::handleCellularUSSDMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    auto message = static_cast<cellular::USSDMessage *>(msg);
    return std::make_shared<cellular::ResponseMessage>(handleUSSDRequest(message->type, message->data));
    return std::make_shared<cellular::ResponseMessage>(
        priv->ussdHandler->handleUSSDRequest(message->type, message->data));
}

auto ServiceCellular::handleStateRequestMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>

M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +3 -11
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 96,7 96,8 @@ class ServiceCellular : public sys::Service
    bool getIMSI(std::string &destination, bool fullNumber = false);
    std::vector<std::string> getNetworkInfo();

    auto areCallsFromFavouritesEnabled() -> bool;
    void externalUSSDRequestHandled();
    bool handleUSSDURC();

  private:
    at::ATURCStream atURCStream;


@@ 136,8 137,6 @@ class ServiceCellular : public sys::Service
    std::unique_ptr<call::Call> ongoingCall;
    std::vector<CalllogRecord> tetheringCalllog;

    ussd::State ussdState = ussd::State::none;

    cellular::service::URCCounter csqCounter;

    bool nextPowerStateChangeAwaiting = false;


@@ 214,15 213,8 @@ class ServiceCellular : public sys::Service
    // db response handlers
    auto handle(db::query::SMSSearchByTypeResult *response) -> bool;

    // ussd handlers
    uint32_t ussdTimeout = 0;
    void setUSSDTimer();
    bool handleUSSDRequest(cellular::USSDMessage::RequestType requestType, const std::string &request = "");
    bool handleIMEIRequest();

    bool handleUSSDURC();
    void handleUSSDTimer();

    std::shared_ptr<cellular::RawCommandRespAsync> handleCellularStartOperatorsScan(
        cellular::StartOperatorsScanMessage *msg);


M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +52 -1
@@ 49,12 49,14 @@ namespace cellular::internal
          volteCapability{
              std::make_unique<VolteCapabilityHandler>(std::make_unique<cellular::service::ImsiParserUS>(),
                                                       std::make_unique<cellular::service::VolteAllowedUSList>(),
                                                       std::make_unique<cellular::service::VolteCapabilityCellular>())}
                                                       std::make_unique<cellular::service::VolteCapabilityCellular>())},
          ussdHandler{std::make_unique<USSDHandler>()}
    {
        initSimCard();
        initSMSSendHandler();
        initTetheringHandler();
        initModemResetHandler();
        initUSSDHandler();
    }

    void ServiceCellularPriv::initSimCard()


@@ 550,6 552,54 @@ namespace cellular::internal
        owner->csqTimer.start();
    }

    void ServiceCellularPriv::initUSSDHandler()
    {
        ussdHandler->onOpenPushSession = [this]() -> bool {
            auto channel = owner->cmux->get(CellularMux::Channel::Commands);
            if (channel == nullptr) {
                LOG_ERROR("No cmux channel provided!");
                return false;
            }
            auto result = channel->cmd(at::AT::CUSD_OPEN_SESSION);
            return result.code == at::Result::Code::OK;
        };

        ussdHandler->onAbortSession = [this]() -> bool {
            auto channel = owner->cmux->get(CellularMux::Channel::Commands);
            if (channel == nullptr) {
                LOG_ERROR("No cmux channel provided!");
                return false;
            }
            auto result = channel->cmd(at::AT::CUSD_CLOSE_SESSION);
            return result.code == at::Result::Code::OK;
        };

        ussdHandler->onSendUssdCode = [this](const std::string &request) -> bool {
            const std::string commandDcs(",15");
            auto channel = owner->cmux->get(CellularMux::Channel::Commands);
            if (channel == nullptr) {
                LOG_ERROR("No cmux channel provided!");
                return false;
            }

            channel->cmd(at::AT::SMS_GSM);
            std::string command = at::factory(at::AT::CUSD_SEND) + request + commandDcs;
            auto result         = channel->cmd(command, std::chrono::seconds(120));
            return result.code == at::Result::Code::OK;
        };

        ussdHandler->onRequestAbortSession = [this]() {
            auto message = std::make_shared<cellular::USSDMessage>(cellular::USSDMessage::RequestType::abortSession);
            owner->bus.sendUnicast(std::move(message), ::service::name::cellular);
        };

        ussdHandler->onRequestOpenPushSession = [this]() {
            auto message =
                std::make_shared<cellular::USSDMessage>(cellular::USSDMessage::RequestType::pushSessionRequest);
            owner->bus.sendUnicast(std::move(message), ::service::name::cellular);
        };
    }

    void ServiceCellularPriv::connectCSQHandler()
    {
        owner->bus.channels.push_back(sys::BusChannel::PhoneLockChanges);


@@ 629,4 679,5 @@ namespace cellular::internal
        simContacts->setChannel(nullptr);
        imeiGetHandler->setChannel(nullptr);
    }

} // namespace cellular::internal

M module-services/service-cellular/src/ServiceCellularPriv.hpp => module-services/service-cellular/src/ServiceCellularPriv.hpp +5 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 17,9 17,11 @@
#include "ModemResetHandler.hpp"
#include "CSQHandler.hpp"
#include "volte/VolteCapabilityHandler.hpp"
#include "ussd/USSDHandler.hpp"

namespace cellular::internal
{
    using cellular::ussd::USSDHandler;
    using service::CSQHandler;
    using service::ModemResetHandler;
    using service::NetworkTime;


@@ 29,7 31,6 @@ namespace cellular::internal
    using service::TetheringHandler;
    using service::VolteCapabilityHandler;
    using service::VolteHandler;

    class ServiceCellularPriv
    {
        ServiceCellular *owner;


@@ 45,6 46,7 @@ namespace cellular::internal
        std::unique_ptr<ModemResetHandler> modemResetHandler;
        std::unique_ptr<CSQHandler> csqHandler;
        std::unique_ptr<VolteCapabilityHandler> volteCapability;
        std::unique_ptr<USSDHandler> ussdHandler;

        State::PowerState nextPowerState = State::PowerState::Off;
        std::uint8_t multiPartSMSUID     = 0;


@@ 71,6 73,7 @@ namespace cellular::internal
        void initTetheringHandler();
        void initModemResetHandler();
        void initCSQHandler();
        void initUSSDHandler();

        /** Send SMS action used by the SMSSendHandler
         * \param record SMS record to send

A module-services/service-cellular/src/ussd/USSDHandler.cpp => module-services/service-cellular/src/ussd/USSDHandler.cpp +102 -0
@@ 0,0 1,102 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "USSDHandler.hpp"

namespace cellular::ussd
{

    bool USSDHandler::handleUSSDRequest(cellular::USSDMessage::RequestType requestType, const std::string &request)
    {
        if (requestType == cellular::USSDMessage::RequestType::pullSessionRequest) {
            if (onSendUssdCode && onSendUssdCode(request)) {
                ussdState = ussd::State::pullRequestSent;
                setUSSDTimer();
            }
            return true;
        }

        if (requestType == cellular::USSDMessage::RequestType::abortSession) {
            if (onAbortSession && onAbortSession()) {
                ussdState = ussd::State::sessionAborted;
                setUSSDTimer();
                if (onRequestOpenPushSession)
                    onRequestOpenPushSession();
            }
            else {
                if (onRequestAbortSession)
                    onRequestAbortSession();
            }
            return true;
        }

        if (requestType == cellular::USSDMessage::RequestType::pushSessionRequest) {

            if (onOpenPushSession && onOpenPushSession()) {
                ussdState = ussd::State::pushSession;
                setUSSDTimer();
            }
            return true;
        }

        return false;
    }
    void USSDHandler::handleUSSDTimer()
    {
        if (ussdTimeout > 0) {
            ussdTimeout -= 1;
        }
        else {
            LOG_WARN("USSD timeout occurred, aborting current session");
            onTimerStop();
            if (onRequestAbortSession)
                onRequestAbortSession();
        }
    }
    void USSDHandler::setUSSDTimer()
    {
        if (not onTimerStart || not onTimerStop) {
            LOG_ERROR("No onTimerStart or onTimerStop callback provided!");
            return;
        }
        switch (ussdState) {
        case ussd::State::pullRequestSent:
            ussdTimeout = pullResponseTimeout;
            break;
        case ussd::State::pullResponseReceived:
            ussdTimeout = pullSesionTimeout;
            break;
        case ussd::State::pushSession:
        case ussd::State::sessionAborted:
        case ussd::State::none:
            ussdTimeout = noTimeout;
            break;
        }
        if (ussdTimeout == noTimeout) {
            onTimerStop();
            return;
        }
        onTimerStart();
    }
    void USSDHandler::externalRequestHandled()
    {
        ussdState = ussd::State::pullRequestSent;
        setUSSDTimer();
    }

    auto USSDHandler::handleURC() -> bool
    {
        switch (ussdState) {
        case ussd::State::pullRequestSent:
            ussdState = State::pullResponseReceived;
            [[fallthrough]];
        case ussd::State::pushSession: {
            setUSSDTimer();
            return true;
        }
        default:
            LOG_WARN("unexpected URC handling state: %s", magic_enum::enum_name(ussdState).data());
            return false;
        }
    }
}; // namespace cellular::ussd

A module-services/service-cellular/src/ussd/USSDHandler.hpp => module-services/service-cellular/src/ussd/USSDHandler.hpp +55 -0
@@ 0,0 1,55 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <service-cellular/CellularMessage.hpp>
#include <cstdint>

namespace cellular::ussd
{

    constexpr std::uint32_t pullResponseTimeout = 30;
    constexpr std::uint32_t pullSesionTimeout   = 60;
    constexpr std::uint32_t noTimeout           = 0;

    enum class State
    {
        none,
        pushSession,
        pullRequestSent,
        pullResponseReceived,
        sessionAborted
    };

    class USSDHandler
    {
      public:
        bool handleUSSDRequest(cellular::USSDMessage::RequestType requestType, const std::string &request = "");
        void handleUSSDTimer();
        void externalRequestHandled();
        auto handleURC() -> bool;
        void setUSSDTimer();

        void setTimerStartCallback(std::function<void(void)> callback)
        {
            onTimerStart = callback;
        }

        void setTimerStopCallback(std::function<void(void)> callback)
        {
            onTimerStop = callback;
        }

        std::function<void(void)> onTimerStop;
        std::function<void(void)> onTimerStart;
        std::function<bool(void)> onOpenPushSession;
        std::function<bool(void)> onAbortSession;
        std::function<bool(const std::string &)> onSendUssdCode;
        std::function<void(void)> onRequestAbortSession;
        std::function<void(void)> onRequestOpenPushSession;

      private:
        State ussdState      = State::none;
        uint32_t ussdTimeout = 0;
    };
} // namespace cellular::ussd

M module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +9 -0
@@ 122,3 122,12 @@ add_catch2_executable(
        LIBS
        module-cellular
)

add_catch2_executable(
        NAME
        cellular-ussd-handler
        SRCS
        unittest_ussdHandler.cpp
        LIBS
        module-cellular
)

A module-services/service-cellular/tests/unittest_ussdHandler.cpp => module-services/service-cellular/tests/unittest_ussdHandler.cpp +148 -0
@@ 0,0 1,148 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>

#include <module-services/service-cellular/src/ussd/USSDHandler.hpp>

TEST_CASE("ussd handler")
{
    using namespace cellular::ussd;

    USSDHandler handler;
    auto onSendCodeCalled               = 0;
    auto onAbortSessionCalled           = 0;
    auto onOpenPushSessionCalled        = 0;
    auto onRequestOpenPushSessionCalled = 0;
    auto onRequestAbortSessionCalled    = 0;

    auto onTimerStartCalled = 0;
    auto onTimerStopCalled  = 0;

    handler.onSendUssdCode = [&onSendCodeCalled](std::string) -> bool {
        onSendCodeCalled++;
        return true;
    };

    handler.onAbortSession = [&onAbortSessionCalled]() -> bool {
        onAbortSessionCalled++;
        return true;
    };

    handler.onOpenPushSession = [&onOpenPushSessionCalled]() -> bool {
        onOpenPushSessionCalled++;
        return true;
    };

    handler.onRequestOpenPushSession = [&onRequestOpenPushSessionCalled]() -> bool {
        onRequestOpenPushSessionCalled++;
        return true;
    };

    handler.onRequestAbortSession = [&onRequestAbortSessionCalled]() -> bool {
        onRequestAbortSessionCalled++;
        return true;
    };

    handler.onTimerStart = [&onTimerStartCalled]() { onTimerStartCalled++; };

    handler.onTimerStop = [&onTimerStopCalled]() { onTimerStopCalled++; };

    SECTION("HandleUSSDRequest - ok pull session request")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::pullSessionRequest);
        REQUIRE(onTimerStartCalled == 1);
        REQUIRE(onSendCodeCalled == 1);

        REQUIRE(onAbortSessionCalled == 0);
        REQUIRE(onOpenPushSessionCalled == 0);
        REQUIRE(onRequestOpenPushSessionCalled == 0);
        REQUIRE(onTimerStopCalled == 0);
        REQUIRE(onRequestAbortSessionCalled == 0);
    }

    SECTION("HandleUSSDRequest - ok abort session request")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::abortSession);

        REQUIRE(onAbortSessionCalled == 1);
        REQUIRE(onRequestOpenPushSessionCalled == 1);
        REQUIRE(onTimerStopCalled == 1);

        REQUIRE(onOpenPushSessionCalled == 0);
        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onSendCodeCalled == 0);
        REQUIRE(onRequestAbortSessionCalled == 0);
    }

    SECTION("HandleUSSDRequest - ok push session request")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::pushSessionRequest);
        REQUIRE(onTimerStopCalled == 1);
        REQUIRE(onOpenPushSessionCalled == 1);

        REQUIRE(onSendCodeCalled == 0);
        REQUIRE(onAbortSessionCalled == 0);
        REQUIRE(onRequestOpenPushSessionCalled == 0);
        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onRequestAbortSessionCalled == 0);
    }

    SECTION("HandleUSSDRequest - failed abort session request")
    {
        handler.onAbortSession = [&onAbortSessionCalled]() -> bool {
            onAbortSessionCalled++;
            return false;
        };
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::abortSession);

        REQUIRE(onAbortSessionCalled == 1);
        REQUIRE(onRequestOpenPushSessionCalled == 0);
        REQUIRE(onRequestAbortSessionCalled == 1);

        REQUIRE(onOpenPushSessionCalled == 0);
        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onSendCodeCalled == 0);
        REQUIRE(onTimerStopCalled == 0);
    }

    SECTION("setUSSDTimer - pullSessionRequest")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::pullSessionRequest);

        REQUIRE(onTimerStartCalled == 1);
        REQUIRE(onTimerStopCalled == 0);

        onTimerStartCalled = 0;
        for (std::uint32_t i = 0; i < pullResponseTimeout; i++) {
            handler.handleUSSDTimer();
        }
        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onTimerStopCalled == 0);

        handler.handleUSSDTimer();
        REQUIRE(onTimerStopCalled == 1);
    }

    SECTION("setUSSDTimer - abortSession")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::abortSession);

        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onTimerStopCalled == 1);

        handler.handleUSSDTimer();
        REQUIRE(onTimerStopCalled == 2);
    }

    SECTION("setUSSDTimer - pushSession")
    {
        handler.handleUSSDRequest(cellular::USSDMessage::RequestType::abortSession);

        REQUIRE(onTimerStartCalled == 0);
        REQUIRE(onTimerStopCalled == 1);

        handler.handleUSSDTimer();
        REQUIRE(onTimerStopCalled == 2);
    }
}

M pure_changelog.md => pure_changelog.md +1 -0
@@ 63,6 63,7 @@
* Fixed returning to call screen from message template
* Fixed displaying wrong information on screen after rejecting call with SMS template
* Fixed lack of contact search list update when returning to list after contact edition
* Fixed wrong USSD flow when user closed USSD popup with back button

## [1.6.0 2023-02-27]