~aleteoryx/muditaos

dd50838789db66c4408e937286844f64f8d7781f — Piotr Tanski 5 years ago b84eda2
[EGD-4051] Based application manager app switching on application stack. (#858)

* [EGD-4051] Based application manager app switching on application stack.

* [EGD-4051] Application manager thorough refactor.
39 files changed, 897 insertions(+), 1108 deletions(-)

M changelog.md
M module-apps/Application.cpp
M module-apps/Application.hpp
M module-apps/UiCommonActions.cpp
M module-apps/UiCommonActions.hpp
M module-apps/application-calendar/windows/AllEventsWindow.cpp
M module-apps/application-calendar/windows/EventReminderWindow.cpp
M module-apps/application-call/ApplicationCall.cpp
M module-apps/application-call/windows/CallWindow.cpp
M module-apps/application-call/windows/EnterNumberWindow.cpp
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/windows/DesktopMainWindow.cpp
M module-apps/application-desktop/windows/LockedInfoWindow.cpp
M module-apps/application-desktop/windows/MenuWindow.cpp
M module-apps/application-desktop/windows/PinLockWindow.cpp
M module-apps/application-messages/ApplicationMessages.cpp
M module-apps/application-messages/windows/NewMessage.cpp
M module-apps/application-messages/windows/SMSTemplatesWindow.cpp
M module-apps/application-phonebook/ApplicationPhonebook.cpp
M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp
M module-apps/application-settings-new/windows/SettingsMainWindow.cpp
M module-apps/application-settings/windows/LanguageWindow.cpp
M module-apps/application-special-input/widgets/SpecialInputTableWidget.cpp
M module-apps/messages/AppMessage.hpp
M module-apps/windows/AppWindow.cpp
M module-apps/windows/NoEvents.cpp
M module-gui/README.md
M module-services/service-appmgr/ApplicationManager.cpp
M module-services/service-appmgr/ApplicationManager.hpp
M module-services/service-appmgr/CMakeLists.txt
A module-services/service-appmgr/Controller.cpp
A module-services/service-appmgr/Controller.hpp
M module-services/service-appmgr/messages/APMMessage.hpp
M module-services/service-evtmgr/EventManager.cpp
M module-services/service-evtmgr/alarm/EventManagerAlarm.cpp
M module-services/service-gui/ServiceGUI.cpp
M module-services/service-time/timeEvents/CalendarTimeEvents.cpp
M source/MessageType.hpp
M source/main.cpp
M changelog.md => changelog.md +3 -0
@@ 5,6 5,9 @@
### Added
* `[settings][bluetooth]` Add "Phone name" window.

### Changed

* `[appmgr]` Application manager refactored.

### Fixed


M module-apps/Application.cpp => module-apps/Application.cpp +34 -36
@@ 16,7 16,7 @@
#include "log/debug.hpp"                                 // for DEBUG_APPLI...
#include "log/log.hpp"                                   // for LOG_INFO
#include "messages/AppMessage.hpp"                       // for AppSwitchMe...
#include "service-appmgr/ApplicationManager.hpp"         // for Application...
#include "service-appmgr/Controller.hpp"                 // for Controller
#include "service-cellular/messages/CellularMessage.hpp" // for CellularNot...
#include "service-db/api/DBServiceAPI.hpp"               // for DBServiceAPI
#include "service-evtmgr/messages/BatteryMessages.hpp"   // for BatteryLeve...


@@ 167,16 167,15 @@ namespace app
#endif

        // case to handle returning to previous application
        if (windowName == "LastWindow") {
        if (windowName.empty()) {
            window = getCurrentWindow()->getName();
            auto msg =
                std::make_shared<AppSwitchWindowMessage>(window, getCurrentWindow()->getName(), std::move(data), cmd);
            sys::Bus::SendUnicast(msg, this->GetName(), this);
        }
        else {
            window   = windowName.empty() ? default_window : windowName;
            auto msg = std::make_shared<AppSwitchWindowMessage>(
                window, getCurrentWindow() ? getCurrentWindow()->getName() : "", std::move(data), cmd);
                windowName, getCurrentWindow() ? getCurrentWindow()->getName() : "", std::move(data), cmd);
            sys::Bus::SendUnicast(msg, this->GetName(), this);
        }
    }


@@ 187,7 186,7 @@ namespace app
        if (prevWindow == gui::name::window::no_window) {
            LOG_INFO("Back to previous application");
            cleanPrevWindw();
            sapm::ApplicationManager::messageSwitchPreviousApplication(this);
            app::manager::Controller::switchBack(this);
        }
        else {
            LOG_INFO("Back to previous window %s", prevWindow.c_str());


@@ 237,6 236,9 @@ namespace app
        else if (msgl->messageType == MessageType::AppRefresh) {
            return handleAppRefresh(msgl);
        }
        else if (msgl->messageType == MessageType::AppFocusLost) {
            return handleAppFocusLost(msgl);
        }
        else if (dynamic_cast<sevm::SIMMessage *>(msgl) != nullptr) {
            return handleSIMMessage(msgl);
        }


@@ 335,7 337,7 @@ namespace app

            if (msg->getTargetApplicationName() == this->GetName()) {
                setState(State::ACTIVE_FORGROUND);
                if (sapm::ApplicationManager::messageConfirmSwitch(this)) {
                if (app::manager::Controller::confirmSwitch(this)) {
                    LOG_INFO("target Window: %s : target description: %s",
                             msg->getTargetWindowName().c_str(),
                             msg->getData() ? msg->getData()->getDescription().c_str() : "");


@@ 352,25 354,9 @@ namespace app
            }
        }
        else if (state == State::ACTIVE_FORGROUND) {
            if (msg->getTargetApplicationName() == this->GetName()) {
                // if window name and data are null pointers this is a message informing
                // that application should go to background mode
                if ((msg->getTargetWindowName() == "") && (msg->getData() == nullptr)) {
                    setState(State::ACTIVE_BACKGROUND);
                    if (sapm::ApplicationManager::messageConfirmSwitch(this)) {
                        handled = true;
                    }
                    else {
                        // TODO send to itself message to close
                        LOG_ERROR("Failed to communicate ");
                    }
                }
                // if application is in front and receives message with defined window it should
                // change to that window.
                else {
                    switchWindow(msg->getTargetWindowName(), std::move(msg->getData()));
                    handled = true;
                }
            if (msg->getTargetApplicationName() == GetName()) {
                switchWindow(msg->getTargetWindowName(), std::move(msg->getData()));
                handled = true;
            }
            else {
                LOG_ERROR("Received switch message outside of activation flow");


@@ 427,7 413,7 @@ namespace app
    sys::Message_t Application::handleAppClose(sys::DataMessage *msgl)
    {
        setState(State::DEACTIVATING);
        sapm::ApplicationManager::messageConfirmClose(this);
        app::manager::Controller::confirmClose(this);
        return msgHandled();
    }



@@ 453,6 439,15 @@ namespace app
        return msgHandled();
    }

    sys::Message_t Application::handleAppFocusLost(sys::DataMessage *msgl)
    {
        if (state == State::ACTIVE_FORGROUND) {
            setState(State::ACTIVE_BACKGROUND);
            app::manager::Controller::confirmSwitch(this);
        }
        return msgHandled();
    }

    sys::Message_t Application::handleSIMMessage(sys::DataMessage *msgl)
    {
        getCurrentWindow()->setSIM();


@@ 462,19 457,16 @@ namespace app

    sys::ReturnCodes Application::InitHandler()
    {
        bool initState = true;

        setState(State::INITIALIZING);
        //	uint32_t start = xTaskGetTickCount();
        settings = DBServiceAPI::SettingsGet(this);
        //	uint32_t stop = xTaskGetTickCount();
        //	LOG_INFO("DBServiceAPI::SettingsGet %d", stop-start);
        initState = (settings.dbID == 1);

        // send response to application manager true if successful, false otherwise.
        sapm::ApplicationManager::messageRegisterApplication(this, initState, startBackground);
        sys::ReturnCodes retCode = (initState ? sys::ReturnCodes::Success : sys::ReturnCodes::Failure);
        return retCode;
        const bool initialised = settings.dbID == 1;
        app::manager::Controller::registerApplication(this, initialised, startBackground);
        if (!initialised) {
            setState(State::DEACTIVATED);
            return sys::ReturnCodes::Failure;
        }
        return sys::ReturnCodes::Success;
    }

    sys::ReturnCodes Application::DeinitHandler()


@@ 534,6 526,12 @@ namespace app
        sys::Bus::SendUnicast(msg, application, sender);
    }

    void Application::messageApplicationLostFocus(sys::Service *sender, std::string application)
    {
        auto msg = std::make_shared<AppLostFocusMessage>();
        sys::Bus::SendUnicast(msg, application, sender);
    }

    void Application::messageInputEventApplication(sys::Service *sender,
                                                   std::string application,
                                                   const gui::InputEvent &event)

M module-apps/Application.hpp => module-apps/Application.hpp +4 -2
@@ 73,7 73,7 @@ namespace app

    /// This is template for creating new applications. Main difference between Application and service is that:
    /// 1. Application has access to GUI and Input
    /// 2. Application lifetime is managed with sapm::ApplicationManager
    /// 2. Application lifetime is managed with app::manager::ApplicationManager
    class Application : public sys::Service
    {
      public:


@@ 126,6 126,7 @@ namespace app
        sys::Message_t handleAppClose(sys::DataMessage *msgl);
        sys::Message_t handleAppRebuild(sys::DataMessage *msgl);
        sys::Message_t handleAppRefresh(sys::DataMessage *msgl);
        sys::Message_t handleAppFocusLost(sys::DataMessage *msgl);
        sys::Message_t handleSIMMessage(sys::DataMessage *msgl);

        std::list<std::unique_ptr<app::GuiTimer>> gui_timers;


@@ 152,7 153,7 @@ namespace app
        void blockEvents(bool isBlocked);

        /// Method sending switch command for another window. It will switch window within active application.
        /// To switch windows between applications use sapm::ApplicationManager::messageSwitchApplication
        /// To switch windows between applications use app::manager::Controller::switchApplication
        /// it will effectively trigger setActiveWindow and change on windows stack
        ///
        /// @param windowName name of window to show, only required parameter, our windows stack uses string names as


@@ 295,6 296,7 @@ namespace app
                                              gui::SwitchData *data = nullptr);
        static void messageCloseApplication(sys::Service *sender, std::string application);
        static void messageRebuildApplication(sys::Service *sender, std::string application);
        static void messageApplicationLostFocus(sys::Service *sender, std::string application);
        /// @}

      protected:

M module-apps/UiCommonActions.cpp => module-apps/UiCommonActions.cpp +27 -12
@@ 9,7 9,10 @@
#include "application-messages/windows/SMSThreadViewWindow.hpp"
#include "application-phonebook/ApplicationPhonebook.hpp"
#include "application-phonebook/data/PhonebookItemData.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "application-special-input/ApplicationSpecialInput.hpp"

#include "service-appmgr/Controller.hpp"
#include "service-appmgr/messages/APMMessage.hpp"

#include <i18/i18.hpp>
#include <log/log.hpp>


@@ 37,10 40,10 @@ namespace app
    auto call(Application *app, const utils::PhoneNumber::View &phoneNumber) -> bool
    {
        assert(app != nullptr);
        auto data = std::make_unique<ExecuteCallData>(phoneNumber);
        auto data             = std::make_unique<ExecuteCallData>(phoneNumber);
        data->disableAppClose = true;

        return sapm::ApplicationManager::messageSwitchApplication(
            app, name_call, window::name_enterNumber, std::move(data));
        return app::manager::Controller::switchApplication(app, name_call, window::name_enterNumber, std::move(data));
    }

    auto prepareCall(Application *app, const std::string &number) -> bool


@@ 48,8 51,7 @@ namespace app
        assert(app != nullptr);
        auto data = std::make_unique<EnterNumberData>(number);

        return sapm::ApplicationManager::messageSwitchApplication(
            app, name_call, window::name_enterNumber, std::move(data));
        return app::manager::Controller::switchApplication(app, name_call, window::name_enterNumber, std::move(data));
    }

    auto sms(Application *app, SmsOperation smsOperation, const utils::PhoneNumber::View &number, const UTF8 textData)


@@ 60,12 62,13 @@ namespace app
        switch (smsOperation) {
        case SmsOperation::New: {
            auto data                        = std::make_unique<SMSSendRequest>(number, textData);
            data->disableAppClose            = true;
            data->ignoreCurrentWindowOnStack = true;
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                app, name_messages, gui::name::window::new_sms, std::move(data));
        }
        case SmsOperation::Template: {
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                app, name_messages, gui::name::window::sms_templates, std::make_unique<SMSSendTemplateRequest>(number));
        }
        default: {


@@ 83,15 86,15 @@ namespace app
        switch (contactOperation) {
        case ContactOperation::Add: {
            data->ignoreCurrentWindowOnStack = true;
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                app, name_phonebook, gui::window::name::new_contact, std::move(data));
        }
        case ContactOperation::Details: {
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                app, name_phonebook, gui::window::name::contact, std::move(data));
        }
        case ContactOperation::Edit: {
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                app,
                name_phonebook,
                gui::window::name::new_contact, // TODO: need to be fixed when contact edition is working


@@ 119,7 122,7 @@ namespace app
                     contactRec.alternativeName.c_str());

            if (contactOperation == ContactOperation::Add) {
                return sapm::ApplicationManager::messageSwitchApplication(
                return app::manager::Controller::switchApplication(
                    app,
                    name_phonebook,
                    gui::window::name::new_contact,


@@ 156,4 159,16 @@ namespace app
        return false;
    }

    auto specialInput(Application *app, std::unique_ptr<gui::SwitchSpecialChar> &&switchData) -> bool
    {
        assert(app != nullptr);

        switchData->disableAppClose = true;
        if (gui::SwitchSpecialChar::Type::Request == switchData->type) {
            return app::manager::Controller::switchApplication(
                app, app::special_input, app::char_select, std::move(switchData));
        }
        return app::manager::Controller::switchBack(
            app, std::make_unique<app::manager::APMSwitchPrevApp>(switchData->requester, std::move(switchData)));
    }
} // namespace app

M module-apps/UiCommonActions.hpp => module-apps/UiCommonActions.hpp +6 -0
@@ 102,4 102,10 @@ namespace app
    ///
    /// @return true if succeed
    auto contact(Application *app, ContactOperation contactOperation, uint32_t contactId) -> bool;

    /// @brief requests display special input window.
    /// @param app          Requesting application
    /// @param switchData   Application switch data.
    /// @return true if succeed.
    auto specialInput(Application *app, std::unique_ptr<gui::SwitchSpecialChar> &&switchData) -> bool;
} // namespace app

M module-apps/application-calendar/windows/AllEventsWindow.cpp => module-apps/application-calendar/windows/AllEventsWindow.cpp +2 -2
@@ 8,7 8,7 @@
#include <gui/widgets/BottomBar.hpp>
#include <gui/widgets/TopBar.hpp>
#include <gui/widgets/Window.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

#include <module-services/service-db/messages/QueryMessage.hpp>
#include <module-db/queries/calendar/QueryEventsGetAllLimited.hpp>


@@ 66,7 66,7 @@ namespace gui
        if (inputEvent.keyCode == gui::KeyCode::KEY_RF &&
            inputEvent.state == gui::InputEvent::State::keyReleasedShort) {
            LOG_DEBUG("Switch to desktop");
            sapm::ApplicationManager::messageSwitchPreviousApplication(application);
            app::manager::Controller::switchBack(application);
        }

        if (AppWindow::onInput(inputEvent)) {

M module-apps/application-calendar/windows/EventReminderWindow.cpp => module-apps/application-calendar/windows/EventReminderWindow.cpp +2 -3
@@ 6,7 6,7 @@
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <gui/widgets/Window.hpp>
#include <time/time_conversion.hpp>
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

namespace gui
{


@@ 156,8 156,7 @@ namespace gui
        LOG_DEBUG("Switch to previous window");
        destroyTimer();

        sapm::ApplicationManager::messageSwitchApplication(
            application, "ApplicationDesktop", gui::name::window::main_window, nullptr);
        app::manager::Controller::switchApplication(application, "ApplicationDesktop", gui::name::window::main_window);
    }

} /* namespace gui */

M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +2 -2
@@ 22,7 22,7 @@
#include <service-cellular/ServiceCellular.hpp>
#include <service-cellular/api/CellularServiceAPI.hpp>
#include <service-audio/api/AudioServiceAPI.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <time/time_conversion.hpp>
#include <ticks.hpp>



@@ 45,7 45,7 @@ namespace app
            app->switchWindow(window::name_call, std::move(data));
        }
        else {
            sapm::ApplicationManager::messageSwitchApplication(app, name_call, window::name_call, std::move(data));
            app::manager::Controller::switchApplication(app, name_call, window::name_call, std::move(data));
        }
    }


