~aleteoryx/muditaos

320174eafc1530c4ae4610499cc5466c9c7f347c — kkleczkowski 5 years ago c42f977
[EGD-4522] USSD sesion handling (#1121)

Added USSD sesion handlig and small fixes on USSD.

Session handling was needed to show proper window on new incoming USSD code.

Co-authored-by: Kuba Kleczkowski <dd>
M changelog.md => changelog.md +1 -0
@@ 19,6 19,7 @@
* `[text]` Added cursor starting position handling.
* `[alarms]` Added main window
* `[PowerManagement]` PowerManagement: Enable FreeRTOS Run Time Statistics
* `[cellular]` USSD session handling.

### Changed


M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +0 -21
@@ 12,7 12,6 @@
#include "windows/Info.hpp"
#include "windows/LanguageWindow.hpp"
#include "windows/SettingsMainWindow.hpp"
#include "windows/USSDWindow.hpp"

#include "windows/UITestWindow.hpp"



@@ 89,22 88,6 @@ namespace app
        // this variable defines whether message was processed.
        bool handled = true;

        if (msgl->messageType == MessageType::CellularNotification) {
            auto msg = dynamic_cast<CellularNotificationMessage *>(msgl);
            if (msg != nullptr) {
                if (msg->type == CellularNotificationMessage::Type::NewIncomingUSSD) {

                    auto window = this->getCurrentWindow();
                    if (window->getName() == gui::window::name::ussd_window) {
                        auto ussdWindow = dynamic_cast<gui::USSDWindow *>(window);
                        if (ussdWindow != nullptr) {
                            ussdWindow->handleIncomingUSSD(msg->data);
                        }
                    }
                }
            }
        }

        if (handled)
            return std::make_shared<sys::ResponseMessage>();
        else


@@ 177,10 160,6 @@ namespace app
                                      return std::make_unique<gui::CellularPassthroughWindow>(app);
                                  });
        }

        windowsFactory.attach(gui::window::name::ussd_window, [](Application *app, const std::string &name) {
            return std::make_unique<gui::USSDWindow>(app);
        });
    }

    void ApplicationSettings::destroyUserInterface()

M module-apps/application-settings/CMakeLists.txt => module-apps/application-settings/CMakeLists.txt +0 -2
@@ 28,7 28,6 @@ target_sources( ${PROJECT_NAME}
        windows/FotaWindow.cpp
        windows/Fota.cpp
        windows/SettingsChange.cpp
        windows/USSDWindow.cpp
        windows/EinkModeWindow.cpp

    PUBLIC


@@ 36,7 35,6 @@ target_sources( ${PROJECT_NAME}
        windows/SettingsMainWindow.hpp
        windows/LanguageWindow.hpp
        windows/DateTimeWindow.hpp
        windows/USSDWindow.hpp
)

add_dependencies(${PROJECT_NAME} version)

M module-apps/application-settings/windows/SettingsMainWindow.cpp => module-apps/application-settings/windows/SettingsMainWindow.cpp +0 -2
@@ 8,7 8,6 @@
#include "log/log.hpp"
#include "CellularPassthroughWindow.hpp"
#include "FotaWindow.hpp"
#include "USSDWindow.hpp"
#include "EinkModeWindow.hpp"

std::list<gui::Option> mainWindowOptions(app::Application *app)


@@ 40,7 39,6 @@ std::list<gui::Option> mainWindowOptions(app::Application *app)
        addMenu(i18("app_settings_cellular_passthrough"), gui::window::cellular_passthrough::window_name);
    }
    addMenu(i18("Fota update"), gui::window::name::fota_window);
    addMenu(i18("USSD test"), gui::window::name::ussd_window);
    addMenu("Eink Mode", gui::window::name::eink);
    addMenu(i18("app_settings_display"));
    addMenu(i18("app_settings_phone_modes"));

