~aleteoryx/muditaos

f94d7f63679e4fb1702495eb136b7596b3cbfc36 — Kuba Kleczkowski 2 years ago 37665c2
[MOS-636] Added MMI/USSD confirmation

USSD/MMI codes are now confirmed after they are sended.
28 files changed, 180 insertions(+), 15 deletions(-)

M image/system_a/data/lang/Deutsch.json
M image/system_a/data/lang/English.json
M image/system_a/data/lang/Espanol.json
M image/system_a/data/lang/Francais.json
M image/system_a/data/lang/Polski.json
M image/system_a/data/lang/Svenska.json
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/CMakeLists.txt
M module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp
M module-apps/application-desktop/include/application-desktop/Names.hpp
A module-apps/application-desktop/windows/MmiConfirmationWindow.cpp
A module-apps/application-desktop/windows/MmiConfirmationWindow.hpp
M module-apps/application-desktop/windows/MmiPullWindow.cpp
M module-apps/application-desktop/windows/MmiPushWindow.cpp
M module-services/service-appmgr/include/service-appmgr/Actions.hpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-cellular/requests/PinChangeRequest.cpp
M module-services/service-cellular/requests/Request.cpp
M module-services/service-cellular/requests/SupplementaryServicesRequest.cpp
M module-services/service-cellular/service-cellular/CellularMessage.hpp
M module-services/service-cellular/service-cellular/requests/PasswordRegistrationRequest.hpp
M module-services/service-cellular/service-cellular/requests/PinChangeRequest.hpp
M module-services/service-cellular/service-cellular/requests/Request.hpp
M module-services/service-cellular/service-cellular/requests/SupplementaryServicesRequest.hpp
M module-services/service-cellular/service-cellular/requests/UssdRequest.hpp
M module-services/service-cellular/src/ServiceCellularPriv.cpp
M products/PurePhone/services/appmgr/ApplicationManager.cpp
M pure_changelog.md
M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +1 -0
@@ 260,6 260,7 @@
  "app_desktop_info_mmi_imei": "IMEI (MEID)",
  "app_desktop_info_mmi_result_success": "Erfolgreich",
  "app_desktop_info_mmi_result_failed": "Fehlgeschlagen",
  "app_desktop_info_mmi_confirmation": "<text>Bitte warten...<br></br> Der MMI-/USSD- Code wird verarbeitet.</text>",
  "sim_header_setup": "<text><token>$SIM</token> einrichten</text>",
  "sim_enter_pin_unlock": "<text>PIN-Code eingeben, um<br></br> die<token>$PINTYPE</token> Karte einzurichten:</text>",
  "sim_enter_enter_current": "<text>Aktuellen PIN-Code eingeben:</text>",

M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +1 -0
@@ 225,6 225,7 @@
  "app_desktop_info_mmi_imei": "IMEI (MEID)",
  "app_desktop_info_mmi_result_success": "Success",
  "app_desktop_info_mmi_result_failed": "Failed",
  "app_desktop_info_mmi_confirmation": "<text>Please wait...<br></br> Processing USSD code.</text>",
  "sim_header_setup": "<text><token>$SIM</token> setup</text>",
  "sim_enter_pin_unlock": "<text>Enter the PIN code to set up <br></br> the <token>$PINTYPE</token> card:</text>",
  "sim_enter_enter_current": "<text>Type current PIN code:</text>",

M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +1 -0
@@ 260,6 260,7 @@
  "app_desktop_info_mmi_imei": "IMEI (MEID)",
  "app_desktop_info_mmi_result_success": "Correcto",
  "app_desktop_info_mmi_result_failed": "Error",
  "app_desktop_info_mmi_confirmation": "<text>Espere, porfavor...<br></br> Procesando el código MMI/USSD.</text>",
  "sim_header_setup": "<text>Configuración de <token>$SIM</token></text>",
  "sim_enter_pin_unlock": "<text>Introduce el código PIN<br></br>para configurar la tarjeta <token>$PINTYPE</token>:</text>",
  "sim_enter_enter_current": "<text>Introduce el código PIN actual:</text>",

M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +1 -0
@@ 229,6 229,7 @@
  "app_desktop_info_mmi_imei": "IMEI (MEID)",
  "app_desktop_info_mmi_result_success": "Succès",
  "app_desktop_info_mmi_result_failed": "Échoué",
  "app_desktop_info_mmi_confirmation": "<text>Veuillez patienter...<br></br> Traitement du code MMI/USSD.</text>",
  "sim_header_setup": "<text>Configuration de la <token>$SIM</token></text>",
  "sim_enter_pin_unlock": "<text>Entrez votre code pour configurer <br></br> la carte <token>$PINTYPE</token> :</text>",
  "sim_enter_enter_current": "<text>Taper votre code actuel :</text>",

