~aleteoryx/muditaos

776a51e592a9258accdfba7dbf86ba19445ab44d — Wojtek Rzepecki 4 years ago efef3c3
[EGD-5969] Add battery charging UI

Battery charging UI modified
according to design
A art/phone/application_desktop/menu/charging_battery_W_G.png => art/phone/application_desktop/menu/charging_battery_W_G.png +0 -0
A image/assets/images/charging_battery_W_G.vpi => image/assets/images/charging_battery_W_G.vpi +0 -0
M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +20 -6
@@ 10,6 10,7 @@
#include "windows/PowerOffWindow.hpp"
#include "windows/DeadBatteryWindow.hpp"
#include "windows/LogoWindow.hpp"
#include "windows/ChargingBatteryWindow.hpp"
#include "windows/LockedInfoWindow.hpp"
#include "windows/Reboot.hpp"
#include "windows/Update.hpp"


@@ 101,7 102,7 @@ namespace app
            return actionHandled();
        });

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


@@ 419,6 420,9 @@ namespace app
        windowsFactory.attach(logo_window, [](Application *app, const std::string newname) {
            return std::make_unique<gui::LogoWindow>(app);
        });
        windowsFactory.attach(charging_battery, [](Application *app, const std::string newname) {
            return std::make_unique<gui::ChargingBatteryWindow>(app);
        });
        windowsFactory.attach(desktop_locked, [](Application *app, const std::string newname) {
            return std::make_unique<gui::LockedInfoWindow>(app);
        });


@@ 478,11 482,21 @@ namespace app

    void ApplicationDesktop::handleLowBatteryNotification(manager::actions::ActionParamsPtr &&data)
    {
        auto actionData               = static_cast<manager::actions::LowBatteryNotificationParams *>(data.get());
        notifications.batteryLowLevel = actionData->getActiveState();
        auto currentWindow            = getCurrentWindow();
        if (currentWindow->getName() == window::name::desktop_main_window) {
            currentWindow->rebuild();
        auto lowBatteryState = static_cast<manager::actions::LowBatteryNotificationParams *>(data.get());
        if (lowBatteryState->isActive()) {
            if (lowBatteryState->isCharging()) {
                switchWindow(app::window::name::charging_battery, std::move(data));
            }
            else {
                switchWindow(app::window::name::dead_battery, std::move(data));
            }
        }
        else {
            auto currentWindow = getCurrentWindow();
            if (currentWindow->getName() == app::window::name::dead_battery ||
                currentWindow->getName() == app::window::name::charging_battery) {
                switchWindow(app::window::name::desktop_main_window);
            }
        }
    }


M module-apps/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/ApplicationDesktop.hpp +1 -3
@@ 44,8 44,6 @@ namespace app
            Counters notSeen;
            Counters notRead;

            bool batteryLowLevel = false;

        } notifications;

        gui::PinLockHandler lockHandler;


@@ 122,7 120,7 @@ namespace app
                     manager::actions::ShowMMIPush,
                     manager::actions::ShowMMIResult,
                     manager::actions::DisplayCMEError,
                     manager::actions::DisplayLowBatteryNotification,
                     manager::actions::DisplayLowBatteryScreen,
                     manager::actions::SystemBrownout,
                     manager::actions::DisplayLogoAtExit}};
        }

M module-apps/application-desktop/CMakeLists.txt => module-apps/application-desktop/CMakeLists.txt +1 -0
@@ 29,6 29,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/windows/PowerOffWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/DeadBatteryWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/LogoWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/ChargingBatteryWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/LockedInfoWindow.cpp"
        "${CMAKE_CURRENT_LIST_DIR}/windows/Reboot.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/Update.cpp"

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

#include "ChargingBatteryWindow.hpp"
#include "InputEvent.hpp"
#include "gui/widgets/Image.hpp"
#include "gui/widgets/BottomBar.hpp"
#include "gui/widgets/TopBar.hpp"
#include "log/log.hpp"
#include <application-desktop/windows/Names.hpp>
#include <service-appmgr/model/ApplicationManager.hpp>
#include <service-appmgr/Controller.hpp>

namespace gui
{
    namespace
    {
        constexpr inline auto imgPositionX = 176;
        constexpr inline auto imgPositionY = 250;
    } // namespace

