~aleteoryx/muditaos

323786c4d2cd22d91d1a966a231b866c75146b8b — Wojtek Rzepecki 5 years ago cc18f9b
[EGD-4797] Battery bar as widget

Battery bar now is present as
a separate widget in top bar.
Additionally refactored passing
battery status.
M module-apps/Application.cpp => module-apps/Application.cpp +5 -31
@@ 84,6 84,8 @@ namespace app

        connect(typeid(AppRefreshMessage),
                [this](sys::Message *msg) -> sys::MessagePointer { return handleAppRefresh(msg); });

        connect(sevm::BatteryStatusChangeMessage(), [&](sys::Message *) { return handleBatteryStatusChange(); });
    }

    Application::~Application() noexcept


@@ 129,12 131,7 @@ namespace app
        // send drawing commands only when if application is in active and visible.
        if (state == State::ACTIVE_FORGROUND) {
            auto window = getCurrentWindow();
            if (Store::Battery::get().state == Store::Battery::State::Charging) {
                window->updateBatteryCharger(true);
            }
            else {
                window->updateBatteryLevel(Store::Battery::get().level);
            }
            window->updateBatteryStatus();
            window->setSIM();
            window->updateSignalStrength();
            window->updateNetworkAccessTechnology();


@@ 216,12 213,6 @@ namespace app
        else if (msgl->messageType == MessageType::KBDKeyEvent) {
            return handleKBDKeyEvent(msgl);
        }
        else if (msgl->messageType == MessageType::EVMBatteryLevel) {
            return handleBatteryLevel(msgl);
        }
        else if (msgl->messageType == MessageType::EVMChargerPlugged) {
            return handleChargerPlugged(msgl);
        }
        else if (msgl->messageType == MessageType::EVMMinuteUpdated) {
            return handleMinuteUpdated(msgl);
        }


@@ 299,31 290,14 @@ namespace app
        return msgHandled();
    }

    sys::MessagePointer Application::handleBatteryLevel(sys::Message *msgl)
    sys::MessagePointer Application::handleBatteryStatusChange()
    {
        auto msg = static_cast<sevm::BatteryLevelMessage *>(msgl);
        LOG_INFO("Battery level: %d", msg->levelPercents);

        if (getCurrentWindow()->updateBatteryLevel(msg->levelPercents)) {
        if (getCurrentWindow()->updateBatteryStatus()) {
            refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
        }
        return msgHandled();
    }

    sys::MessagePointer Application::handleChargerPlugged(sys::Message *msgl)
    {
        auto *msg = static_cast<sevm::BatteryPlugMessage *>(msgl);
        if (msg->plugged == true) {
            LOG_INFO("Charger connected");
        }
        else {
            LOG_INFO("Charger disconnected");
        }
        getCurrentWindow()->updateBatteryCharger(msg->plugged);
        refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
        return msgHandled();
    }

    sys::MessagePointer Application::handleMinuteUpdated(sys::Message *msgl)
    {
        auto *msg = static_cast<sevm::RtcMinuteAlarmMessage *>(msgl);

M module-apps/Application.hpp => module-apps/Application.hpp +1 -2
@@ 167,8 167,7 @@ namespace app
        sys::MessagePointer handleNetworkAccessTechnologyUpdate(sys::Message *msgl);
        sys::MessagePointer handleInputEvent(sys::Message *msgl);
        sys::MessagePointer handleKBDKeyEvent(sys::Message *msgl);
        sys::MessagePointer handleBatteryLevel(sys::Message *msgl);
        sys::MessagePointer handleChargerPlugged(sys::Message *msgl);
        sys::MessagePointer handleBatteryStatusChange();
        sys::MessagePointer handleMinuteUpdated(sys::Message *msgl);
        sys::MessagePointer handleAction(sys::Message *msgl);
        sys::MessagePointer handleApplicationSwitch(sys::Message *msgl);

M module-apps/windows/AppWindow.cpp => module-apps/windows/AppWindow.cpp +2 -11
@@ 73,19 73,10 @@ namespace gui
        return true;
    }

    bool AppWindow::updateBatteryCharger(bool charging)
    bool AppWindow::updateBatteryStatus()
    {
        topBar->updateBattery(charging);
        return true;
    }

    // updates battery level in the window
    bool AppWindow::updateBatteryLevel(uint32_t percentage)
    {
        // get old value of battery level, calcualte new level and comapre both
        // if they are different make a change and return true, otherwise return false;
        if (topBar != nullptr) {
            return topBar->updateBattery(percentage);
            return topBar->updateBattery();
        }
        return false;
    }

M module-apps/windows/AppWindow.hpp => module-apps/windows/AppWindow.hpp +1 -3
@@ 62,11 62,9 @@ namespace gui

        virtual bool onDatabaseMessage(sys::Message *msg);

        bool updateBatteryCharger(bool charging);
        bool setSIM();
        // updates battery level in the window
        bool updateBatteryLevel(uint32_t percentage);
        // updates battery level in the window
        bool updateBatteryStatus();
        bool updateSignalStrength();
        bool updateNetworkAccessTechnology();
        virtual bool updateTime(const UTF8 &timeStr);

M module-gui/gui/widgets/CMakeLists.txt => module-gui/gui/widgets/CMakeLists.txt +1 -0
@@ 22,6 22,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/BoxLayoutSizeStore.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/TopBar.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/TopBar/SIM.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/TopBar/BatteryWidget.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/Text.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/TextBlock.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/TextDocument.cpp"

M module-gui/gui/widgets/TopBar.cpp => module-gui/gui/widgets/TopBar.cpp +4 -90
@@ 74,22 74,6 @@ namespace gui::top_bar
        };
    }

    void TopBar::batteryShowBars(uint32_t val)
    {
        if (val > batteryBars.size()) {
            LOG_ERROR("Trying to set battery level out of scope");
            val = batteryBars.size();
        }
        for (unsigned int i = 0; i < batteryBars.size(); ++i) {
            if (configuration.isEnabled(Indicator::Battery)) {
                batteryBars[i]->setVisible(i == val);
            }
            else {
                batteryBars[i]->setVisible(false);
            }
        }
    }

    void TopBar::prepareWidget()
    {
        signal[0] = new gui::Image(this, signalOffset, 17, 0, 0, "signal0");


@@ 100,24 84,7 @@ namespace gui::top_bar
        signal[5] = new gui::Image(this, signalOffset, 17, 0, 0, "signal5");
        updateSignalStrength();

        // icons for battery
        batteryBars = {
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery_low_W_M"),
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery1_W_M"),
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery2_W_M"),
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery3_W_M"),
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery4_W_M"),
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery5_W_M"),
        };
        batteryShowBars(0);

        batteryChargings[Store::Battery::State::Charging] =
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery_charging_W_M");
        batteryChargings[Store::Battery::State::PluggedNotCharging] =
            new gui::Image(this, batteryOffset, 15, 0, 0, "battery_charging_ready_W_M");
        for (auto &el : batteryChargings) {
            el.second->setVisible(false);
        }
        batteryWidget = new BatteryWidget(this, batteryOffset, 15);

        const auto design_sim_offset = 376; // this offset is not final, but it is pixel Purefect
        sim                          = new SIM(this, design_sim_offset, 12);


@@ 181,7 148,7 @@ namespace gui::top_bar
            }
            break;
        case Indicator::Battery:
            showBattery(enabled);
            batteryWidget->show(Store::Battery::get(), enabled);
            break;
        case Indicator::SimCard:
            showSim(enabled);


@@ 192,65 159,12 @@ namespace gui::top_bar
        }
    }

    uint32_t TopBar::calculateBatteryBars(uint32_t percentage)
    bool TopBar::updateBattery()
    {
        uint32_t level = 0;
        if (percentage <= 5) // level critical
            level = 0;
        else if (percentage <= 27)
            level = 1;
        else if (percentage <= 50)
            level = 2;
        else if (percentage <= 73)
            level = 3;
        else if (percentage <= 95)
            level = 4;
        else
            level = 5;

        if (level >= batteryBarsCount) {
            LOG_ERROR("Battery level calculations are done wrong!");
            return batteryBarsCount - 1;
        }
        return level;
    }

    bool TopBar::updateBattery(uint32_t percent)
    {
        showBattery(configuration.isEnabled(Indicator::Battery));
        batteryWidget->show(Store::Battery::get(), configuration.isEnabled(Indicator::Battery));
        return true;
    }

    bool TopBar::updateBattery(bool plugged)
    {
        showBattery(configuration.isEnabled(Indicator::Battery));
        return true;
    }

    void TopBar::showBattery(bool shown)
    {
        // hide battery bars icons
        for (const auto &bars : batteryBars) {
            bars->setVisible(false);
        }
        // hide battery charging icons
        for (const auto &charging : batteryChargings) {
            charging.second->setVisible(false);
        }

        if (shown) {
            switch (Store::Battery::get().state) {
            case Store::Battery::State::Discharging:
                batteryShowBars(calculateBatteryBars(Store::Battery::get().level));
                break;
            case Store::Battery::State::Charging:
            case Store::Battery::State::PluggedNotCharging:
                batteryChargings[Store::Battery::get().state]->setVisible(true);
                break;
            }
        }
    }

    void TopBar::showSim(bool enabled)
    {
        if (!enabled) {

M module-gui/gui/widgets/TopBar.hpp => module-gui/gui/widgets/TopBar.hpp +4 -8
@@ 7,6 7,7 @@
#include "Label.hpp"
#include "Rect.hpp"
#include "TopBar/SIM.hpp"
#include "TopBar/BatteryWidget.hpp"
#include <common_data/EventStore.hpp>

#include <vector>


@@ 82,18 83,14 @@ namespace gui::top_bar
        std::map<const Store::Battery::State, Image *> batteryChargings = {
            {Store::Battery::State::Charging, nullptr}, {Store::Battery::State::PluggedNotCharging, nullptr}};
        gui::SIM *sim = nullptr;
        gui::BatteryWidget *batteryWidget = nullptr;
        Configuration configuration;
        static TimeMode timeMode;

        void prepareWidget();

        /// show bars in number - 0 bars, 1 bar, 2 bars...
        void batteryShowBars(uint32_t val);
        void showBattery(bool shown);
        void showSim(bool enabled);

        static uint32_t calculateBatteryBars(uint32_t percentage);

        /**
         * Sets the status of the top bar indicator.
         * @param indicator     Indicator


@@ 111,12 108,11 @@ namespace gui::top_bar
        [[nodiscard]] auto getConfiguration() const noexcept -> const Configuration &;

        /**
         * @brief Sets charge level of the battery based on percent value. This will cause appropriate image to be
         * @brief Sets charge level of the battery. This will cause appropriate image to be
         * displayed.
         * @return if display should be refreshed or not
         */
        bool updateBattery(uint32_t percent);
        bool updateBattery(bool plugged);
        bool updateBattery();

        /**
         * @brief updates signal strength. This will cause appropriate image to be displayed.

A module-gui/gui/widgets/TopBar/BatteryWidget.cpp => module-gui/gui/widgets/TopBar/BatteryWidget.cpp +67 -0
@@ 0,0 1,67 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BatteryWidget.hpp"

namespace gui
{
    namespace
    {
        constexpr auto batteryLow           = "battery_low_W_M";
        constexpr auto batteryCharging      = "battery_charging_W_M";
        constexpr auto batteryChargingReady = "battery_charging_ready_W_M";
        constexpr auto battery1             = "battery1_W_M";
        constexpr auto battery2             = "battery2_W_M";
        constexpr auto battery3             = "battery3_W_M";
        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 level5Threshold = 95;
    } // namespace

    BatteryWidget::BatteryWidget(Item *parent, uint32_t x, uint32_t y) : Image(parent, x, y, 0, 0)
    {
        set(battery1);
    }

    void BatteryWidget::show(const Store::Battery batteryContext, bool shown)
    {
        if (shown) {
            switch (batteryContext.state) {
            case Store::Battery::State::Discharging:
                showBatteryBars(batteryContext.level);
                break;
            case Store::Battery::State::Charging:
                set(batteryCharging);
                break;
            case Store::Battery::State::PluggedNotCharging:
                set(batteryChargingReady);
                break;
            }
        }
        else {
            setVisible(false);
        }
    }

    void BatteryWidget::showBatteryBars(std::uint32_t percentage)
    {
        if (percentage <= level1Threshold)
            set(batteryLow);
        else if (percentage <= level2Threshold)
            set(battery1);
        else if (percentage <= level3Threshold)
            set(battery2);
        else if (percentage <= level4Threshold)
            set(battery3);
        else if (percentage <= level5Threshold)
            set(battery4);
        else
            set(battery5);
    }

} // namespace gui

A module-gui/gui/widgets/TopBar/BatteryWidget.hpp => module-gui/gui/widgets/TopBar/BatteryWidget.hpp +20 -0
@@ 0,0 1,20 @@
// 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 "../Image.hpp"
#include <common_data/EventStore.hpp>

namespace gui
{
    class BatteryWidget : public Image
    {
      public:
        BatteryWidget(Item *parent, uint32_t x, uint32_t y);
        void show(const Store::Battery batteryContext, bool shown);

      private:
        void showBatteryBars(std::uint32_t percentage);
    };
} // namespace gui

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +18 -26
@@ 39,6 39,7 @@
#include <vector>
#include <module-apps/messages/AppMessage.hpp>
#include <SystemManager/messages/CpuFrequencyMessage.hpp>
#include <common_data/EventStore.hpp>

EventManager::EventManager(const std::string &name)
    : sys::Service(name), screenLightControl(std::make_unique<screen_light_control::ScreenLightControl>(this))


@@ 122,32 123,6 @@ sys::MessagePointer EventManager::DataReceivedHandler(sys::DataMessage *msgl, sy
            LOG_INFO("Switching focus to %s", targetApplication.c_str());
        }
    }
    else if (msgl->messageType == MessageType::EVMBatteryLevel && msgl->sender == this->GetName()) {
        auto *msg = static_cast<sevm::BatteryLevelMessage *>(msgl);

        auto message = std::make_shared<sevm::BatteryLevelMessage>(msg->levelPercents, msg->fullyCharged);

        if (!targetApplication.empty()) {
            bus.sendUnicast(message, targetApplication);
        }

        handled = true;
    }
    else if (msgl->messageType == MessageType::EVMChargerPlugged && msgl->sender == this->GetName()) {
        auto *msg = static_cast<sevm::BatteryPlugMessage *>(msgl);

        auto message     = std::make_shared<sevm::BatteryPlugMessage>();
        message->plugged = msg->plugged;

        if (!message->plugged) {
            bus.sendUnicast(message, service::name::system_manager);
        }

        if (!targetApplication.empty()) {
            bus.sendUnicast(message, targetApplication);
        }
        handled = true;
    }
    else if (msgl->messageType == MessageType::EVMMinuteUpdated && msgl->sender == this->GetName()) {

        HandleAlarmTrigger(msgl);


@@ 287,6 262,23 @@ sys::ReturnCodes EventManager::InitHandler()
        return msg;
    });

    connect(sevm::BatteryStatusChangeMessage(), [&](sys::Message *msgl) {
        if (msgl->sender == this->GetName()) {
            LOG_INFO("Battery level: %d , charging: %d",
                     Store::Battery::get().level,
                     Store::Battery::get().state == Store::Battery::State::Charging);

            if (Store::Battery::get().state == Store::Battery::State::Discharging) {
                bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::system_manager);
            }

            if (!targetApplication.empty()) {
                bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), targetApplication);
            }
        }
        return std::make_shared<sys::ResponseMessage>();
    });

    // initialize keyboard worker
    EventWorker = std::make_unique<WorkerEvent>(this);


M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +6 -6
@@ 93,8 93,8 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
        if (notification == static_cast<std::uint8_t>(bsp::battery_charger::batteryIRQSource::INTB)) {
            auto topINT = bsp::battery_charger::getTopControllerINTSource();
            if (topINT & static_cast<std::uint8_t>(bsp::battery_charger::topControllerIRQsource::CHGR_INT)) {
                auto message     = std::make_shared<sevm::BatteryPlugMessage>();
                message->plugged = bsp::battery_charger::getChargeStatus();
                bsp::battery_charger::getChargeStatus();
                auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
                service->bus.sendUnicast(std::move(message), service::name::evt_manager);
                bsp::battery_charger::clearAllChargerIRQs();
            }


@@ 107,8 107,8 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
                if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::SOCOnePercentChange)) {
                    bsp::battery_charger::clearFuelGuageIRQ(
                        static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::SOCOnePercentChange));
                    bsp::battery_charger::StateOfCharge battLevel = bsp::battery_charger::getBatteryLevel();
                    auto message = std::make_shared<sevm::BatteryLevelMessage>(battLevel, false);
                    bsp::battery_charger::getBatteryLevel();
                    auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
                    service->bus.sendUnicast(std::move(message), service::name::evt_manager);
                    battery_level_check::checkBatteryLevelCritical();
                }


@@ 118,8 118,8 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
                        static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::maxTemp) |
                        static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::minTemp));
                    bsp::battery_charger::checkTemperatureRange();
                    auto message     = std::make_shared<sevm::BatteryPlugMessage>();
                    message->plugged = bsp::battery_charger::getChargeStatus();
                    bsp::battery_charger::getChargeStatus();
                    auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
                    service->bus.sendUnicast(std::move(message), service::name::evt_manager);
                }
            }

A module-services/service-evtmgr/doc/battery_status_notification.md => module-services/service-evtmgr/doc/battery_status_notification.md +4 -0
@@ 0,0 1,4 @@
# Battery Status propagation in system

Battery status information is propagated according to following diagram:
![](battery_status_notification.svg)
\ No newline at end of file

A module-services/service-evtmgr/doc/battery_status_notification.puml => module-services/service-evtmgr/doc/battery_status_notification.puml +24 -0
@@ 0,0 1,24 @@
@startuml
participant "Battery Charger" as bc
participant "Worker Event" as we
participant "Event Manager" as evm
participant "System Manager" as sm
participant "Current application" as ca
participant "TopBar" as tb
participant "Battery Widget" as bw
participant "Event Store\nBattery" as es

bc -> we : Interrupt
we -> bc : Store status to EventStore
bc -> es : modify()
we -> evm : BatteryStatusChangeMessage
group If Discharging
    evm -> sm : BatteryStatusChangeMessage
    sm -> sm : If State::ShutdownReady:\n state = State:Shutdown
end
evm -> ca : BatteryStatusChangeMessage
ca -> tb : updateBattery()
tb <-> es : get() 
tb -> bw : show(batteryContext)

@enduml

A module-services/service-evtmgr/doc/battery_status_notification.svg => module-services/service-evtmgr/doc/battery_status_notification.svg +34 -0
@@ 0,0 1,34 @@
<?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="486px" preserveAspectRatio="none" style="width:1340px;height:486px;" version="1.1" viewBox="0 0 1340 486" width="1340px" zoomAndPan="magnify"><defs><filter height="300%" id="f1uj3fz6xy4wx1" 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><rect fill="#FFFFFF" filter="url(#f1uj3fz6xy4wx1)" height="103.5313" style="stroke:#000000;stroke-width:2.0;" width="468.5" x="411.5" y="190.125"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="68" x2="68" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="263" x2="263" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="481.5" x2="481.5" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="700.5" x2="700.5" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="875" x2="875" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="1001" x2="1001" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="1162.5" x2="1162.5" y1="56.5938" y2="427.1875"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="1281.5" x2="1281.5" y1="56.5938" y2="427.1875"/><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="122" x="5" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="108" x="12" y="41.292">Battery Charger</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="122" x="5" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="108" x="12" y="446.1826">Battery Charger</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="106" x="208" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92" x="215" y="41.292">Worker Event</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="106" x="208" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="92" x="215" y="446.1826">Worker Event</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="117" x="421.5" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="103" x="428.5" y="41.292">Event Manager</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="117" x="421.5" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="103" x="428.5" y="446.1826">Event Manager</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="129" x="634.5" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="115" x="641.5" y="41.292">System Manager</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="129" x="634.5" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="115" x="641.5" y="446.1826">System Manager</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="144" x="801" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="130" x="808" y="41.292">Current application</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="144" x="801" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="130" x="808" y="446.1826">Current application</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="64" x="967" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="50" x="974" y="41.292">TopBar</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="64" x="967" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="50" x="974" y="446.1826">TopBar</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="115" x="1103.5" y="21.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="101" x="1110.5" y="41.292">Battery Widget</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="115" x="1103.5" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="101" x="1110.5" y="446.1826">Battery Widget</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="46.5938" style="stroke:#A80036;stroke-width:1.5;" width="94" x="1232.5" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="80" x="1239.5" y="24.9951">Event Store</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="49" x="1255" y="41.292">Battery</text><rect fill="#FEFECE" filter="url(#f1uj3fz6xy4wx1)" height="46.5938" style="stroke:#A80036;stroke-width:1.5;" width="94" x="1232.5" y="426.1875"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="80" x="1239.5" y="446.1826">Event Store</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="49" x="1255" y="462.4795">Battery</text><polygon fill="#A80036" points="251,83.7266,261,87.7266,251,91.7266,255,87.7266" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="68" x2="257" y1="87.7266" y2="87.7266"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="55" x="75" y="82.6606">Interrupt</text><polygon fill="#A80036" points="79,112.8594,69,116.8594,79,120.8594,75,116.8594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="73" x2="262" y1="116.8594" y2="116.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="171" x="85" y="111.7935">Store status to EventStore</text><polygon fill="#A80036" points="1269.5,141.9922,1279.5,145.9922,1269.5,149.9922,1273.5,145.9922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="68" x2="1275.5" y1="145.9922" y2="145.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="53" x="75" y="140.9263">modify()</text><polygon fill="#A80036" points="470,171.125,480,175.125,470,179.125,474,175.125" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="263" x2="476" y1="175.125" y2="175.125"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="195" x="270" y="170.0591">BatteryStatusChangeMessage</text><path d="M411.5,190.125 L559.5,190.125 L559.5,197.125 L549.5,207.125 L411.5,207.125 L411.5,190.125 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="103.5313" style="stroke:#000000;stroke-width:2.0;" width="468.5" x="411.5" y="190.125"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="103" x="426.5" y="203.1919">If Discharging</text><polygon fill="#A80036" points="689,224.3906,699,228.3906,689,232.3906,693,228.3906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="482" x2="695" y1="228.3906" y2="228.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="195" x="489" y="223.3247">BatteryStatusChangeMessage</text><line style="stroke:#A80036;stroke-width:1.0;" x1="701" x2="743" y1="272.6563" y2="272.6563"/><line style="stroke:#A80036;stroke-width:1.0;" x1="743" x2="743" y1="272.6563" y2="285.6563"/><line style="stroke:#A80036;stroke-width:1.0;" x1="702" x2="743" y1="285.6563" y2="285.6563"/><polygon fill="#A80036" points="712,281.6563,702,285.6563,712,289.6563,708,285.6563" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="160" x="708" y="252.4575">If State::ShutdownReady:</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154" x="712" y="267.5903">state = State:Shutdown</text><polygon fill="#A80036" points="863,317.7891,873,321.7891,863,325.7891,867,321.7891" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="482" x2="869" y1="321.7891" y2="321.7891"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="195" x="489" y="316.7231">BatteryStatusChangeMessage</text><polygon fill="#A80036" points="989,346.9219,999,350.9219,989,354.9219,993,350.9219" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="875" x2="995" y1="350.9219" y2="350.9219"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="102" x="882" y="345.856">updateBattery()</text><polygon fill="#A80036" points="1012,376.0547,1002,380.0547,1012,384.0547,1008,380.0547" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1269.5,376.0547,1279.5,380.0547,1269.5,384.0547,1273.5,380.0547" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="1006" x2="1275.5" y1="380.0547" y2="380.0547"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="31" x="1018" y="374.9888">get()</text><polygon fill="#A80036" points="1151,405.1875,1161,409.1875,1151,413.1875,1155,409.1875" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="1001" x2="1157" y1="409.1875" y2="409.1875"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="138" x="1008" y="404.1216">show(batteryContext)</text><!--MD5=[c6c243b94a88456e8572e27fdc18c06d]
@startuml
participant "Battery Charger" as bc
participant "Worker Event" as we
participant "Event Manager" as evm
participant "System Manager" as sm
participant "Current application" as ca
participant "TopBar" as tb
participant "Battery Widget" as bw
participant "Event Store\nBattery" as es

bc -> we : Interrupt
we -> bc : Store status to EventStore
bc -> es : modify()
we -> evm : BatteryStatusChangeMessage
group If Discharging
    evm -> sm : BatteryStatusChangeMessage
    sm -> sm : If State::ShutdownReady:\n state = State:Shutdown
end
evm -> ca : BatteryStatusChangeMessage
ca -> tb : updateBattery()
tb <-> es : get() 
tb -> bw : show(batteryContext)

@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 +2 -20
@@ 9,27 9,9 @@

namespace sevm
{
    class BatteryLevelMessage : public Message
    {
      public:
        BatteryLevelMessage(uint8_t levelPercents, bool fullyCharged)
            : Message(MessageType::EVMBatteryLevel), levelPercents(levelPercents), fullyCharged(fullyCharged)
        {
            type = Type::Data;
        }
        uint8_t levelPercents = 0;
        bool fullyCharged     = false;
    };
    class BatteryStatusChangeMessage : public sys::Message
    {};

    class BatteryPlugMessage : public Message
    {
      public:
        BatteryPlugMessage() : Message(MessageType::EVMChargerPlugged)
        {
            type = Type::Data;
        }
        bool plugged = false;
    };
    class BatterySetCriticalLevel : public sys::Message
    {
      public:

M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +6 -6
@@ 286,17 286,17 @@ namespace sys
            return MessageNone{};
        });

        connect(sevm::KbdMessage(), [&](Message *) {
            // we are in shutdown mode - we received that there was red key pressed -> we need to reboot
            if (state == State::Shutdown) {
                set(State::Reboot);
        connect(sevm::BatteryStatusChangeMessage(), [&](Message *) {
            if ((state == State::Shutdown) && (Store::Battery::get().state == Store::Battery::State::Discharging)) {
                set(State::ShutdownReady);
            }
            return MessageNone{};
        });

        connect(sevm::BatteryPlugMessage(), [&](Message *) {
        connect(sevm::KbdMessage(), [&](Message *) {
            // we are in shutdown mode - we received that there was red key pressed -> we need to reboot
            if (state == State::Shutdown) {
                set(State::ShutdownReady);
                set(State::Reboot);
            }
            return MessageNone{};
        });

M source/MessageType.hpp => source/MessageType.hpp +0 -3
@@ 173,9 173,6 @@ enum class MessageType
    SystemManagerCpuFrequency,
    SystemManagerRegistration,

    // battery charger messages
    EVMBatteryLevel,
    EVMChargerPlugged,
    // rtc messages
    EVMMinuteUpdated, ///< This message is send to current focused application on every minute time change.
    EVMTimeUpdated,   ///< This message is send on every time update.