M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +1 -0
@@ 252,6 252,7 @@
  "app_desktop_info_mmi_imei": "IMEI (MEID)",
  "app_desktop_info_mmi_result_success": "Udało się",
  "app_desktop_info_mmi_result_failed": "Nie udało się",
  "app_desktop_info_mmi_confirmation": "<text>Proszę czekać...<br></br> Przetwarzanie kodu MMI/USSD.</text>",
  "sim_header_setup": "<text>Konfiguracja <token>$SIM</token></text>",
  "sim_enter_pin_unlock": "<text>Wprowadź kod PIN, by skonfigurować <br></br>kartę <token>$PINTYPE</token>:</text>",
  "sim_enter_enter_current": "<text>Wprowadź aktualny kod PIN:</text>",

M image/system_a/data/lang/Svenska.json => image/system_a/data/lang/Svenska.json +1 -0
@@ 211,6 211,7 @@
  "app_desktop_info_mmi_imei": "IMEI-nummer (MEID)",
  "app_desktop_info_mmi_result_success": "Lyckades",
  "app_desktop_info_mmi_result_failed": "Misslyckades",
  "app_desktop_info_mmi_confirmation": "<text>Var god vänta...<br></br> Bearbetar MMI/USSD-kod.</text>",
  "sim_header_setup": "<text><token>$SIM</token>-inställningar</text>",
  "sim_enter_pin_unlock": "Den förra PIN-koden:",
  "sim_change_pin": "Ändra PIN-koden",

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +9 -1
@@ 10,6 10,7 @@
#include "MmiInternalMsgWindow.hpp"
#include "MmiPullWindow.hpp"
#include "WindowsPopupFilter.hpp"
#include "MmiConfirmationWindow.hpp"

#include <apps-common/messages/AppMessage.hpp>
#include <module-gui/gui/widgets/status-bar/SIM.hpp>