D module-apps/application-settings/windows/USSDWindow.cpp => module-apps/application-settings/windows/USSDWindow.cpp +0 -120
@@ 1,120 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "USSDWindow.hpp"
#include "../ApplicationSettings.hpp"
#include "Label.hpp"
#include "Margins.hpp"
#include "module-utils/i18n/i18n.hpp"
#include "messages/AppMessage.hpp"
#include <service-appmgr/model/ApplicationManager.hpp>
#include <GridLayout.hpp>
#include <Style.hpp>
#include <functional>
#include <memory>
#include <Font.hpp>
#include <service-cellular/CellularServiceAPI.hpp>

namespace gui
{

    USSDWindow::USSDWindow(app::Application *app) : AppWindow(app, gui::window::name::ussd_window)
    {
        buildInterface();
    }

    void USSDWindow::rebuild()
    {}

    void USSDWindow::buildInterface()
    {
        AppWindow::buildInterface();
        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle("USSD test");

        uint32_t h = style::settings::ussd::commonYPos;

        incomingLabel = addTitle("Incoming code");
        incomingLabel->setPosition(style::settings::ussd::commonXPos, h);
        h += style::settings::ussd::commonLabelH;

        received = addText();

        received->setPosition(style::settings::ussd::commonXPos, h);
        h += style::settings::ussd::commonTextH;

        outgoingLabel = addTitle("Outgoing code");
        outgoingLabel->setPosition(style::settings::ussd::commonXPos, h);
        h += style::settings::ussd::commonLabelH;

        pullToSend = addText();
        pullToSend->setPosition(style::settings::ussd::commonXPos, h);
        pullToSend->activatedCallback = [=](gui::Item &) {
            std::string data = pullToSend->getText().c_str();
            CellularServiceAPI::USSDRequest(
                this->application, CellularUSSDMessage::RequestType::pullSesionRequest, data);
            return true;
        };
        pullToSend->setEditMode(EditMode::Edit);
        pullToSend->setInputMode(new InputMode(
            {InputMode::digit},
            [=](const UTF8 &text) { bottomBarTemporaryMode(text); },
            [=]() { bottomBarRestoreFromTemporaryMode(); },
            [=]() { selectSpecialCharacter(); }));
        setFocusItem(pullToSend);
    }

    void USSDWindow::destroyInterface()
    {
        erase();
    }

    void USSDWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {}

    gui::Label *USSDWindow::addTitle(const UTF8 &title)
    {
        gui::Label *label = new gui::Label(this,
                                           style::settings::ussd::commonXPos,
                                           style::settings::ussd::commonYPos,
                                           style::settings::ussd::commonW,
                                           style::settings::ussd::commonLabelH,
                                           title);
        label->setFilled(false);
        label->setPenFocusWidth(style::window::default_border_focus_w);
        label->setPenWidth(style::window::default_border_no_focus_w);

        label->setFont(style::window::font::verysmall);
        label->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));

        return label;
    }
    gui::Text *USSDWindow::addText(void)
    {
        gui::Text *text = new gui::Text(this,
                                        style::settings::ussd::commonXPos,
                                        style::settings::ussd::commonYPos,
                                        style::settings::ussd::commonW,
                                        style::settings::ussd::commonTextH);
        text->setFilled(false);
        text->setPenFocusWidth(style::window::default_border_focus_w);
        text->setPenWidth(style::window::default_border_no_focus_w);

        text->setFont(style::window::font::verysmall);
        text->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        text->setEdges(RectangleEdge::All);
        return text;
    }

    void USSDWindow::handleIncomingUSSD(const std::string &data)
    {
        received->setText(UTF8(data));
    }
} // namespace gui

D module-apps/application-settings/windows/USSDWindow.hpp => module-apps/application-settings/windows/USSDWindow.hpp +0 -49
@@ 1,49 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <functional>
#include <string>

#include "AppWindow.hpp"
#include "gui/widgets/Image.hpp"
#include "gui/widgets/Label.hpp"
#include "gui/widgets/Window.hpp"
#include <memory>
#include <Text.hpp>

namespace gui
{
    namespace window
    {
        namespace name
        {
            inline constexpr auto ussd_window = "ussd_window";
        } // namespace name
    }     // namespace window
    class USSDWindow : public AppWindow
    {
      protected:
        gui::Label *incomingLabel = nullptr;
        gui::Label *outgoingLabel = nullptr;