M module-apps/application-call/windows/CallWindow.cpp => module-apps/application-call/windows/CallWindow.cpp +2 -2
@@ 8,7 8,7 @@
#include "InputEvent.hpp"
#include "application-call/widgets/Icons.hpp"
#include "log/log.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

#include "application-call/ApplicationCall.hpp"
#include "application-call/data/CallSwitchData.hpp"


@@ 421,7 421,7 @@ namespace gui
        timerCallback = [this](Item &, Timer &timer) {
            setState(State::IDLE);
            detachTimer(timer);
            sapm::ApplicationManager::messageSwitchPreviousApplication(application);
            app::manager::Controller::switchBack(application);
            return true;
        };
        application->connect(std::move(timer), this);

M module-apps/application-call/windows/EnterNumberWindow.cpp => module-apps/application-call/windows/EnterNumberWindow.cpp +3 -3
@@ 11,7 11,7 @@
#include <country.hpp>
#include <i18/i18.hpp>
#include <InputMode.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-cellular/api/CellularServiceAPI.hpp>
#include <UiCommonActions.hpp>



@@ 108,7 108,7 @@ namespace gui
                // if there isn't any char in phone number field return to previous application
                if (enteredNumber.empty()) {
                    formatter->Clear();
                    sapm::ApplicationManager::messageSwitchPreviousApplication(application);
                    app::manager::Controller::switchBack(application);
                }
                // if there is the last char just clear input
                else if (enteredNumber.size() == 1) {


@@ 134,7 134,7 @@ namespace gui
            if (inputEvent.keyCode == KeyCode::KEY_RF) {
                // if there isn't any char in phone number field return to previous application
                if (enteredNumber.empty()) {
                    sapm::ApplicationManager::messageSwitchPreviousApplication(application);
                    app::manager::Controller::switchBack(application);
                    return true;
                }


M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +3 -3
@@ 17,7 17,7 @@
#include <service-db/api/DBServiceAPI.hpp>
#include <application-settings-new/ApplicationSettings.hpp>
#include <application-settings/ApplicationSettings.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-cellular/ServiceCellular.hpp>
#include <application-calllog/ApplicationCallLog.hpp>
#include <messages/QueryMessage.hpp>


@@ 146,7 146,7 @@ namespace app
        assert(msg);
        if (msg->request == cellular::State::ST::URCReady) {
            if (need_sim_select && !lockHandler.lock.isLocked()) {
                sapm::ApplicationManager::messageSwitchApplication(this, app::name_settings, app::sim_select, nullptr);
                app::manager::Controller::switchApplication(this, app::name_settings, app::sim_select, nullptr);
                return true;
            }
            else if (need_sim_select == false) {


@@ 164,7 164,7 @@ namespace app
    bool ApplicationDesktop::showCalls()
    {
        LOG_DEBUG("show calls!");
        return sapm::ApplicationManager::messageSwitchApplication(
        return app::manager::Controller::switchApplication(
            this, app::CallLogAppStr, gui::name::window::main_window, nullptr);
    }


M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +3 -3
@@ 12,7 12,7 @@
#include "application-desktop/data/LockPhoneData.hpp"
#include "application-messages/ApplicationMessages.hpp"
#include "gui/widgets/Image.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"
#include "service-time/ServiceTime.hpp"
#include "service-time/messages/TimeMessage.hpp"
#include <UiCommonActions.hpp>


@@ 113,7 113,7 @@ namespace gui
                LOG_ERROR("Couldn't fit in all notifications");
            }
            if (app->need_sim_select && Store::GSM::get()->sim == Store::GSM::SIM::SIM_UNKNOWN) {
                sapm::ApplicationManager::messageSwitchApplication(
                app::manager::Controller::switchApplication(
                    this->application, app::name_settings, app::sim_select, nullptr);
            }



@@ 373,7 373,7 @@ namespace gui
                utils::localize.get("app_desktop_unread_messages"),
                std::to_string(app->notifications.notSeen.SMS),
                [this]() -> bool {
                    return sapm::ApplicationManager::messageSwitchApplication(
                    return app::manager::Controller::switchApplication(
                        application, app::name_messages, gui::name::window::main_window, nullptr);
                },
                [app]() -> bool { return app->clearMessagesNotification(); });

M module-apps/application-desktop/windows/LockedInfoWindow.cpp => module-apps/application-desktop/windows/LockedInfoWindow.cpp +3 -3
@@ 3,7 3,7 @@

#include "LockedInfoWindow.hpp"

#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"
#include "gui/widgets/BottomBar.hpp"
#include "gui/widgets/TopBar.hpp"
#include "RichTextParser.hpp"


@@ 44,8 44,8 @@ bool LockedInfoWindow::onInput(const InputEvent &inputEvent)
{
    if (inputEvent.isShortPress()) {
        if (inputEvent.keyCode == KeyCode::KEY_LF && bottomBar->isActive(BottomBar::Side::LEFT)) {
            sapm::ApplicationManager::messageSwitchApplication(
                application, app::name_phonebook, gui::window::name::ice_contacts, nullptr);
            app::manager::Controller::switchApplication(
                application, app::name_phonebook, gui::window::name::ice_contacts);
            return true;
        }
        else if (inputEvent.keyCode == KeyCode::KEY_RF && bottomBar->isActive(BottomBar::Side::RIGHT)) {

M module-apps/application-desktop/windows/MenuWindow.cpp => module-apps/application-desktop/windows/MenuWindow.cpp +11 -11
@@ 6,7 6,7 @@
#include "InputEvent.hpp"
#include "Item.hpp"
#include "Navigation.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

#include <tools/Common.hpp>
#include <Style.hpp>


@@ 129,7 129,7 @@ namespace gui
                new gui::Tile("menu_calendar_W_G",
                              "app_desktop_menu_calendar",
                              [=](gui::Item &item) {
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationCalendar", gui::name::window::main_window, nullptr);
                                  return true;
                              }),


@@ 138,7 138,7 @@ namespace gui
                              "app_desktop_menu_phone",
                              [=](gui::Item &item) {
                                  LOG_INFO("Call Log");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationCallLog", gui::name::window::main_window, nullptr);
                                  return true;
                              },


@@ 147,7 147,7 @@ namespace gui
                              "app_desktop_menu_contacts",
                              [=](gui::Item &item) {
                                  LOG_INFO("Phonebook");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationPhonebook", gui::name::window::main_window, nullptr);
                                  return true;
                              }),


@@ 156,7 156,7 @@ namespace gui
                              "app_desktop_menu_messages",
                              [=](gui::Item &item) {
                                  LOG_INFO("Messages");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationMessages", gui::name::window::main_window, nullptr);
                                  return true;
                              },


@@ 165,7 165,7 @@ namespace gui
                              "app_desktop_menu_music",
                              [=](gui::Item &item) {
                                  LOG_INFO("Music Player");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationMusicPlayer", gui::name::window::main_window, nullptr);
                                  return true;
                              }},


@@ 173,7 173,7 @@ namespace gui
                              "app_desktop_menu_meditation",
                              [=](gui::Item &item) {
                                  LOG_INFO("Meditation");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationMeditation", gui::name::window::main_window, nullptr);
                                  return true;
                              }},


@@ 181,7 181,7 @@ namespace gui
                              "app_desktop_menu_settings_new",
                              [=](gui::Item &item) {
                                  LOG_INFO("page 1 settings");
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, APP_SETTINGS_NEW, gui::name::window::main_window, nullptr);
                                  return true;
                              }},


@@ 194,21 194,21 @@ namespace gui
                new gui::Tile{"menu_tools_notes_W_G",
                              "app_desktop_tools_notes",
                              [=](gui::Item &item) {
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationNotes", gui::name::window::main_window, nullptr);
                                  return true;
                              }},
                new gui::Tile{"menu_tools_calculator_W_G",
                              "app_desktop_tools_calculator",
                              [=](gui::Item &item) {
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationCalculator", gui::name::window::main_window, nullptr);
                                  return true;
                              }},
                new gui::Tile{"menu_tools_recorder_W_G",
                              "app_desktop_tools_antenna",
                              [=](gui::Item &item) {
                                  sapm::ApplicationManager::messageSwitchApplication(
                                  app::manager::Controller::switchApplication(
                                      application, "ApplicationAntenna", gui::name::window::main_window, nullptr);
                                  return true;
                              }},

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

// application manager
#include "InputEvent.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

// module-gui
#include "gui/widgets/BottomBar.hpp"


@@ 95,7 95,7 @@ namespace gui
        }
        // accept only LF, enter, RF, #, and numeric values;
        if (inputEvent.keyCode == KeyCode::KEY_LF && bottomBar->isActive(BottomBar::Side::LEFT)) {
            sapm::ApplicationManager::messageSwitchApplication(
            app::manager::Controller::switchApplication(
                application, app::name_phonebook, gui::window::name::ice_contacts, nullptr);
            return true;
        }

M module-apps/application-messages/ApplicationMessages.cpp => module-apps/application-messages/ApplicationMessages.cpp +1 -1
@@ 88,7 88,7 @@ namespace app
            case MessageType::DBQuery:
                if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp)) {
                    auto result = queryResponse->getResult();
                    if (result->hasListener()) {
                    if (result && result->hasListener()) {
                        if (result->handle()) {
                            refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
                        }

M module-apps/application-messages/windows/NewMessage.cpp => module-apps/application-messages/windows/NewMessage.cpp +2 -2
@@ 9,7 9,7 @@

#include <application-phonebook/ApplicationPhonebook.hpp>
#include <application-phonebook/windows/PhonebookSearchResults.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-db/api/DBServiceAPI.hpp>
#include <i18/i18.hpp>
#include <BoxLayout.hpp>


@@ 80,7 80,7 @@ namespace gui
        if (recipient->getText().empty()) {
            auto data             = std::make_unique<PhonebookSearchReuqest>();
            data->disableAppClose = true;
            return sapm::ApplicationManager::messageSwitchApplication(
            return app::manager::Controller::switchApplication(
                application, app::name_phonebook, name::window::main_window, std::move(data));
        }
        return true;

M module-apps/application-messages/windows/SMSTemplatesWindow.cpp => module-apps/application-messages/windows/SMSTemplatesWindow.cpp +4 -4
@@ 7,7 7,7 @@
#include "application-messages/widgets/SMSTemplateItem.hpp"
#include "application-messages/data/MessagesStyle.hpp"

#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-db/messages/DBSMSTemplateMessage.hpp>
#include <i18/i18.hpp>
#include <Style.hpp>


@@ 82,9 82,9 @@ namespace gui
        app->templatesCallback = [=](std::shared_ptr<SMSTemplateRecord> templ) {
            LOG_DEBUG("SMS template id = %" PRIu32 "sent to %s", templ->ID, phoneNumber.getFormatted().c_str());
            app->sendSms(phoneNumber, templ->text);
            sapm::ApplicationManager::messageSwitchPreviousApplication(
                app,
                std::make_unique<sapm::APMSwitchPrevApp>(application->GetName(), std::make_unique<SMSTemplateSent>()));
            app::manager::Controller::switchBack(app,
                                                 std::make_unique<app::manager::APMSwitchPrevApp>(
                                                     application->GetName(), std::make_unique<SMSTemplateSent>()));
            return true;
        };
    }

M module-apps/application-phonebook/ApplicationPhonebook.cpp => module-apps/application-phonebook/ApplicationPhonebook.cpp +3 -3
@@ 15,7 15,7 @@
#include "windows/PhonebookSearch.hpp"
#include "windows/PhonebookSearchResults.hpp"
#include "windows/PhonebookIceContacts.hpp"
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

namespace app
{


@@ 161,8 161,8 @@ namespace app
                    std::unique_ptr<PhonebookSearchReuqest> data = std::make_unique<PhonebookSearchReuqest>();
                    data->result                                 = item->contact;
                    data->setDescription("PhonebookSearchRequest");
                    return sapm::ApplicationManager::messageSwitchPreviousApplication(
                        this, std::make_unique<sapm::APMSwitchPrevApp>(GetName(), std::move(data)));
                    return app::manager::Controller::switchBack(
                        this, std::make_unique<app::manager::APMSwitchPrevApp>(GetName(), std::move(data)));
                };
            }
            LOG_DEBUG("Switching to search results window.");

M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp => module-apps/application-phonebook/windows/PhonebookMainWindow.cpp +4 -3
@@ 9,7 9,7 @@
#include <messages/QueryMessage.hpp>
#include <queries/phonebook/QueryContactGet.hpp>

#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <module-services/service-db/messages/DBNotificationMessage.hpp>

namespace gui


@@ 106,8 106,9 @@ namespace gui
                std::unique_ptr<PhonebookSearchReuqest> data = std::make_unique<PhonebookSearchReuqest>();
                data->result                                 = item->contact;
                data->setDescription("PhonebookSearchRequest");
                return sapm::ApplicationManager::messageSwitchPreviousApplication(
                    application, std::make_unique<sapm::APMSwitchPrevApp>(application->GetName(), std::move(data)));
                return app::manager::Controller::switchBack(
                    application,
                    std::make_unique<app::manager::APMSwitchPrevApp>(application->GetName(), std::move(data)));
            };

            leftArrowImage->setVisible(false);

M module-apps/application-settings-new/windows/SettingsMainWindow.cpp => module-apps/application-settings-new/windows/SettingsMainWindow.cpp +2 -2
@@ 6,7 6,7 @@

#include <i18/i18.hpp>
#include <log/log.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

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


@@ 32,7 32,7 @@ std::list<gui::Option> mainWindowOptionsNew(app::Application *app)
                                           return false;
                                       }
                                       LOG_INFO("switching to %s page", window.c_str());
                                       sapm::ApplicationManager::messageSwitchApplication(
                                       app::manager::Controller::switchApplication(
                                           app, "ApplicationSettings", gui::name::window::main_window, nullptr);
                                       app->switchWindow(window, nullptr);
                                       return true;

M module-apps/application-settings/windows/LanguageWindow.cpp => module-apps/application-settings/windows/LanguageWindow.cpp +5 -5
@@ 4,7 4,7 @@
#include <memory>
#include <functional>

#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

#include "../ApplicationSettings.hpp"



@@ 53,27 53,27 @@ namespace gui
        // add option connectivity option
        options.push_back(addOptionLabel(utils::localize.get("app_settings_language_english"), [=](gui::Item &item) {
            LOG_INFO("selected language: english");
            sapm::ApplicationManager::messageChangeLanguage(application, utils::Lang::En);
            app::manager::Controller::changeLanguage(application, utils::Lang::En);
            return true;
        }));

        // add option date and time option
        options.push_back(addOptionLabel(utils::localize.get("app_settings_language_polish"), [=](gui::Item &) {
            LOG_INFO("selected language: polish");
            sapm::ApplicationManager::messageChangeLanguage(application, utils::Lang::Pl);
            app::manager::Controller::changeLanguage(application, utils::Lang::Pl);
            return true;
        }));

        // add option display option
        options.push_back(addOptionLabel(utils::localize.get("app_settings_language_german"), [=](gui::Item &) {
            LOG_INFO("selected language: german");
            sapm::ApplicationManager::messageChangeLanguage(application, utils::Lang::De);
            app::manager::Controller::changeLanguage(application, utils::Lang::De);
            return true;
        }));

        options.push_back(addOptionLabel(utils::localize.get("app_settings_language_spanish"), [=](gui::Item &) {
            LOG_INFO("selected language: spanish");
            sapm::ApplicationManager::messageChangeLanguage(application, utils::Lang::Sp);
            app::manager::Controller::changeLanguage(application, utils::Lang::Sp);
            return true;
        }));


M module-apps/application-special-input/widgets/SpecialInputTableWidget.cpp => module-apps/application-special-input/widgets/SpecialInputTableWidget.cpp +5 -2
@@ 7,10 7,13 @@
#include "application-special-input/data/SpecialCharactersTableStyle.hpp"
#include <cassert>
#include <module-apps/application-special-input/ApplicationSpecialInput.hpp>
#include <module-services/service-appmgr/ApplicationManager.hpp>
#include <module-services/service-appmgr/Controller.hpp>

#include "Style.hpp"
#include "messages/AppMessage.hpp"

#include "UiCommonActions.hpp"

namespace gui
{



@@ 78,7 81,7 @@ namespace gui
        it->activatedCallback = [=](Item &it) {
            setFocusItem(nullptr);
            LOG_INFO("handled special char for %s", application->getCurrentWindow()->getName().c_str());
            sapm::ApplicationManager::messageSwitchSpecialInput(
            app::specialInput(
                application,
                std::make_unique<gui::SwitchSpecialChar>(gui::SwitchSpecialChar::Type::Response, app->requester, str));
            return true;

M module-apps/messages/AppMessage.hpp => module-apps/messages/AppMessage.hpp +6 -0
@@ 163,5 163,11 @@ namespace app
        virtual ~AppRebuildMessage(){};
    };

    class AppLostFocusMessage : public AppMessage
    {
      public:
        AppLostFocusMessage() : AppMessage{MessageType::AppFocusLost}
        {}
    };
};     // namespace app
#endif /* MODULE_APPS_MESSAGES_APPMESSAGE_HPP_ */

M module-apps/windows/AppWindow.cpp => module-apps/windows/AppWindow.cpp +4 -3
@@ 4,10 4,11 @@
#include "AppWindow.hpp"
#include "Application.hpp"
#include "InputEvent.hpp"
#include "UiCommonActions.hpp"
#include <Style.hpp>
#include <application-desktop/ApplicationDesktop.hpp>
#include <i18/i18.hpp>
#include <service-appmgr/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>
#include <service-audio/api/AudioServiceAPI.hpp>

using namespace style::header;


@@ 131,7 132,7 @@ namespace gui

        if (inputEvent.state == InputEvent::State::keyReleasedLong && inputEvent.keyCode == gui::KeyCode::KEY_RF) {
            LOG_INFO("exit to main menu");
            sapm::ApplicationManager::messageSwitchApplication(
            app::manager::Controller::switchApplication(
                application, app::name_desktop, gui::name::window::main_window, nullptr);
        }
        // process only if key is released


@@ 217,7 218,7 @@ namespace gui

    bool AppWindow::selectSpecialCharacter()
    {
        return sapm::ApplicationManager::messageSwitchSpecialInput(
        return app::specialInput(
            application,
            std::make_unique<gui::SwitchSpecialChar>(gui::SwitchSpecialChar::Type::Request, application->GetName()));
    }

M module-apps/windows/NoEvents.cpp => module-apps/windows/NoEvents.cpp +2 -6
@@ 5,12 5,8 @@
#include "Dialog.hpp"
#include "DialogMetadataMessage.hpp"
#include "log/log.hpp"
#include <service-appmgr/ApplicationManager.hpp>
#include <i18/i18.hpp>
#include <module-services/service-db/messages/QueryMessage.hpp>
#include <module-db/Interface/EventsRecord.hpp>
#include <module-apps/application-calendar/ApplicationCalendar.hpp>
#include <module-db/queries/calendar/QueryEventsGetFiltered.hpp>

#include <service-appmgr/Controller.hpp>

using namespace gui;


M module-gui/README.md => module-gui/README.md +2 -2
@@ 20,11 20,11 @@ This article includes details on how MuditaOS widgets are rendered and how the G

### How does it work on the application side

Please see `app::Application`, `sapm::ApplicationManager` for detailed information on how messages are handled between both. This is just general documentation.
Please see `app::Application`, `app::manager::ApplicationManager` for detailed information on how messages are handled between both. This is just general documentation.

![Simplified app start diagram](how_app_start_work.svg "Simplified hi level app start")

These actions are done on a chained bus request between: `app::Application`, `sapm::ApplicationManager` and `sapm::EventWorker`
These actions are done on a chained bus request between: `app::Application`, `app::manager::ApplicationManager` and `sapm::EventWorker`

All of these are asynchronous and there is little state machine maintenance.


M module-services/service-appmgr/ApplicationManager.cpp => module-services/service-appmgr/ApplicationManager.cpp +447 -683
@@ 1,409 1,244 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <memory>

#include "SystemManager/SystemManager.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-evtmgr/EventManager.hpp"
#include "messages/APMMessage.hpp"
#include "AppMessage.hpp"
#include "application-call/data/CallSwitchData.hpp"

#include "service-db/api/DBServiceAPI.hpp"
#include "service-cellular/ServiceCellular.hpp"
#include "service-cellular/api/CellularServiceAPI.hpp"
#include "service-appmgr/Controller.hpp"

#include <memory>
#include <utility>
#include <module-apps/application-desktop/data/LockPhoneData.hpp>

// services
#include "service-eink/ServiceEink.hpp"
#include "service-gui/ServiceGUI.hpp"

#include "Service/Timer.hpp"
#include "application-call/ApplicationCall.hpp"
#include "application-desktop/ApplicationDesktop.hpp"
#include "application-special-input/ApplicationSpecialInput.hpp"

/// Auto phone lock disabled for now till the times when it's debugged
/// #define AUTO_PHONE_LOCK_ENABLED
#include "Service/Message.hpp"
#include "AppMessage.hpp"

#include "Service/Timer.hpp"
#include "service-db/api/DBServiceAPI.hpp"
#include "service-evtmgr/EventManager.hpp"
#include "service-eink/ServiceEink.hpp"
#include "service-gui/ServiceGUI.hpp"

// module-utils
#include "log/log.hpp"
#include "i18/i18.hpp"
#include <cassert>

namespace sapm
{
// Auto phone lock disabled for now till the times when it's debugged
// #define AUTO_PHONE_LOCK_ENABLED

    ApplicationDescription::ApplicationDescription(std::unique_ptr<app::ApplicationLauncher> launcher)
        : switchData{nullptr}
namespace app::manager
{
    namespace
    {
        this->launcher = std::move(launcher);
    }
        constexpr char GUIServiceName[]                = "ServiceGUI";
        constexpr char EInkServiceName[]               = "ServiceEink";
        constexpr auto default_application_locktime_ms = 30000;

    VirtualAppManager::VirtualAppManager(std::vector<std::unique_ptr<app::ApplicationLauncher>> &launchers)
    {
        for (uint32_t i = 0; i < launchers.size(); ++i) {
            applications.push_back(new ApplicationDescription(std::move(launchers[i])));
        utils::Lang toUtilsLanguage(SettingsLanguage language)
        {
            switch (language) {
            case SettingsLanguage::ENGLISH:
                return utils::Lang::En;
            case SettingsLanguage::POLISH:
                return utils::Lang::Pl;
            case SettingsLanguage::GERMAN:
                return utils::Lang::De;
            case SettingsLanguage::SPANISH:
                return utils::Lang::Sp;
            default:
                return utils::Lang::En;
            }
        }
    }

    VirtualAppManager::~VirtualAppManager()
    {
        for (auto it = applications.begin(); it != applications.end(); it++) {
            delete *it;
        SettingsLanguage toSettingsLanguage(utils::Lang language)
        {
            switch (language) {
            case utils::Lang::En:
                return SettingsLanguage::ENGLISH;
            case utils::Lang::Pl:
                return SettingsLanguage::POLISH;
            case utils::Lang::De:
                return SettingsLanguage::GERMAN;
            case utils::Lang::Sp:
                return SettingsLanguage::SPANISH;
            default:
                return SettingsLanguage::ENGLISH;
            }
        }
    }
    } // namespace

    ApplicationHandle::ApplicationHandle(std::unique_ptr<app::ApplicationLauncher> &&_launcher)
        : launcher{std::move(_launcher)}
    {}

    const char *VirtualAppManager::stateStr(State st)
    auto ApplicationHandle::name() const -> Name
    {
        switch (st) {
        case State::IDLE:
            return "IDLE";
        case State::CLOSING_PREV_APP:
            return "CLOSING_PREV_APP";
        case State::WAITING_CLOSE_CONFIRMATION:
            return "WAITING_CLOSE_CONFIRMATION";
        case State::STARTING_NEW_APP:
            return "STARTING_NEW_APP";
        case State::WAITING_NEW_APP_REGISTRATION:
            return "WAITING_NEW_APP_REGISTRATION";
        case State::WAITING_LOST_FOCUS_CONFIRMATION:
            return "WAITING_LOST_FOCUS_CONFIRMATION";
        case State::WAITING_GET_FOCUS_CONFIRMATION:
            return "WAITING_GET_FOCUS_CONFIRMATION";
        }
        // there was enum added - fix it adding it to case
        return "FIX_ME";
        return launcher ? launcher->getName() : InvalidAppName.data();
    }

    ApplicationDescription *VirtualAppManager::appFront()
    auto ApplicationHandle::state() const noexcept -> State
    {
        return applications.front();
        return launcher && launcher->handle ? launcher->handle->getState() : State::NONE;
    }

    ApplicationDescription *VirtualAppManager::appGet(const std::string &name)
    void ApplicationHandle::setState(State state) noexcept
    {
        auto el = std::find_if(applications.begin(), applications.end(), [=](auto a) {
            if (a->name() == name)
                return true;
            else
                return false;
        });
        if (el == applications.end())
            return nullptr;
        else {
            return *el;
        if (launcher && launcher->handle) {
            launcher->handle->setState(state);
        }
    }

    /// set application as first on the applications vector
    bool VirtualAppManager::appMoveFront(ApplicationDescription *app)
    auto ApplicationHandle::preventsBlocking() const noexcept -> bool
    {
        if (!app) {
            return false;
        }
        auto el = std::find_if(applications.begin(), applications.end(), [=](auto a) { return a == app; });
        if (el != applications.end()) {
            applications.push_front(std::move(*el));
            applications.erase(el);
            return true;
        }
        return false;
        return launcher ? launcher->isBlocking() : false;
    }

    /// get previous visible app - one on FOREGROUND
    ApplicationDescription *VirtualAppManager::appPrev()
    auto ApplicationHandle::closeable() const noexcept -> bool
    {
        static bool init = true;
        if (init) {
            init = false;
            return nullptr;
        }
        if (applications.size() < 2) {
            return nullptr;
        }
        return *std::next(applications.begin());
        return launcher ? launcher->isCloseable() : false;
    }

    void VirtualAppManager::setState(State st)
    auto ApplicationHandle::started() const noexcept -> bool
    {
        LOG_DEBUG("app: [%s] prev: [%s], state: (%s) -> (%s)",
                  appFront()->name().c_str(),
                  appPrev() ? appPrev()->name().c_str() : "",
                  stateStr(state),
                  stateStr(st));
        state = st;
        const auto appState = state();
        return appState == State::ACTIVE_FORGROUND || appState == State::ACTIVE_BACKGROUND ||
               appState == State::ACTIVATING;
    }

    std::list<ApplicationDescription *> &VirtualAppManager::getApps()
    void ApplicationHandle::run(sys::Service *caller)
    {
        return applications;
        if (launcher) {
            launcher->run(caller);
        }
    }

    void VirtualAppManager::debug_log_app_list()
    void ApplicationHandle::runInBackground(sys::Service *caller)
    {
        std::string apps = "\n";
        for (auto &el : getApps()) {
            apps += "-> " + el->name() + " " + app::Application::stateStr(el->getState()) + "\n";
        if (launcher) {
            launcher->runBackground(caller);
        }

#if DEBUG_APPLICATION_MANAGEMENT == 1
        LOG_DEBUG(apps.c_str());
#endif
    }

    ApplicationManager::ApplicationManager(const std::string &name,
                                           sys::SystemManager *sysmgr,
                                           std::vector<std::unique_ptr<app::ApplicationLauncher>> &launchers)
        : Service(name), VirtualAppManager(launchers), systemManager{sysmgr}
    ApplicationManagerBase::ApplicationManagerBase(std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers)
    {
        blockingTimer = std::make_unique<sys::Timer>(
            "BlockTimer", this, std::numeric_limits<sys::ms>().max(), sys::Timer::Type::SingleShot);
        blockingTimer->connect([&](sys::Timer &) { phoneLockCB(); });
        std::vector<std::unique_ptr<app::ApplicationLauncher>> container = std::move(launchers);
        for (auto &&launcher : container) {
            applications.push_back(std::make_unique<ApplicationHandle>(std::move(launcher)));
        }
    }

        connect(typeid(APMAction), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto actionMsg = static_cast<APMAction *>(request);
            handleAction(actionMsg);
            return std::make_shared<sys::ResponseMessage>();
        });
    void ApplicationManagerBase::setState(State _state) noexcept
    {
        state = _state;
    }

    ApplicationManager::~ApplicationManager()
    void ApplicationManagerBase::pushApplication(const ApplicationHandle::Name &name)
    {
        systemManager = nullptr;
        stack.push_front(name);
    }

    bool ApplicationManager::closeServices()
    void ApplicationManagerBase::popApplication()
    {
        bool ret = sys::SystemManager::DestroyService("ServiceGUI", this);
        if (ret) {
            LOG_INFO("Service: %s closed", "ServiceGUI");
        }
        else {
            LOG_FATAL("Service: %s is still running", "ServiceGUI");
        }
        ret = sys::SystemManager::DestroyService("ServiceEink", this);
        if (ret) {
            LOG_INFO("Service: %s closed", "ServiceEink");
        }
        else {
            LOG_FATAL("Service: %s is still running", "ServiceEink");
        if (!stack.empty()) {
            stack.pop_front();
        }
        return true;
    }

    bool ApplicationManager::closeApplications()
    void ApplicationManagerBase::clearStack()
    {
        stack.clear();
    }

        // if application is started, its in first plane or it's working in background
        // it will be closed using SystemManager's API.
        for (auto &app : getApps()) {
            if (app != nullptr && ((app->getState() == app::Application::State::ACTIVE_FORGROUND) ||
                                   (app->getState() == app::Application::State::ACTIVE_BACKGROUND) ||
                                   (app->getState() == app::Application::State::ACTIVATING))) {
                LOG_INFO("Closing application: %s", app->name().c_str());
                bool ret = sys::SystemManager::DestroyService(app->name(), this);
                if (ret) {
                    LOG_INFO("Application: %s closed", app->name().c_str());
                }
                else {
                    LOG_FATAL("Application: %s is still running", app->name().c_str());
                }
                app->setState(app::Application::State::DEACTIVATED);
    auto ApplicationManagerBase::getFocusedApplication() const noexcept -> ApplicationHandle *
    {
        for (const auto &appName : stack) {
            if (auto app = getApplication(appName);
                app != nullptr && app->state() == app::Application::State::ACTIVE_FORGROUND) {
                return app;
            }
        }
        return true;
        return nullptr;
    }

    sys::Message_t ApplicationManager::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
    auto ApplicationManagerBase::getLaunchingApplication() const noexcept -> ApplicationHandle *
    {

        auto msgType = msgl->messageType;

        switch (msgType) {
        case MessageType::APMCheckAppRunning: {
            auto appcheck = dynamic_cast<sapm::APMCheckApp *>(msgl);
            assert(appcheck);
            auto ret = std::make_shared<APMCheckApp>(this->GetName(), appcheck->appNameToCheck);
            if (appGet(appcheck->appNameToCheck) != nullptr) {
                ret->isRunning = true;
            }
            else {
                ret->isRunning = false;
            }
            return ret;
        } break;
        case MessageType::APMInitPowerSaveMode: {
            handlePowerSavingModeInit();
        } break;
        case MessageType::APMPreventBlocking: {
            blockingTimer->reload();
        } break;
        case MessageType::APMSwitch: {
            sapm::APMSwitch *msg = reinterpret_cast<sapm::APMSwitch *>(msgl);
            handleSwitchApplication(msg);
        } break;
        case MessageType::APMSwitchPrevApp: {
            sapm::APMSwitchPrevApp *msg = reinterpret_cast<sapm::APMSwitchPrevApp *>(msgl);
            if (!handleSwitchPrevApplication(msg)) {
                LOG_ERROR("Switch from app: %s failed", msg->getSenderName().c_str());
            }
        } break;
        case MessageType::APMConfirmSwitch: {
            sapm::APMConfirmSwitch *msg = reinterpret_cast<sapm::APMConfirmSwitch *>(msgl);
            handleSwitchConfirmation(msg);
        } break;
        case MessageType::APMConfirmClose: {
            sapm::APMConfirmClose *msg = reinterpret_cast<sapm::APMConfirmClose *>(msgl);
            LOG_INFO("APMConfirmClose %s", msg->getSenderName().c_str());
            handleCloseConfirmation(msg);

            // if application manager was waiting for close confirmation and name of the application
            // for launching is defined then start application function is called
            if ((getState() == State::WAITING_CLOSE_CONFIRMATION) && (launchApplicationName.empty() == false)) {
                startApplication(launchApplicationName);
            }
        } break;
        case MessageType::APMDeleydClose: {
            sapm::APMDelayedClose *msg = reinterpret_cast<sapm::APMDelayedClose *>(msgl);
            LOG_INFO("APMDeleydClose %s", msg->getApplication().c_str());
            sys::SystemManager::DestroyService(msg->getApplication().c_str(), this);
        } break;
        case MessageType::APMRegister: {
            sapm::APMRegister *msg = reinterpret_cast<sapm::APMRegister *>(msgl);
            LOG_INFO("APMregister [%s] (%s)", msg->getSenderName().c_str(), (msg->getStatus() ? "true" : "false"));
            handleRegisterApplication(msg);
        } break;
        case MessageType::APMChangeLanguage: {
            sapm::APMChangeLanguage *msg = reinterpret_cast<sapm::APMChangeLanguage *>(msgl);
            std::string lang;
            if (msg->getLanguage() == utils::Lang::En)
                lang = "English";
            if (msg->getLanguage() == utils::Lang::Pl)
                lang = "Polish";
            if (msg->getLanguage() == utils::Lang::De)
                lang = "German";
            if (msg->getLanguage() == utils::Lang::Sp)
                lang = "Spanish";
            LOG_INFO("APChangeLanguage; %s %s", msg->getSenderName().c_str(), lang.c_str());
            handleLanguageChange(msg);
        } break;
        case MessageType::APMClose: {
            closeApplications();
            closeServices();
        } break;
        default: {
        } break;
        };

        return std::make_shared<sys::ResponseMessage>();
        if (stack.empty()) {
            return nullptr;
        }
        auto app = getApplication(stack.front());
        return app->state() != app::Application::State::ACTIVE_FORGROUND ? app : nullptr;
    }

    void ApplicationManager::phoneLockCB()
    auto ApplicationManagerBase::getPreviousApplication() const noexcept -> ApplicationHandle *
    {
#ifdef AUTO_PHONE_LOCK_ENABLED

        LOG_INFO("screen Locking Timer Triggered");
        blockingTimer->stop();

        // check if application that has focus doesn't have a flag that prevents system from blocking and going to
        // low power mode
        ApplicationDescription *appDescription = appGet(focusApplicationName);
        if (appDescription->preventsLocking()) {
            blockingTimer->reload();
            return;
        if (stack.size() < 2) {
            return nullptr;
        }
        return getApplication(stack[1]);
    }

        // if desktop has focus switch to main window and set it locked.
        if (focusApplicationName == app::name_desktop) {
            // switch data must contain target window and information about blocking

            app::Application::messageSwitchApplication(
                this, app::name_desktop, gui::name::window::main_window, std::make_unique<gui::LockPhoneData>());
    auto ApplicationManagerBase::getApplication(const ApplicationHandle::Name &name) const noexcept
        -> ApplicationHandle *
    {
        auto it = std::find_if(
            applications.begin(), applications.end(), [&name](const auto &app) { return app->name() == name; });
        if (it == applications.end()) {
            return nullptr;
        }
        else {
            // get the application description for application that is on top and set blocking flag for it
            appDescription->blockClosing = true;

            std::unique_ptr<gui::LockPhoneData> data = std::make_unique<gui::LockPhoneData>();
            data->setPrevApplication(focusApplicationName);
        return it->get();
    }

            // run normal flow of applications change
            messageSwitchApplication(this, app::name_desktop, gui::name::window::main_window, std::move(data));
        }
#endif
    ApplicationManager::ApplicationManager(const std::string &serviceName,
                                           std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers,
                                           const ApplicationHandle::Name &_rootApplicationName)
        : Service{serviceName}, ApplicationManagerBase(std::move(launchers)), rootApplicationName{_rootApplicationName},
          blockingTimer{std::make_unique<sys::Timer>(
              "BlockTimer", this, std::numeric_limits<sys::ms>::max(), sys::Timer::Type::SingleShot)}
    {
        registerMessageHandlers();
        blockingTimer->connect([this](sys::Timer &) { onPhoneLocked(); });
    }

    // Invoked during initialization
    sys::ReturnCodes ApplicationManager::InitHandler()
    {

        // get settings to initialize language in applications
        settings = DBServiceAPI::SettingsGet(this);
        blockingTimer->setInterval(settings.lockTime != 0 ? settings.lockTime : default_application_locktime_ms);
        utils::localize.Switch(toUtilsLanguage(settings.language));

        // reset blocking timer to the value specified in settings
        uint32_t lockTime = settings.lockTime;
        if (lockTime == 0) {
            lockTime = default_application_locktime;
        startSystemServices();
        startBackgroundApplications();
        if (auto app = getApplication(rootApplicationName); app != nullptr) {
            Controller::switchApplication(this, rootApplicationName, std::string{}, nullptr);
        }
        blockingTimer->setInterval(lockTime);

        if (settings.language == SettingsLanguage::ENGLISH) {
            utils::localize.Switch(utils::Lang::En);
        }
        else if (settings.language == SettingsLanguage::POLISH) {
            utils::localize.Switch(utils::Lang::Pl);
        }
        else if (settings.language == SettingsLanguage::GERMAN) {
            utils::localize.Switch(utils::Lang::De);
        }
        else if (settings.language == SettingsLanguage::SPANISH) {
            utils::localize.Switch(utils::Lang::Sp);
        }
        return sys::ReturnCodes::Success;
    }

        bool ret;
        ret = sys::SystemManager::CreateService(std::make_shared<sgui::ServiceGUI>("ServiceGUI", GetName(), 480, 600),
                                                this);
        if (!ret) {
    void ApplicationManager::startSystemServices()
    {
        if (bool ret = sys::SystemManager::CreateService(
                std::make_shared<sgui::ServiceGUI>(GUIServiceName, GetName(), 480, 600), this);
            !ret) {
            LOG_ERROR("Failed to initialize GUI service");
        }
        ret = sys::SystemManager::CreateService(std::make_shared<ServiceEink>("ServiceEink", GetName()), this);
        if (!ret) {
            LOG_ERROR("Failed to initialize EINK service");
        if (bool ret =
                sys::SystemManager::CreateService(std::make_shared<ServiceEink>(EInkServiceName, GetName()), this);
            !ret) {
            LOG_ERROR("Failed to initialize EInk service");
        }
    }

        // search for application with specified name and run it
#if 1 // change to 0 if you want to run only viewer application for kickstarter

        // TODO this should be checked by parameter in launcher, not started by hand (if bg task -> runBackground())
        const std::string app_desktop          = app::name_desktop;
        const std::vector<std::string> bg_apps = {app::name_call, app::special_input};
    void ApplicationManager::suspendSystemServices()
    {
        sys::SystemManager::SuspendService(GUIServiceName, this);
        sys::SystemManager::SuspendService(EInkServiceName, this);
    }

        for (auto &el : bg_apps) {
            auto app = appGet(el);
            if (app != nullptr) {
                app->launcher->runBackground(this);
    void ApplicationManager::startBackgroundApplications()
    {
        for (const auto &name : std::vector<ApplicationHandle::Name>{app::name_call, app::special_input}) {
            if (auto app = getApplication(name); app != nullptr) {
                app->runInBackground(this);
            }
        }

        auto app = appGet(app_desktop);
        if (app != nullptr) {
            messageSwitchApplication(this, app->launcher->getName(), "", nullptr);
        }

#else
        std::string runCallAppName = "ApplicationViewer";

        auto it = applications.find(runCallAppName);
        if (it != applications.end()) {
            messageSwitchApplication(this, it->second->lanucher->getName(), "", nullptr);
        }
#endif

        return sys::ReturnCodes::Success;
    }

    sys::ReturnCodes ApplicationManager::DeinitHandler()


@@ 413,139 248,209 @@ namespace sapm
        return sys::ReturnCodes::Success;
    }

    auto ApplicationManager::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msgl,
                                                 [[maybe_unused]] sys::ResponseMessage *resp) -> sys::Message_t
    {
        return std::make_shared<sys::ResponseMessage>();
    }

    void ApplicationManager::registerMessageHandlers()
    {
        connect(typeid(APMCheckApp), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg       = static_cast<APMCheckApp *>(request);
            auto ret       = std::make_shared<APMCheckApp>(GetName(), msg->checkAppName);
            ret->isRunning = getApplication(msg->checkAppName) != nullptr;
            return ret;
        });
        connect(typeid(APMInitPowerSaveMode), [this](sys::DataMessage *, sys::ResponseMessage *) {
            handlePowerSavingModeInit();
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMPreventBlocking), [this](sys::DataMessage *, sys::ResponseMessage *) {
            blockingTimer->reload();
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMSwitch), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMSwitch *>(request);
            handleSwitchApplication(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMSwitchPrevApp), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMSwitchPrevApp *>(request);
            handleSwitchBack(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMConfirmSwitch), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMConfirmSwitch *>(request);
            handleSwitchConfirmation(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMConfirmClose), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMConfirmClose *>(request);
            handleCloseConfirmation(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMDelayedClose), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMDelayedClose *>(request);
            closeService(msg->getApplication());
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMRegister), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMRegister *>(request);
            handleRegisterApplication(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMChangeLanguage), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto msg = static_cast<APMChangeLanguage *>(request);
            handleLanguageChange(msg);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMClose), [this](sys::DataMessage *, sys::ResponseMessage *) {
            closeApplications();
            closeServices();
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(APMAction), [this](sys::DataMessage *request, sys::ResponseMessage *) {
            auto actionMsg = static_cast<APMAction *>(request);
            handleAction(actionMsg);
            return std::make_shared<sys::ResponseMessage>();
        });
    }

    sys::ReturnCodes ApplicationManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
    {
        LOG_FATAL("[ServiceAppMgr] PowerModeHandler: %s", c_str(mode));
        LOG_INFO("Power mode: %s", c_str(mode));

        switch (mode) {
        case sys::ServicePowerMode ::Active:
            sys::SystemManager::ResumeService("ServiceEink", this);
            sys::SystemManager::ResumeService("ServiceGUI", this);
            sys::SystemManager::ResumeService(EInkServiceName, this);
            sys::SystemManager::ResumeService(GUIServiceName, this);
            break;
        case sys::ServicePowerMode ::SuspendToRAM:
            [[fallthrough]];
        case sys::ServicePowerMode ::SuspendToNVM:
            sys::SystemManager::SuspendService("ServiceGUI", this);
            sys::SystemManager::SuspendService("ServiceEink", this);
            suspendSystemServices();
            break;
        }

        return sys::ReturnCodes::Success;
    }

    bool ApplicationManager::startApplication(const std::string &appName)
    auto ApplicationManager::startApplication(ApplicationHandle &app) -> bool
    {

        setState(State::STARTING_NEW_APP);
        // search map for application's description structure with specified name
        auto app = appGet(appName);
        if (app == nullptr) {
            LOG_ERROR("Can't run: %s no such app", appName.c_str());
            return false;
        }

        if (app->getState() == app::Application::State::ACTIVE_BACKGROUND) {
            setState(State::WAITING_GET_FOCUS_CONFIRMATION);
            LOG_INFO("switching focus to application: [%s] window [%s]", appName.c_str(), app->switchWindow.c_str());
            app::Application::messageSwitchApplication(
                this, launchApplicationName, app->switchWindow, std::move(app->switchData));
        if (app.state() == ApplicationHandle::State::ACTIVE_BACKGROUND) {
            LOG_INFO("Switching focus to application [%s] (window [%s])", app.name().c_str(), app.switchWindow.c_str());
            setState(State::AwaitingFocusConfirmation);
            app::Application::messageSwitchApplication(this, app.name(), app.switchWindow, std::move(app.switchData));
        }
        else {
            setState(State::WAITING_NEW_APP_REGISTRATION);
            LOG_INFO("starting application: %s", appName.c_str());
            app->launcher->run(this);
            LOG_INFO("Starting application %s", app.name().c_str());
            app.run(this);
        }

        return true;
    }

    bool ApplicationManager::handlePowerSavingModeInit()
    auto ApplicationManager::closeServices() -> bool
    {
        closeService(GUIServiceName);
        closeService(EInkServiceName);
        return true;
    }

        LOG_INFO("Going to suspend mode");
    auto ApplicationManager::closeApplications() -> bool
    {
        for (const auto &app : getApplications()) {
            if (app->started()) {
                LOG_INFO("Closing application %s", app->name().c_str());
                closeService(app->name());
                app->setState(ApplicationHandle::State::DEACTIVATED);
            }
        }
        return true;
    }

        sys::SystemManager::SuspendService("ServiceGUI", this);
        sys::SystemManager::SuspendService("ServiceEink", this);
    void ApplicationManager::closeService(const std::string &name)
    {
        bool ret = sys::SystemManager::DestroyService(name, this);
        if (ret) {
            LOG_INFO("Service/Application %s closed", name.c_str());
        }
        else {
            LOG_FATAL("Service/Application %s is still running", name.c_str());
        }
    }

    auto ApplicationManager::handlePowerSavingModeInit() -> bool
    {
        LOG_INFO("Going to suspend mode");
        suspendSystemServices();
        sys::SystemManager::SuspendSystem(this);

        return true;
    }

    // tries to switch the application
    bool ApplicationManager::handleSwitchApplication(APMSwitch *msg)
    auto ApplicationManager::handleSwitchApplication(APMSwitch *msg) -> bool
    {

        // first check if there is application specified in the message
        auto app = appGet(msg->getName());
        if (!app) {
            LOG_ERROR("Cant switch to app: %s , doesn't exist", msg->getName().c_str());
        auto app = getApplication(msg->getName());
        if (app == nullptr) {
            LOG_ERROR("Failed to switch to application %s: No such application.", msg->getName().c_str());
            return false;
        }

        // check if specified application is not the application that is currently running
        // this is applicable to all applications except desktop
        if ((focusApplicationName == msg->getName())) {
            LOG_WARN("Trying to return currently active application");
        auto currentlyFocusedApp = getFocusedApplication();
        if (currentlyFocusedApp == nullptr) {
            LOG_INFO("No focused application at the moment. Starting new application...");
            onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
            startApplication(*app);
            return true;
        }

        if (app->name() == currentlyFocusedApp->name()) {
            LOG_WARN("Failed to return to currently focused application.");
            return false;
        }

        // store the name of the application to be executed and start closing previous application
        launchApplicationName = msg->getName();
        onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
        const bool isFocusedAppCloseable = !(app->switchData && app->switchData->disableAppClose) &&
                                           currentlyFocusedApp->closeable() && !currentlyFocusedApp->blockClosing;
        requestApplicationClose(*currentlyFocusedApp, isFocusedAppCloseable);
        return true;
    }

        // store window and data if there is any
        app->switchData   = std::move(msg->getData());
        app->switchWindow = msg->getWindow();
        setState(State::CLOSING_PREV_APP);
    void ApplicationManager::onApplicationSwitch(ApplicationHandle &app,
                                                 std::unique_ptr<gui::SwitchData> &&data,
                                                 std::string targetWindow)
    {
        if (app.name() == rootApplicationName) {
            clearStack();
        }
        pushApplication(app.name());
        app.switchData   = std::move(data);
        app.switchWindow = std::move(targetWindow);
    }

        // check if there was previous application
        if (!focusApplicationName.empty()) {
            if (launchApplicationName == app::name_desktop) {
                appStack.clear();
            }
            else {
                appStack.push_back(focusApplicationName);
                LOG_DEBUG("LaunchApp: %s", launchApplicationName.c_str());
            }
            /// if we want to disable closing previous app - then forbid killing it - it will be moved to background
            /// instead
            bool kill_prev = true;
            if (app->switchData != nullptr && app->switchData->disableAppClose) {
                kill_prev = false;
            }
            previousApplicationName = focusApplicationName;
            auto app                = appGet(previousApplicationName);
            // if application's launcher defines that it can be closed send message with close signal
            if (kill_prev && (app->closeable()) && (app->blockClosing == false)) {
                LOG_INFO("APMSwitch waiting for close confirmation from: %s", previousApplicationName.c_str());
                setState(State::WAITING_CLOSE_CONFIRMATION);
                app::Application::messageCloseApplication(this, previousApplicationName);
            }
            // if application is not closeable send lost focus message
            else {
                LOG_INFO("APMSwitch Waiting for lost focus from: %s", previousApplicationName.c_str());
                setState(State::WAITING_LOST_FOCUS_CONFIRMATION);
                app::Application::messageSwitchApplication(this, previousApplicationName, "", nullptr);
            }
    void ApplicationManager::requestApplicationClose(ApplicationHandle &app, bool isCloseable)
    {
        if (isCloseable) {
            LOG_INFO("Closing application %s", app.name().c_str());
            setState(State::AwaitingCloseConfirmation);
            app::Application::messageCloseApplication(this, app.name());
        }
        // if there was no application to close or application can't be closed change internal state to
        // STARTING_NEW_APP and send execute lanuchers for that application
        else {
            startApplication(app->name());
            LOG_INFO("Application %s is about to lose focus.", app.name().c_str());
            setState(State::AwaitingLostFocusConfirmation);
            app::Application::messageApplicationLostFocus(this, app.name());
        }

        return true;
    }

    auto ApplicationManager::handleAction(APMAction *actionMsg) -> bool
    {
        auto &action         = actionMsg->getAction();
        const auto targetApp = appGet(action.targetApplication);
        const auto targetApp = getApplication(action.targetApplication);
        if (targetApp == nullptr) {
            LOG_ERROR("Failed to switch to %s application: No such application.", action.targetApplication.c_str());
            return false;
        }

        if (targetApp->getState() == app::Application::State::ACTIVE_FORGROUND) {
        if (targetApp->state() == app::Application::State::ACTIVE_FORGROUND) {
            // If the app is already focused, then switch window.
            auto msg = std::make_shared<app::AppSwitchWindowMessage>(
                action.targetWindow, std::string{}, std::move(action.data), gui::ShowMode::GUI_SHOW_INIT);


@@ 556,354 461,213 @@ namespace sapm
        return handleSwitchApplication(&switchRequest);
    }

    // tries to switch the application
    bool ApplicationManager::handleSwitchPrevApplication(APMSwitchPrevApp *msg)
    auto ApplicationManager::handleSwitchBack(APMSwitchPrevApp *msg) -> bool
    {

        // if there is no previous application return false and do nothing
        if (previousApplicationName.empty()) {
        auto previousApp = getPreviousApplication();
        if (previousApp == nullptr) {
            LOG_WARN("Failed to switch to the previous application: No such application.");
            return false;
        }

        if (appStack.empty()) {
            LOG_ERROR("appStack is empty");
            return false;
        }

        previousApplicationName = appStack.back();
        appStack.pop_back();
        if (previousApplicationName == app::name_desktop && appStack.size()) {
            std::string names = "";
            for (auto &el : appStack) {
                names += el + "<-";
            }
            LOG_ERROR("%s isn't top application! [%s]", app::name_desktop.c_str(), names.c_str());
        }

        // check if previous application is stored in the description vector
        auto app = appGet(previousApplicationName);
        if (!app) {
            // specified application was not found, exiting
            LOG_ERROR("Unable to find previous application: %s", previousApplicationName.c_str());
            return false;
        auto currentlyFocusedApp = getFocusedApplication();
        if (currentlyFocusedApp == nullptr) {
            LOG_INFO("No focused application at the moment. Starting previous application...");
            onApplicationSwitchToPrev(*previousApp, std::move(msg->getData()));
            startApplication(*previousApp);
            return true;
        }

        // check if specified application is not the application that is currently running
        if (focusApplicationName == previousApplicationName) {
            LOG_WARN("Trying to return currently active application");
        if (previousApp->name() == currentlyFocusedApp->name()) {
            LOG_WARN("Failed to return to currently focused application.");
            return false;
        }

        LOG_DEBUG("Switch PrevApp: [%s](%s) -> [%s](%s)",
                  focusApplicationName.c_str(),
                  app::Application::stateStr(appGet(previousApplicationName)->getState()),
                  previousApplicationName.c_str(),
                  app::Application::stateStr(appGet(previousApplicationName)->getState()));
        // set name of the application to be executed and start closing previous application
        launchApplicationName = previousApplicationName;
        // store window and data if there is any
        app->switchData   = std::move(msg->getData());
        app->switchWindow = "LastWindow";
        setState(State::CLOSING_PREV_APP);

        // check if there was previous application
        if (!focusApplicationName.empty()) {
            previousApplicationName = focusApplicationName;
            auto app                = appGet(previousApplicationName);

            // if application's launcher defines that it can be closed send message with close signal
            if (app->closeable()) {
                LOG_INFO("Closing application: %s", previousApplicationName.c_str());
                setState(State::WAITING_CLOSE_CONFIRMATION);
                app::Application::messageCloseApplication(this, previousApplicationName);
            }
            // if application is not closeable send lost focus message
            else {
                setState(State::WAITING_LOST_FOCUS_CONFIRMATION);
                app::Application::messageSwitchApplication(this, previousApplicationName, "", nullptr);
            }
        }
        // if there was no application to close or application can't be closed change internal state to
        // STARTING_NEW_APP and send execute lanuchers for that application
        else {
            startApplication(app->name());
        }
        LOG_DEBUG("Switch applications: [%s](%s) -> [%s](%s)",
                  currentlyFocusedApp->name().c_str(),
                  app::Application::stateStr(currentlyFocusedApp->state()),
                  previousApp->name().c_str(),
                  app::Application::stateStr(previousApp->state()));

        onApplicationSwitchToPrev(*previousApp, std::move(msg->getData()));
        requestApplicationClose(*currentlyFocusedApp, currentlyFocusedApp->closeable());
        return true;
    }

    bool ApplicationManager::handleRegisterApplication(APMRegister *msg)
    void ApplicationManager::onApplicationSwitchToPrev(ApplicationHandle &previousApp,
                                                       std::unique_ptr<gui::SwitchData> &&data,
                                                       std::string targetWindow)
    {
        auto app = appGet(msg->getSenderName());
        popApplication();
        previousApp.switchData   = std::move(data);
        previousApp.switchWindow = std::move(targetWindow);
    }

    auto ApplicationManager::handleRegisterApplication(APMRegister *msg) -> bool
    {
        auto app = getApplication(msg->getSenderName());
        if (app == nullptr) {
            LOG_ERROR("can't register: %s no such app in `applicationsk`", msg->getSenderName().c_str());
            LOG_ERROR("Failed to register %s: No such application.", msg->getSenderName().c_str());
            return false;
        }
        LOG_DEBUG("Register ---------> %s", msg->getSenderName().c_str());

        if (msg->getSenderName() == launchApplicationName) {
            // application starts in background
            if (msg->getStartBackground()) {
                app->setState(app::Application::State::ACTIVE_BACKGROUND);
                setState(State::IDLE);
            }
            else {
                app->setState(app::Application::State::ACTIVATING);
                setState(State::WAITING_GET_FOCUS_CONFIRMATION);
                LOG_INFO("switchApplication %s %s",
                         launchApplicationName.c_str(),
                         app->switchData ? app->switchData->getDescription().c_str() : "");
                app::Application::messageSwitchApplication(
                    this, launchApplicationName, app->switchWindow, std::move(app->switchData));
            }
        if (msg->getStatus()) {
            onApplicationRegistered(*app, msg->getStartBackground());
        }
        else {
            app->setState(app::Application::State::ACTIVE_BACKGROUND);
            onApplicationRegistrationFailure(*app);
        }

        LOG_DEBUG("Send notification!");
        auto notification = std::make_shared<APMCheckApp>(this->GetName(), msg->getSenderName());
        auto notification = std::make_shared<APMCheckApp>(GetName(), app->name());
        sys::Bus::SendMulticast(notification, sys::BusChannels::AppManagerNotifications, this);

        return true;
    }

    bool ApplicationManager::handleLanguageChange(sapm::APMChangeLanguage *msg)
    void ApplicationManager::onApplicationRegistered(ApplicationHandle &app, bool startInBackground)
    {
        LOG_DEBUG("Application %s registered successfully.", app.name().c_str());

        // check if selected language is different than the one that is in the settings
        // if they are the same, return doing nothing
        SettingsLanguage requestedLanguage;
        switch (msg->getLanguage()) {
        case utils::Lang::En:
            requestedLanguage = SettingsLanguage::ENGLISH;
            break;
        case utils::Lang::Pl:
            requestedLanguage = SettingsLanguage::POLISH;
            break;
        case utils::Lang::De:
            requestedLanguage = SettingsLanguage::GERMAN;
            break;
        case utils::Lang::Sp:
            requestedLanguage = SettingsLanguage::SPANISH;
            break;
        default:
            requestedLanguage = SettingsLanguage::ENGLISH;
            break;
        };
        auto launchingApp = getLaunchingApplication();
        if (launchingApp == nullptr || launchingApp->name() != app.name()) {
            app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
            return;
        }

        // if requested language is different than current update settings and i18 translations
        if (requestedLanguage != settings.language) {
            settings          = DBServiceAPI::SettingsGet(this);
            settings.language = requestedLanguage;
            DBServiceAPI::SettingsUpdate(this, settings);
            utils::localize.Switch(msg->getLanguage());
        if (startInBackground) {
            setState(State::Running);
            app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
        }
        else {
            LOG_WARN("Selected language is already set. Ignoring command.");
            return true;
        }

        // iterate over all applications in the background or foreground state and send them rebuild command
        for (auto &app : getApps()) {
            if (app && app->launcher && app->launcher->handle &&
                (app->launcher->handle->getState() == app::Application::State::ACTIVE_BACKGROUND ||
                 app->launcher->handle->getState() == app::Application::State::ACTIVE_FORGROUND)) {
                app::Application::messageRebuildApplication(this, app->name());
            }
            LOG_INFO("Switch application to %s", app.name().c_str());
            app.setState(ApplicationHandle::State::ACTIVATING);
            setState(State::AwaitingFocusConfirmation);
            app::Application::messageSwitchApplication(this, app.name(), app.switchWindow, std::move(app.switchData));
        }

        return true;
    }

    bool ApplicationManager::handleSwitchConfirmation(APMConfirmSwitch *msg)
    void ApplicationManager::onApplicationRegistrationFailure(ApplicationHandle &app)
    {
        std::string app_name =
            getState() == State::WAITING_GET_FOCUS_CONFIRMATION ? msg->getSenderName() : focusApplicationName;
        ApplicationDescription *app = appGet(app_name);
        if (app == nullptr) {
            LOG_ERROR("Can't handle switch confirmation to: %s", app_name.c_str());
            return false;
        }

        /// move application with focus to front
        {
            auto app = appGet(msg->getSenderName());
            if (app && app->getState() == app::Application::State::ACTIVE_FORGROUND) {
                appMoveFront(app);
                debug_log_app_list();
                // notify event manager which application should receive keyboard messages
                EventManager::messageSetApplication(this, app->name());
            }
            else {
                LOG_DEBUG("Focus switch ingored cause: %d %s",
                          app == nullptr,
                          app == nullptr ? "" : app::Application::stateStr(app->getState()));
            }
        }
        // this is the case when application manager is waiting for newly started application to confim that it has
        // successfully gained focus.
        if (getState() == State::WAITING_GET_FOCUS_CONFIRMATION || getState() == State::IDLE) {
            LOG_INFO("APMConfirmSwitch focus confirmed by: [%s]", msg->getSenderName().c_str());
            focusApplicationName  = launchApplicationName;
            launchApplicationName = "";

            app->blockClosing = false;
            app->setState(app::Application::State::ACTIVE_FORGROUND);
            setState(State::IDLE);
            return true;
        }
        // this is the case where application manager is waiting for non-closeable application
        // to confirm that app has lost focus.
        else if (getState() == State::WAITING_LOST_FOCUS_CONFIRMATION) {
            if (msg->getSenderName() == focusApplicationName) {
                LOG_INFO("APMConfirmSwitch Lost focus confirmed by: %s", msg->getSenderName().c_str());
                previousApplicationName = focusApplicationName;
                focusApplicationName    = "";
                app->setState(app::Application::State::ACTIVE_BACKGROUND);
                app->switchWindow = "LastWindow";
                startApplication(launchApplicationName);
                return true;
            }
        }
        LOG_ERROR("APMConfirmSwitch %s : %s state %s",
                  msg->getSenderName().c_str(),
                  focusApplicationName.c_str(),
                  stateStr(getState()));
        return false;
        LOG_ERROR("Failed to register %s: Application initialisation error.", app.name().c_str());
        Controller::switchBack(this);
    }

    bool ApplicationManager::handleCloseConfirmation(APMConfirmClose *msg)
    auto ApplicationManager::handleLanguageChange(app::manager::APMChangeLanguage *msg) -> bool
    {
        auto app = appGet(msg->getSenderName());
        if (app == nullptr) {
            LOG_ERROR("can't handle: %s app: %s doesn't exist", __FUNCTION__, msg->getSenderName().c_str());
            return false;
        const auto requestedLanguage = toSettingsLanguage(msg->getLanguage());
        if (requestedLanguage == settings.language) {
            LOG_WARN("The selected language is already set. Ignore.");
            return true;
        }

        // if application is running and it's not closeable set state to active background
        // otherwise it means that application is ready to be closed by using DestroyService api
        if (app->closeable()) {
            // internally send close message to allow response message to be sended to application
            // that has confirmed close request.
            app->setState(app::Application::State::DEACTIVATED);
            auto msg = std::make_shared<sapm::APMDelayedClose>(this->GetName(), previousApplicationName);
            sys::Bus::SendUnicast(msg, "ApplicationManager", this);
        }
        else {
            app->setState(app::Application::State::ACTIVE_BACKGROUND);
        }
        settings          = DBServiceAPI::SettingsGet(this);
        settings.language = requestedLanguage;

        DBServiceAPI::SettingsUpdate(this, settings);
        utils::localize.Switch(msg->getLanguage());
        rebuildActiveApplications();
        return true;
    }

    // Static methods
    auto ApplicationManager::sendAction(sys::Service *sender, Action &&action) -> bool
    void ApplicationManager::rebuildActiveApplications()
    {
        auto msg = std::make_shared<APMAction>(sender->GetName(), std::move(action));
        return sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        for (const auto &app : getApplications()) {
            if (app && app->launcher && app->launcher->handle) {
                if (const auto appState = app->state(); appState == ApplicationHandle::State::ACTIVE_FORGROUND ||
                                                        appState == ApplicationHandle::State::ACTIVE_BACKGROUND) {
                    app::Application::messageRebuildApplication(this, app->name());
                }
            }
        }
    }

    bool ApplicationManager::messageSwitchApplication(sys::Service *sender,
                                                      const std::string &applicationName,
                                                      const std::string &windowName,
                                                      std::unique_ptr<gui::SwitchData> data)
    auto ApplicationManager::handleSwitchConfirmation(APMConfirmSwitch *msg) -> bool
    {
        auto msg = std::make_shared<sapm::APMSwitch>(sender->GetName(), applicationName, windowName, std::move(data));
        return sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        auto senderApp = getApplication(msg->getSenderName());
        if (senderApp == nullptr) {
            LOG_ERROR("Failed to switch to %s. No such application.", msg->getSenderName().c_str());
            return false;
        }
        LOG_INFO(
            "Switch confirmed by %s (%s).", senderApp->name().c_str(), app::Application::stateStr(senderApp->state()));
        return onSwitchConfirmed(*senderApp);
    }

    bool ApplicationManager::messageSwitchSpecialInput(sys::Service *sender,
                                                       std::unique_ptr<gui::SwitchSpecialChar> data)
    auto ApplicationManager::onSwitchConfirmed(ApplicationHandle &app) -> bool
    {
        auto val = data->requester;
        // forbid killing prev app, it could be done better - i.e. with state (not this disableAppClose parameter)
        data->disableAppClose = true;
        return (gui::SwitchSpecialChar::Type::Request == data->type)
                   ? messageSwitchApplication(sender, app::special_input, app::char_select, std::move(data))
                   : messageSwitchPreviousApplication(
                         sender, std::make_unique<APMSwitchPrevApp>(data->requester, std::move(data)));
        if (getState() == State::AwaitingFocusConfirmation || getState() == State::Running) {
            app.blockClosing = false;
            app.setState(ApplicationHandle::State::ACTIVE_FORGROUND);
            setState(State::Running);
            EventManager::messageSetApplication(this, app.name());
            return true;
        }
        if (getState() == State::AwaitingLostFocusConfirmation) {
            if (auto launchingApp = getLaunchingApplication(); launchingApp != nullptr) {
                LOG_INFO("Lost focus confirmed by %s. Starting %s application.",
                         app.name().c_str(),
                         launchingApp->name().c_str());
                app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
                app.switchWindow.clear();
                startApplication(*launchingApp);
                return true;
            }
        }
        return false;
    }

    bool ApplicationManager::messageConfirmSwitch(sys::Service *sender)
    auto ApplicationManager::handleCloseConfirmation(APMConfirmClose *msg) -> bool
    {

        auto msg = std::make_shared<sapm::APMConfirmSwitch>(sender->GetName());
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
        auto senderApp = getApplication(msg->getSenderName());
        if (senderApp == nullptr) {
            LOG_ERROR("Failed to handle close confirmation from %s: No such application.",
                      msg->getSenderName().c_str());
            return false;
        }
        return onCloseConfirmed(*senderApp);
    }
    bool ApplicationManager::messageConfirmClose(sys::Service *sender)
    {

        auto msg = std::make_shared<sapm::APMConfirmClose>(sender->GetName());
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
    }
    bool ApplicationManager::messageSwitchPreviousApplication(sys::Service *sender,
                                                              std::unique_ptr<APMSwitchPrevApp> msg)
    auto ApplicationManager::onCloseConfirmed(ApplicationHandle &app) -> bool
    {

        std::shared_ptr<APMSwitchPrevApp> sendMsg;
        if (!msg) {
            sendMsg = std::make_shared<sapm::APMSwitchPrevApp>(sender->GetName());
        if (app.closeable()) {
            app.setState(ApplicationHandle::State::DEACTIVATED);
            Controller::closeApplication(this, app.name());
        }
        else {
            sendMsg = std::move(msg);
            app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
        }
        sys::Bus::SendUnicast(sendMsg, "ApplicationManager", sender);
        return true;
    }

    bool ApplicationManager::messageRegisterApplication(sys::Service *sender,
                                                        const bool &status,
                                                        const bool &startBackground)
    {
        auto msg = std::make_shared<sapm::APMRegister>(sender->GetName(), status, startBackground);
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
    }

    bool ApplicationManager::messageChangeLanguage(sys::Service *sender, utils::Lang language)
    {
        auto msg = std::make_shared<sapm::APMChangeLanguage>(sender->GetName(), language);
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
    }

    bool ApplicationManager::messageCloseApplicationManager(sys::Service *sender)
    {
        auto msg = std::make_shared<sapm::APMClose>(sender->GetName());
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        if (const auto launchingApp = getLaunchingApplication();
            launchingApp != nullptr && getState() == State::AwaitingCloseConfirmation) {
            startApplication(*launchingApp);
        }
        return true;
    }

    bool ApplicationManager::messagePreventBlocking(sys::Service *sender)
    void ApplicationManager::onPhoneLocked()
    {
        auto msg = std::make_shared<sapm::APMPreventBlocking>(sender->GetName());
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
    }
#ifdef AUTO_PHONE_LOCK_ENABLED
        LOG_INFO("Screen lock timer triggered.");
        blockingTimer->stop();

    bool ApplicationManager::messageInitPowerSaveMode(sys::Service *sender)
    {
        auto msg = std::make_shared<sapm::APMInitPowerSaveMode>(sender->GetName());
        sys::Bus::SendUnicast(msg, "ApplicationManager", sender);
        return true;
    }
        auto focusedApp = getFocusedApplication();
        if (focusedApp == nullptr || focusedApp->preventsBlocking()) {
            blockingTimer->reload();
            return;
        }

    bool ApplicationManager::appRunning(sys::Service *sender, const std::string &name)
    {
        auto msg     = std::make_shared<sapm::APMCheckApp>(sender->GetName(), name);
        auto msg_ret = sys::Bus::SendUnicast(msg, "ApplicationManager", sender, 5000);
        if (msg_ret.first != sys::ReturnCodes::Success) {
            LOG_ERROR("Cant send message!");
        if (focusedApp->name() == rootApplicationName) {
            app::Application::messageSwitchApplication(
                this,
                rootApplicationName,
                gui::name::window::main_window,
                std::make_unique<gui::LockPhoneData>(gui::LockPhoneData::Request::NoPin));
        }
        auto ret = dynamic_cast<sapm::APMCheckApp *>(msg_ret.second.get());
        if (ret != nullptr && ret->isRunning) {
            return true;
        else {
            focusedApp->blockClosing = true;
            std::unique_ptr<gui::LockPhoneData> data =
                std::make_unique<gui::LockPhoneData>(gui::LockPhoneData::Request::NoPin);
            data->setPrevApplication(focusedApp->name());
            Controller::switchApplication(this, rootApplicationName, gui::name::window::main_window, std::move(data));
        }
        return false;
        // return true;
#endif
    }

} /* namespace sapm */
} // namespace app::manager

M module-services/service-appmgr/ApplicationManager.hpp => module-services/service-appmgr/ApplicationManager.hpp +106 -227
@@ 1,267 1,146 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_SERVICES_SERVICE_APPMGR_APPLICATIONMANAGER_HPP_
#define MODULE_SERVICES_SERVICE_APPMGR_APPLICATIONMANAGER_HPP_
#pragma once

#include <cstdint>
#include <memory>
#include <string>
#include <map>
#include <string.h>

#include "Application.hpp"
#include "ApplicationLauncher.hpp"
#include "SystemManager/SystemManager.hpp"
#include "messages/APMMessage.hpp"
#include "i18/i18.hpp"

inline uint32_t default_application_locktime = 30000;

namespace app
{
    class ApplicationLauncher;
}

namespace sapm
namespace app::manager
{

    class ApplicationDescription
    class ApplicationHandle
    {
      public:
        ApplicationDescription(std::unique_ptr<app::ApplicationLauncher> launcher);
        virtual ~ApplicationDescription()
        {}
        // name of the application. It's used to find proper application during switching
        std::string name()
        {
            if (launcher) {
                return launcher->getName();
            }
            else {
                return "NONE";
            }
        }
        // launcher to application to the application's start function
        std::unique_ptr<app::ApplicationLauncher> launcher = nullptr;
        // informs application manager that this application temporary musn't be closed.
        // This flag is used to prevent application closing when application is closeable and there is incoming call.
        // This flag is also used when closeable application is on front and there is a timeout to block the
        // applicatioin.
        bool blockClosing = false;
        // switching data stored when application manager had to run init function
        std::unique_ptr<gui::SwitchData> switchData = nullptr;
        std::string switchWindow                    = "";

        // prevents from blocking the system
        bool preventsLocking()
        {
            if (launcher != nullptr) {
                return launcher->isBlocking();
            }
            else {
                return false;
            }
        }

        // informs if it is possible to close application when it looses focus.
        bool closeable()
        {
            if (launcher != nullptr) {
                return launcher->isCloseable();
            }
            return false;
        }

        app::Application::State getState()
        {
            if ((launcher == nullptr) || (launcher->handle == nullptr)) {
                return app::Application::State::NONE;
            }
            else {
                return launcher->handle->getState();
            }
        }

        void setState(app::Application::State st)
        {
            if ((launcher == nullptr) || (launcher->handle == nullptr)) {
                LOG_ERROR("No %s", launcher == nullptr ? "launcher" : "handle");
            }
            else {
                launcher->handle->setState(st);
            }
        }
        static inline constexpr std::string_view InvalidAppName{"NONE"};

        using State = app::Application::State;
        using Name  = std::string;

        explicit ApplicationHandle(std::unique_ptr<app::ApplicationLauncher> &&_launcher);

        void setState(State state) noexcept;
        void run(sys::Service *caller);
        void runInBackground(sys::Service *caller);

        auto name() const -> Name;
        auto state() const noexcept -> State;
        auto preventsBlocking() const noexcept -> bool;
        auto closeable() const noexcept -> bool;
        auto started() const noexcept -> bool;

        std::unique_ptr<app::ApplicationLauncher> launcher; // Handle to the application's start function.
        std::unique_ptr<gui::SwitchData> switchData;
        std::string switchWindow;
        bool blockClosing =
            false; //< Informs the application manager that this application mustn't be closed temporarily.
                   // This flag is used to prevent application closing when application is closeable and there is
                   // incoming call. This flag is also used when closeable application is on front and there is a
                   // timeout to block the application.
    };

    /// this is only to force usage of get/set methods in ApplicatioManager
    class VirtualAppManager
    class ApplicationManagerBase
    {
      public:
        using ApplicationsContainer = std::vector<std::unique_ptr<ApplicationHandle>>;
        using ApplicationsStack     = std::deque<ApplicationHandle::Name>;
        enum class State
        {
            IDLE,
            CLOSING_PREV_APP,
            WAITING_CLOSE_CONFIRMATION,
            STARTING_NEW_APP,
            WAITING_NEW_APP_REGISTRATION,
            WAITING_LOST_FOCUS_CONFIRMATION,
            WAITING_GET_FOCUS_CONFIRMATION
            Running,
            AwaitingFocusConfirmation,
            AwaitingCloseConfirmation,
            AwaitingLostFocusConfirmation
        };

        VirtualAppManager(std::vector<std::unique_ptr<app::ApplicationLauncher>> &launchers);
        virtual ~VirtualAppManager();
        explicit ApplicationManagerBase(std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers);
        virtual ~ApplicationManagerBase() = default;

      private:
        State state = State::IDLE;
        std::list<ApplicationDescription *> applications;
        void pushApplication(const ApplicationHandle::Name &name);
        void popApplication();
        void clearStack();

      public:
        std::list<std::string> appStack;
        State getState()
        auto getFocusedApplication() const noexcept -> ApplicationHandle *;
        auto getLaunchingApplication() const noexcept -> ApplicationHandle *;
        auto getPreviousApplication() const noexcept -> ApplicationHandle *;
        auto getApplication(const ApplicationHandle::Name &name) const noexcept -> ApplicationHandle *;
        auto getApplications() const noexcept -> const ApplicationsContainer &
        {
            return applications;
        }

        void setState(State _state) noexcept;
        auto getState() const noexcept -> State
        {
            return state;
        }
        static const char *stateStr(State st);
        ApplicationDescription *appFront();
        ApplicationDescription *appGet(const std::string &name);
        /// set application as first on the applications vector
        bool appMoveFront(ApplicationDescription *app);
        /// get previous visible app - one on FOREGROUND
        ApplicationDescription *appPrev();
        void setState(State st);
        std::list<ApplicationDescription *> &getApps();
        void debug_log_app_list();

      private:
        State state = State::Running;
        ApplicationsContainer applications;
        ApplicationsStack stack;
    };

    class ApplicationManager : public sys::Service, public VirtualAppManager
    class ApplicationManager : public sys::Service, private ApplicationManagerBase
    {

        SettingsRecord settings;

        sys::SystemManager *systemManager;

        //
        std::unique_ptr<utils::i18> i18;

        // application that currently has focus. This means that is has rights to display screens and receive keyboard
        // events.
        std::string focusApplicationName = "";
        // after loosing focus application becomes previous application and this is its name
        std::string previousApplicationName = "";
        // name of the application scheduled for launching
        std::string launchApplicationName = "";
        // timer to count time from last user's activity. If it reaches time defined in settings database application
        // manager is sending signal to power manager and changing window to the desktop window in the blocked state.
        std::unique_ptr<sys::Timer> blockingTimer;

        // tries to switch the application
        bool handleSwitchApplication(APMSwitch *msg);
        auto handleAction(APMAction *actionMsg) -> bool;
        //	bool handleSwitchApplicationWithData( APMSwitchWithData* msg);
        bool handleCloseConfirmation(APMConfirmClose *msg);
        bool handleSwitchConfirmation(APMConfirmSwitch *msg);
        bool handleSwitchPrevApplication(APMSwitchPrevApp *msg);
        bool handleRegisterApplication(APMRegister *msg);
        bool handleLanguageChange(sapm::APMChangeLanguage *msg);
        bool handlePowerSavingModeInit();
        /**
         * @brief Closes all running applications.
         */
        bool startApplication(const std::string &appName);
        /**
         * @brief Closes eink and gui services.
         */
        bool closeApplications();
        bool closeServices();

      public:
        ApplicationManager(const std::string &name,
                           sys::SystemManager *sysmgr,
                           std::vector<std::unique_ptr<app::ApplicationLauncher>> &launchers);
        virtual ~ApplicationManager();
        static inline const std::string ServiceName = "ApplicationManager";

        sys::Message_t DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override;
        ApplicationManager(const std::string &serviceName,
                           std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers,
                           const ApplicationHandle::Name &_rootApplicationName);

        // Invoked during initialization
        sys::ReturnCodes InitHandler() override;

        sys::ReturnCodes DeinitHandler() override;

        sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override final;

        /**
         * @brief Sends the action request to application manager.
         * @param sender    Sender service name.
         * @param action    Action request
         * @return true on success, false otherwise.
         */
        static auto sendAction(sys::Service *sender, Action &&action) -> bool;

        /**
         * @brief Sends request to application manager to switch from current application to specific window in
         * application with specified name .
         */
        static bool messageSwitchApplication(sys::Service *sender,
                                             const std::string &applicationName,
                                             const std::string &windowName,
                                             std::unique_ptr<gui::SwitchData> data = nullptr);

        static bool messageSwitchSpecialInput(sys::Service *sender, std::unique_ptr<gui::SwitchSpecialChar> data);
        /**
         * @brief Sends request to application manager to switch from current application to specific window in
         * application with specified name. Allows sending data to destination application.
         */
        //    static bool messageSwitchApplicationWithData( sys::Service* sender, const std::string& applicationName,
        //    const std::string& windowName, std::unique_ptr<app::SwitchData>& switchData );
        /**
         * @Brief Function allows sending confirmation to the switch request. This is sent both by application that
         * gains and looses focus.
         */
        static bool messageConfirmSwitch(sys::Service *sender);
        /**
         * @brief Function allows application to confirm close request.
         */
        static bool messageConfirmClose(sys::Service *sender);
        /**
         * @brief Allows requesting Application Manager to run previous application.
         */
        static bool messageSwitchPreviousApplication(sys::Service *sender,
                                                     std::unique_ptr<APMSwitchPrevApp> msg = nullptr);
        /**
         * @brief Sends information from application to manager about result of application's init function.
         * If successful message will contain name and true value, otherwise false value will be transmitted.
         */
        static bool messageRegisterApplication(sys::Service *sender, const bool &status, const bool &startBackground);
        /**
         * @brief Sends message to application manager to inform it about change of the phone's language performed by
         * the user.
         */
        static bool messageChangeLanguage(sys::Service *sender, utils::Lang language);
        /**
         * @brief Sends message to application manager that it should close itself and as a result.
         */
        static bool messageCloseApplicationManager(sys::Service *sender);
        /**
         * @brief Sends message to inform Application Manager to reset timer responsible for blocking phone
         */
        static bool messagePreventBlocking(sys::Service *sender);
        /**
         * @brief Sends message to Application Manager. This will initialize procedure of switching to power saving
         * mode.
         */
        static bool messageInitPowerSaveMode(sys::Service *sender);

        /**
         * @brief Sends message to Application Manager.
         *
         * \returns true if app manager running and app is registered == running, false othervise
         */
        static bool appRunning(sys::Service *sender, const std::string &name);
        auto InitHandler() -> sys::ReturnCodes override;
        auto DeinitHandler() -> sys::ReturnCodes override;
        auto SwitchPowerModeHandler(const sys::ServicePowerMode mode) -> sys::ReturnCodes override;
        auto DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) -> sys::Message_t override;

      private:
        void phoneLockCB();
        auto startApplication(ApplicationHandle &app) -> bool;
        void startSystemServices();
        void startBackgroundApplications();
        void rebuildActiveApplications();
        void suspendSystemServices();
        auto closeServices() -> bool;
        auto closeApplications() -> bool;
        void closeService(const std::string &name);

        // Message handlers
        void registerMessageHandlers();
        auto handleAction(APMAction *actionMsg) -> bool;
        auto handleSwitchApplication(APMSwitch *msg) -> bool;
        auto handleCloseConfirmation(APMConfirmClose *msg) -> bool;
        auto handleSwitchConfirmation(APMConfirmSwitch *msg) -> bool;
        auto handleSwitchBack(APMSwitchPrevApp *msg) -> bool;
        auto handleRegisterApplication(APMRegister *msg) -> bool;
        auto handleLanguageChange(APMChangeLanguage *msg) -> bool;
        auto handlePowerSavingModeInit() -> bool;

        void requestApplicationClose(ApplicationHandle &app, bool isCloseable);
        void onApplicationSwitch(ApplicationHandle &app,
                                 std::unique_ptr<gui::SwitchData> &&data,
                                 std::string targetWindow);
        void onApplicationSwitchToPrev(ApplicationHandle &previousApp,
                                       std::unique_ptr<gui::SwitchData> &&data,
                                       std::string targetWindow = {});
        void onApplicationRegistered(ApplicationHandle &app, bool startInBackground);
        void onApplicationRegistrationFailure(ApplicationHandle &app);
        auto onSwitchConfirmed(ApplicationHandle &app) -> bool;
        auto onCloseConfirmed(ApplicationHandle &app) -> bool;
        void onPhoneLocked();

        ApplicationHandle::Name rootApplicationName;
        SettingsRecord settings;
        std::unique_ptr<sys::Timer> blockingTimer; //< timer to count time from last user's activity. If it reaches time
                                                   // defined in settings database application
                                                   // manager is sending signal to power manager and changing window to
                                                   // the desktop window in the blocked state.
    };

} /* namespace sapm */

#endif /* MODULE_SERVICES_SERVICE_APPMGR_APPLICATIONMANAGER_HPP_ */
} // namespace app::manager

M module-services/service-appmgr/CMakeLists.txt => module-services/service-appmgr/CMakeLists.txt +6 -9
@@ 1,25 1,22 @@
include_directories( ${CMAKE_PROJECT_NAME}

include_directories(${CMAKE_PROJECT_NAME}
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}"
#		"${CMAKE_CURRENT_LIST_DIR}/messages"
)

include_directories( ${PROJECT_NAME}

include_directories(${PROJECT_NAME}
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}"
		"${CMAKE_CURRENT_LIST_DIR}/.."
#		"${CMAKE_CURRENT_LIST_DIR}/messages"
)

message( "${PROJECT_NAME}  ${CMAKE_CURRENT_LIST_DIR}" )

target_sources( ${PROJECT_NAME}
message("${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}")

target_sources(${PROJECT_NAME}
	PRIVATE
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationManager.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/Controller.cpp"
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationManager.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/Controller.hpp"
)


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

#include "Controller.hpp"

#include "module-sys/Service/Bus.hpp"

namespace app::manager
{
    auto Controller::registerApplication(sys::Service *sender, bool status, bool startBackground) -> bool
    {
        auto msg = std::make_shared<app::manager::APMRegister>(sender->GetName(), status, startBackground);
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::sendAction(sys::Service *sender, Action &&action) -> bool
    {
        auto msg = std::make_shared<app::manager::APMAction>(sender->GetName(), std::move(action));
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::switchApplication(sys::Service *sender,
                                       const ApplicationHandle::Name &applicationName,
                                       const std::string &windowName,
                                       std::unique_ptr<gui::SwitchData> data) -> bool
    {
        auto msg =
            std::make_shared<app::manager::APMSwitch>(sender->GetName(), applicationName, windowName, std::move(data));
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::confirmSwitch(sys::Service *sender) -> bool
    {

        auto msg = std::make_shared<app::manager::APMConfirmSwitch>(sender->GetName());
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::confirmClose(sys::Service *sender) -> bool
    {
        auto msg = std::make_shared<app::manager::APMConfirmClose>(sender->GetName());
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::closeApplication(sys::Service *sender, const ApplicationHandle::Name &name) -> bool
    {
        auto msg = std::make_shared<app::manager::APMDelayedClose>(sender->GetName(), name);
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::switchBack(sys::Service *sender, std::unique_ptr<APMSwitchPrevApp> msg) -> bool
    {

        std::shared_ptr<APMSwitchPrevApp> switchMsg =
            msg ? std::move(msg) : std::make_shared<app::manager::APMSwitchPrevApp>(sender->GetName());
        return sys::Bus::SendUnicast(switchMsg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::changeLanguage(sys::Service *sender, utils::Lang language) -> bool
    {
        auto msg = std::make_shared<app::manager::APMChangeLanguage>(sender->GetName(), language);
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::stopApplicationManager(sys::Service *sender) -> bool
    {
        auto msg = std::make_shared<app::manager::APMClose>(sender->GetName());
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::preventBlockingDevice(sys::Service *sender) -> bool
    {
        auto msg = std::make_shared<app::manager::APMPreventBlocking>(sender->GetName());
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }

    auto Controller::changePowerSaveMode(sys::Service *sender) -> bool
    {
        auto msg = std::make_shared<app::manager::APMInitPowerSaveMode>(sender->GetName());
        return sys::Bus::SendUnicast(msg, ApplicationManager::ServiceName, sender);
    }
} // namespace app::manager

A module-services/service-appmgr/Controller.hpp => module-services/service-appmgr/Controller.hpp +32 -0
@@ 0,0 1,32 @@
// 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 "ApplicationManager.hpp"

#include "module-sys/Service/Service.hpp"

namespace app::manager
{
    class Controller
    {
      public:
        Controller() = delete;

        static auto sendAction(sys::Service *sender, Action &&action) -> bool;
        static auto registerApplication(sys::Service *sender, bool status, bool startBackground) -> bool;
        static auto switchApplication(sys::Service *sender,
                                      const ApplicationHandle::Name &applicationName,
                                      const std::string &windowName,
                                      std::unique_ptr<gui::SwitchData> data = nullptr) -> bool;
        static auto switchBack(sys::Service *sender, std::unique_ptr<APMSwitchPrevApp> msg = nullptr) -> bool;
        static auto closeApplication(sys::Service *sender, const ApplicationHandle::Name &name) -> bool;
        static auto changeLanguage(sys::Service *sender, utils::Lang language) -> bool;
        static auto changePowerSaveMode(sys::Service *sender) -> bool;
        static auto stopApplicationManager(sys::Service *sender) -> bool;
        static auto preventBlockingDevice(sys::Service *sender) -> bool;
        static auto confirmSwitch(sys::Service *sender) -> bool;
        static auto confirmClose(sys::Service *sender) -> bool;
    };
} // namespace app::manager

M module-services/service-appmgr/messages/APMMessage.hpp => module-services/service-appmgr/messages/APMMessage.hpp +52 -50
@@ 1,8 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_SERVICES_SERVICE_APPMGR_MESSAGES_APMMESSAGE_HPP_
#define MODULE_SERVICES_SERVICE_APPMGR_MESSAGES_APMMESSAGE_HPP_
#pragma once

#include "Service/Message.hpp"
#include "MessageType.hpp"


@@ 11,36 10,27 @@

#include "i18/i18.hpp"

namespace sapm
namespace app::manager
{

    /*
     * @brief Template for all messages that go to application manager
     */
    /// A template for all messages to application manager.
    class APMMessage : public sys::DataMessage
    {
      protected:
        // name of the application that is sending message to application manager.
        /// name of the application that is sending message to application manager.
        std::string senderName;

      public:
        APMMessage(MessageType messageType, const std::string &senderName)
            : sys::DataMessage(messageType), senderName{senderName} {};
        virtual ~APMMessage(){};
        APMMessage(MessageType messageType, std::string senderName)
            : sys::DataMessage(messageType), senderName{std::move(senderName)}
        {}

        std::string getSenderName()
        [[nodiscard]] auto getSenderName() const noexcept -> std::string
        {
            return senderName;
        }
    };

    //	APMSwitch, //request to switch to given application, optionally also to specified window
    //  APMSwitchToNotification, //request to switch to given notification (application and specified window)
    //	APMSwitchData, //request to switch to given application, optionally also to specified window with provided data.
    //	APMSwitchPrevApp, //Request to switch to previous application.
    //	APMConfirmSwitch, //Used when application confirms that it is loosing focus and also when application confirms
    // that is has gained focus 	APMConfirmClose, //Sent by application to confirm completion of the close procedure

    /// Requests a switch to a given application. Optionally to a specified window, too.
    class APMSwitch : public APMMessage
    {
        std::string application;


@@ 49,26 39,30 @@ namespace sapm

      public:
        APMSwitch(const std::string &senderName,
                  const std::string &applicationName,
                  const std::string &windowName,
                  std::string applicationName,
                  std::string windowName,
                  std::unique_ptr<gui::SwitchData> data)
            : APMMessage(MessageType::APMSwitch, senderName),
              application{applicationName}, window{windowName}, data{std::move(data)}
              application{std::move(applicationName)}, window{std::move(windowName)}, data{std::move(data)}
        {}
        const std::string &getName() const

        [[nodiscard]] auto getName() const noexcept -> const std::string &
        {
            return application;
        };
        const std::string &getWindow() const
        }

        [[nodiscard]] auto getWindow() const noexcept -> const std::string &
        {
            return window;
        };
        std::unique_ptr<gui::SwitchData> &getData()
        }

        [[nodiscard]] auto getData() noexcept -> std::unique_ptr<gui::SwitchData> &
        {
            return data;
        };
        }
    };

    /// Requests a switch to a previous application.
    class APMSwitchPrevApp : public APMMessage
    {
        std::unique_ptr<gui::SwitchData> data;


@@ 77,12 71,14 @@ namespace sapm
        APMSwitchPrevApp(const std::string &name, std::unique_ptr<gui::SwitchData> data = nullptr)
            : APMMessage(MessageType::APMSwitchPrevApp, name), data{std::move(data)}
        {}
        std::unique_ptr<gui::SwitchData> &getData()

        [[nodiscard]] auto getData() noexcept -> std::unique_ptr<gui::SwitchData> &
        {
            return data;
        };
        }
    };

    /// Confirms that the applications lost/gained focus.
    class APMConfirmSwitch : public APMMessage
    {
      public:


@@ 90,6 86,7 @@ namespace sapm
        {}
    };

    /// Confirms that the application closed successfully.
    class APMConfirmClose : public APMMessage
    {
      public:


@@ 97,46 94,47 @@ namespace sapm
        {}
    };

    /// Confirms that the application registered successfully.
    class APMRegister : public APMMessage
    {
      protected:
        bool status;
        bool startBackground;

      public:
        APMRegister(const std::string &senderName, const bool &status, const bool &startBackground)
        APMRegister(const std::string &senderName, bool status, bool startBackground)
            : APMMessage(MessageType::APMRegister, senderName), status{status}, startBackground{startBackground}
        {}

        const bool &getStatus()
        [[nodiscard]] auto getStatus() const noexcept -> bool
        {
            return status;
        };
        const bool &getStartBackground()
        }

        [[nodiscard]] auto getStartBackground() const noexcept -> bool
        {
            return startBackground;
        };
        }
    };

    /// Requests the application to close.
    class APMDelayedClose : public APMMessage
    {
      protected:
        std::string application;

      public:
        APMDelayedClose(const std::string &senderName, std::string application)
            : APMMessage(MessageType::APMDeleydClose, senderName), application{application}
            : APMMessage(MessageType::APMDelayedClose, senderName), application{std::move(application)}
        {}

        const std::string &getApplication()
        [[nodiscard]] auto getApplication() const noexcept -> const std::string &
        {
            return application;
        };
        }
    };

    /// Requests to change the language.
    class APMChangeLanguage : public APMMessage
    {
      protected:
        utils::Lang language;

      public:


@@ 144,12 142,13 @@ namespace sapm
            : APMMessage(MessageType::APMChangeLanguage, senderName), language{language}
        {}

        const utils::Lang &getLanguage()
        [[nodiscard]] auto getLanguage() const noexcept -> utils::Lang
        {
            return language;
        };
        }
    };

    /// Requests the application manager to close.
    class APMClose : public APMMessage
    {
      public:


@@ 157,6 156,7 @@ namespace sapm
        {}
    };

    /// Requests application manager to prevent device blocking.
    class APMPreventBlocking : public APMMessage
    {
      public:


@@ 164,6 164,7 @@ namespace sapm
        {}
    };

    /// Requests the application manager to enter power save mode.
    class APMInitPowerSaveMode : public APMMessage
    {
      public:


@@ 171,14 172,17 @@ namespace sapm
        {}
    };

    /// Requests the application manager to check the status of the application.
    class APMCheckApp : public APMMessage
    {
      public:
        APMCheckApp(const std::string &senderName, const std::string &appNameToCheck)
            : APMMessage(MessageType::APMCheckAppRunning, senderName), appNameToCheck(appNameToCheck)
        APMCheckApp(const std::string &senderName, std::string applicationName)
            : APMMessage(MessageType::APMCheckAppRunning, senderName),
              checkAppName(std::move(applicationName)), isRunning{false}
        {}
        const std::string appNameToCheck;
        bool isRunning = false;

        std::string checkAppName;
        bool isRunning;
    };

    struct Action


@@ 203,6 207,4 @@ namespace sapm
      private:
        Action action;
    };
} /* namespace sapm */

#endif /* MODULE_SERVICES_SERVICE_APPMGR_MESSAGES_APMMESSAGE_HPP_ */
} // namespace app::manager

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +2 -2
@@ 19,7 19,7 @@
#include "vfs.hpp"

#include "bsp/battery-charger/battery_charger.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"
#include "service-db/api/DBServiceAPI.hpp"
#include "service-db/messages/DBNotificationMessage.hpp"
#include "AudioServiceAPI.hpp"


@@ 98,7 98,7 @@ sys::Message_t EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
            sys::Bus::SendUnicast(message, targetApplication, this);
        }
        // notify application manager to prevent screen locking
        sapm::ApplicationManager::messagePreventBlocking(this);
        app::manager::Controller::preventBlockingDevice(this);
        handled = true;
    }
    else if (msgl->messageType == MessageType::EVMFocusApplication) {

M module-services/service-evtmgr/alarm/EventManagerAlarm.cpp => module-services/service-evtmgr/alarm/EventManagerAlarm.cpp +2 -2
@@ 19,7 19,7 @@
#include "vfs.hpp"

#include "service-db/api/DBServiceAPI.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

void EventManager::HandleAlarmTrigger(sys::DataMessage *msgl)
{


@@ 55,7 55,7 @@ void EventManager::HandleAlarmTrigger(sys::DataMessage *msgl)
            alarmIsValid = false;
            // run bell application
            std::unique_ptr<gui::SwitchData> switchMessage = std::make_unique<sevm::EVMAlarmSwitchData>(alarmID);
            sapm::ApplicationManager::messageSwitchApplication(this, "bell", "main", std::move(switchMessage));
            app::manager::Controller::switchApplication(this, "bell", "main", std::move(switchMessage));
        }
        // check if alarm is not obsolete
        else if ((alarmTimestamp < (currentTime % 86400)) && ((currentTime + 60) % 86400) > (currentTime % 86400)) {

M module-services/service-gui/ServiceGUI.cpp => module-services/service-gui/ServiceGUI.cpp +2 -2
@@ 19,7 19,7 @@
#include "service-eink/messages/ImageMessage.hpp"

#include "ServiceGUI.hpp"
#include "service-appmgr/ApplicationManager.hpp"
#include "service-appmgr/Controller.hpp"

#include "../gui/core/ImageManager.hpp"
#include "log/log.hpp"


@@ 198,7 198,7 @@ namespace sgui
                suspendInProgress = false;
                LOG_DEBUG("last rendering before suspend is finished.");

                sapm::ApplicationManager::messageInitPowerSaveMode(this);
                app::manager::Controller::changePowerSaveMode(this);
            }
            // mode = gui::RefreshModes::GUI_REFRESH_FAST;
            // check if something new was rendered. If so render counter has greater value than

M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +2 -2
@@ 3,7 3,7 @@

#include "CalendarTimeEvents.hpp"

#include <module-services/service-appmgr/ApplicationManager.hpp>
#include <module-services/service-appmgr/Controller.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-services/service-db/messages/DBNotificationMessage.hpp>
#include <module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp>


@@ 71,7 71,7 @@ namespace stm
        auto event = std::make_shared<EventsRecord>(eventRecord);
        eventData->setData(event);

        sapm::ApplicationManager::messageSwitchApplication(
        app::manager::Controller::switchApplication(
            service(), app::name_calendar, style::window::calendar::name::event_reminder_window, std::move(eventData));
    }
} // namespace stm

M source/MessageType.hpp => source/MessageType.hpp +14 -13
@@ 125,19 125,19 @@ enum class MessageType
    AudioMessage,

    // application manager
    APMAction,               ///< Used to send an action request to application manager.
    APMCheckAppRunning,      ///< check if application is running in application manager
    APMSwitch,               ///< request to switch to given application, optionally also to specified window
    APMSwitchToNotification, ///< request to switch to given notification (application and specified window)
    APMSwitchPrevApp,        ///< Request to switch to previous application.
    APMConfirmSwitch, ///< Used when application confirms that it is loosing focus and also when application confirms
                      ///< that is has gained focus
    APMConfirmClose,  ///< Sent by application to confirm completion of the close procedure
    APMRegister,      ///< when application finishes initHandler it is sending this messag to inform whether init was
                      ///< successful or not.
    APMDeleydClose, ///< this message is sent internally from and to application manager to close specified application.
    APMChangeLanguage, ///< this message is sent from any application to inform application manager that it should send
                       ///< gui rebuild command to all applications in background and currently active application.
    APMAction,          ///< Used to send an action request to application manager.
    APMCheckAppRunning, ///< check if application is running in application manager
    APMSwitch,          ///< request to switch to given application, optionally also to specified window
    APMSwitchPrevApp,   ///< Request to switch to previous application.
    APMConfirmSwitch,   ///< Used when application confirms that it is loosing focus and also when application confirms
                        ///< that is has gained focus
    APMConfirmClose,    ///< Sent by application to confirm completion of the close procedure
    APMRegister,        ///< when application finishes initHandler it is sending this messag to inform whether init was
                        ///< successful or not.
    APMDelayedClose,    ///< this message is sent internally from and to application manager to close specified
                        ///< application.
    APMChangeLanguage,  ///< this message is sent from any application to inform application manager that it should send
                        ///< gui rebuild command to all applications in background and currently active application.
    APMClose, ///< this message will trigger application manager to close itself, all running applications gui and eink
              ///< services.
    APMPreventBlocking,   ///< Prevents application manager from initializing device blocking.


@@ 156,6 156,7 @@ enum class MessageType
                ///< by the user)
    AppClose,
    AppFocus,
    AppFocusLost,

    EVMFocusApplication,
    EVMKeyboardProfile,

M source/main.cpp => source/main.cpp +3 -1
@@ 143,7 143,9 @@ int main()

        // start application manager
        ret &= sysmgr->CreateService(
            std::make_shared<sapm::ApplicationManager>("ApplicationManager", sysmgr.get(), applications), sysmgr.get());
            std::make_shared<app::manager::ApplicationManager>(
                app::manager::ApplicationManager::ServiceName, std::move(applications), app::name_desktop),
            sysmgr.get());

        return ret;
    });