@@ 50,6 51,11 @@ namespace app
            return actionHandled();
        });

        addActionReceiver(app::manager::actions::ShowMMIConfirmation, [this](auto &&data) {
            switchWindow(app::window::name::desktop_mmi_confirmation, std::move(data));
            return actionHandled();
        });

        addActionReceiver(app::manager::actions::DisplayLowBatteryScreen, [this](auto &&data) {
            handleLowBatteryNotification(std::move(data));
            return actionHandled();


@@ 166,7 172,9 @@ namespace app
            gui::popup::window::tethering_off_window, [](ApplicationCommon *app, const std::string &name) {
                return std::make_unique<gui::TetheringOffPopup>(app, gui::popup::window::tethering_off_window);
            });

        windowsFactory.attach(desktop_mmi_confirmation, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MmiConfirmationWindow>(app, name);
        });
        attachPopups({gui::popup::ID::Volume,
                      gui::popup::ID::Tethering,
                      gui::popup::ID::BluetoothAuthenticate,

M module-apps/application-desktop/CMakeLists.txt => module-apps/application-desktop/CMakeLists.txt +1 -0
@@ 42,6 42,7 @@ target_sources(application-desktop
		windows/MmiPullWindow.hpp
		windows/MmiPushWindow.cpp
		windows/MmiPushWindow.hpp
		windows/MmiConfirmationWindow.cpp
	PUBLIC
		include/application-desktop/ApplicationDesktop.hpp
		include/application-desktop/Constants.hpp

M module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp +1 -0
@@ 59,6 59,7 @@ namespace app
                     manager::actions::ShowMMIResponse,
                     manager::actions::ShowMMIPush,
                     manager::actions::ShowMMIResult,
                     manager::actions::ShowMMIConfirmation,
                     manager::actions::DisplayLowBatteryScreen,
                     manager::actions::SystemBrownout,
                     manager::actions::DisplayLogoAtExit,

M module-apps/application-desktop/include/application-desktop/Names.hpp => module-apps/application-desktop/include/application-desktop/Names.hpp +1 -0
@@ 20,4 20,5 @@ namespace app::window::name
    inline constexpr auto desktop_mmi_pull           = "MmiPullWindow";
    inline constexpr auto desktop_mmi_push           = "MmiPushWindow";
    inline constexpr auto desktop_mmi_internal       = "MmiInternalMsgWindow";
    inline constexpr auto desktop_mmi_confirmation   = "MmiConfirmationWindow";
}; // namespace app::window::name

A module-apps/application-desktop/windows/MmiConfirmationWindow.cpp => module-apps/application-desktop/windows/MmiConfirmationWindow.cpp +72 -0
@@ 0,0 1,72 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "MmiConfirmationWindow.hpp"

#include <i18n/i18n.hpp>
#include <Image.hpp>
#include <apps-common/ApplicationCommon.hpp>
#include <service-appmgr/data/MmiActionsParams.hpp>

using namespace gui;

namespace style::desktop
{
    namespace image
    {
        constexpr uint32_t x = 176;
        constexpr uint32_t y = 135;
    } // namespace image
    namespace text
    {
        constexpr uint32_t x = 40;
        constexpr uint32_t y = 300;
        constexpr uint32_t w = 400;
        constexpr uint32_t h = 300;
    } // namespace text

} // namespace style::desktop

MmiConfirmationWindow::MmiConfirmationWindow(app::ApplicationCommon *app, const std::string &name)
    : gui::WindowWithTimer(app, name)
{
    AppWindow::buildInterface();
    navBar->setText(nav_bar::Side::Center, utils::translate(style::strings::common::ok));
    icon = new Icon(this,
                    style::window::default_left_margin,
                    style::window::default_vertical_pos,
                    style::window::default_body_width,
                    style::window::default_body_height,
                    "progress_128px_W_G",
                    utils::translate("app_desktop_info_mmi_confirmation"));
    icon->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
    icon->image->setMargins(Margins(0, icon::image_top_margin, 0, icon::image_bottom_margin));
}

bool MmiConfirmationWindow::onInput(const InputEvent &inputEvent)
{
    if (inputEvent.isShortRelease()) {
        switch (inputEvent.getKeyCode()) {
        case KeyCode::KEY_ENTER: {
            application->returnToPreviousWindow();
            return true;
        }
        case KeyCode::KEY_RF: {
            return true;
        }
        default:
            break;
        }
    }
    return AppWindow::onInput(inputEvent);
}

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

MmiConfirmationWindow::~MmiConfirmationWindow()
{
    destroyInterface();
}

A module-apps/application-desktop/windows/MmiConfirmationWindow.hpp => module-apps/application-desktop/windows/MmiConfirmationWindow.hpp +28 -0
@@ 0,0 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <AppWindow.hpp>
#include <module-apps/apps-common/popups/WindowWithTimer.hpp>
#include <DialogMetadata.hpp>
#include <Text.hpp>
#include <Icon.hpp>

#include <functional>

namespace gui
{
    class MmiConfirmationWindow : public WindowWithTimer
    {
      protected:
        Icon *icon = nullptr;

      public:
        MmiConfirmationWindow(app::ApplicationCommon *app, const std::string &name);
        ~MmiConfirmationWindow() override;
        bool onInput(const InputEvent &inputEvent) override;
        void destroyInterface() override;
    };

}; // namespace gui

M module-apps/application-desktop/windows/MmiPullWindow.cpp => module-apps/application-desktop/windows/MmiPullWindow.cpp +2 -1
@@ 4,6 4,7 @@
#include "DesktopInputWidget.hpp"
#include "Mmi.hpp"
#include "MmiPullWindow.hpp"
#include "Names.hpp"

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


@@ 84,7 85,7 @@ bool MmiPullWindow::onInput(const InputEvent &inputEvent)
        switch (inputEvent.getKeyCode()) {
        case KeyCode::KEY_RF: {
            CellularServiceAPI::USSDRequest(this->application, cellular::USSDMessage::RequestType::abortSession, "");
            application->returnToPreviousWindow();
            application->switchWindow(app::window::name::desktop_main_window);
            return true;
        }
        default:

M module-apps/application-desktop/windows/MmiPushWindow.cpp => module-apps/application-desktop/windows/MmiPushWindow.cpp +2 -1
@@ 3,6 3,7 @@

#include "Mmi.hpp"
#include "MmiPushWindow.hpp"
#include "Names.hpp"

#include <i18n/i18n.hpp>
#include <Image.hpp>


@@ 57,7 58,7 @@ bool MmiPushWindow::onInput(const InputEvent &inputEvent)
    if (inputEvent.isShortRelease()) {
        switch (inputEvent.getKeyCode()) {
        case KeyCode::KEY_ENTER: {
            application->returnToPreviousWindow();
            application->switchWindow(app::window::name::desktop_main_window);
            return true;
        }
        case KeyCode::KEY_RF: {

M module-services/service-appmgr/include/service-appmgr/Actions.hpp => module-services/service-appmgr/include/service-appmgr/Actions.hpp +1 -0
@@ 48,6 48,7 @@ namespace app::manager
            ShowMMIResult,
            ShowMMIResponse,
            ShowMMIPush,
            ShowMMIConfirmation,
            SmsRejectNoSim,
            DisplayLowBatteryScreen,
            SystemBrownout,

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +5 -0
@@ 1793,12 1793,17 @@ auto ServiceCellular::handleCellularCallRequestMessage(cellular::CallRequestMess

    auto request = factory.create();
    CellularRequestHandler handler(*this);
    const auto confirmation = request->confirmRequest();
    if (confirmation) {
        bus.sendUnicast(confirmation, ::service::name::appmgr);
    }
    auto result = channel->cmd(request->command());
    request->handle(handler, result);
    if (!result) {
        log_last_AT_error(channel);
    }
    LOG_INFO("isHandled %d, %s", static_cast<int>(request->isHandled()), utils::enumToString(result.code).c_str());

    if (!request->isHandled()) {
        cellular::CallRequestGeneralError::ErrorType errorType = translate(result.code);
        auto message = std::make_shared<cellular::CallRequestGeneralError>(errorType);

M module-services/service-cellular/requests/PinChangeRequest.cpp => module-services/service-cellular/requests/PinChangeRequest.cpp +2 -1
@@ 27,7 27,8 @@ namespace cellular
{

    PinChangeRequest::PinChangeRequest(const std::string &data, GroupMatch matchGroups)
        : Request(data), requestOldPinOrPuk(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::OldPassword)]),
        : ConfirmingRequest(data),
          requestOldPinOrPuk(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::OldPassword)]),
          requestNewPin(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::NewPassword)]),
          requestNewPinRepeat(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::NewPasswordRepeat)])
    {

M module-services/service-cellular/requests/Request.cpp => module-services/service-cellular/requests/Request.cpp +10 -0
@@ 32,6 32,11 @@ namespace cellular
        return true;
    }

    std::shared_ptr<sys::DataMessage> Request::confirmRequest() const noexcept
    {
        return sys::MessageNone{};
    }

    at::Cmd Request::buildCommand(at::AT atCommand,
                                  const std::vector<commandBuilderFunc> &builderFunctions,
                                  bool trim) const


@@ 54,4 59,9 @@ namespace cellular

        return cmd;
    }

    std::shared_ptr<sys::DataMessage> ConfirmingRequest::confirmRequest() const noexcept
    {
        return std::make_shared<cellular::MMIConfirmationMessage>();
    }
}; // namespace cellular

M module-services/service-cellular/requests/SupplementaryServicesRequest.cpp => module-services/service-cellular/requests/SupplementaryServicesRequest.cpp +1 -1
@@ 31,7 31,7 @@ namespace
namespace cellular
{
    SupplementaryServicesRequest::SupplementaryServicesRequest(const std::string &data, GroupMatch matchGroups)
        : Request(data),
        : ConfirmingRequest(data),
          serviceCode(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::ServiceCode)]),
          supplementaryInfoA(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::SupInfoA)]),
          supplementaryInfoB(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::SupInfoB)]),

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +13 -0
@@ 433,6 433,19 @@ namespace cellular
        }
    };

    class MMIConfirmationMessage : public sys::DataMessage, public app::manager::actions::ConvertibleToAction
    {
      public:
        MMIConfirmationMessage()
        {}

        [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>
        {
            return std::make_unique<app::manager::ActionRequest>(
                sender, app::manager::actions::ShowMMIConfirmation, nullptr);
        }
    };

    class SetOperatorAutoSelectResponse : public ResponseMessage
    {
      public:

M module-services/service-cellular/service-cellular/requests/PasswordRegistrationRequest.hpp => module-services/service-cellular/service-cellular/requests/PasswordRegistrationRequest.hpp +2 -2
@@ 25,11 25,11 @@ namespace cellular
        NewPasswordRepeat   //! (?:\*([0-9]*)
    };

    class PasswordRegistrationRequest : public Request
    class PasswordRegistrationRequest : public ConfirmingRequest
    {
      public:
        PasswordRegistrationRequest(const std::string &data, GroupMatch matchGroups)
            : Request(data),
            : ConfirmingRequest(data),
              requestBarringService(
                  matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::BarringServiceCode)]),
              requestOldPassword(matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::OldPassword)]),