    ChargingBatteryWindow::ChargingBatteryWindow(app::Application *app)
        : AppWindow(app, app::window::name::dead_battery)
    {
        buildInterface();
    }

    void ChargingBatteryWindow::rebuild()
    {
        destroyInterface();
        buildInterface();
    }

    void ChargingBatteryWindow::buildInterface()
    {
        AppWindow::buildInterface();
        bottomBar->setVisible(false);
        topBar->setVisible(false);
        new gui::Image(this, imgPositionX, imgPositionY, 0, 0, "charging_battery_W_G");
    }

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

    bool ChargingBatteryWindow::onInput(const InputEvent &inputEvent)
    {
        // Ignore all inputs
        return true;
    }

} /* namespace gui */

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

#pragma once

#include <vector>
#include "AppWindow.hpp"

namespace gui
{
    class ChargingBatteryWindow : public AppWindow
    {
      public:
        explicit ChargingBatteryWindow(app::Application *app);
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        bool onInput(const InputEvent &inputEvent) override;
    };

} /* namespace gui */

M module-apps/application-desktop/windows/DeadBatteryWindow.cpp => module-apps/application-desktop/windows/DeadBatteryWindow.cpp +9 -4
@@ 16,9 16,8 @@ namespace gui
{
    namespace
    {
        constexpr inline auto SHUTDOWN_TIMER_MS = 500;
        constexpr inline auto IMG_POS_X         = 176;
        constexpr inline auto IMG_POS_Y         = 250;
        constexpr inline auto imgPositionX = 176;
        constexpr inline auto imgPositionY = 250;
    } // namespace

    DeadBatteryWindow::DeadBatteryWindow(app::Application *app) : AppWindow(app, app::window::name::dead_battery)


@@ 37,11 36,17 @@ namespace gui
        AppWindow::buildInterface();
        bottomBar->setVisible(false);
        topBar->setVisible(false);
        new gui::Image(this, IMG_POS_X, IMG_POS_Y, 0, 0, "dead_battery_W_G");
        new gui::Image(this, imgPositionX, imgPositionY, 0, 0, "dead_battery_W_G");
    }

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

    bool DeadBatteryWindow::onInput(const InputEvent &inputEvent)
    {
        // Ignore all inputs
        return true;
    }
} /* namespace gui */

M module-apps/application-desktop/windows/DeadBatteryWindow.hpp => module-apps/application-desktop/windows/DeadBatteryWindow.hpp +1 -0
@@ 16,6 16,7 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        bool onInput(const InputEvent &inputEvent) override;
    };

} /* namespace gui */