        gui::Text *pullToSend = nullptr;
        gui::Text *received   = nullptr;

        gui::VBox *box = nullptr;

        gui::Label *addTitle(const UTF8 &title);
        gui::Text *addText(void);

      public:
        USSDWindow(app::Application *app);

        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        void set_navigation();
        void handleIncomingUSSD(const std::string &data);
    };
} // namespace gui

M module-cellular/at/Urc.hpp => module-cellular/at/Urc.hpp +2 -3
@@ 18,7 18,7 @@ namespace at::urc
         * @param urcHead - Urc message head
         * @param tokenDelimiter - sign that separates parameters in Urc message
         */
        Urc(const std::string &urcBody, const std::string &urcHead = std::string(), char tokenDelimiter = ',');
        Urc(const std::string &urcBody, const std::string &urcHead = std::string());

        virtual ~Urc() = default;



@@ 80,9 80,8 @@ namespace at::urc
        /**
         * Splits Urc into head and tokenized data, cleans tokens from whitespaces and quotes
         * @param str - string to be split
         * @param tokenDelimiter - sign that separates parameters in Urc message
         */
        void split(const std::string &str, char tokenDelimiter = ',');
        virtual void split(const std::string &str);
    };

} // namespace at::urc

M module-cellular/at/UrcCusd.hpp => module-cellular/at/UrcCusd.hpp +2 -1
@@ 30,7 30,7 @@ namespace at::urc
            OperationNotSupported,
            NetworkTimeOut
        };

        Cusd(const std::string &urcBody, const std::string &urcHead = std::string());
        static constexpr std::string_view head = "+CUSD";
        static auto isURC(const std::string uHead) -> bool
        {


@@ 45,6 45,7 @@ namespace at::urc
        [[nodiscard]] auto getMessage() const noexcept -> std::optional<std::string>;
        [[nodiscard]] auto getStatus() const noexcept -> std::optional<StatusType>;
        [[nodiscard]] auto getDCS() const noexcept -> std::optional<int>;
        void split(const std::string &str) override;

        void Handle(UrcHandler &h) final
        {

M module-cellular/at/src/Commands.cpp => module-cellular/at/src/Commands.cpp +1 -1
@@ 30,7 30,7 @@ namespace at
        case commadsSet::smsInit:
            ret.push_back(AT::SET_SMS_STORAGE);
            ret.push_back(AT::SMS_TEXT_FORMAT);
            ret.push_back(AT::SMS_UCSC2);
            ret.push_back(AT::SMS_GSM);
            ret.push_back(AT::LIST_MESSAGES);
            break;
        }

M module-cellular/at/src/Urc.cpp => module-cellular/at/src/Urc.cpp +5 -4
@@ 6,14 6,15 @@

namespace at::urc
{
    Urc::Urc(const std::string &urcBody, const std::string &urcHead, char tokenDelimiter)
        : urcBody(urcBody), urcHead(urcHead)
    Urc::Urc(const std::string &urcBody, const std::string &urcHead) : urcBody(urcBody), urcHead(urcHead)
    {
        split(urcBody, tokenDelimiter);
        split(urcBody);
    }

    void Urc::split(const std::string &str, char tokenDelimiter)
    void Urc::split(const std::string &str)
    {
        constexpr char tokenDelimiter = ',';

        tokens                            = utils::split(str, tokenDelimiter);
        constexpr auto urcStringDelimiter = "\"";
        for (auto &t : tokens) {

M module-cellular/at/src/UrcCusd.cpp => module-cellular/at/src/UrcCusd.cpp +29 -0
@@ 7,6 7,10 @@

using namespace at::urc;

Cusd::Cusd(const std::string &urcBody, const std::string &urcHead) : Urc(urcBody, urcHead)
{
    split(urcBody);
}
auto Cusd::isValid() const noexcept -> bool
{
    return tokens.size() == magic_enum::enum_count<Tokens>();


@@ 70,3 74,28 @@ auto Cusd::getDCS() const noexcept -> std::optional<int>

    return dcs;
}
void Cusd::split(const std::string &str)
{
    constexpr auto commaString    = ",";
    constexpr char tokenDelimiter = '\"';

    tokens = utils::split(str, tokenDelimiter);
    for (auto &t : tokens) {
        utils::findAndReplaceAll(t, "\"", "");
        t = utils::trim(t);
    }

    auto dcs       = tokens[Tokens::DCS];
    auto dcsTokens = utils::split(dcs, commaString);

    if (dcsTokens.size() > 1) {
        tokens.pop_back();
        for (auto el : dcsTokens) {
            tokens.push_back(el);
        }
    }
    for (auto &t : tokens) {
        utils::findAndReplaceAll(t, commaString, "");
        t = utils::trim(t);
    }
}

M module-cellular/at/src/UrcFactory.cpp => module-cellular/at/src/UrcFactory.cpp +0 -1
@@ 19,7 19,6 @@ std::unique_ptr<Urc> UrcFactory::Create(const std::string &urcMessage)
    if (urcMessage.empty()) {
        return std::make_unique<Urc>(std::string());
    }

    const char headDelimiter = ':';
    auto it                  = std::find(urcMessage.begin(), urcMessage.end(), headDelimiter);
    std::string head         = std::string(urcMessage.begin(), it);

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +11 -8
@@ 9,6 9,7 @@
#include <module-sys/Service/Bus.hpp>
#include <service-antenna/AntennaServiceAPI.hpp>
#include <service-evtmgr/Constants.hpp>
#include <service-appmgr/Controller.hpp>

// this static function will be replaced by Settings API
static bool isSettingsAutomaticTimeSyncEnabled()


@@ 65,26 66,28 @@ void CellularUrcHandler::Handle(Cmti &urc)

void CellularUrcHandler::Handle(Cusd &urc)
{
    response     = std::nullopt;
    auto message = urc.getMessage();
    if (!message) {
        return;
    }

    if (urc.isActionNeeded()) {
        if (cellularService.ussdState == ussd::State::pullRequestSent) {
            cellularService.ussdState = ussd::State::pullResponseReceived;
            cellularService.setUSSDTimer();
            auto msg = std::make_shared<CellularMMIResponseMessage>(*message);
            sys::Bus::SendUnicast(msg, app::manager::ApplicationManager::ServiceName, &cellularService);
        }
    }
    else {
        CellularServiceAPI::USSDRequest(&cellularService, CellularUSSDMessage::RequestType::abortSesion);
        cellularService.ussdState = ussd::State::sesionAborted;
        cellularService.setUSSDTimer();
        auto msg = std::make_shared<CellularMMIPushMessage>(*message);
        sys::Bus::SendUnicast(msg, app::manager::ApplicationManager::ServiceName, &cellularService);
    }

    auto message = urc.getMessage();
    if (!message) {
        response = std::nullopt;
        return;
    }

    response =
        std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::NewIncomingUSSD, *message);
    urc.setHandled(true);
}


M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +0 -5
@@ 659,11 659,6 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl,
            auto resp   = handleAllMessagesFromMessageStorage();
            responseMsg = std::make_shared<CellularResponseMessage>(resp);
        } break;
        case CellularNotificationMessage::Type::NewIncomingUSSD: {

            auto message = std::make_shared<CellularMMIResponseMessage>(msg->data);
            sys::Bus::SendUnicast(message, app::manager::ApplicationManager::ServiceName, this);
        } break;
        case CellularNotificationMessage::Type::SignalStrengthUpdate:
        case CellularNotificationMessage::Type::NetworkStatusUpdate: {
            // skipped

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +0 -1
@@ 69,7 69,6 @@ class CellularNotificationMessage : public CellularMessage
        RawCommand,               // send raw command to modem -> returns raw, tokenised result
        PowerDownDeregistering,   // modem informed it has started to disconnect from network
        PowerDownDeregistered,    // modem informed it has disconnected from network
        NewIncomingUSSD,          // modem received new ussd code from network
        SMSDone,                  // SMS initialization finished
    };