M module-services/service-cellular/service-cellular/requests/PinChangeRequest.hpp => module-services/service-cellular/service-cellular/requests/PinChangeRequest.hpp +1 -1
@@ 20,7 20,7 @@ namespace cellular
        NewPasswordRepeat //! (?:\*([0-9]*))
    };

    class PinChangeRequest : public Request
    class PinChangeRequest : public ConfirmingRequest
    {
      public:
        enum class PassChangeType

M module-services/service-cellular/service-cellular/requests/Request.hpp => module-services/service-cellular/service-cellular/requests/Request.hpp +12 -2
@@ 3,6 3,7 @@

#pragma once

#include <service-cellular/CellularMessage.hpp>
#include <at/Result.hpp>
#include <at/Commands.hpp>
#include "service-cellular/RequestHandler.hpp"


@@ 21,19 22,21 @@ namespace cellular
        virtual void setHandled(bool handled)                      = 0;
        virtual bool checkModemResponse(const at::Result &result)  = 0;
        [[nodiscard]] virtual bool isHandled() const noexcept      = 0;
        [[nodiscard]] virtual bool isValid() const noexcept        = 0;
        [[nodiscard]] virtual bool isValid() const noexcept                       = 0;
        virtual std::shared_ptr<sys::DataMessage> confirmRequest() const noexcept = 0;
        virtual ~IRequest(){};
    };

    class Request : public IRequest
    {
      public:
        Request(const std::string &data) : request(data){};
        explicit Request(const std::string &data) : request(data){};

        void setHandled(bool handled) final;
        bool isHandled() const noexcept final;
        bool checkModemResponse(const at::Result &result) final;
        bool isValid() const noexcept override;
        std::shared_ptr<sys::DataMessage> confirmRequest() const noexcept override;

      protected:
        using commandBuilderFunc = std::function<std::string()>;


@@ 50,4 53,11 @@ namespace cellular
        bool isRequestHandled = false;
        std::string request;
    };

    class ConfirmingRequest : public Request
    {
      public:
        explicit ConfirmingRequest(const std::string &data) : Request(data){};
        std::shared_ptr<sys::DataMessage> confirmRequest() const noexcept final;
    };
}; // namespace cellular

M module-services/service-cellular/service-cellular/requests/SupplementaryServicesRequest.hpp => module-services/service-cellular/service-cellular/requests/SupplementaryServicesRequest.hpp +1 -1
@@ 28,7 28,7 @@ namespace cellular
        SupInfoC     //! (?:\*([^\*\#]+))  - Supplementary Information C (optional)
    };

    class SupplementaryServicesRequest : public Request
    class SupplementaryServicesRequest : public ConfirmingRequest
    {
      public:
        static std::unique_ptr<SupplementaryServicesRequest> create(const std::string &data, GroupMatch matchGroups);

M module-services/service-cellular/service-cellular/requests/UssdRequest.hpp => module-services/service-cellular/service-cellular/requests/UssdRequest.hpp +2 -2
@@ 12,10 12,10 @@ namespace cellular
{
    constexpr inline auto UssdRegex = "^[\\*\\#].*[\\#]$";

    class UssdRequest : public Request
    class UssdRequest : public ConfirmingRequest
    {
      public:
        UssdRequest(const std::string &data) : Request(data){};
        explicit UssdRequest(const std::string &data) : ConfirmingRequest(data){};
        auto command() -> at::Cmd final;

        static auto create(const std::string &data, GroupMatch) -> std::unique_ptr<UssdRequest>;

M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +6 -2
@@ 587,8 587,12 @@ namespace cellular::internal

            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;
            const auto result   = channel->cmd(command, std::chrono::seconds(120));
            if (result.code == at::Result::Code::OK) {
                owner->bus.sendUnicast(std::make_shared<cellular::MMIConfirmationMessage>(), ::service::name::appmgr);
                return true;
            }
            return false;
        };

        ussdHandler->onRequestAbortSession = [this]() {

M products/PurePhone/services/appmgr/ApplicationManager.cpp => products/PurePhone/services/appmgr/ApplicationManager.cpp +1 -0
@@ 399,6 399,7 @@ namespace app::manager
        connect(typeid(cellular::MMIResultMessage), convertibleToActionHandler);
        connect(typeid(cellular::MMIResponseMessage), convertibleToActionHandler);
        connect(typeid(cellular::MMIPushMessage), convertibleToActionHandler);
        connect(typeid(cellular::MMIConfirmationMessage), convertibleToActionHandler);
        connect(typeid(cellular::NoSimNotification), convertibleToActionHandler);
        connect(typeid(cellular::NotAnEmergencyNotification), convertibleToActionHandler);
        connect(typeid(cellular::NoNetworkConenctionNotification), convertibleToActionHandler);

M pure_changelog.md => pure_changelog.md +1 -0
@@ 4,6 4,7 @@

### Added
* Added input mode selection display timeout
* Added MMI/USSD code confirmation

### Changed / Improved