M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +0 -3
@@ 251,9 251,6 @@ namespace gui
            bottomBar->setActive(BottomBar::Side::LEFT, !isFocused);
        };

        if (app->notifications.batteryLowLevel) {
            notifications->addNotification("battery1_W_M", utils::localize.get("app_desktop_low_battery_notification"));
        }
        if (app->notifications.notSeen.Calls > 0) {
            notifications->addNotification(
                "phone",

M module-apps/application-desktop/windows/Names.hpp => module-apps/application-desktop/windows/Names.hpp +1 -0
@@ 11,6 11,7 @@ namespace app::window::name
    inline constexpr auto desktop_reboot             = "Reboot";
    inline constexpr auto desktop_poweroff           = "PowerOffWindow";
    inline constexpr auto dead_battery               = "DeadBatteryWindow";
    inline constexpr auto charging_battery           = "CharginBatteryWindow";
    inline constexpr auto logo_window                = "LogoWindow";
    inline constexpr auto desktop_pin_lock           = "PinLockWindow";
    inline constexpr auto desktop_locked             = "LockedInfoWindow";

M module-gui/gui/widgets/TopBar/BatteryBar.cpp => module-gui/gui/widgets/TopBar/BatteryBar.cpp +9 -9
@@ 20,10 20,10 @@ namespace gui::top_bar
        constexpr auto battery4             = "battery4_W_M";
        constexpr auto battery5             = "battery5_W_M";

        constexpr auto level1Threshold = 5;
        constexpr auto level2Threshold = 27;
        constexpr auto level3Threshold = 50;
        constexpr auto level4Threshold = 73;
        constexpr auto level1Threshold = 15;
        constexpr auto level2Threshold = 35;
        constexpr auto level3Threshold = 55;
        constexpr auto level4Threshold = 75;
        constexpr auto level5Threshold = 95;
    } // namespace



@@ 37,19 37,19 @@ namespace gui::top_bar

    void BatteryBar::showBatteryLevel(std::uint32_t percentage)
    {
        if (percentage <= level1Threshold) {
        if (percentage < level1Threshold) {
            img->set(batteryLow);
        }
        else if (percentage <= level2Threshold) {
        else if (percentage < level2Threshold) {
            img->set(battery1);
        }
        else if (percentage <= level3Threshold) {
        else if (percentage < level3Threshold) {
            img->set(battery2);
        }
        else if (percentage <= level4Threshold) {
        else if (percentage < level4Threshold) {
            img->set(battery3);
        }
        else if (percentage <= level5Threshold) {
        else if (percentage < level5Threshold) {
            img->set(battery4);
        }
        else {

M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +1 -1
@@ 196,8 196,8 @@ namespace app::manager
            act = ActionRequest{this->GetName(), app::manager::actions::SystemBrownout, nullptr};
            break;
        case sys::CloseReason::RegularPowerDown:
            break;
        case sys::CloseReason::Reboot:
        case sys::CloseReason::LowBattery:
            break;
        }
        handleActionRequest(&act);

M module-services/service-appmgr/service-appmgr/Actions.hpp => module-services/service-appmgr/service-appmgr/Actions.hpp +1 -1
@@ 52,7 52,7 @@ namespace app::manager
            ShowMMIPush,
            SmsRejectNoSim,
            DisplayCMEError,
            DisplayLowBatteryNotification,
            DisplayLowBatteryScreen,
            SystemBrownout,
            RequestScreenPasscode,
            DisplayLogoAtExit,

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +2 -0
@@ 97,6 97,7 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
                bsp::battery_charger::getChargeStatus();
                auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
                service->bus.sendUnicast(std::move(message), service::name::evt_manager);
                battery_level_check::checkBatteryLevelCritical();
                bsp::battery_charger::clearAllChargerIRQs();
            }
            if (topINT & static_cast<std::uint8_t>(bsp::battery_charger::topControllerIRQsource::FG_INT)) {


@@ 122,6 123,7 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
                    bsp::battery_charger::getChargeStatus();
                    auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
                    service->bus.sendUnicast(std::move(message), service::name::evt_manager);
                    battery_level_check::checkBatteryLevelCritical();
                }
            }
        }

M module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.cpp => module-services/service-evtmgr/battery-level-check/BatteryLevelCheck.cpp +111 -41
@@ 7,46 7,139 @@
#include <agents/settings/SystemSettings.hpp>
#include <common_data/EventStore.hpp>
#include <Utils.hpp>
#include <module-utils/sml/include/boost/sml.hpp>

namespace battery_level_check
{
    namespace
    {
        enum class CheckState
        {
            InitialCheck,
            LevelCritical,
            LevelNormal
        };

        CheckState state = CheckState::InitialCheck;

        unsigned int batteryLevelCritical = 0;

        constexpr auto batteryShutdownLevel = 5;

        sys::Service *parentService = nullptr;

        std::shared_ptr<settings::Settings> settings = nullptr;

        bool isBatteryLevelCritical(unsigned int level)
        void sendCriticalLevelMessage(bool charging)
        {
            return level < batteryLevelCritical;
            auto levelCriticalMessage = std::make_shared<sevm::BatteryLevelCriticalMessage>(charging);
            parentService->bus.sendUnicast(std::move(levelCriticalMessage), service::name::system_manager);
        }

        void sendCriticalLevelMessage()
        void sendShutdownLevelMessage()
        {
            auto levelCriticalMessage = std::make_shared<sevm::BatteryLevelCriticalMessage>();
            parentService->bus.sendUnicast(levelCriticalMessage, service::name::system_manager);
            auto shutdownMessage = std::make_shared<sevm::BatteryShutdownLevelMessage>();
            parentService->bus.sendUnicast(std::move(shutdownMessage), service::name::system_manager);
        }

        void sendNormalLevelMessage()
        {
            auto levelNormalMessage = std::make_shared<sevm::BatteryLevelNormalMessage>();
            parentService->bus.sendUnicast(levelNormalMessage, service::name::system_manager);
            parentService->bus.sendUnicast(std::move(levelNormalMessage), service::name::system_manager);
        }

        namespace sml = boost::sml;

        // events
        struct criticalLevelCheck
        {};
        struct confirmState
        {};

        // guards
        struct isNormal
        {
            bool operator()() const
            {
                return Store::Battery::get().level >= batteryLevelCritical;
            }
        } isNormal;
        struct isCriticalNotCharging
        {
            bool operator()() const
            {
                return Store::Battery::get().level < batteryLevelCritical &&
                       Store::Battery::get().state != Store::Battery::State::Charging;
            }
        } isCriticalNotCharging;
        struct isCriticalCharging
        {
            bool operator()() const
            {
                return Store::Battery::get().level < batteryLevelCritical &&
                       Store::Battery::get().state == Store::Battery::State::Charging;
            }
        } isCriticalCharging;
        struct isShutdown
        {
            bool operator()() const
            {
                return Store::Battery::get().level < batteryShutdownLevel;
            }
        } isShutdown;

        // actions
        struct sendCriticalNotCharging
        {
            void operator()()
            {
                sendCriticalLevelMessage(false);
            }
        } sendCriticalNotCharging;
        struct sendCriticalCharging
        {
            void operator()()
            {
                sendCriticalLevelMessage(true);
            }
        } sendCriticalCharging;
        struct sendNormal
        {
            void operator()()
            {
                sendNormalLevelMessage();
            }
        } sendNormal;
        struct sendShutdown
        {
            void operator()()
            {
                sendShutdownLevelMessage();
            }
        } sendShutdown;

        struct StateMachine
        {
            auto operator()() const
            {
                using namespace sml;
                // clang-format off
                return make_transition_table(
                *"InitialCheck"_s + event<criticalLevelCheck> [ isCriticalNotCharging ] / sendCriticalNotCharging = "LevelCriticalNotCharging"_s,
                "InitialCheck"_s + event<criticalLevelCheck> [ isCriticalCharging ] / sendCriticalCharging = "LevelCriticalCharging"_s,
                "InitialCheck"_s + event<criticalLevelCheck> [ isNormal ] / sendNormal = "LevelNormal"_s,
                "LevelNormal"_s + event<criticalLevelCheck> [ isCriticalNotCharging ] / sendCriticalNotCharging = "LevelCriticalNotCharging"_s,
                "LevelCriticalNotCharging"_s + event<criticalLevelCheck> [ isCriticalCharging ] / sendCriticalCharging = "LevelCriticalCharging"_s,
                "LevelCriticalCharging"_s + event<criticalLevelCheck> [ isCriticalNotCharging ] / sendCriticalNotCharging = "LevelCriticalNotCharging"_s,
                "LevelCriticalNotCharging"_s + event<criticalLevelCheck> [ isNormal ] / sendNormal = "LevelNormal"_s,
                "LevelCriticalCharging"_s + event<criticalLevelCheck> [ isNormal ] / sendNormal = "LevelNormal"_s,
                "LevelCriticalNotCharging"_s + event<criticalLevelCheck> [ isShutdown ] / sendShutdown = "Shutdown"_s,
                "LevelNormal"_s + event<confirmState> / sendNormal = "LevelNormal"_s,
                "LevelCriticalNotCharging"_s + event<confirmState> / sendCriticalNotCharging = "LevelCriticalNotCharging"_s,
                "LevelCriticalCharging"_s + event<confirmState> / sendCriticalCharging = "LevelCriticalCharging"_s,
                "Shutdown"_s = X
                );
                // clang-format on
            }
        };

        std::unique_ptr<sml::sm<StateMachine>> sm;
    } // namespace

    void init(sys::Service *service, std::shared_ptr<settings::Settings> &setts)
    {
        sm            = std::make_unique<sml::sm<StateMachine>>();
        parentService = service;
        settings      = setts;
        settings->registerValueChange(


@@ 59,40 152,17 @@ namespace battery_level_check
    {
        settings->unregisterValueChange(settings::Battery::batteryCriticalLevel, settings::SettingsScope::Global);
        settings.reset();
        sm.reset();
    }

    void checkBatteryLevelCritical()
    {
        switch (state) {
        case CheckState::InitialCheck:
            if (isBatteryLevelCritical(Store::Battery::get().level)) {
                sendCriticalLevelMessage();
                state = CheckState::LevelCritical;
            }
            else {
                sendNormalLevelMessage();
                state = CheckState::LevelNormal;
            }
            break;
        case CheckState::LevelCritical:
            if (!isBatteryLevelCritical(Store::Battery::get().level)) {
                sendNormalLevelMessage();
                state = CheckState::LevelNormal;
            }
            break;
        case CheckState::LevelNormal:
            if (isBatteryLevelCritical(Store::Battery::get().level)) {
                sendCriticalLevelMessage();
                state = CheckState::LevelCritical;
            }
            break;
        }
        sm->process_event(criticalLevelCheck{});
    }

    void checkBatteryLevelCriticalWithConfirmation()
    {
        state = CheckState::InitialCheck;
        checkBatteryLevelCritical();
        sm->process_event(confirmState{});
    }

    void setBatteryCriticalLevel(unsigned int level)

A module-services/service-evtmgr/doc/battery_level_check_state_machine.puml => module-services/service-evtmgr/doc/battery_level_check_state_machine.puml +18 -0
@@ 0,0 1,18 @@
@startuml

[*] --> InitialCheck
InitialCheck --> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
InitialCheck --> LevelCriticalCharging : criticalLevelCheck [isCriticalCharging] / sendCriticalCharging
InitialCheck --> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelNormal --> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
LevelCriticalNotCharging --> LevelCriticalCharging : criticalLevelCheck [isCriticalCharging] / sendCriticalCharging
LevelCriticalCharging --> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
LevelCriticalNotCharging --> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelCriticalCharging --> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelCriticalNotCharging --> Shutdown : criticalLevelCheck [isShutdown] / sendShutdown
LevelNormal --> LevelNormal : confirmState / sendNormal
LevelCriticalNotCharging --> LevelCriticalNotCharging : confirmState / sendCriticalNotCharging
LevelCriticalCharging --> LevelCriticalCharging : confirmState / sendCriticalCharging
Shutdown --> terminate

@enduml

A module-services/service-evtmgr/doc/battery_level_check_state_machine.svg => module-services/service-evtmgr/doc/battery_level_check_state_machine.svg +42 -0
@@ 0,0 1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="532px" preserveAspectRatio="none" style="width:2304px;height:532px;" version="1.1" viewBox="0 0 2304 532" width="2304px" zoomAndPan="magnify"><defs><filter height="300%" id="fxto8wylu90j9" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><ellipse cx="1660" cy="16" fill="#000000" filter="url(#fxto8wylu90j9)" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><g id="InitialCheck"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="98" x="1611" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="1611" x2="1709" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="78" x="1621" y="104.9951">InitialCheck</text></g><g id="LevelCriticalNotCharging"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="186" x="665" y="214"/><line style="stroke:#A80036;stroke-width:1.5;" x1="665" x2="851" y1="240.2969" y2="240.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="166" x="675" y="231.9951">LevelCriticalNotCharging</text></g><g id="LevelCriticalCharging"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="162" x="1192" y="341"/><line style="stroke:#A80036;stroke-width:1.5;" x1="1192" x2="1354" y1="367.2969" y2="367.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="142" x="1202" y="358.9951">LevelCriticalCharging</text></g><g id="LevelNormal"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="103" x="949.5" y="468"/><line style="stroke:#A80036;stroke-width:1.5;" x1="949.5" x2="1052.5" y1="494.2969" y2="494.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="83" x="959.5" y="485.9951">LevelNormal</text></g><g id="Shutdown"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="90" x="7" y="341"/><line style="stroke:#A80036;stroke-width:1.5;" x1="7" x2="97" y1="367.2969" y2="367.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="70" x="17" y="358.9951">Shutdown</text></g><g id="terminate"><rect fill="#FEFECE" filter="url(#fxto8wylu90j9)" height="50" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="86" x="9" y="468"/><line style="stroke:#A80036;stroke-width:1.5;" x1="9" x2="95" y1="494.2969" y2="494.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="66" x="19" y="485.9951">terminate</text></g><!--MD5=[d4999903ff2dd24919f2b1538b17fdaa]
link *start to InitialCheck--><path d="M1660,26.01 C1660,38.7 1660,62.41 1660,81.57 " fill="none" id="*start-to-InitialCheck" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1660,86.84,1664,77.84,1660,81.84,1656,77.84,1660,86.84" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[92dce6cefb7a02d934e3cfca3b958627]
link InitialCheck to LevelCriticalNotCharging--><path d="M1610.88,118.21 C1527.5,127.2 1353.02,146.61 1206,167 C1085.43,183.72 947.12,206.13 856.46,221.27 " fill="none" id="InitialCheck-to-LevelCriticalNotCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="851.37,222.12,860.9086,224.5725,856.3008,221.2911,859.5823,216.6833,851.37,222.12" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="426" x="1207" y="180.0669">criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging</text><!--MD5=[7cf26f7c5c06732917a715b46f14b13e]
link InitialCheck to LevelCriticalCharging--><path d="M1664.04,137.08 C1669.53,178.87 1673.89,264.75 1627,311 C1590.18,347.31 1451.73,359.23 1359.28,363.13 " fill="none" id="InitialCheck-to-LevelCriticalCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1354.09,363.34,1363.253,366.951,1359.0854,363.1259,1362.9105,358.9583,1354.09,363.34" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="380" x="1667" y="243.5669">criticalLevelCheck [isCriticalCharging] / sendCriticalCharging</text><!--MD5=[c538625450f55e3fab0d1c9574b1c463]
link InitialCheck to LevelNormal--><path d="M1709.34,114.11 C1834.24,118.72 2146.77,142.38 2056,264 C1934.28,427.09 1259.67,477.56 1057.97,489.11 " fill="none" id="InitialCheck-to-LevelNormal" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1052.72,489.41,1061.9335,492.89,1057.7119,489.1248,1061.4771,484.9031,1052.72,489.41" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="274" x="2022" y="307.0669">criticalLevelCheck [isNormal] / sendNormal</text><!--MD5=[29a0cbaa3e7031085e7c32fba5460bf1]
link LevelNormal to LevelCriticalNotCharging--><path d="M949.33,488.03 C889.16,480.33 792.23,457.66 747,391 C722.41,354.77 734.48,301.75 745.91,269.13 " fill="none" id="LevelNormal-to-LevelCriticalNotCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="747.74,264.08,740.9242,271.1895,746.0439,268.7835,748.4498,273.9032,747.74,264.08" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="426" x="748" y="370.5669">criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging</text><!--MD5=[f5c482fa1c56c0203ea304ee6ca6a7f3]
link LevelCriticalNotCharging to LevelNormal--><path d="M664.87,251.54 C550.89,269.41 380.81,310.43 448,391 C510.81,466.32 815.79,485.62 944.02,490.45 " fill="none" id="LevelCriticalNotCharging-to-LevelNormal" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="949.25,490.64,940.4051,486.3078,944.2535,490.4539,940.1073,494.3022,949.25,490.64" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="274" x="449" y="370.5669">criticalLevelCheck [isNormal] / sendNormal</text><!--MD5=[bb16dae49642355397c65a9ba7bb3e8f]
link LevelCriticalNotCharging to LevelCriticalCharging--><path d="M851.11,242.72 C966.47,247.5 1155.24,260.34 1216,294 C1233.42,303.65 1247.5,320.99 1257.3,336.12 " fill="none" id="LevelCriticalNotCharging-to-LevelCriticalCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1260.21,340.74,1258.7996,330.9927,1257.5459,336.5088,1252.0297,335.2552,1260.21,340.74" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="380" x="1238" y="307.0669">criticalLevelCheck [isCriticalCharging] / sendCriticalCharging</text><!--MD5=[b4c2a83ad0cf32e6fb8562f37b395c46]
link LevelCriticalCharging to LevelCriticalNotCharging--><path d="M1191.85,345.68 C1182.82,343.92 1173.74,342.3 1165,341 C1122.56,334.66 813.52,337.78 780,311 C767.61,301.1 762.04,284.34 759.61,269.59 " fill="none" id="LevelCriticalCharging-to-LevelCriticalNotCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="758.85,264.26,756.1477,273.7309,759.5491,269.2109,764.0691,272.6123,758.85,264.26" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="426" x="781" y="307.0669">criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging</text><!--MD5=[38f0fa53fd35c1a33d34344416b0d935]
link LevelCriticalCharging to LevelNormal--><path d="M1220.56,391.1 C1173.75,412.61 1105.38,444.03 1057.4,466.08 " fill="none" id="LevelCriticalCharging-to-LevelNormal" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1052.82,468.19,1062.6678,468.0444,1057.3585,466.092,1059.311,460.7828,1052.82,468.19" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="274" x="1154" y="434.0669">criticalLevelCheck [isNormal] / sendNormal</text><!--MD5=[743e923f215b3613f3f57ec27ffb5d84]
link LevelCriticalNotCharging to Shutdown--><path d="M664.79,240.21 C481.87,241.59 90.01,249.75 49,294 C38.84,304.96 38.97,321.44 41.92,335.77 " fill="none" id="LevelCriticalNotCharging-to-Shutdown" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="43.12,340.94,44.9793,331.2682,41.9884,336.0697,37.1869,333.0788,43.12,340.94" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="306" x="50" y="307.0669">criticalLevelCheck [isShutdown] / sendShutdown</text><!--MD5=[0301a2f87f8ca24f4e57abf82bd26793]
link LevelNormal to LevelNormal--><path d="M1052.51,481.4 C1071.7,481.02 1087.5,484.89 1087.5,493 C1087.5,500.35 1074.52,504.22 1057.8,504.59 " fill="none" id="LevelNormal-to-LevelNormal" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1052.51,504.6,1061.5214,508.5743,1057.51,504.5857,1061.4985,500.5743,1052.51,504.6" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="173" x="1093.5" y="497.5669">confirmState / sendNormal</text><!--MD5=[812772c8344e0faa39bad966b02f4d9a]
link LevelCriticalNotCharging to LevelCriticalNotCharging--><path d="M851.2,227.72 C871.37,228.82 886,232.58 886,239 C886,244.87 873.78,248.51 856.27,249.94 " fill="none" id="LevelCriticalNotCharging-to-LevelCriticalNotCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="851.2,250.28,860.4436,253.6795,856.1892,249.9512,859.9175,245.6968,851.2,250.28" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="249" x="892" y="243.5669">confirmState / sendCriticalNotCharging</text><!--MD5=[116352c5a36105c1a0ba6f320acea20f]
link LevelCriticalCharging to LevelCriticalCharging--><path d="M1354.04,354.55 C1374.07,355.37 1389,359.19 1389,366 C1389,372.23 1376.52,375.95 1359.08,377.18 " fill="none" id="LevelCriticalCharging-to-LevelCriticalCharging" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1354.04,377.45,1363.2436,380.9563,1359.0326,377.179,1362.8099,372.968,1354.04,377.45" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="226" x="1395" y="370.5669">confirmState / sendCriticalCharging</text><!--MD5=[37b33c3e4312a7df9ac254896c7d9da3]
link Shutdown to terminate--><path d="M52,391.1 C52,411.59 52,441.08 52,462.88 " fill="none" id="Shutdown-to-terminate" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="52,467.97,56,458.97,52,462.97,48,458.97,52,467.97" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[600677706eb106810a650089e6f085b5]
@startuml

[*] - -> InitialCheck
InitialCheck - -> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
InitialCheck - -> LevelCriticalCharging : criticalLevelCheck [isCriticalCharging] / sendCriticalCharging
InitialCheck - -> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelNormal - -> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
LevelCriticalNotCharging - -> LevelCriticalCharging : criticalLevelCheck [isCriticalCharging] / sendCriticalCharging
LevelCriticalCharging - -> LevelCriticalNotCharging : criticalLevelCheck [isCriticalNotCharging] / sendCriticalNotCharging
LevelCriticalNotCharging - -> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelCriticalCharging - -> LevelNormal : criticalLevelCheck [isNormal] / sendNormal
LevelCriticalNotCharging - -> Shutdown : criticalLevelCheck [isShutdown] / sendShutdown
LevelNormal - -> LevelNormal : confirmState / sendNormal
LevelCriticalNotCharging - -> LevelCriticalNotCharging : confirmState / sendCriticalNotCharging
LevelCriticalCharging - -> LevelCriticalCharging : confirmState / sendCriticalCharging
Shutdown - -> terminate

@enduml

PlantUML version 1.2021.00(Sun Jan 10 11:25:05 CET 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: pl
Country: PL
--></g></svg>
\ No newline at end of file

M module-services/service-evtmgr/service-evtmgr/BatteryMessages.hpp => module-services/service-evtmgr/service-evtmgr/BatteryMessages.hpp +15 -0
@@ 23,6 23,21 @@ namespace sevm
    class BatteryLevelCriticalCheckMessage : public sys::Message
    {};
    class BatteryLevelCriticalMessage : public sys::Message
    {
      public:
        explicit BatteryLevelCriticalMessage(bool charging) : charging(charging)
        {}

        bool isCharging() const noexcept
        {
            return charging;
        }

      private:
        bool charging;
    };

    class BatteryShutdownLevelMessage : public sys::Message
    {};

    class BatteryLevelNormalMessage : public sys::Message

M module-sys/Service/Common.hpp => module-sys/Service/Common.hpp +2 -1
@@ 46,7 46,8 @@ namespace sys
    {
        RegularPowerDown,
        Reboot,
        SystemBrownout
        SystemBrownout,
        LowBattery
    };

} // namespace sys

M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +9 -2
@@ 387,16 387,23 @@ namespace sys
            return MessageNone{};
        });

        connect(sevm::BatteryShutdownLevelMessage(), [&](Message *) {
            LOG_INFO("Battery level too low - shutting down the system");
            CloseSystemHandler(CloseReason::LowBattery);
            return MessageNone{};
        });

        connect(CellularCheckIfStartAllowedMessage(), [&](Message *) {
            EventManagerServiceAPI::checkBatteryLevelCriticalState(this);
            return MessageNone{};
        });

        connect(sevm::BatteryLevelCriticalMessage(), [&](Message *) {
        connect(sevm::BatteryLevelCriticalMessage(bool{}), [&](Message *req) {
            LOG_INFO("Battery Critical Level reached!");
            CellularServiceAPI::ChangeModulePowerState(this, cellular::State::PowerState::Off);

            auto msg = std::make_shared<CriticalBatteryLevelNotification>(true);
            auto request = static_cast<sevm::BatteryLevelCriticalMessage *>(req);
            auto msg     = std::make_shared<CriticalBatteryLevelNotification>(true, request->isCharging());
            bus.sendUnicast(msg, app::manager::ApplicationManager::ServiceName);

            return MessageNone{};

M module-sys/SystemManager/data/SystemManagerActionsParams.hpp => module-sys/SystemManager/data/SystemManagerActionsParams.hpp +11 -4
@@ 10,15 10,22 @@ namespace app::manager::actions
    class LowBatteryNotificationParams : public ActionParams
    {
      public:
        explicit LowBatteryNotificationParams(bool isActive) : isActive(isActive){};
        explicit LowBatteryNotificationParams(bool isActive, bool isCharging)
            : active(isActive), charging(isCharging){};

        [[nodiscard]] bool getActiveState() const noexcept
        [[nodiscard]] bool isActive() const noexcept
        {
            return isActive;
            return active;
        }

        [[nodiscard]] bool isCharging() const noexcept
        {
            return charging;
        }

      private:
        bool isActive;
        bool active;
        bool charging;
    };

} // namespace app::manager::actions

M module-sys/SystemManager/messages/SystemManagerMessage.hpp => module-sys/SystemManager/messages/SystemManagerMessage.hpp +5 -3
@@ 22,19 22,21 @@ namespace sys
    class CriticalBatteryLevelNotification : public sys::Message, public app::manager::actions::ConvertibleToAction
    {
      public:
        explicit CriticalBatteryLevelNotification(bool isActive) : sys::Message(), isActive(isActive)
        explicit CriticalBatteryLevelNotification(bool isActive, bool isCharging = false)
            : sys::Message(), isActive(isActive), isCharging(isCharging)
        {}

        [[nodiscard]] auto toAction() const -> std::unique_ptr<app::manager::ActionRequest>
        {
            return std::make_unique<app::manager::ActionRequest>(
                service::name::system_manager,
                app::manager::actions::DisplayLowBatteryNotification,
                std::make_unique<app::manager::actions::LowBatteryNotificationParams>(isActive));
                app::manager::actions::DisplayLowBatteryScreen,
                std::make_unique<app::manager::actions::LowBatteryNotificationParams>(isActive, isCharging));
        }

      private:
        bool isActive;
        bool isCharging;
    };

} // namespace sys