~aleteoryx/muditaos

674a7683645c7263ee7ca632f86f6a8c8b4a5846 — Lefucjusz 2 years ago a99d9e3
[MOS-669] Add too hot battery notification when charging

* Added notification showing on the main
screen if the battery has reached too
high temperature to continue charging.
* Code cleanups.
41 files changed, 675 insertions(+), 580 deletions(-)

M image/system_a/data/lang/Deutsch.json
M image/system_a/data/lang/English.json
M image/system_a/data/lang/Espanol.json
M image/system_a/data/lang/Francais.json
M image/system_a/data/lang/Polski.json
M image/system_a/data/lang/Svenska.json
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp
D module-apps/application-desktop/windows/Reboot.cpp
D module-apps/application-desktop/windows/Reboot.hpp
M module-apps/apps-common/notifications/NotificationData.cpp
M module-apps/apps-common/notifications/NotificationData.hpp
M module-apps/apps-common/notifications/NotificationListItem.cpp
M module-apps/apps-common/notifications/NotificationListItem.hpp
M module-apps/apps-common/notifications/NotificationProvider.cpp
M module-apps/apps-common/notifications/NotificationProvider.hpp
M module-apps/apps-common/notifications/NotificationTilesBox.cpp
M module-apps/apps-common/notifications/NotificationTilesPresenter.cpp
M module-apps/apps-common/notifications/NotificationsConfiguration.cpp
M module-apps/apps-common/notifications/NotificationsConfiguration.hpp
M module-apps/apps-common/notifications/NotificationsHandler.cpp
M module-apps/apps-common/notifications/NotificationsHandler.hpp
M module-apps/apps-common/notifications/NotificationsListPresenter.cpp
M module-apps/apps-common/notifications/NotificationsListPresenter.hpp
M module-bsp/board/linux/hal/battery_charger/BatteryCharger.cpp
M module-bsp/board/rt1051/bellpx/hal/battery_charger/BatteryCharger.cpp
M module-bsp/board/rt1051/puretx/bsp/battery_charger/MAX77818.hpp
M module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.cpp
M module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.hpp
M module-bsp/board/rt1051/puretx/hal/battery_charger/BatteryCharger.cpp
M module-bsp/hal/include/hal/battery_charger/AbstractBatteryCharger.hpp
M module-services/service-evtmgr/EventManager.cpp
M module-services/service-evtmgr/battery/BatteryController.cpp
M module-services/service-evtmgr/battery/BatteryController.hpp
M module-services/service-evtmgr/battery/BatteryState.cpp
M module-utils/EventStore/EventStore.cpp
M module-utils/EventStore/EventStore.hpp
M products/PurePhone/CMakeLists.txt
M products/PurePhone/assets/assets_common.json
M products/PurePhone/services/appmgr/ApplicationManager.cpp
M products/PurePhone/services/appmgr/include/appmgr/ApplicationManager.hpp
M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +1 -0
@@ 280,6 280,7 @@
    "app_desktop_unlock": "ENTSPERREN",
    "app_desktop_unread_messages": "<text>Ungelesene Nachrichten</text>",
    "app_desktop_unread_single_message": "<text>Ungelesene Nachricht</text>",
    "app_desktop_battery_too_hot": "<text>Batterie zu heiß, lädt nicht</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_countdown_desc": "Beginnt in",
    "app_meditation_interval_chime": "Glocken-Intervall",

M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +1 -0
@@ 283,6 283,7 @@
    "app_desktop_unlock": "UNLOCK",
    "app_desktop_unread_messages": "<text>Unread messages</text>",
    "app_desktop_unread_single_message": "<text>Unread message</text>",
    "app_desktop_battery_too_hot": "<text>Battery too hot, not charging</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_countdown_desc": "Starts in",
    "app_meditation_interval_chime": "Interval chime",

M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +1 -0
@@ 279,6 279,7 @@
    "app_desktop_unlock": "DESBLOQUEAR",
    "app_desktop_unread_messages": "<text>Mensajes no le\u00eddos</text>",
    "app_desktop_unread_single_message": "<text>Mensaje no le\u00eddo</text>",
    "app_desktop_battery_too_hot": "<text>Batería caliente, no carga</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_countdown_desc": "Empieza en",
    "app_meditation_interval_chime": "Campanilla de intervalo",

M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +1 -0
@@ 247,6 247,7 @@
    "app_desktop_unlock": "D\u00c9V\u00c9ROUILLER",
    "app_desktop_unread_messages": "<text>Messages non lus</text>",
    "app_desktop_unread_single_message": "<text>Message non lu</text>",
    "app_desktop_battery_too_hot": "<text>Batterie chaude, pas de charge</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_countdown_desc": "D\u00e9but dans",
    "app_meditation_interval_chime": "Carillon d'intervalle",

M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +1 -0
@@ 272,6 272,7 @@
    "app_desktop_unlock": "ODBLOKUJ",
    "app_desktop_unread_messages": "<text>Nowe wiadomo\u015bci</text>",
    "app_desktop_unread_single_message": "<text>Nowa wiadomo\u015b\u0107</text>",
    "app_desktop_battery_too_hot": "<text>Bateria zbyt gorąca, nie ładuje</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_countdown_desc": "Startuje za",
    "app_meditation_interval_chime": "Cykliczny d\u017awi\u0119k",

M image/system_a/data/lang/Svenska.json => image/system_a/data/lang/Svenska.json +1 -0
@@ 147,6 147,7 @@
    "app_desktop_unlock": "L\u00c5S UPP",
    "app_desktop_unread_messages": "<text>Ol\u00e4sta meddelanden</text>",
    "app_desktop_unread_single_message": "<text>Ol\u00e4st meddelande</text>",
    "app_desktop_battery_too_hot": "<text>Batteri för varmt, laddas inte</text>",
    "app_emoji_input_window": "Emoji",
    "app_meditation_interval_chime": "Klinga d\u00e5 och d\u00e5",
    "app_meditation_interval_every_x_minutes": "Var %0:e minut",

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +31 -33
@@ 82,7 82,7 @@ namespace app
    // Invoked upon receiving data message
    sys::MessagePointer ApplicationDesktop::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
    {
        auto retMsg = Application::DataReceivedHandler(msgl);
        const auto retMsg = Application::DataReceivedHandler(msgl);
        // if message was handled by application's template there is no need to process further.
        if (dynamic_cast<sys::ResponseMessage *>(retMsg.get())->retCode == sys::ReturnCodes::Success) {
            return retMsg;


@@ 96,25 96,22 @@ namespace app
        Application::handleAsyncResponse(resp);

        if (resp != nullptr) {
            if (auto msg = dynamic_cast<db::QueryResponse *>(resp)) {
                auto result = msg->getResult();
            if (const auto msg = dynamic_cast<db::QueryResponse *>(resp)) {
                const auto result = msg->getResult();
                if (dbNotificationHandler.handle(result.get())) {
                    refreshMenuWindow();
                }
            }
            return std::make_shared<sys::ResponseMessage>();
        }
        else {
            return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved);
        }
        return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved);
    }

    void ApplicationDesktop::handleNotificationsChanged(std::unique_ptr<gui::SwitchData> notificationsParams)
    {
        if (auto window = getCurrentWindow()->getName();
            window == app::window::name::desktop_main_window || window == gui::popup::window::phone_lock_window) {

            auto refreshMode = getRefreshModeFromNotifications(notificationsParams.get());
        if (const auto window = getCurrentWindow()->getName();
            (window == app::window::name::desktop_main_window) || (window == gui::popup::window::phone_lock_window)) {
            const auto refreshMode = getRefreshModeFromNotifications(notificationsParams.get());
            updateCurrentWindow(std::move(notificationsParams), gui::ShowMode::GUI_SHOW_INIT, refreshMode);
        }
    }


@@ 122,7 119,7 @@ namespace app
    // Invoked during initialization
    sys::ReturnCodes ApplicationDesktop::InitHandler()
    {
        auto ret = Application::InitHandler();
        const auto ret = Application::InitHandler();
        if (ret != sys::ReturnCodes::Success) {
            return ret;
        }


@@ 130,7 127,7 @@ namespace app
        createUserInterface();

        connect(typeid(db::NotificationMessage), [&](sys::Message *request) {
            auto notificationMessage = static_cast<db::NotificationMessage *>(request);
            const auto notificationMessage = static_cast<db::NotificationMessage *>(request);
            dbNotificationHandler.handle(notificationMessage);
            return sys::MessageNone{};
        });


@@ 143,41 140,42 @@ namespace app
    void ApplicationDesktop::createUserInterface()
    {
        using namespace app::window::name;
        using namespace gui::popup::window;

        windowsFactory.attach(desktop_main_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::DesktopMainWindow>(app);
        });
        windowsFactory.attach(desktop_menu, [this](ApplicationCommon *app, const std::string newname) {
        windowsFactory.attach(desktop_menu, [this](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MenuWindow>(app, dbNotificationHandler);
        });
        windowsFactory.attach(dead_battery, [](ApplicationCommon *app, const std::string newname) {
        windowsFactory.attach(dead_battery, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::DeadBatteryWindow>(app);
        });
        windowsFactory.attach(closing_window, [](ApplicationCommon *app, const std::string newname) {
        windowsFactory.attach(closing_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::ClosingWindow>(app);
        });
        windowsFactory.attach(charging_battery, [](ApplicationCommon *app, const std::string newname) {
        windowsFactory.attach(charging_battery, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::ChargingBatteryWindow>(app);
        });
        windowsFactory.attach(desktop_mmi_pull, [](ApplicationCommon *app, const std::string newname) {
            return std::make_unique<gui::MmiPullWindow>(app, desktop_mmi_pull);
        windowsFactory.attach(desktop_mmi_pull, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MmiPullWindow>(app, name);
        });
        windowsFactory.attach(desktop_mmi_push, [](ApplicationCommon *app, const std::string newname) {
            return std::make_unique<gui::MmiPushWindow>(app, desktop_mmi_push);
        windowsFactory.attach(desktop_mmi_push, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MmiPushWindow>(app, name);
        });
        windowsFactory.attach(desktop_mmi_internal, [](ApplicationCommon *app, const std::string newname) {
            return std::make_unique<gui::MmiInternalMsgWindow>(app, desktop_mmi_internal);
        windowsFactory.attach(desktop_mmi_internal, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MmiInternalMsgWindow>(app, name);
        });
        windowsFactory.attach(tethering_menu_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::TetheringMenuPopup>(app, name);
        });
        windowsFactory.attach(tethering_off_window, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::TetheringOffPopup>(app, name);
        });
        windowsFactory.attach(gui::popup::window::tethering_menu_window,
                              [](ApplicationCommon *app, const std::string &name) {
                                  return std::make_unique<gui::TetheringMenuPopup>(app, name);
                              });
        windowsFactory.attach(
            gui::popup::window::tethering_off_window, [](ApplicationCommon *app, const std::string &name) {
                return std::make_unique<gui::TetheringOffPopup>(app, gui::popup::window::tethering_off_window);
            });
        windowsFactory.attach(desktop_mmi_confirmation, [](ApplicationCommon *app, const std::string &name) {
            return std::make_unique<gui::MmiConfirmationWindow>(app, name);
        });

        attachPopups({gui::popup::ID::Volume,
                      gui::popup::ID::Tethering,
                      gui::popup::ID::BluetoothAuthenticate,


@@ 192,7 190,7 @@ namespace app

    bool ApplicationDesktop::refreshMenuWindow()
    {
        if (auto menuWindow = dynamic_cast<gui::MenuWindow *>(getWindow(app::window::name::desktop_menu));
        if (const auto menuWindow = dynamic_cast<gui::MenuWindow *>(getWindow(app::window::name::desktop_menu));
            menuWindow != nullptr) {
            menuWindow->refresh();
            return true;


@@ 202,9 200,9 @@ namespace app

    void ApplicationDesktop::handleLowBatteryNotification(manager::actions::ActionParamsPtr &&data)
    {
        auto lowBatteryState = static_cast<manager::actions::LowBatteryNotificationParams *>(data.get());
        const auto lowBatteryState = static_cast<manager::actions::LowBatteryNotificationParams *>(data.get());
        blockAllPopups       = lowBatteryState->isActive();
        auto currentWindow   = getCurrentWindow();
        const auto currentWindow   = getCurrentWindow();
        if (currentWindow->getName() == app::window::name::dead_battery ||
            currentWindow->getName() == app::window::name::charging_battery) {
            data->ignoreCurrentWindowOnStack = true;

M module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/include/application-desktop/ApplicationDesktop.hpp +0 -2
@@ 39,8 39,6 @@ namespace app
        // done
        void handleNotificationsChanged(std::unique_ptr<gui::SwitchData> notificationsParams) override;

        void setOsUpdateVersion(const std::string &value);

      private:
        bool refreshMenuWindow();
        void handleLowBatteryNotification(manager::actions::ActionParamsPtr &&data);

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

#include "ApplicationDesktop.hpp"
#include "Reboot.hpp"

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

namespace gui
{

    RebootWindow::RebootWindow(app::ApplicationCommon *app, std::unique_ptr<PowerOffPresenter> &&presenter)
        : AppWindow(app, app::window::name::desktop_reboot), presenter(std::move(presenter))
    {
        buildInterface();
    }

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

    void RebootWindow::buildInterface()
    {
        AppWindow::buildInterface();

        auto text_y_offset = 270;
        auto text_height   = 300;

        text = new Text(this,
                        style::window::default_left_margin,
                        text_y_offset,
                        style::window_width - style::window::default_left_margin * 2,
                        text_height);
        text->setText(utils::translate("phone_needs_rebooting"));
        text->setFilled(false);
        text->setBorderColor(gui::ColorFullBlack);
        text->setFont(style::header::font::title);
        text->setEdges(RectangleEdge::None);
        text->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Bottom));
    }

    void RebootWindow::destroyInterface()
    {
        erase();
        invalidate();
    }

    void RebootWindow::invalidate() noexcept
    {
        text = nullptr;
    }

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

    bool RebootWindow::onInput(const InputEvent &inputEvent)
    {
        presenter->powerOff();
        return true;
    }

} /* namespace gui */

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

#pragma once

#include <AppWindow.hpp>
#include <popups/presenter/PowerOffPresenter.hpp>
#include <Text.hpp>

#include <vector>

namespace gui
{
    class RebootWindow : public AppWindow
    {
      public:
        RebootWindow(app::ApplicationCommon *app, std::unique_ptr<PowerOffPresenter> &&presenter);
        ~RebootWindow() override = default;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        bool onInput(const InputEvent &inputEvent) override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;

      private:
        void invalidate() noexcept;

        std::unique_ptr<PowerOffPresenter> presenter;
        Text *text = nullptr;
    };

} /* namespace gui */

M module-apps/apps-common/notifications/NotificationData.cpp => module-apps/apps-common/notifications/NotificationData.cpp +80 -74
@@ 1,97 1,103 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationData.hpp"
#include <gsl/assert>
uint32_t notifications::Notification::priorityPool = 0;

using namespace notifications;

Notification::Notification(NotificationType type, NotificationPriority priorityType) : type{type}
namespace notifications
{
    switch (priorityType) {
    case NotificationPriority::Next:
        if (priorityPool == highestPriority) {
            priorityPool = 0;
    std::uint32_t Notification::priorityPool = 0;

    Notification::Notification(NotificationType type, NotificationPriority priorityType) : type{type}
    {
        switch (priorityType) {
        case NotificationPriority::Next:
            if (priorityPool == highestPriority) {
                priorityPool = 0;
            }
            priority = ++priorityPool;
            break;
        case NotificationPriority::Highest:
            priority = highestPriority;
            break;
        case NotificationPriority::Lowest:
            priority = lowestPriority;
            break;
        }
        priority = ++priorityPool;
        break;
    case NotificationPriority::Highest:
        priority = highestPriority;
        break;
    case NotificationPriority::Lowest:
        priority = lowestPriority;
        break;
    }
}

auto Notification::getType() const noexcept -> NotificationType
{
    return type;
}
    auto Notification::getType() const noexcept -> NotificationType
    {
        return type;
    }

auto Notification::getPriority() const noexcept -> uint32_t
{
    return priority;
}
    auto Notification::getPriority() const noexcept -> std::uint32_t
    {
        return priority;
    }

NotificationWithContact::NotificationWithContact(NotificationType type,
                                                 unsigned value,
                                                 std::optional<ContactRecord> record)
    : Notification(type), value{value}, record{std::move(record)}
{}
    NotificationWithContact::NotificationWithContact(NotificationType type,
                                                     unsigned value,
                                                     std::optional<ContactRecord> record)
        : Notification(type), value{value}, record{std::move(record)}
    {}

auto NotificationWithContact::hasRecord() const noexcept -> bool
{
    return record.has_value();
}
    auto NotificationWithContact::hasRecord() const noexcept -> bool
    {
        return record.has_value();
    }

auto NotificationWithContact::getRecord() const noexcept -> const ContactRecord &
{
    Expects(hasRecord());
    return record.value();
}
    auto NotificationWithContact::getRecord() const noexcept -> const ContactRecord &
    {
        Expects(hasRecord());
        return record.value();
    }

auto NotificationWithContact::getValue() const noexcept -> unsigned
{
    return value;
}
    auto NotificationWithContact::getValue() const noexcept -> unsigned
    {
        return value;
    }

NotificationWithCounter::NotificationWithCounter(NotificationType type, unsigned value)
    : Notification(type), value{value}
{}
    NotificationWithCounter::NotificationWithCounter(NotificationType type, unsigned value)
        : Notification(type), value{value}
    {}

auto NotificationWithCounter::getValue() const noexcept -> unsigned
{
    return value;
}
    auto NotificationWithCounter::getValue() const noexcept -> unsigned
    {
        return value;
    }

NotificationWithTime::NotificationWithTime(NotificationType type,
                                           NotificationPriority priorityType,
                                           std::string formattedTime)
    : Notification(type, priorityType), formattedTime(std::move(formattedTime))
{}
    NotificationWithTime::NotificationWithTime(NotificationType type,
                                               NotificationPriority priorityType,
                                               std::string formattedTime)
        : Notification(type, priorityType), formattedTime(std::move(formattedTime))
    {}

auto NotificationWithTime::getTime() const noexcept -> const std::string &
{
    return formattedTime;
}
    auto NotificationWithTime::getTime() const noexcept -> const std::string &
    {
        return formattedTime;
    }

    NotSeenSMSNotification::NotSeenSMSNotification(unsigned value, std::optional<ContactRecord> record)
        : NotificationWithContact(NotificationType::NotSeenSms, value, std::move(record))
    {}

NotSeenSMSNotification::NotSeenSMSNotification(unsigned value, std::optional<ContactRecord> record)
    : NotificationWithContact(NotificationType::NotSeenSms, value, std::move(record))
{}
    NotSeenCallNotification::NotSeenCallNotification(unsigned value, std::optional<ContactRecord> record)
        : NotificationWithContact(NotificationType::NotSeenCall, value, std::move(record))
    {}

NotSeenCallNotification::NotSeenCallNotification(unsigned value, std::optional<ContactRecord> record)
    : NotificationWithContact(NotificationType::NotSeenCall, value, std::move(record))
{}
    TetheringNotification::TetheringNotification() : Notification(NotificationType::Tethering)
    {}

TetheringNotification::TetheringNotification() : Notification(NotificationType::Tethering)
{}
    AlarmSnoozeNotification::AlarmSnoozeNotification(unsigned value)
        : NotificationWithCounter(NotificationType::AlarmSnooze, value)
    {}

AlarmSnoozeNotification::AlarmSnoozeNotification(unsigned value)
    : NotificationWithCounter(NotificationType::AlarmSnooze, value)
{}
    PhoneLockNotification::PhoneLockNotification(std::string formattedTime)
        : NotificationWithTime(NotificationType::PhoneLock, NotificationPriority::Highest, std::move(formattedTime))
    {}

PhoneLockNotification::PhoneLockNotification(std::string formattedTime)
    : NotificationWithTime(NotificationType::PhoneLock, NotificationPriority::Highest, std::move(formattedTime))
{}
    BatteryTooHotNotification::BatteryTooHotNotification()
        : Notification(NotificationType::BatteryTooHot, NotificationPriority::Highest)
    {}
} // namespace notifications

M module-apps/apps-common/notifications/NotificationData.hpp => module-apps/apps-common/notifications/NotificationData.hpp +12 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 16,7 16,8 @@ namespace notifications
        NotSeenCall,
        Tethering,
        AlarmSnooze,
        PhoneLock
        PhoneLock,
        BatteryTooHot
    };

    enum class NotificationPriority


@@ 34,19 35,19 @@ namespace notifications

    class Notification
    {
        static constexpr auto highestPriority = std::numeric_limits<uint32_t>::max();
        static constexpr auto highestPriority = std::numeric_limits<std::uint32_t>::max();
        static constexpr auto lowestPriority  = 0;
        static uint32_t priorityPool;
        static std::uint32_t priorityPool;

        NotificationType type;
        uint32_t priority;
        std::uint32_t priority;

      protected:
        explicit Notification(NotificationType type, NotificationPriority priorityType = NotificationPriority::Next);

      public:
        [[nodiscard]] auto getType() const noexcept -> NotificationType;
        [[nodiscard]] auto getPriority() const noexcept -> uint32_t;
        [[nodiscard]] auto getPriority() const noexcept -> std::uint32_t;

        virtual ~Notification() = default;
    };


@@ 117,4 118,9 @@ namespace notifications
        explicit PhoneLockNotification(std::string formattedTime);
    };

    class BatteryTooHotNotification : public Notification
    {
      public:
        BatteryTooHotNotification();
    };
} // namespace notifications

M module-apps/apps-common/notifications/NotificationListItem.cpp => module-apps/apps-common/notifications/NotificationListItem.cpp +7 -6
@@ 18,14 18,14 @@ namespace
{
    auto buildImageInactive(const UTF8 &img) -> gui::Image *
    {
        auto thumbnail        = new gui::Image(img);
        const auto thumbnail  = new gui::Image(img);
        thumbnail->activeItem = false;
        return thumbnail;
    }

    auto buildNotificationIcon(const UTF8 &icon) -> gui::Image *
    {
        auto thumbnail = buildImageInactive(icon);
        const auto thumbnail = buildImageInactive(icon);
        thumbnail->setMinimumWidth(style::notifications::iconWidth);
        thumbnail->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
        thumbnail->setMargins(


@@ 33,9 33,9 @@ namespace
        return thumbnail;
    }

    auto buildNotificationNameLabel(uint32_t width) -> gui::TextFixedSize *
    auto buildNotificationNameLabel([[maybe_unused]] std::uint32_t width) -> gui::TextFixedSize *
    {
        auto text =
        const auto text =
            new gui::TextFixedSize(nullptr, 0, 0, style::notifications::textMinWidth, style::notifications::itemHeight);

        text->setMaximumSize(style::notifications::textMaxWidth, Axis::X);


@@ 95,7 95,8 @@ namespace
        {notifications::NotificationType::NotSeenCall, "calls_notification_icon_W_G"},
        {notifications::NotificationType::Tethering, "tethering_notification_icon_W_G"},
        {notifications::NotificationType::AlarmSnooze, "alarm_notification_icon_W_G"},
        {notifications::NotificationType::PhoneLock, "lock_notification_icon_W_G"}};
        {notifications::NotificationType::PhoneLock, "lock_notification_icon_W_G"},
        {notifications::NotificationType::BatteryTooHot, "battery_notification_icon_W_G"}};
} // namespace

NotificationListItem::NotificationListItem(NotificationType type) : type{type}


@@ 151,7 152,7 @@ NotificationWithOnOffButton::NotificationWithOnOffButton(notifications::Notifica
                                                         gui::ButtonTriState::State state)
    : NotificationListItem(type)
{
    auto button = new ButtonTriState(nullptr, state);
    const auto button = new ButtonTriState(nullptr, state);
    button->setMargins(Margins(0, 0, 20, 0));
    box->addWidget(button);
}

M module-apps/apps-common/notifications/NotificationListItem.hpp => module-apps/apps-common/notifications/NotificationListItem.hpp +0 -1
@@ 12,7 12,6 @@

namespace gui
{

    class TextFixedSize;

    class NotificationListItem : public ListItem

M module-apps/apps-common/notifications/NotificationProvider.cpp => module-apps/apps-common/notifications/NotificationProvider.cpp +33 -14
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationProvider.hpp"


@@ 11,8 11,8 @@

using namespace notifications;

NotificationProvider::NotificationProvider(sys::Service *ownerService, NotificationsConfiguration &notifcationConfig)
    : ownerService{ownerService}, notifcationConfig{notifcationConfig}
NotificationProvider::NotificationProvider(sys::Service *ownerService, NotificationsConfiguration &notificationConfig)
    : ownerService{ownerService}, notificationConfig{notificationConfig}
{}

template <NotificationType type, typename T>


@@ 75,7 75,7 @@ void NotificationProvider::handle(db::query::notifications::GetAllResult *msg)
        }
    }

    notifcationConfig.updateCurrentList(listPolicy);
    notificationConfig.updateCurrentList(listPolicy);

    if (notificationsChanged && listPolicy.updateListAllowed()) {
        send();


@@ 120,6 120,25 @@ void NotificationProvider::handleSnooze(unsigned snoozeCount)
    send();
}

void NotificationProvider::handleBatteryTooHot(bool isBatteryTooHot, bool allowUpdate)
{
    auto notificationsChanged    = false;
    const auto notificationShown = (notifications.count(NotificationType::BatteryTooHot) != 0);

    if (isBatteryTooHot && !notificationShown) {
        notifications[NotificationType::BatteryTooHot] = std::make_shared<notifications::BatteryTooHotNotification>();
        notificationsChanged                           = true;
    }
    else if (!isBatteryTooHot && notificationShown) {
        notifications.erase(NotificationType::BatteryTooHot);
        notificationsChanged = true;
    }

    if (notificationsChanged && allowUpdate) {
        send();
    }
}

void NotificationProvider::requestNotSeenNotifications()
{
    DBServiceAPI::GetQuery(


@@ 141,20 160,20 @@ namespace

void NotificationProvider::send(NotificationOnReceiveUpdate updateOnReceive)
{
    notifcationConfig.updateCurrentList(listPolicy);
    using namespace app::manager;

    notificationConfig.updateCurrentList(listPolicy);

    std::list<std::shared_ptr<const Notification>> toSendNotifications;
    transform(notifications.begin(), notifications.end(), back_inserter(toSendNotifications), get_second());
    std::list<std::shared_ptr<const Notification>> notificationsToSend;
    std::transform(notifications.begin(), notifications.end(), std::back_inserter(notificationsToSend), get_second());

    toSendNotifications.sort(
    notificationsToSend.sort(
        [](const std::shared_ptr<const Notification> &lhs, const std::shared_ptr<const Notification> &rhs) {
            return (lhs->getPriority() > rhs->getPriority());
        });

    auto fastRefreshOnUpdate = updateOnReceive == NotificationOnReceiveUpdate::PartialRebuild;
    app::manager::Controller::sendAction(
        ownerService,
        app::manager::actions::NotificationsChanged,
        std::make_unique<app::manager::actions::NotificationsChangedParams>(
            std::move(toSendNotifications), listPolicy.showListWhenLocked(), fastRefreshOnUpdate));
    const auto fastRefreshOnUpdate = (updateOnReceive == NotificationOnReceiveUpdate::PartialRebuild);
    auto data                      = std::make_unique<actions::NotificationsChangedParams>(
        std::move(notificationsToSend), listPolicy.showListWhenLocked(), fastRefreshOnUpdate);
    Controller::sendAction(ownerService, actions::NotificationsChanged, std::move(data));
}

M module-apps/apps-common/notifications/NotificationProvider.hpp => module-apps/apps-common/notifications/NotificationProvider.hpp +4 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 26,20 26,20 @@ namespace db

namespace notifications
{

    class NotificationProvider
    {
        template <NotificationType type, typename T>
        bool handleNotSeenWithCounter(NotificationsRecord &&record);

      public:
        explicit NotificationProvider(sys::Service *ownerService, NotificationsConfiguration &notifcationConfig);
        NotificationProvider(sys::Service *ownerService, NotificationsConfiguration &notificationConfig);

        void handle(locks::PhoneLockTimeUpdate *msg);
        void handle(db::query::notifications::GetAllResult *msg);
        void handle(db::NotificationMessage *msg);
        void handle(sys::phone_modes::Tethering tethering);
        void handleSnooze(unsigned snoozeCount);
        void handleBatteryTooHot(bool tooHot, bool allowUpdate = true);
        void requestNotSeenNotifications();
        void send(NotificationOnReceiveUpdate updateOnReceive = NotificationOnReceiveUpdate::FullRebuild);



@@ 47,9 47,8 @@ namespace notifications

      private:
        sys::Service *ownerService;
        NotificationsConfiguration &notifcationConfig;
        NotificationsConfiguration &notificationConfig;
        NotificationsListPolicy listPolicy;
        Notifications notifications;
    };

} // namespace notifications

M module-apps/apps-common/notifications/NotificationTilesBox.cpp => module-apps/apps-common/notifications/NotificationTilesBox.cpp +3 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationTilesBox.hpp"


@@ 13,10 13,10 @@ namespace gui
                                               std::shared_ptr<NotificationTilesPresenter> notificationsPresenter)
        : HBox(
              parent, 0, 0, ::style::window::default_body_width, ::style::wallpaper::notificationTiles::tileIconHeight),
          notificationsPresenter(notificationsPresenter)
          notificationsPresenter(std::move(notificationsPresenter))
    {
        setEdges(RectangleEdge::None);
        setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
        notificationsPresenter->attach(this);
        this->notificationsPresenter->attach(this);
    }
} // namespace gui

M module-apps/apps-common/notifications/NotificationTilesPresenter.cpp => module-apps/apps-common/notifications/NotificationTilesPresenter.cpp +8 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationTilesPresenter.hpp"


@@ 14,10 14,11 @@ namespace
    constexpr auto tetheringIcon = "tethering_notification_icon_W_G";
    constexpr auto alarmIcon     = "alarm_notification_icon_W_G";
    constexpr auto lockIcon      = "lock_notification_icon_W_G";
    constexpr auto batteryIcon   = "battery_notification_icon_W_G";

    auto buildNotificationIcon(const UTF8 &imageName) -> gui::Image *
    {
        auto icon = new gui::Image(imageName);
        const auto icon = new gui::Image(imageName);
        icon->setMinimumWidth(::style::wallpaper::notificationTiles::tileIconHeight);
        icon->setMargins(gui::Margins(::style::wallpaper::notificationTiles::tileIconMarigin,
                                      0,


@@ 30,9 31,9 @@ namespace
NotificationTilesPresenter::NotificationTilesPresenter()
{}

void NotificationTilesPresenter::attach(HBox *tilesBox)
void NotificationTilesPresenter::attach(HBox *newTilesBox)
{
    this->tilesBox = tilesBox;
    tilesBox = newTilesBox;
}

void NotificationTilesPresenter::updateData(app::manager::actions::NotificationsChangedParams *params,


@@ 58,6 59,9 @@ void NotificationTilesPresenter::updateData(app::manager::actions::Notifications
        else if (typeid(*notification) == typeid(notifications::PhoneLockNotification)) {
            tilesBox->addWidget(buildNotificationIcon(lockIcon));
        }
        else if (typeid(*notification) == typeid(notifications::BatteryTooHotNotification)) {
            tilesBox->addWidget(buildNotificationIcon(batteryIcon));
        }
        else if (typeid(*notification) == typeid(notifications::AlarmSnoozeNotification)) {
            tilesBox->addWidget(buildNotificationIcon(alarmIcon));
        }

M module-apps/apps-common/notifications/NotificationsConfiguration.cpp => module-apps/apps-common/notifications/NotificationsConfiguration.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationsConfiguration.hpp"


@@ 10,7 10,7 @@ using namespace notifications;
NotificationsConfiguration::NotificationsConfiguration(std::shared_ptr<sys::phone_modes::Observer> phoneModeObserver,
                                                       std::shared_ptr<settings::Settings> settings,
                                                       const locks::PhoneLockHandler &phoneLockHandler)
    : phoneModeObserver{phoneModeObserver}, settings{settings}, phoneLockHandler{phoneLockHandler}
    : phoneModeObserver{std::move(phoneModeObserver)}, settings{std::move(settings)}, phoneLockHandler{phoneLockHandler}
{}

void NotificationsConfiguration::updateCurrentCall(CallNotificationPolicy &policy)

M module-apps/apps-common/notifications/NotificationsConfiguration.hpp => module-apps/apps-common/notifications/NotificationsConfiguration.hpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 24,7 24,6 @@ namespace notifications

      private:
        auto getDNDNotificationsOnLockedScreen() const noexcept -> bool;
        auto getDNDCallsFromFavourites() const noexcept -> bool;
        std::shared_ptr<sys::phone_modes::Observer> phoneModeObserver;
        std::shared_ptr<settings::Settings> settings;
        const locks::PhoneLockHandler &phoneLockHandler;

M module-apps/apps-common/notifications/NotificationsHandler.cpp => module-apps/apps-common/notifications/NotificationsHandler.cpp +5 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NotificationsHandler.hpp"


@@ 7,14 7,14 @@

using namespace notifications;

NotificationsHandler::NotificationsHandler(sys::Service *parentService, NotificationsConfiguration &notifcationConfig)
    : parentService{parentService}, notifcationConfig{notifcationConfig}
NotificationsHandler::NotificationsHandler(sys::Service *parentService, NotificationsConfiguration &notificationConfig)
    : parentService{parentService}, notificationConfig{notificationConfig}
{}

void NotificationsHandler::registerMessageHandlers()
{
    parentService->connect(typeid(cellular::IncomingSMSNotificationMessage),
                           [&](sys::Message *request) -> sys::MessagePointer {
                           [&]([[maybe_unused]] sys::Message *request) -> sys::MessagePointer {
                               incomingSMSHandler();
                               return sys::msgHandled();
                           });


@@ 22,7 22,7 @@ void NotificationsHandler::registerMessageHandlers()

void NotificationsHandler::incomingSMSHandler()
{
    notifcationConfig.updateCurrentSMS(currentSMSPolicy);
    notificationConfig.updateCurrentSMS(currentSMSPolicy);
    playbackSMSRingtone();
}


M module-apps/apps-common/notifications/NotificationsHandler.hpp => module-apps/apps-common/notifications/NotificationsHandler.hpp +3 -7
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 15,19 15,15 @@ namespace notifications
    class NotificationsHandler
    {
      public:
        NotificationsHandler(sys::Service *parentService, NotificationsConfiguration &notifcationConfig);
        NotificationsHandler(sys::Service *parentService, NotificationsConfiguration &notificationConfig);
        void registerMessageHandlers();

      private:
        void incomingSMSHandler();

        void policyNumberCheck(const utils::PhoneNumber::View &number);
        void playbackCallRingtone();
        void playbackSMSRingtone();

        sys::Service *parentService = nullptr;
        NotificationsConfiguration &notifcationConfig;
        CallNotificationPolicy currentCallPolicy;
        NotificationsConfiguration &notificationConfig;
        SMSNotificationPolicy currentSMSPolicy;
    };
} // namespace notifications

M module-apps/apps-common/notifications/NotificationsListPresenter.cpp => module-apps/apps-common/notifications/NotificationsListPresenter.cpp +36 -20
@@ 26,7 26,7 @@ NotificationsListPresenter::NotificationsListPresenter()
    : app::InternalModel<gui::NotificationListItem *>{}, gui::ListItemProvider{}
{}

unsigned int NotificationsListPresenter::requestRecordsCount()
unsigned NotificationsListPresenter::requestRecordsCount()
{
    return internalData.size();
}


@@ 36,13 36,13 @@ gui::ListItem *NotificationsListPresenter::getItem(gui::Order order)
    return getRecord(order);
}

void NotificationsListPresenter::requestRecords(uint32_t offset, uint32_t limit)
void NotificationsListPresenter::requestRecords(std::uint32_t offset, std::uint32_t limit)
{
    setupModel(offset, limit);
    list->onProviderDataUpdate();
}

unsigned int NotificationsListPresenter::getMinimalItemSpaceRequired() const
unsigned NotificationsListPresenter::getMinimalItemSpaceRequired() const
{
    return style::notifications::itemHeight;
}


@@ 59,13 59,11 @@ bool NotificationsListPresenter::hasDismissibleNotification() const noexcept

void NotificationsListPresenter::dismissAll()
{
    for (auto it = std::begin(internalData); it != std::end(internalData); it++) {
        if (auto item = *it; item->isDismissible()) {
            if (item->dismissCallback) {
                item->dismissCallback();
            }
    std::for_each(internalData.cbegin(), internalData.cend(), [](const auto &item) {
        if (item->isDismissible() && item->dismissCallback) {
            item->dismissCallback();
        }
    }
    });
}

bool NotificationsListPresenter::isEmpty() const noexcept


@@ 76,7 74,8 @@ bool NotificationsListPresenter::isEmpty() const noexcept
auto NotificationsListPresenter::create(const notifications::NotSeenSMSNotification *notification)
    -> NotificationListItem *
{
    auto item = new NotificationWithEventCounter(notifications::NotificationType::NotSeenSms, notification->getValue());
    const auto item =
        new NotificationWithEventCounter(notifications::NotificationType::NotSeenSms, notification->getValue());
    setNotificationText(item,
                        notification,
                        (notification->getValue() == 1) ? "app_desktop_unread_single_message"


@@ 87,17 86,17 @@ auto NotificationsListPresenter::create(const notifications::NotSeenSMSNotificat
auto NotificationsListPresenter::create(const notifications::NotSeenCallNotification *notification)
    -> NotificationListItem *
{
    auto item =
    const auto item =
        new NotificationWithEventCounter(notifications::NotificationType::NotSeenCall, notification->getValue());
    setNotificationText(item, notification, "app_desktop_missed_calls");
    item->deleteByList = false;
    return item;
}

auto NotificationsListPresenter::create(const notifications::TetheringNotification *notification)
auto NotificationsListPresenter::create([[maybe_unused]] const notifications::TetheringNotification *notification)
    -> NotificationListItem *
{
    auto item =
    const auto item =
        new NotificationWithOnOffButton(notifications::NotificationType::Tethering, gui::ButtonTriState::State::On);
    item->setName(utils::translate("Tethering"), false);
    item->deleteByList = false;


@@ 107,7 106,7 @@ auto NotificationsListPresenter::create(const notifications::TetheringNotificati
auto NotificationsListPresenter::create(const notifications::AlarmSnoozeNotification *notification)
    -> NotificationListItem *
{
    auto item =
    const auto item =
        new NotificationWithEventCounter(notifications::NotificationType::AlarmSnooze, notification->getValue());
    item->setName(utils::translate("app_desktop_alarm_snooze"), true);
    item->deleteByList = false;


@@ 117,18 116,30 @@ auto NotificationsListPresenter::create(const notifications::AlarmSnoozeNotifica
auto NotificationsListPresenter::create(const notifications::PhoneLockNotification *notification)
    -> NotificationListItem *
{
    auto item = new NotificationListItem(notifications::NotificationType::PhoneLock);
    const auto item = new NotificationListItem(notifications::NotificationType::PhoneLock);

    item->setName(utils::translate("phone_lock_notification"), true, {{"$TIME", notification->getTime()}});
    item->deleteByList = false;
    return item;
}

auto NotificationsListPresenter::create([[maybe_unused]] const notifications::BatteryTooHotNotification *notification)
    -> NotificationListItem *
{
    const auto item = new NotificationListItem(notifications::NotificationType::BatteryTooHot);

    item->setName(utils::translate("app_desktop_battery_too_hot"), true);
    item->deleteByList = false;
    item->activeItem   = false;
    return item;
}

void NotificationsListPresenter::updateData(app::manager::actions::NotificationsChangedParams *params,
                                            bool callAndSMSVisibility)
{
    if (list == nullptr) {
        LOG_ERROR("ListView object not provided");
        return;
    }

    list->prepareRebuildCallback = [this, toRemove = std::move(internalData)] {


@@ 140,23 151,28 @@ void NotificationsListPresenter::updateData(app::manager::actions::Notifications

    for (const auto &notification : params->getNotifications()) {
        if (typeid(*notification) == typeid(notifications::NotSeenSMSNotification) && callAndSMSVisibility) {
            auto sms = static_cast<const notifications::NotSeenSMSNotification *>(notification.get());
            const auto sms = static_cast<const notifications::NotSeenSMSNotification *>(notification.get());
            internalData.push_back(create(sms));
        }
        else if (typeid(*notification) == typeid(notifications::NotSeenCallNotification) && callAndSMSVisibility) {
            auto call = static_cast<const notifications::NotSeenCallNotification *>(notification.get());
            const auto call = static_cast<const notifications::NotSeenCallNotification *>(notification.get());
            internalData.push_back(create(call));
        }
        else if (typeid(*notification) == typeid(notifications::TetheringNotification)) {
            auto tethering = static_cast<const notifications::TetheringNotification *>(notification.get());
            const auto tethering = static_cast<const notifications::TetheringNotification *>(notification.get());
            internalData.push_back(create(tethering));
        }
        else if (typeid(*notification) == typeid(notifications::PhoneLockNotification)) {
            auto phoneLock = static_cast<const notifications::PhoneLockNotification *>(notification.get());
            const auto phoneLock = static_cast<const notifications::PhoneLockNotification *>(notification.get());
            internalData.push_back(create(phoneLock));
        }
        else if (typeid(*notification) == typeid(notifications::BatteryTooHotNotification)) {
            const auto batteryTooHot =
                static_cast<const notifications::BatteryTooHotNotification *>(notification.get());
            internalData.push_back(create(batteryTooHot));
        }
        else if (typeid(*notification) == typeid(notifications::AlarmSnoozeNotification)) {
            auto snooze = static_cast<const notifications::AlarmSnoozeNotification *>(notification.get());
            const auto snooze = static_cast<const notifications::AlarmSnoozeNotification *>(notification.get());
            internalData.push_back(create(snooze));
        }
    }

M module-apps/apps-common/notifications/NotificationsListPresenter.hpp => module-apps/apps-common/notifications/NotificationsListPresenter.hpp +6 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 18,10 18,10 @@ namespace gui
                                       public app::InternalModel<gui::NotificationListItem *>,
                                       public gui::ListItemProvider
    {
        [[nodiscard]] unsigned int requestRecordsCount() final;
        [[nodiscard]] unsigned int getMinimalItemSpaceRequired() const final;
        [[nodiscard]] unsigned requestRecordsCount() final;
        [[nodiscard]] unsigned getMinimalItemSpaceRequired() const final;
        ListItem *getItem(Order order) final;
        void requestRecords(uint32_t offset, uint32_t limit) final;
        void requestRecords(std::uint32_t offset, std::uint32_t limit) final;

      protected:
        [[nodiscard]] virtual auto create(const notifications::NotSeenSMSNotification *notification)


@@ 34,6 34,8 @@ namespace gui
            -> NotificationListItem *;
        [[nodiscard]] virtual auto create(const notifications::PhoneLockNotification *notification)
            -> NotificationListItem *;
        [[nodiscard]] virtual auto create(const notifications::BatteryTooHotNotification *notification)
            -> NotificationListItem *;

      public:
        NotificationsListPresenter();


@@ 43,5 45,4 @@ namespace gui
        void updateData(app::manager::actions::NotificationsChangedParams *params, bool callAndSMSVisibility) final;
        void dismissAll() final;
    };

} // namespace gui

M module-bsp/board/linux/hal/battery_charger/BatteryCharger.cpp => module-bsp/board/linux/hal/battery_charger/BatteryCharger.cpp +10 -3
@@ 40,6 40,7 @@ namespace hal::battery
        std::optional<SOC> getSOC() const final;
        ChargingStatus getChargingStatus() const final;
        ChargerPresence getChargerPresence() const final;
        TemperatureState getTemperatureState() const final;

      private:
        void worker();


@@ 84,6 85,7 @@ namespace hal::battery
    {
        return batteryLevel;
    }

    AbstractBatteryCharger::ChargingStatus BatteryCharger::getChargingStatus() const
    {
        if (isPlugged && batteryLevel >= 100) {


@@ 96,22 98,28 @@ namespace hal::battery
            return ChargingStatus::Discharging;
        }
    }

    AbstractBatteryCharger::ChargerPresence BatteryCharger::getChargerPresence() const
    {
        return isPlugged ? AbstractBatteryCharger::ChargerPresence::PluggedIn
                         : AbstractBatteryCharger::ChargerPresence::Unplugged;
    }

    AbstractBatteryCharger::TemperatureState BatteryCharger::getTemperatureState() const
    {
        return AbstractBatteryCharger::TemperatureState::Normal;
    }

    void BatteryCharger::worker()
    {
        mkfifo(batteryFIFO, fifoFileAccessRights);

        // Open FIFO for write only
        int fd = open(batteryFIFO, O_RDONLY | O_NONBLOCK);
        const auto fd = open(batteryFIFO, O_RDONLY | O_NONBLOCK);

        while (shouldRun) {
            std::uint8_t buff[fifoBuffSize];
            std::int32_t readBytes = read(fd, buff, fifoBuffSize);
            const auto readBytes = read(fd, buff, fifoBuffSize);

            if (readBytes > 0) {
                Events evt{};


@@ 156,5 164,4 @@ namespace hal::battery
    {
        return std::make_unique<BatteryCharger>(irqQueueHandle);
    }

} // namespace hal::battery

M module-bsp/board/rt1051/bellpx/hal/battery_charger/BatteryCharger.cpp => module-bsp/board/rt1051/bellpx/hal/battery_charger/BatteryCharger.cpp +7 -1
@@ 80,6 80,7 @@ namespace hal::battery
        std::optional<SOC> getSOC() const final;
        ChargingStatus getChargingStatus() const final;
        ChargerPresence getChargerPresence() const final;
        TemperatureState getTemperatureState() const final;

        static BatteryWorkerQueue &getWorkerQueueHandle();



@@ 201,6 202,11 @@ namespace hal::battery
                                                                  : AbstractBatteryCharger::ChargerPresence::PluggedIn;
    }

    AbstractBatteryCharger::TemperatureState BellBatteryCharger::getTemperatureState() const
    {
        return AbstractBatteryCharger::TemperatureState::Normal; // Harmony has no battery temperature sensor
    }

    BellBatteryCharger::BatteryWorkerQueue &BellBatteryCharger::getWorkerQueueHandle()
    {
        return *worker_queue;


@@ 209,6 215,7 @@ namespace hal::battery
    {
        xQueueSend(this->notification_channel, &event, default_timeout);
    }

    BellBatteryCharger::~BellBatteryCharger()
    {
        xTimerDelete(reinit_timer, default_timeout);


@@ 276,5 283,4 @@ namespace hal::battery
    {
        return std::make_unique<BellBatteryCharger>(irqQueueHandle);
    }

} // namespace hal::battery

M module-bsp/board/rt1051/puretx/bsp/battery_charger/MAX77818.hpp => module-bsp/board/rt1051/puretx/bsp/battery_charger/MAX77818.hpp +10 -8
@@ 162,14 162,16 @@ namespace bsp::battery_charger
    // CHG_DETAILS_01 register
    enum class CHG_DETAILS_01
    {
        CHARGER_PREQUALIFICATION = 0x00,
        CHARGER_CC               = 0x01,
        CHARGER_CV               = 0x02,
        CHARGER_TOPOFF           = 0x03,
        CHARGER_DONE             = 0x04,
        CHARGER_TIMER_FAULT      = 0x06,
        CHARGER_BATTERY_DETECT   = 0x07,
        CHARGER_OFF              = 0x08,
        CHARGER_PREQUALIFICATION     = 0x00,
        CHARGER_CC                   = 0x01,
        CHARGER_CV                   = 0x02,
        CHARGER_TOPOFF               = 0x03,
        CHARGER_DONE                 = 0x04,
        CHARGER_TIMER_FAULT          = 0x06,
        CHARGER_BATTERY_DETECT       = 0x07,
        CHARGER_OFF                  = 0x08,
        CHARGER_OFF_OVERHEATED       = 0x0A,
        CHARGER_OFF_WATCHDOG_EXPIRED = 0x0B
    };

    // CHG_CNFG_00 register

M module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.cpp => module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.cpp +104 -81
@@ 26,59 26,59 @@ namespace bsp::battery_charger
    {
        using Crc32 = std::uint32_t;

        constexpr std::uint32_t i2cSubaddressSize = 1;
        constexpr std::uint32_t i2cSubaddressSize{1};

        const auto cfgFile = purefs::dir::getSystemVarDirPath() / "batteryFuelGaugeConfig.cfg";

        constexpr auto registersToStore              = 0xFF + 1;
        constexpr auto registersToStore{0xFF + 1};
        constexpr auto configFileSizeWithoutChecksum = registersToStore * sizeof(Register);
        constexpr auto configFileSizeWithChecksum    = configFileSizeWithoutChecksum + sizeof(Crc32);

        constexpr std::uint8_t VSYS_MIN = 0x80; // 3.6V
        constexpr std::uint8_t VSYS_MIN{0x80}; // 3.6V

        constexpr units::SOC fullyChargedSOC       = 100;
        constexpr units::SOC dischargingSocDelta   = 5;
        constexpr units::SOC chargingSocDelta      = 1;
        constexpr units::SOC maxSocPercentageError = 20;
        constexpr units::SOC fullyChargedSOC{100};
        constexpr units::SOC dischargingSocDelta{5};
        constexpr units::SOC chargingSocDelta{1};
        constexpr units::SOC maxSocPercentageError{20};

        constexpr std::uint16_t maxVoltagemV = 4400;
        constexpr std::uint16_t minVoltagemV = 3600;
        constexpr std::uint16_t maxVoltagemV{4400};
        constexpr std::uint16_t minVoltagemV{3600};

        constexpr auto currentSenseGain = 0.15625f;  // mA
        constexpr auto voltageSenseGain = 0.078125f; // mV
        constexpr auto currentSenseGain{0.15625f};  // mA
        constexpr auto voltageSenseGain{0.078125f}; // mV

        constexpr std::uint16_t maxMinMilliVoltGain = 20;
        constexpr std::uint16_t maxMinMilliVoltGain{20};

        // NTC calibration values
        constexpr std::uint16_t temperatureConversionGain   = 0xEE56;
        constexpr std::uint16_t temperatureConversionOffset = 0x1DA4;
        constexpr std::uint16_t temperatureConversionGain{0xEE56};
        constexpr std::uint16_t temperatureConversionOffset{0x1DA4};

        namespace fuel_gauge_params
        {
            /// Parameters calculated in in MAXIM EVKIT software
            /// Initial parameters for fuel gauge battery model
            constexpr std::uint16_t LearnCFG    = 0x2602;
            constexpr std::uint16_t FilterCFG   = 0xCEA0; // Current filter Tc = 0.7s
            constexpr std::uint16_t MiscCFG     = 0x01D0;
            constexpr std::uint16_t RelaxCFG    = 0x2039;
            constexpr std::uint16_t RCOMP0      = 0x0070;
            constexpr std::uint16_t TempCo      = 0x263D;
            constexpr std::uint16_t QResidual00 = 0x2280;
            constexpr std::uint16_t QResidual10 = 0x1000;
            constexpr std::uint16_t QResidual20 = 0x0681;
            constexpr std::uint16_t QResidual30 = 0x0682;
            constexpr std::uint16_t LearnCFG{0x2602};
            constexpr std::uint16_t FilterCFG{0xCEA0}; // Current filter Tc = 0.7s
            constexpr std::uint16_t MiscCFG{0x01D0};
            constexpr std::uint16_t RelaxCFG{0x2039};
            constexpr std::uint16_t RCOMP0{0x0070};
            constexpr std::uint16_t TempCo{0x263D};
            constexpr std::uint16_t QResidual00{0x2280};
            constexpr std::uint16_t QResidual10{0x1000};
            constexpr std::uint16_t QResidual20{0x0681};
            constexpr std::uint16_t QResidual30{0x0682};
            /// 1600mAh initial battery capacity
            constexpr std::uint16_t FullCAPNom = 0x0C80;
            constexpr std::uint16_t FullCAPRep = 0x0C80;
            constexpr std::uint16_t DesignCap  = 0x0C80;
            constexpr std::uint16_t dQacc      = 0x00C8;
            constexpr std::uint16_t dPacc      = 0x0C80;
            constexpr std::uint16_t FullCAPNom{0x0C80};
            constexpr std::uint16_t FullCAPRep{0x0C80};
            constexpr std::uint16_t DesignCap{0x0C80};
            constexpr std::uint16_t dQacc{0x00C8};
            constexpr std::uint16_t dPacc{0x0C80};
            /// Charge termination current = 150mA
            constexpr std::uint16_t ICHGTerm = 0x03C0;
            constexpr std::uint16_t ICHGTerm{0x03C0};
            /// Empty battery = 3V
            constexpr std::uint16_t V_empty = 0x965A;
            constexpr std::uint16_t V_empty{0x965A};
            /// Fully charged threshold = 90%
            constexpr std::uint16_t FullSOCthr = 0x5A00;
            constexpr std::uint16_t FullSOCthr{0x5A00};
        } // namespace fuel_gauge_params

        enum class FileConfigRetval


@@ 93,15 93,6 @@ namespace bsp::battery_charger
            ConfigFuelGaugeModelError
        };

        enum class TemperatureRanges
        {
            Cold,
            Cdeg1to15,
            Cdeg15to35,
            Cdeg35to45,
            Hot
        };

        struct TemperatureThresholds
        {
            int lowTemperatureThreshold;


@@ 138,8 129,7 @@ namespace bsp::battery_charger
            {TemperatureRanges::Cdeg1to15, {1, 15, 0, 15 + highHysteresis}},
            {TemperatureRanges::Cdeg15to35, {15, 35, 15 - lowHysteresis, 35 + highHysteresis}},
            {TemperatureRanges::Cdeg35to45, {35, 45, 35 - lowHysteresis, 45 + highHysteresis}},
            {TemperatureRanges::Hot,
             {45, std::numeric_limits<std::int8_t>::max(), 45 - lowHysteresis, maxAlertDisabled}}};
            {TemperatureRanges::Hot, {45, std::numeric_limits<std::int8_t>::max(), 45, maxAlertDisabled}}};

        std::shared_ptr<drivers::DriverI2C> i2c;
        std::shared_ptr<drivers::DriverGPIO> gpio;


@@ 201,6 191,11 @@ namespace bsp::battery_charger
            return ret;
        }

        inline constexpr bool isChargerInputValid(std::uint8_t chargerStatus)
        {
            return static_cast<bool>(chargerStatus & static_cast<std::uint8_t>(CHG_INT::CHGIN_I));
        }

        units::SOC getBatteryLevelFromRegisterValue(const Register registerValue)
        {
            /// 16 bit result. The high byte indicates 1% per LSB. The low byte reports fractional percent. We don't


@@ 211,7 206,7 @@ namespace bsp::battery_charger
        int fuelGaugeWrite(Registers registerAddress, std::uint16_t value)
        {
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));
            const auto ret = i2c->Write(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));

            if (ret != sizeof(value)) {
                return kStatus_Fail;


@@ 222,9 217,9 @@ namespace bsp::battery_charger
        std::pair<int, std::uint16_t> fuelGaugeRead(Registers registerAddress)
        {
            std::uint16_t value;
            int status                  = kStatus_Success;
            auto status                 = kStatus_Success;
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Read(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));
            const auto ret = i2c->Read(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));

            if (ret != sizeof(value)) {
                status = kStatus_Fail;


@@ 235,7 230,7 @@ namespace bsp::battery_charger
        int chargerWrite(Registers registerAddress, std::uint8_t value)
        {
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(batteryChargerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));
            const auto ret = i2c->Write(batteryChargerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));

            if (ret != sizeof(value)) {
                return kStatus_Fail;


@@ 246,9 241,9 @@ namespace bsp::battery_charger
        std::pair<int, std::uint8_t> chargerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                       = kStatus_Success;
            auto status                      = kStatus_Success;
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret                         = i2c->Read(batteryChargerAddress, &value, sizeof(value));
            const auto ret                   = i2c->Read(batteryChargerAddress, &value, sizeof(value));

            if (ret != sizeof(value)) {
                status = kStatus_Fail;


@@ 259,7 254,7 @@ namespace bsp::battery_charger
        int chargerTopControllerWrite(Registers registerAddress, std::uint8_t value)
        {
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(topControllerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));
            const auto ret = i2c->Write(topControllerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(value));

            if (ret != sizeof(value)) {
                return kStatus_Fail;


@@ 270,7 265,7 @@ namespace bsp::battery_charger
        std::pair<int, std::uint8_t> chargerTopControllerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                      = kStatus_Success;
            auto status                     = kStatus_Success;
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            const auto ret                  = i2c->Read(topControllerAddress, &value, sizeof(value));
            if (ret != sizeof(value)) {


@@ 360,7 355,7 @@ namespace bsp::battery_charger

        BatteryRetval configureFuelGaugeBatteryModel()
        {
            int status = fuelGaugeWrite(Registers::LearnCFG_REG, fuel_gauge_params::LearnCFG);
            auto status = fuelGaugeWrite(Registers::LearnCFG_REG, fuel_gauge_params::LearnCFG);
            status |= fuelGaugeWrite(Registers::FilterCFG_REG, fuel_gauge_params::FilterCFG);
            status |= fuelGaugeWrite(Registers::MiscCFG_REG, fuel_gauge_params::MiscCFG);
            status |= fuelGaugeWrite(Registers::RelaxCFG_REG, fuel_gauge_params::RelaxCFG);


@@ 413,7 408,7 @@ namespace bsp::battery_charger
            }

            for (auto i = 0; i < registersToStore; ++i) {
                auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                const auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                if (regVal.first != kStatus_Success) {
                    file.close();
                    return FileConfigRetval::ReadingRegisterError;


@@ 492,11 487,11 @@ namespace bsp::battery_charger
        {
            std::vector<Register> storedData(registersToStore);

            if (auto retVal = saveConfigurationFile(storedData); retVal != FileConfigRetval::OK) {
            if (const auto retVal = saveConfigurationFile(storedData); retVal != FileConfigRetval::OK) {
                LOG_ERROR("Save configuration file error: %s", magic_enum::enum_name(retVal).data());
                return retVal;
            }
            if (auto retVal = verifySavedConfigurationFile(storedData); retVal != FileConfigRetval::OK) {
            if (const auto retVal = verifySavedConfigurationFile(storedData); retVal != FileConfigRetval::OK) {
                LOG_ERROR("Verify configuration file error: %s", magic_enum::enum_name(retVal).data());
                return retVal;
            }


@@ 525,7 520,7 @@ namespace bsp::battery_charger
            std::vector<Register> readData(registersToStore);

            // then we read the battery configuration from the saved file
            if (auto retVal = readConfigurationFile(readData); retVal != FileConfigRetval::OK) {
            if (const auto retVal = readConfigurationFile(readData); retVal != FileConfigRetval::OK) {
                // if there is a problem with reading the data, leave the default configuration and exit
                LOG_ERROR("Read configuration file error: %s", magic_enum::enum_name(retVal).data());
                storeConfiguration();


@@ 539,7 534,7 @@ namespace bsp::battery_charger
            // from the file
            if (batteryLevelAfterDefaultConfiguration.has_value() &&
                !isSocDataDiscrepancy(batteryLevelAfterDefaultConfiguration.value(), savedBatteryLevel)) {
                if (auto retVal = storeFuelGaugeRegisters(readData); retVal != FileConfigRetval::OK) {
                if (const auto retVal = storeFuelGaugeRegisters(readData); retVal != FileConfigRetval::OK) {
                    LOG_ERROR("Store configuration file error: %s", magic_enum::enum_name(retVal).data());
                    return retVal;
                }


@@ 667,7 662,7 @@ namespace bsp::battery_charger
            return utils::twosComplimentToInt(temperatureInt);
        }

        void chargingFinishedAction()
        void onChargingFinished()
        {
            LOG_DEBUG("Charging finished");
        }


@@ 701,6 696,9 @@ namespace bsp::battery_charger
                LOG_DEBUG("Cell temperature too high, charging disabled");
                disableCharging();
                break;
            default:
                LOG_DEBUG("Unhandled battery temperature range");
                break;
            }

            setTemperatureThresholds(temperatureRanges.at(temperatureRange).alertLow,


@@ 790,7 788,7 @@ namespace bsp::battery_charger

    std::optional<units::SOC> getBatteryLevel()
    {
        auto readout = fuelGaugeRead(Registers::RepSOC_REG);
        const auto readout = fuelGaugeRead(Registers::RepSOC_REG);
        if (readout.first != kStatus_Success) {
            LOG_ERROR("Failed to get battery level");
            return std::nullopt;


@@ 806,6 804,25 @@ namespace bsp::battery_charger
        return soc;
    }

    TemperatureRanges getTemperatureRange()
    {
        const auto temperature = getCellTemperature();
        if (!temperature.has_value()) {
            return TemperatureRanges::Unknown;
        }

        LOG_DEBUG("Cell temperature: %dC", temperature.value());

        for (const auto &[range, thresholds] : temperatureRanges) {
            if ((temperature > thresholds.lowTemperatureThreshold) &&
                (temperature <= thresholds.highTemperatureThreshold)) {
                return range;
            }
        }

        return TemperatureRanges::Unknown;
    }

    BatteryRetval getChargeStatus()
    {
        BatteryRetval retVal{};


@@ 816,9 833,9 @@ namespace bsp::battery_charger
            LOG_ERROR("Failed to read charger INT source");
        }

        const auto summary = chargerRead(Registers::CHG_INT_OK);
        if (summary.first != kStatus_Success) {
            LOG_ERROR("Failed to read charger summary");
        const auto chargerStatus = chargerRead(Registers::CHG_INT_OK);
        if (chargerStatus.first != kStatus_Success) {
            LOG_ERROR("Failed to read charger status");
            return BatteryRetval::ChargerError;
        }



@@ 829,11 846,11 @@ namespace bsp::battery_charger

        const auto chargingSetup = chargerRead(Registers::CHG_CNFG_00);
        if (chargingSetup.first != kStatus_Success) {
            LOG_ERROR("Failed to read charging setup!");
            LOG_ERROR("Failed to read charging setup");
            return BatteryRetval::ChargerError;
        }

        if (static_cast<bool>(summary.second & static_cast<std::uint8_t>(CHG_INT::CHGIN_I))) {
        if (isChargerInputValid(chargerStatus.second)) {
            retVal = BatteryRetval::ChargerCharging;
        }
        else {


@@ 843,15 860,30 @@ namespace bsp::battery_charger
        switch (static_cast<CHG_DETAILS_01>(chargerDetails.value())) {
        case CHG_DETAILS_01::CHARGER_DONE:
            retVal = BatteryRetval::ChargingDone;
            chargingFinishedAction();
            onChargingFinished();
            break;

        case CHG_DETAILS_01::CHARGER_OFF:
            if (chargingSetup.second != static_cast<std::uint8_t>(ChargerMode::ChargerOnBuckOn)) {
                retVal = BatteryRetval::ChargerNotCharging;
                if (isChargerInputValid(chargerStatus.second)) {
                    retVal = BatteryRetval::ChargerPluggedNotCharging;
                }
                else {
                    retVal = BatteryRetval::ChargerNotCharging;
                }
            }
            break;

        case CHG_DETAILS_01::CHARGER_OFF_OVERHEATED:
            retVal = BatteryRetval::ChargerNotCharging;
            LOG_WARN("Not charging due to exceeded junction temperature");
            break;

        case CHG_DETAILS_01::CHARGER_OFF_WATCHDOG_EXPIRED:
            retVal = BatteryRetval::ChargerNotCharging;
            LOG_WARN("Not charging due to expired watchdog timer");
            break;

        case CHG_DETAILS_01::CHARGER_PREQUALIFICATION:
        case CHG_DETAILS_01::CHARGER_CC:
        case CHG_DETAILS_01::CHARGER_CV:


@@ 863,6 895,10 @@ namespace bsp::battery_charger
        case CHG_DETAILS_01::CHARGER_BATTERY_DETECT:
            retVal = BatteryRetval::ChargerError;
            break;

        default:
            LOG_ERROR("Unhandled charger details value: 0x%02X", chargerDetails.value());
            break;
        }

        return retVal;


@@ 903,20 939,7 @@ namespace bsp::battery_charger

    void checkTemperatureRange()
    {
        const auto temperature = getCellTemperature();
        if (!temperature.has_value()) {
            return;
        }

        LOG_DEBUG("Cell temperature: %dC", temperature.value());

        for (const auto &[range, thresholds] : temperatureRanges) {
            if ((temperature > thresholds.lowTemperatureThreshold) &&
                (temperature <= thresholds.highTemperatureThreshold)) {
                processTemperatureRange(range);
                break;
            }
        }
        processTemperatureRange(getTemperatureRange());
    }

    std::optional<std::uint8_t> getTopControllerINTSource()


@@ 1000,6 1023,6 @@ namespace bsp::battery_charger
            LOG_ERROR("Failed to read charger status");
            return false;
        }
        return static_cast<bool>(chargerStatus.second & static_cast<std::uint8_t>(CHG_INT::CHGIN_I));
        return isChargerInputValid(chargerStatus.second);
    }
} // namespace bsp::battery_charger

M module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.hpp => module-bsp/board/rt1051/puretx/bsp/battery_charger/battery_charger.hpp +12 -0
@@ 28,10 28,21 @@ namespace bsp::battery_charger
        OK,
        ChargerError,
        ChargerNotCharging,
        ChargerPluggedNotCharging,
        ChargerCharging,
        ChargingDone
    };

    enum class TemperatureRanges
    {
        Cold,
        Cdeg1to15,
        Cdeg15to35,
        Cdeg35to45,
        Hot,
        Unknown
    };

    enum class TopControllerIRQsource
    {
        CHGR_INT = (1 << 0),


@@ 59,6 70,7 @@ namespace bsp::battery_charger
    void deinit();

    [[nodiscard]] std::optional<units::SOC> getBatteryLevel();
    [[nodiscard]] TemperatureRanges getTemperatureRange();

    void storeBatteryLevelChange(units::SOC newSocValue);


M module-bsp/board/rt1051/puretx/hal/battery_charger/BatteryCharger.cpp => module-bsp/board/rt1051/puretx/hal/battery_charger/BatteryCharger.cpp +27 -2
@@ 31,12 31,31 @@ namespace
        case Status::ChargingDone:
            return NewState::ChargingDone;
        case Status::ChargerNotCharging:
            return NewState ::Discharging;
            return NewState::Discharging;
        default:
            return NewState::PluggedNotCharging;
        }
    }

    hal::battery::AbstractBatteryCharger::TemperatureState transformTemperatureState(
        bsp::battery_charger::TemperatureRanges range)
    {
        using Range = bsp::battery_charger::TemperatureRanges;
        using State = hal::battery::AbstractBatteryCharger::TemperatureState;
        switch (range) {
        case Range::Cdeg1to15:
        case Range::Cdeg15to35:
        case Range::Cdeg35to45:
            return State::Normal;
        case Range::Cold:
            return State::TooLow;
        case Range::Hot:
            return State::TooHigh;
        default:
            return State::Unknown;
        }
    }

    /// A few constants to make code readability better
    constexpr auto int_b_soc_change =
        static_cast<std::uint16_t>(bsp::battery_charger::BatteryINTBSource::SOCOnePercentChange);


@@ 73,7 92,7 @@ namespace hal::battery
            enum class Type
            {
                ControllerINTB,
                USBChargerAttached,
                USBChargerAttached
            };
            Type type;
            std::uint8_t chargerType{};


@@ 87,6 106,7 @@ namespace hal::battery
        std::optional<SOC> getSOC() const final;
        ChargingStatus getChargingStatus() const final;
        ChargerPresence getChargerPresence() const final;
        TemperatureState getTemperatureState() const final;

        static BatteryWorkerQueue &getWorkerQueueHandle();



@@ 185,6 205,11 @@ namespace hal::battery
        return scaledSoc;
    }

    AbstractBatteryCharger::TemperatureState PureBatteryCharger::getTemperatureState() const
    {
        return transformTemperatureState(bsp::battery_charger::getTemperatureRange());
    }

    AbstractBatteryCharger::ChargingStatus PureBatteryCharger::getChargingStatus() const
    {
        return transformChargingState(bsp::battery_charger::getChargeStatus());

M module-bsp/hal/include/hal/battery_charger/AbstractBatteryCharger.hpp => module-bsp/hal/include/hal/battery_charger/AbstractBatteryCharger.hpp +9 -0
@@ 40,6 40,14 @@ namespace hal::battery
            Unplugged
        };

        enum class TemperatureState : std::uint8_t
        {
            Normal,
            TooLow,
            TooHigh,
            Unknown
        };

        struct Factory
        {
            static std::unique_ptr<AbstractBatteryCharger> create(xQueueHandle);


@@ 51,6 59,7 @@ namespace hal::battery
        virtual std::optional<SOC> getSOC() const                = 0;
        virtual ChargingStatus getChargingStatus() const         = 0;
        virtual ChargerPresence getChargerPresence() const       = 0;
        virtual TemperatureState getTemperatureState() const     = 0;

        static_assert(sizeof(Events) == sizeof(std::uint8_t),
                      "All events processed by event manager ought to have size of std::uint8_t");

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +2 -0
@@ 30,6 30,7 @@
#include <service-time/service-time/TimeMessage.hpp>
#include <service-bluetooth/messages/Status.hpp>
#include <service-bluetooth/ServiceBluetoothName.hpp>
#include <service-appmgr/ServiceApplicationManagerName.hpp>

#include <cassert>
#include <fstream>


@@ 144,6 145,7 @@ sys::ReturnCodes EventManagerCommon::InitHandler()
            if (!targetApplication.empty()) {
                bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), targetApplication);
            }
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::appmgr);
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::service_desktop);
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::bluetooth);
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::cellular);

M module-services/service-evtmgr/battery/BatteryController.cpp => module-services/service-evtmgr/battery/BatteryController.cpp +30 -6
@@ 73,6 73,22 @@ namespace
            return NewState::Normal;
        }
    }

    Store::Battery::Temperature transformTemperatureState(AbstractBatteryCharger::TemperatureState state)
    {
        using State    = AbstractBatteryCharger::TemperatureState;
        using NewState = Store::Battery::Temperature;
        switch (state) {
        case State::Normal:
            return NewState::Normal;
        case State::TooLow:
            return NewState::TooLow;
        case State::TooHigh:
            return NewState::TooHigh;
        default:
            return NewState::Unknown;
        }
    }
} // namespace

BatteryController::BatteryController(sys::Service *service, xQueueHandle notificationChannel, EventManagerParams params)


@@ 106,12 122,15 @@ BatteryController::BatteryController(sys::Service *service, xQueueHandle notific
{
    updateSoc();
    Store::Battery::modify().state = transformChargingState(charger->getChargingStatus());
    batteryState.check(transformChargingState(Store::Battery::modify().state), Store::Battery::modify().level);
    Store::Battery::modify().temperature = transformTemperatureState(charger->getTemperatureState());
    batteryState.check(transformChargingState(Store::Battery::get().state),
                       static_cast<float>(Store::Battery::get().level));

    LOG_INFO("Initial charger state: %s", magic_enum::enum_name(Store::Battery::get().state).data());
    LOG_INFO("Initial battery SOC: %d", Store::Battery::get().level);
    LOG_INFO("Initial battery voltage: %" PRIu32 "mV", getVoltage());
    LOG_INFO("Initial battery state: %s", magic_enum::enum_name(Store::Battery::get().levelState).data());
    LOG_INFO("Initial battery temperature range: %s", magic_enum::enum_name(Store::Battery::get().temperature).data());
}

void sevm::battery::BatteryController::handleNotification(Events evt)


@@ 139,31 158,36 @@ void sevm::battery::BatteryController::poll()

void sevm::battery::BatteryController::printCurrentState()
{
    LOG_INFO("Charger state: %s | Battery SOC: %d%% | Voltage: %" PRIu32 "mV | Level state: %s",
    LOG_INFO("Charger state: %s | Battery SOC: %d%% | Voltage: %" PRIu32 "mV | Level state: %s | Temperature: %s",
             magic_enum::enum_name(Store::Battery::get().state).data(),
             Store::Battery::get().level,
             getVoltage(),
             magic_enum::enum_name(Store::Battery::get().levelState).data());
             magic_enum::enum_name(Store::Battery::get().levelState).data(),
             magic_enum::enum_name(Store::Battery::get().temperature).data());
}

void sevm::battery::BatteryController::update()
{
    const auto lastSoc   = Store::Battery::get().level;
    const auto lastState = Store::Battery::get().state;
    const auto lastTemperature = Store::Battery::get().temperature;

    updateSoc();
    Store::Battery::modify().state = transformChargingState(charger->getChargingStatus());
    Store::Battery::modify().temperature = transformTemperatureState(charger->getTemperatureState());

    const auto currentSoc   = Store::Battery::get().level;
    const auto currentState = Store::Battery::get().state;
    const auto currentTemperature = Store::Battery::get().temperature;

    /// Send BatteryStatusChangeMessage only when battery SOC or charger state has changed
    if (lastSoc != currentSoc || lastState != currentState) {
    /// Send BatteryStatusChangeMessage only when battery SOC, charger state or temperature has changed
    if ((lastSoc != currentSoc) || (lastState != currentState) || (lastTemperature != currentTemperature)) {
        auto message = std::make_shared<sevm::BatteryStatusChangeMessage>();
        service->bus.sendUnicast(std::move(message), service::name::evt_manager);
    }

    batteryState.check(transformChargingState(Store::Battery::modify().state), Store::Battery::modify().level);
    batteryState.check(transformChargingState(Store::Battery::get().state),
                       static_cast<float>(Store::Battery::get().level));

    printCurrentState();
}

M module-services/service-evtmgr/battery/BatteryController.hpp => module-services/service-evtmgr/battery/BatteryController.hpp +1 -0
@@ 33,6 33,7 @@ namespace sevm::battery
        void printCurrentState();
        void checkChargerPresence();
        units::Voltage getVoltage();

        sys::Service *service{nullptr};
        std::unique_ptr<hal::battery::AbstractBatteryCharger> charger;
        BatteryBrownoutDetector brownoutDetector;

M module-services/service-evtmgr/battery/BatteryState.cpp => module-services/service-evtmgr/battery/BatteryState.cpp +1 -1
@@ 144,5 144,5 @@ void BatteryState::check(const ChargingState state, const float soc)
}

BatteryState::BatteryState(sys::Service *service, NotifyStateChangedCallback notifyCallback, Thresholds thresholds)
    : pimpl{std::make_shared<Pimpl>(notifyCallback, thresholds)}
    : pimpl{std::make_shared<Pimpl>(std::move(notifyCallback), thresholds)}
{}

M module-utils/EventStore/EventStore.cpp => module-utils/EventStore/EventStore.cpp +1 -1
@@ 9,7 9,7 @@
namespace Store
{
    // if it grows bigger than these few variables - consider moving it to ram with i.e.
    // delayed construction singletone
    // delayed construction singleton
    Battery battery;
    bool Battery::updated = true;


M module-utils/EventStore/EventStore.hpp => module-utils/EventStore/EventStore.hpp +10 -2
@@ 16,7 16,6 @@

namespace cpp_freertos
{
    // fw decl
    class MutexStandard;
} // namespace cpp_freertos



@@ 43,7 42,16 @@ namespace Store
            ChargingDone,
            PluggedNotCharging,
        } state            = State::Discharging;
        unsigned int level = 0;

        enum class Temperature : std::uint8_t
        {
            Normal,
            TooLow,
            TooHigh,
            Unknown
        } temperature = Temperature::Normal;

        unsigned level = 0;

        /// @brief Returns const reference to Battery instance, used to read battery state
        /// @return const Battery&

M products/PurePhone/CMakeLists.txt => products/PurePhone/CMakeLists.txt +2 -2
@@ 161,14 161,14 @@ download_asset_release_json(json-common-target
                            ${CMAKE_CURRENT_SOURCE_DIR}/assets/assets_common.json
                            ${SYSROOT_PATH}/
                            MuditaOSPublicAssets
                            0.0.10
                            0.0.11
                            ${MUDITA_CACHE_DIR}
    )
download_asset_release_json(json-community-target
                            ${CMAKE_CURRENT_SOURCE_DIR}/assets/assets_community.json
                            ${SYSROOT_PATH}/system_a/
                            MuditaOSPublicAssets
                            0.0.10
                            0.0.11
                            ${MUDITA_CACHE_DIR}
    )
download_asset_json(json-rt1051-target

M products/PurePhone/assets/assets_common.json => products/PurePhone/assets/assets_common.json +173 -172
@@ 1,177 1,178 @@
{
    "assets": [
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_nowplaying_play_list_W_M.vpi", "output": "system_a/assets/images/music-player/mp_nowplaying_play_list_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_note_W_G.vpi", "output": "system_a/assets/images/music-player/mp_note_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_line_arrow_down_W_G.vpi", "output": "system_a/assets/images/music-player/mp_line_arrow_down_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_next_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_next_gray_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_pause_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_pause_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_prev_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_prev_gray_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_bar_W_G.vpi", "output": "system_a/assets/images/music-player/mp_bar_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_next_W_G.vpi", "output": "system_a/assets/images/music-player/mp_next_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_nowplaying_paused_list_W_M.vpi", "output": "system_a/assets/images/music-player/mp_nowplaying_paused_list_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_pause_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_pause_gray_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_play_W_G.vpi", "output": "system_a/assets/images/music-player/mp_play_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_line_arrow_up_W_G.vpi", "output": "system_a/assets/images/music-player/mp_line_arrow_up_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_pause_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_pause_gray_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_prev_W_G.vpi", "output": "system_a/assets/images/music-player/mp_prev_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_pause_W_G.vpi", "output": "system_a/assets/images/music-player/mp_pause_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_bar_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_bar_gray_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/small_tick_32px_W_M.vpi", "output": "system_a/assets/images/small_tick_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_32px_W_G.vpi", "output": "system_a/assets/images/arrow_left_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_messages_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_messages_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_meditation_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_meditation_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_torch_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_torch_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_alarm_disabled_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_alarm_disabled_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_music_player_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_music_player_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_recorder_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_recorder_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_calendar_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_calendar_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_alarm_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_alarm_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_phone_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_phone_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_settings_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_settings_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_notes_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_notes_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_contacts_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_contacts_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_calculator_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_calculator_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/dot_12px_hard_alpha_W_M.vpi", "output": "system_a/assets/images/dot_12px_hard_alpha_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/label_rectangle_W_M.vpi", "output": "system_a/assets/images/label_rectangle_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/delete_24px_W_G.vpi", "output": "system_a/assets/images/delete_24px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_24px_W_G.vpi", "output": "system_a/assets/images/arrow_right_24px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_32px_W_G.vpi", "output": "system_a/assets/images/arrow_right_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_empty_grey_circle_speed_dial.vpi", "output": "system_a/assets/images/phonebook/phonebook_empty_grey_circle_speed_dial.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_speed_dial_32px_W_G.vpi", "output": "system_a/assets/images/phonebook/phonebook_speed_dial_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_blocked_32px_W_G.vpi", "output": "system_a/assets/images/phonebook/phonebook_blocked_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_heart_32px_W_M.vpi", "output": "system_a/assets/images/phonebook/phonebook_heart_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/sim1_option_32px_W_G.vpi", "output": "system_a/assets/images/sim1_option_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/enter_icon_alpha_W_M.vpi", "output": "system_a/assets/images/enter_icon_alpha_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/logo_no_text.vpi", "output": "system_a/assets/images/logo_no_text.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_noconnection_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_noconnection_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_noconnection_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_noconnection_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_roaming_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_roaming_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/locked_status_W_G.vpi", "output": "system_a/assets/images/status-bar/locked_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/locked_status_W_M.vpi", "output": "system_a/assets/images/status-bar/locked_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_1_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/sim_1_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_2_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/sim_2_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/no_sim_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/no_sim_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/no_sim_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/no_sim_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_1_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/sim_1_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_2_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/sim_2_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_ready_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_ready_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_5_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_5_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_4_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_4_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_5_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_5_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_1_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_1_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_2_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_2_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_1_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_1_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_3_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_3_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_ready_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_ready_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_low_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_low_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_3_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_3_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_low_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_low_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_2_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_2_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_4_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_4_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/alarmclock_status_W_M.vpi", "output": "system_a/assets/images/status-bar/alarmclock_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_connected_status_W_M.vpi", "output": "system_a/assets/images/status-bar/bt_connected_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_connected_status_W_G.vpi", "output": "system_a/assets/images/status-bar/bt_connected_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_status_W_G.vpi", "output": "system_a/assets/images/status-bar/bt_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/alarmclock_status_W_G.vpi", "output": "system_a/assets/images/status-bar/alarmclock_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_status_W_M.vpi", "output": "system_a/assets/images/status-bar/bt_status_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/tethering_status_W_G.vpi", "output": "system_a/assets/images/status-bar/tethering_status_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/dot_12px_hard_alpha_W_G.vpi", "output": "system_a/assets/images/dot_12px_hard_alpha_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_20px_W_M.vpi", "output": "system_a/assets/images/arrow_left_20px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_empty_32px_W_G.vpi", "output": "system_a/assets/images/arrow_right_empty_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/search_32px_W_G.vpi", "output": "system_a/assets/images/search_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/sim2_option_32px_W_G.vpi", "output": "system_a/assets/images/sim2_option_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/tethering_128px_W_G.vpi", "output": "system_a/assets/images/notifications/tethering_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/info_128px_W_G.vpi", "output": "system_a/assets/images/notifications/info_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/lock_128px_W_G.vpi", "output": "system_a/assets/images/notifications/lock_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/search_128px_W_G.vpi", "output": "system_a/assets/images/notifications/search_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/turn_off_128px_W_G.vpi", "output": "system_a/assets/images/notifications/turn_off_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/bluetooth_128px_W_G.vpi", "output": "system_a/assets/images/notifications/bluetooth_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/block_128px_W_G.vpi", "output": "system_a/assets/images/notifications/block_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/delete_128px_W_G.vpi", "output": "system_a/assets/images/notifications/delete_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/fail_128px_W_G.vpi", "output": "system_a/assets/images/notifications/fail_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/progress_128px_W_G.vpi", "output": "system_a/assets/images/notifications/progress_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/error_128px_W_G.vpi", "output": "system_a/assets/images/notifications/error_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/success_128px_W_G.vpi", "output": "system_a/assets/images/notifications/success_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/sim_128px_W_G.vpi", "output": "system_a/assets/images/notifications/sim_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_mute_W_M.vpi", "output": "system_a/assets/images/call/call_mute_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_mute_on_W_M.vpi", "output": "system_a/assets/images/call/call_mute_on_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_speaker_W_M.vpi", "output": "system_a/assets/images/call/call_speaker_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_add_W_M.vpi", "output": "system_a/assets/images/call/call_add_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_message_W_M.vpi", "output": "system_a/assets/images/call/call_message_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_speaker_on_W_M.vpi", "output": "system_a/assets/images/call/call_speaker_on_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/circle_top.mpi", "output": "system_a/assets/images/call/circle_top.mpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/circle_bottom.mpi", "output": "system_a/assets/images/call/circle_bottom.mpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calendar_event_dot.vpi", "output": "system_a/assets/images/calendar_event_dot.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/dead_battery_W_G.vpi", "output": "system_a/assets/images/dead_battery_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/messages_error_32px_W_M.vpi", "output": "system_a/assets/images/messages/messages_error_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/messages_reply_32px_W_M.vpi", "output": "system_a/assets/images/messages/messages_reply_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_3.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_3.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Eurlope.vpi", "output": "system_a/assets/images/settings/settings_certification_Eurlope.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Australia.vpi", "output": "system_a/assets/images/settings/settings_certification_Australia.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_4.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_4.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Canada.vpi", "output": "system_a/assets/images/settings/settings_certification_Canada.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_fc.vpi", "output": "system_a/assets/images/settings/settings_certification_fc.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_UKCA.vpi", "output": "system_a/assets/images/settings/settings_certification_UKCA.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_US.vpi", "output": "system_a/assets/images/settings/settings_certification_US.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_2.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_2.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_ce.vpi", "output": "system_a/assets/images/settings/settings_certification_ce.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_ic.vpi", "output": "system_a/assets/images/settings/settings_certification_ic.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_1.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_1.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/empty_list_add_W_G.vpi", "output": "system_a/assets/images/empty_list_add_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/charging_battery_W_G.vpi", "output": "system_a/assets/images/charging_battery_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_empty_128px_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_empty_128px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_in_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_in_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_out_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_out_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_in_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_in_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_den_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_den_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_den_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_den_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_out_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_out_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/call_32px_W_G.vpi", "output": "system_a/assets/images/call_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_20px_W_M.vpi", "output": "system_a/assets/images/arrow_right_20px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/plus_32px_W_G.vpi", "output": "system_a/assets/images/plus_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages_32px_W_G.vpi", "output": "system_a/assets/images/messages_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/plus_32px_W_M.vpi", "output": "system_a/assets/images/plus_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook_32px_W_G.vpi", "output": "system_a/assets/images/phonebook_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/messages_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/messages_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/lock_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/lock_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/calls_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/calls_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/now_playing_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/now_playing_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/tethering_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/tethering_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/alarm_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/alarm_notification_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/alarm/vertical_arcs_W_G.vpi", "output": "system_a/assets/images/alarm/vertical_arcs_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/alarm/snooze_icon_W_G.vpi", "output": "system_a/assets/images/alarm/snooze_icon_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_24px_W_G.vpi", "output": "system_a/assets/images/arrow_left_24px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/bluetooth_32px_W_M.vpi", "output": "system_a/assets/images/bluetooth_32px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/ice_32px_W_G.vpi", "output": "system_a/assets/images/ice_32px_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/logo_W_G.vpi", "output": "system_a/assets/images/logo_W_G.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/quote_W_G.vpi", "output": "system_a/assets/images/quote_W_G.vpi" },
        {"name":"release.tgz", "tarfile" :"./image/assets/images/common/alarm_colon_select_W_M.vpi", "output": "system_a/assets/images/alarm_colon_select_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/old_messages_arrow_24px_W_M.vpi", "output": "system_a/assets/images/messages/old_messages_arrow_24px_W_M.vpi" },
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_nowplaying_play_list_W_M.vpi", "output": "system_a/assets/images/music-player/mp_nowplaying_play_list_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_note_W_G.vpi", "output": "system_a/assets/images/music-player/mp_note_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_line_arrow_down_W_G.vpi", "output": "system_a/assets/images/music-player/mp_line_arrow_down_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_next_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_next_gray_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_pause_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_pause_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_prev_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_prev_gray_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_bar_W_G.vpi", "output": "system_a/assets/images/music-player/mp_bar_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_next_W_G.vpi", "output": "system_a/assets/images/music-player/mp_next_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_nowplaying_paused_list_W_M.vpi", "output": "system_a/assets/images/music-player/mp_nowplaying_paused_list_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_pause_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_pause_gray_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_play_W_G.vpi", "output": "system_a/assets/images/music-player/mp_play_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_line_arrow_up_W_G.vpi", "output": "system_a/assets/images/music-player/mp_line_arrow_up_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_now_playing_icon_pause_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_now_playing_icon_pause_gray_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_prev_W_G.vpi", "output": "system_a/assets/images/music-player/mp_prev_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_pause_W_G.vpi", "output": "system_a/assets/images/music-player/mp_pause_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/music-player/mp_bar_gray_W_G.vpi", "output": "system_a/assets/images/music-player/mp_bar_gray_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/small_tick_32px_W_M.vpi", "output": "system_a/assets/images/small_tick_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_32px_W_G.vpi", "output": "system_a/assets/images/arrow_left_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_messages_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_messages_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_meditation_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_meditation_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_torch_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_torch_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_alarm_disabled_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_alarm_disabled_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_music_player_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_music_player_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_recorder_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_recorder_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_calendar_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_calendar_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_alarm_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_alarm_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_phone_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_phone_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_settings_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_settings_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_notes_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_notes_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_contacts_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_contacts_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-menu/menu_tools_calculator_W_G.vpi", "output": "system_a/assets/images/desktop-menu/menu_tools_calculator_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/dot_12px_hard_alpha_W_M.vpi", "output": "system_a/assets/images/dot_12px_hard_alpha_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/label_rectangle_W_M.vpi", "output": "system_a/assets/images/label_rectangle_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/delete_24px_W_G.vpi", "output": "system_a/assets/images/delete_24px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_24px_W_G.vpi", "output": "system_a/assets/images/arrow_right_24px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_32px_W_G.vpi", "output": "system_a/assets/images/arrow_right_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_empty_grey_circle_speed_dial.vpi", "output": "system_a/assets/images/phonebook/phonebook_empty_grey_circle_speed_dial.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_speed_dial_32px_W_G.vpi", "output": "system_a/assets/images/phonebook/phonebook_speed_dial_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_blocked_32px_W_G.vpi", "output": "system_a/assets/images/phonebook/phonebook_blocked_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook/phonebook_heart_32px_W_M.vpi", "output": "system_a/assets/images/phonebook/phonebook_heart_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/sim1_option_32px_W_G.vpi", "output": "system_a/assets/images/sim1_option_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/enter_icon_alpha_W_M.vpi", "output": "system_a/assets/images/enter_icon_alpha_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/logo_no_text.vpi", "output": "system_a/assets/images/logo_no_text.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_noconnection_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_noconnection_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_noconnection_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_noconnection_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_2_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_2_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_LTE_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_3_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_3_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_roaming_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_roaming_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_1_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_1_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_4_roaming_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_4_roaming_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_W_G.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/signal/gsm_0_W_M.vpi", "output": "system_a/assets/images/status-bar/signal/gsm_0_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/locked_status_W_G.vpi", "output": "system_a/assets/images/status-bar/locked_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/locked_status_W_M.vpi", "output": "system_a/assets/images/status-bar/locked_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_1_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/sim_1_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_2_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/sim_2_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/no_sim_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/no_sim_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/no_sim_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/no_sim_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_1_status_W_M.vpi", "output": "system_a/assets/images/status-bar/sim/sim_1_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/sim/sim_2_status_W_G.vpi", "output": "system_a/assets/images/status-bar/sim/sim_2_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_ready_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_ready_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_5_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_5_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_4_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_4_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_5_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_5_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_1_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_1_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_2_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_2_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_1_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_1_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_3_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_3_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_ready_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_ready_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_low_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_low_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_3_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_3_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_low_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_low_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_2_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_2_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_charging_W_G.vpi", "output": "system_a/assets/images/status-bar/battery/battery_charging_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/battery/battery_4_W_M.vpi", "output": "system_a/assets/images/status-bar/battery/battery_4_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/alarmclock_status_W_M.vpi", "output": "system_a/assets/images/status-bar/alarmclock_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_connected_status_W_M.vpi", "output": "system_a/assets/images/status-bar/bt_connected_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_connected_status_W_G.vpi", "output": "system_a/assets/images/status-bar/bt_connected_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_status_W_G.vpi", "output": "system_a/assets/images/status-bar/bt_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/alarmclock_status_W_G.vpi", "output": "system_a/assets/images/status-bar/alarmclock_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/bt_status_W_M.vpi", "output": "system_a/assets/images/status-bar/bt_status_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/status-bar/tethering_status_W_G.vpi", "output": "system_a/assets/images/status-bar/tethering_status_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/dot_12px_hard_alpha_W_G.vpi", "output": "system_a/assets/images/dot_12px_hard_alpha_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_20px_W_M.vpi", "output": "system_a/assets/images/arrow_left_20px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_empty_32px_W_G.vpi", "output": "system_a/assets/images/arrow_right_empty_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/search_32px_W_G.vpi", "output": "system_a/assets/images/search_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/sim2_option_32px_W_G.vpi", "output": "system_a/assets/images/sim2_option_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/tethering_128px_W_G.vpi", "output": "system_a/assets/images/notifications/tethering_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/info_128px_W_G.vpi", "output": "system_a/assets/images/notifications/info_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/lock_128px_W_G.vpi", "output": "system_a/assets/images/notifications/lock_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/search_128px_W_G.vpi", "output": "system_a/assets/images/notifications/search_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/turn_off_128px_W_G.vpi", "output": "system_a/assets/images/notifications/turn_off_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/bluetooth_128px_W_G.vpi", "output": "system_a/assets/images/notifications/bluetooth_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/block_128px_W_G.vpi", "output": "system_a/assets/images/notifications/block_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/delete_128px_W_G.vpi", "output": "system_a/assets/images/notifications/delete_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/fail_128px_W_G.vpi", "output": "system_a/assets/images/notifications/fail_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/progress_128px_W_G.vpi", "output": "system_a/assets/images/notifications/progress_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/error_128px_W_G.vpi", "output": "system_a/assets/images/notifications/error_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/success_128px_W_G.vpi", "output": "system_a/assets/images/notifications/success_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/notifications/sim_128px_W_G.vpi", "output": "system_a/assets/images/notifications/sim_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_mute_W_M.vpi", "output": "system_a/assets/images/call/call_mute_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_mute_on_W_M.vpi", "output": "system_a/assets/images/call/call_mute_on_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_speaker_W_M.vpi", "output": "system_a/assets/images/call/call_speaker_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_add_W_M.vpi", "output": "system_a/assets/images/call/call_add_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_message_W_M.vpi", "output": "system_a/assets/images/call/call_message_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/call_speaker_on_W_M.vpi", "output": "system_a/assets/images/call/call_speaker_on_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/circle_top.mpi", "output": "system_a/assets/images/call/circle_top.mpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call/circle_bottom.mpi", "output": "system_a/assets/images/call/circle_bottom.mpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calendar_event_dot.vpi", "output": "system_a/assets/images/calendar_event_dot.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/dead_battery_W_G.vpi", "output": "system_a/assets/images/dead_battery_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/messages_error_32px_W_M.vpi", "output": "system_a/assets/images/messages/messages_error_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/messages_reply_32px_W_M.vpi", "output": "system_a/assets/images/messages/messages_reply_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_3.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_3.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Eurlope.vpi", "output": "system_a/assets/images/settings/settings_certification_Eurlope.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Australia.vpi", "output": "system_a/assets/images/settings/settings_certification_Australia.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_4.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_4.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_Canada.vpi", "output": "system_a/assets/images/settings/settings_certification_Canada.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_fc.vpi", "output": "system_a/assets/images/settings/settings_certification_fc.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_UKCA.vpi", "output": "system_a/assets/images/settings/settings_certification_UKCA.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_US.vpi", "output": "system_a/assets/images/settings/settings_certification_US.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_2.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_2.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_ce.vpi", "output": "system_a/assets/images/settings/settings_certification_ce.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/settings_certification_ic.vpi", "output": "system_a/assets/images/settings/settings_certification_ic.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/settings/empty_list_add_test_W_G_1.vpi", "output": "system_a/assets/images/settings/empty_list_add_test_W_G_1.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/empty_list_add_W_G.vpi", "output": "system_a/assets/images/empty_list_add_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/charging_battery_W_G.vpi", "output": "system_a/assets/images/charging_battery_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_empty_128px_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_empty_128px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_in_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_in_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_out_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_out_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_in_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_in_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_den_W_G.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_den_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_den_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_den_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/calllog/calllog_arrow_out_W_M.vpi", "output": "system_a/assets/images/calllog/calllog_arrow_out_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/call_32px_W_G.vpi", "output": "system_a/assets/images/call_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_right_20px_W_M.vpi", "output": "system_a/assets/images/arrow_right_20px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/plus_32px_W_G.vpi", "output": "system_a/assets/images/plus_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages_32px_W_G.vpi", "output": "system_a/assets/images/messages_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/plus_32px_W_M.vpi", "output": "system_a/assets/images/plus_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/phonebook_32px_W_G.vpi", "output": "system_a/assets/images/phonebook_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/messages_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/messages_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/lock_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/lock_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/calls_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/calls_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/now_playing_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/now_playing_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/tethering_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/tethering_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/alarm_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/alarm_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/desktop-notifications/battery_notification_icon_W_G.vpi", "output": "system_a/assets/images/desktop-notifications/battery_notification_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/alarm/vertical_arcs_W_G.vpi", "output": "system_a/assets/images/alarm/vertical_arcs_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/alarm/snooze_icon_W_G.vpi", "output": "system_a/assets/images/alarm/snooze_icon_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/arrow_left_24px_W_G.vpi", "output": "system_a/assets/images/arrow_left_24px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/bluetooth_32px_W_M.vpi", "output": "system_a/assets/images/bluetooth_32px_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/ice_32px_W_G.vpi", "output": "system_a/assets/images/ice_32px_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/logo_W_G.vpi", "output": "system_a/assets/images/logo_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/quote_W_G.vpi", "output": "system_a/assets/images/quote_W_G.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/common/alarm_colon_select_W_M.vpi", "output": "system_a/assets/images/alarm_colon_select_W_M.vpi"},
        {"name":"release.tgz", "tarfile": "./image/assets/images/messages/old_messages_arrow_24px_W_M.vpi", "output": "system_a/assets/images/messages/old_messages_arrow_24px_W_M.vpi"},

        {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/meditation/gong.mp3", "output": "system_a/assets/audio/meditation/gong.mp3"},
        {"name" : "release_audio.tgz", "tarfile": "./image/assets/audio/pure/sms/sms_drum.mp3", "output": "system_a/assets/audio/sms/sms_drum.mp3"},

M products/PurePhone/services/appmgr/ApplicationManager.cpp => products/PurePhone/services/appmgr/ApplicationManager.cpp +35 -12
@@ 34,6 34,12 @@ namespace app::manager
    namespace
    {
        constexpr auto autoLockTimerName = "AutoLockTimer";

        bool isBatteryTooHotWhilePlugged()
        {
            return ((Store::Battery::get().state == Store::Battery::State::PluggedNotCharging) &&
                    (Store::Battery::get().temperature == Store::Battery::Temperature::TooHigh));
        }
    } // namespace

    ApplicationManager::ApplicationManager(const ApplicationName &serviceName,


@@ 48,6 54,10 @@ namespace app::manager
        autoLockTimer = sys::TimerFactory::createSingleShotTimer(
            this, autoLockTimerName, sys::timer::InfiniteTimeout, [this](sys::Timer &) { onPhoneLocked(); });

        /* Store state in notificationProvider, but do not propagate notifications yet */
        constexpr auto updateAllowed = false;
        notificationProvider.handleBatteryTooHot(isBatteryTooHotWhilePlugged(), updateAllowed);

        bus.channels.push_back(sys::BusChannel::BluetoothModeChanges);
        bus.channels.push_back(sys::BusChannel::BluetoothNotifications);
        bus.channels.push_back(sys::BusChannel::PhoneModeChanges);


@@ 68,16 78,16 @@ namespace app::manager
        phoneLockHandler.setPhoneLockHash(
            settings->getValue(settings::SystemProperties::lockPassHash, settings::SettingsScope::Global));

        phoneLockHandler.setPhoneLockTime(utils::getNumericValue<time_t>(
        phoneLockHandler.setPhoneLockTime(utils::getNumericValue<std::time_t>(
            settings->getValue(settings::SystemProperties::unlockLockTime, settings::SettingsScope::Global)));

        phoneLockHandler.setNextUnlockAttemptLockTime(utils::getNumericValue<time_t>(
        phoneLockHandler.setNextUnlockAttemptLockTime(utils::getNumericValue<std::time_t>(
            settings->getValue(settings::SystemProperties::unlockAttemptLockTime, settings::SettingsScope::Global)));

        phoneLockHandler.setNoLockTimeAttemptsLeft(utils::getNumericValue<unsigned int>(
        phoneLockHandler.setNoLockTimeAttemptsLeft(utils::getNumericValue<unsigned>(
            settings->getValue(settings::SystemProperties::noLockTimeAttemptsLeft, settings::SettingsScope::Global)));

        wallpaperModel.setWallpaper(static_cast<gui::WallpaperOption>(utils::getNumericValue<unsigned int>(
        wallpaperModel.setWallpaper(static_cast<gui::WallpaperOption>(utils::getNumericValue<unsigned>(
            settings->getValue(settings::Wallpaper::option, settings::SettingsScope::Global))));

        settings->registerValueChange(


@@ 101,14 111,13 @@ namespace app::manager

        settings->registerValueChange(
            settings::SystemProperties::autoLockTimeInSec,
            [this](std::string value) { lockTimeChanged(std::move(value)); },
            [this](const std::string &value) { lockTimeChanged(value); },
            settings::SettingsScope::Global);

        settings->registerValueChange(
            settings::Wallpaper::option,
            [this](std::string value) {
                wallpaperModel.setWallpaper(
                    static_cast<gui::WallpaperOption>(utils::getNumericValue<unsigned int>(value)));
            [this](const std::string &value) {
                wallpaperModel.setWallpaper(static_cast<gui::WallpaperOption>(utils::getNumericValue<unsigned>(value)));
            },
            settings::SettingsScope::Global);



@@ 180,7 189,7 @@ namespace app::manager
            return sys::msgHandled();
        });

        // PhoneLock connects
        /* PhoneLock connects */
        connect(typeid(locks::LockPhone), [&]([[maybe_unused]] sys::Message *request) -> sys::MessagePointer {
            return phoneLockHandler.handleLockRequest();
        });


@@ 234,7 243,7 @@ namespace app::manager
            return phoneLockHandler.handleExternalAvailabilityChange(data->getAvailability());
        });

        // SimLock connects
        /* SimLock connects */
        connect(typeid(cellular::msg::notification::SimNeedPin), [&](sys::Message *request) -> sys::MessagePointer {
            auto data = static_cast<cellular::msg::notification::SimNeedPin *>(request);
            if (phoneLockHandler.isPhoneLocked()) {


@@ 360,6 369,7 @@ namespace app::manager
                    return sys::msgNotHandled();
                });

        /* Bluetooth connects */
        connect(typeid(sys::bluetooth::BluetoothModeChanged), [&](sys::Message *request) -> sys::MessagePointer {
            auto data = static_cast<sys::bluetooth::BluetoothModeChanged *>(request);
            handleBluetoothModeChanged(data->getBluetoothMode());


@@ 389,6 399,7 @@ namespace app::manager
            return sys::MessageNone{};
        });

        /* Alarm connects */
        alarms::AlarmServiceAPI::requestRegisterSnoozedAlarmsCountChangeCallback(this);
        connect(typeid(alarms::SnoozedAlarmsCountChangeMessage), [&](sys::Message *request) -> sys::MessagePointer {
            auto data = static_cast<alarms::SnoozedAlarmsCountChangeMessage *>(request);


@@ 403,6 414,13 @@ namespace app::manager
            return sys::msgHandled();
        });

        /* Battery connects */
        connect(typeid(sevm::BatteryStatusChangeMessage), [&](sys::Message *request) -> sys::MessagePointer {
            handleBatteryStatusChange();
            return sys::msgHandled();
        });

        /* Handled as actions connects */
        auto convertibleToActionHandler = [this](sys::Message *request) { return handleMessageAsAction(request); };
        connect(typeid(cellular::MMIResultMessage), convertibleToActionHandler);
        connect(typeid(cellular::MMIResponseMessage), convertibleToActionHandler);


@@ 491,6 509,11 @@ namespace app::manager
        notificationProvider.handleSnooze(snoozeCount);
    }

    void ApplicationManager::handleBatteryStatusChange()
    {
        notificationProvider.handleBatteryTooHot(isBatteryTooHotWhilePlugged());
    }

    auto ApplicationManager::handleAutoLockSetRequest(SetAutoLockTimeoutRequest *request)
        -> std::shared_ptr<sys::ResponseMessage>
    {


@@ 515,13 538,13 @@ namespace app::manager
        return sys::msgNotHandled();
    }

    void ApplicationManager::lockTimeChanged(std::string value)
    void ApplicationManager::lockTimeChanged(const std::string &value)
    {
        if (value.empty()) {
            LOG_ERROR("No value for auto-locking time period, request ignored");
            return;
        }
        const auto interval = std::chrono::seconds{utils::getNumericValue<unsigned int>(value)};
        const auto interval = std::chrono::seconds{utils::getNumericValue<unsigned>(value)};
        if (interval.count() == 0) {
            LOG_ERROR("Invalid auto-locking time period of 0s, request ignored");
            return;

M products/PurePhone/services/appmgr/include/appmgr/ApplicationManager.hpp => products/PurePhone/services/appmgr/include/appmgr/ApplicationManager.hpp +4 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 30,14 30,15 @@ namespace app::manager
        void changeBluetoothMode(const ApplicationHandle *app);
        void changeAlarmClockStatus(const ApplicationHandle *app);
        void handleTetheringChanged(sys::phone_modes::Tethering tethering);
        void changeTetheringState(const sys::phone_modes::Tethering state, const ApplicationHandle *app);
        void changeTetheringState(sys::phone_modes::Tethering state, const ApplicationHandle *app);
        void handleSnoozeCountChange(unsigned snoozeCount);
        void handleBatteryStatusChange();
        void processKeypadBacklightState(bsp::keypad_backlight::State keypadLightState);
        void registerMessageHandlers() override;
        void startBackgroundApplications();
        auto handleAutoLockSetRequest(SetAutoLockTimeoutRequest *request) -> std::shared_ptr<sys::ResponseMessage>;
        auto handleDeveloperModeRequest(sys::Message *request) -> sys::MessagePointer override;
        void lockTimeChanged(std::string value);
        void lockTimeChanged(const std::string &value);
        /// @brief method is called on auto-locking timer tick event (blockTimer)
        /// @detailed It sends AutoLock action to ApplicationDesktop to lock the screen.
        /// @note AutoLock action is sent only if following conditions are met: