~aleteoryx/muditaos

4f63943a4cf586e168fbb996f11adb7db40ff3e6 — rrandomsky 1 year, 11 months ago 7a55cea
[BH-1792] Updated button handling during pre wake up

Button action behavior has been updated for pre-wake.
Now, if pre-wake is in progress, the first press, in addition to pressing
the front light, disables the pre-wake function.
32 files changed, 302 insertions(+), 62 deletions(-)

M harmony_changelog.md
M module-db/Interface/EventRecord.hpp
M module-services/service-time/AlarmMessageHandler.cpp
M module-services/service-time/AlarmMessageHandler.hpp
M module-services/service-time/AlarmOperations.cpp
M module-services/service-time/AlarmOperations.hpp
M module-services/service-time/AlarmServiceAPI.cpp
M module-services/service-time/ServiceTime.cpp
M module-services/service-time/include/service-time/AlarmMessage.hpp
M module-services/service-time/include/service-time/AlarmServiceAPI.hpp
M module-services/service-time/include/service-time/AlarmStatus.hpp
M products/BellHybrid/apps/Application.cpp
M products/BellHybrid/apps/application-bell-main/presenters/StateController.cpp
M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.cpp
M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.hpp
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationPausedWindow.cpp
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningProgressWindow.cpp
M products/BellHybrid/apps/common/CMakeLists.txt
M products/BellHybrid/apps/common/include/common/layouts/BaseHomeScreenLayoutProvider.hpp
M products/BellHybrid/apps/common/include/common/models/AbstractAlarmModel.hpp
M products/BellHybrid/apps/common/include/common/models/AlarmModel.hpp
A products/BellHybrid/apps/common/include/common/models/PreWakeUpModel.hpp
M products/BellHybrid/apps/common/src/AlarmModel.cpp
M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassic.cpp
M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutVertical.cpp
A products/BellHybrid/apps/common/src/models/PreWakeUpModel.cpp
M products/BellHybrid/apps/common/src/widgets/BellBattery.cpp
M products/BellHybrid/apps/include/Application.hpp
M products/BellHybrid/services/audio/ServiceAudio.cpp
M products/BellHybrid/services/time/AlarmOperations.cpp
M products/BellHybrid/services/time/include/time/AlarmOperations.hpp
M products/BellHybrid/services/time/tests/test-BellAlarmOperations.cpp
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 11,6 11,7 @@
### Changed / Improved
* Updated FSL drivers from NXP
* Increased speed of update process
* Updated button handling during pre wake up

## [2.6.0 2024-03-07]


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

#pragma once


@@ 60,9 60,11 @@ struct SingleEventRecord : public Record, public EventInfo
                      TimePoint startDate,
                      TimePoint endDate,
                      bool wasHandledDuringCall = false)
        : EventInfo{startDate, endDate}, parent{parent}, wasHandledDuringPhoneCall(wasHandledDuringCall){};
        : EventInfo{startDate, endDate}, parent{parent}, wasHandledDuringPhoneCall(wasHandledDuringCall),
          isPreWakeUpAlreadyHandledByUser(false){};

    auto isValid() const -> bool;

    bool wasHandledDuringPhoneCall;
    bool isPreWakeUpAlreadyHandledByUser;
};

M module-services/service-time/AlarmMessageHandler.cpp => module-services/service-time/AlarmMessageHandler.cpp +10 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AlarmMessageHandler.hpp"


@@ 186,6 186,15 @@ namespace alarms
        }
    }

    auto AlarmMessageHandler::handleTurnOffPreWakeUp(TurnOffPreWakeUpRequestMessage *request)
        -> std::shared_ptr<TurnOffPreWakeUpResponseMessage>
    {
        return handleWithCallback<TurnOffPreWakeUpRequestMessage, TurnOffPreWakeUpResponseMessage, bool>(
            request, [&](TurnOffPreWakeUpRequestMessage *request, IAlarmOperations::OnTurnOffPreWakeUp callback) {
                alarmOperations->turnOffPreWakeUp(callback);
            });
    }

    template <class RequestType, class ResponseType, class CallbackParamType>
    auto AlarmMessageHandler::handleWithCallback(
        RequestType *request,

M module-services/service-time/AlarmMessageHandler.hpp => module-services/service-time/AlarmMessageHandler.hpp +3 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 48,6 48,8 @@ namespace alarms
        auto handleGetSnoozedAlarms(GetSnoozedAlarmsRequestMessage *request)
            -> std::shared_ptr<GetSnoozedAlarmsResponseMessage>;
        auto handleBatteryStateChange(sevm::BatteryStateChangeMessage *request) -> void;
        auto handleTurnOffPreWakeUp(TurnOffPreWakeUpRequestMessage *request)
            -> std::shared_ptr<TurnOffPreWakeUpResponseMessage>;

      private:
        stm::ServiceTime *service = nullptr;

M module-services/service-time/AlarmOperations.cpp => module-services/service-time/AlarmOperations.cpp +4 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AlarmOperations.hpp"


@@ 510,4 510,7 @@ namespace alarms
    {
        onAlarmDuringPhoneCallCallback = callback;
    }

    void AlarmOperationsCommon::turnOffPreWakeUp(OnTurnOffPreWakeUp callback)
    {}
} // namespace alarms

M module-services/service-time/AlarmOperations.hpp => module-services/service-time/AlarmOperations.hpp +4 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 34,6 34,7 @@ namespace alarms
        using OnToggleAllProcessed          = std::function<void(bool)>;
        using CheckIfPhoneCallIsOngoing     = std::function<bool(void)>;
        using OnAlarmDuringPhoneCall        = std::function<void(void)>;
        using OnTurnOffPreWakeUp            = std::function<void(bool)>;

        virtual ~IAlarmOperations() noexcept = default;



@@ 70,6 71,7 @@ namespace alarms
        virtual void handleNormalBatteryLevel()                                                              = 0;
        virtual void addCheckIfPhoneCallIsOngoingCallback(CheckIfPhoneCallIsOngoing)                         = 0;
        virtual void addAlarmDuringPhoneCallCallback(OnAlarmDuringPhoneCall)                                 = 0;
        virtual void turnOffPreWakeUp(OnTurnOffPreWakeUp)                                                    = 0;
    };

    class IAlarmOperationsFactory


@@ 118,6 120,7 @@ namespace alarms
        void handleNormalBatteryLevel() override;
        void addCheckIfPhoneCallIsOngoingCallback(CheckIfPhoneCallIsOngoing callback) override;
        void addAlarmDuringPhoneCallCallback(OnAlarmDuringPhoneCall callback) override;
        void turnOffPreWakeUp(OnTurnOffPreWakeUp callback) override;

      protected:
        std::unique_ptr<AbstractAlarmEventsRepository> alarmEventsRepo;

M module-services/service-time/AlarmServiceAPI.cpp => module-services/service-time/AlarmServiceAPI.cpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ServiceTimeName.hpp"


@@ 10,7 10,6 @@

namespace alarms
{

    namespace AlarmServiceAPI
    {
        template <class requestType, typename... Types>


@@ 74,6 73,11 @@ namespace alarms
        {
            return sendRequest<RegisterActiveAlarmsIndicatorHandlerRequestMessage>(serv);
        }

        bool requestTurnOffPreWakeUp(sys::Service *serv)
        {
            return sendRequest<TurnOffPreWakeUpRequestMessage>(serv);
        }
    }; // namespace AlarmServiceAPI

} // namespace alarms

M module-services/service-time/ServiceTime.cpp => module-services/service-time/ServiceTime.cpp +5 -2
@@ 35,8 35,7 @@ namespace stm
    }

    ServiceTime::~ServiceTime()
    {
    }
    {}

    sys::ReturnCodes ServiceTime::InitHandler()
    {


@@ 215,6 214,10 @@ namespace stm
            alarmMessageHandler->handleBatteryStateChange(message);
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(alarms::TurnOffPreWakeUpRequestMessage), [&](sys::Message *request) -> sys::MessagePointer {
            return alarmMessageHandler->handleTurnOffPreWakeUp(
                static_cast<alarms::TurnOffPreWakeUpRequestMessage *>(request));
        });
    }

    auto ServiceTime::handleSetAutomaticDateAndTimeRequest(sys::Message *request)

M module-services/service-time/include/service-time/AlarmMessage.hpp => module-services/service-time/include/service-time/AlarmMessage.hpp +29 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 272,4 272,32 @@ namespace alarms
            : snoozedAlarms(std::move(snoozedAlarms)){};
        const std::vector<SingleEventRecord> snoozedAlarms;
    };

    class TurnOffPreWakeUpResponseMessage : public AlarmResponse
    {
      public:
        explicit TurnOffPreWakeUpResponseMessage(const bool success = false) : success(success){};
        const bool success{};
    };

    class PreWakeUpChangeState : public AlarmMessage
    {
      public:
        explicit PreWakeUpChangeState(bool isActive) : activity(isActive)
        {}

        bool isActive() const
        {
            return activity;
        };

      private:
        bool activity;
    };

    class TurnOffPreWakeUpRequestMessage : public AlarmMessage
    {
      public:
        TurnOffPreWakeUpRequestMessage(){};
    };
} // namespace alarms

M module-services/service-time/include/service-time/AlarmServiceAPI.hpp => module-services/service-time/include/service-time/AlarmServiceAPI.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 31,6 31,7 @@ namespace alarms
        bool requestStopAllSnoozedAlarms(sys::Service *serv);
        bool requestRegisterSnoozedAlarmsCountChangeCallback(sys::Service *serv);
        bool requestRegisterActiveAlarmsIndicatorHandler(sys::Service *serv);
        bool requestTurnOffPreWakeUp(sys::Service *serv);
    }; // namespace AlarmServiceAPI

} // namespace alarms

M module-services/service-time/include/service-time/AlarmStatus.hpp => module-services/service-time/include/service-time/AlarmStatus.hpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 14,4 14,4 @@ namespace alarms
        Ringing,
        Queued
    };
}
} // namespace alarms

M products/BellHybrid/apps/Application.cpp => products/BellHybrid/apps/Application.cpp +42 -1
@@ 17,6 17,9 @@
#include <common/popups/BedtimeNotificationWindow.hpp>
#include <common/popups/ChargingNotificationWindow.hpp>
#include <apps-common/WindowsPopupFilter.hpp>
#include <service-time/AlarmMessage.hpp>
#include <service-evtmgr/KbdMessage.hpp>
#include <products/BellHybrid/keymap/include/keymap/KeyMap.hpp>

namespace app
{


@@ 33,10 36,15 @@ namespace app
                        (isCurrentWindow(gui::popup::resolveWindowName(gui::popup::ID::PowerOff))) ||
                        (isCurrentWindow(gui::BellTurnOffWindow::name)));
            if (val == true) {
                LOG_ERROR("Block popup - as curent window is in higher order popup");
                LOG_ERROR("Block popup - as current window is in higher order popup");
            }
            return val ? gui::popup::FilterType::Ignore : gui::popup::FilterType::Show;
        });

        preWakeUpModel = std::make_unique<PreWakeUpModel>(this);
        bus.channels.push_back(sys::BusChannel::AlarmNotifications);
        connect(typeid(alarms::PreWakeUpChangeState),
                [&](sys::Message *msg) { return handlePreWakeUpChangeState(msg); });
    }

    sys::ReturnCodes Application::InitHandler()


@@ 134,6 142,18 @@ namespace app
    sys::MessagePointer Application::handleKBDKeyEvent(sys::Message *msgl)
    {
        onKeyPressed();
        if (preWakeUpModel && preWakeUpModel->isActive()) {
            if (this->getState() != app::ApplicationCommon::State::ACTIVE_FORGROUND) {
                LOG_FATAL("Terrible terrible damage! Application with no focus grabbed key!");
                return sys::msgNotHandled();
            }
            const auto msg        = static_cast<sevm::KbdMessage *>(msgl);
            const auto inputEvent = keyTranslator->translate(msg->key);
            if (!inputEvent.is(gui::KeyCode::KEY_UNDEFINED) && isInputEventToHandlePreWakeUp(inputEvent)) {
                preWakeUpModel->turnOffPreWakeUp();
                return sys::msgHandled();
            }
        }
        return ApplicationCommon::handleKBDKeyEvent(msgl);
    }



@@ 155,6 175,16 @@ namespace app
        return ApplicationCommon::handleAppFocusLost(msgl);
    }

    sys::MessagePointer Application::handlePreWakeUpChangeState(sys::Message *msg)
    {
        auto *message = dynamic_cast<alarms::PreWakeUpChangeState *>(msg);
        if (message == nullptr) {
            return sys::msgNotHandled();
        }
        preWakeUpModel->setActive(message->isActive());
        return sys::msgHandled();
    }

    void Application::onKeyPressed()
    {
        restartIdleTimer();


@@ 201,9 231,20 @@ namespace app
        startIdleTimer();
        idleTimerActiveFlag = true;
    }

    void Application::suspendIdleTimer()
    {
        stopIdleTimer();
        idleTimerActiveFlag = false;
    }

    bool Application::isInputEventToHandlePreWakeUp(const gui::InputEvent inputEvent)
    {
        const auto key = mapKey(inputEvent.getKeyCode());
        if (inputEvent.isShortRelease() && key != KeyMap::Frontlight && key != KeyMap::DeepPressDown &&
            key != KeyMap::DeepPressUp) {
            return true;
        }
        return false;
    }
} // namespace app

M products/BellHybrid/apps/application-bell-main/presenters/StateController.cpp => products/BellHybrid/apps/application-bell-main/presenters/StateController.cpp +1 -0
@@ 211,6 211,7 @@ namespace app::home_screen
                            AbstractPresenter &presenter,
                            AbstractAlarmModel &alarmModel,
                            AbstractTimeModel &timeModel) {
                alarmModel.turnOffPreWakeUp();
                alarmModel.activate(true);
                presenter.spawnTimer();
                view.setTextDescription(utils::time::getBottomDescription(

M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.cpp => products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RelaxationPausedPresenter.hpp"

M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.hpp => products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationPausedPresenter.hpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationPausedWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationPausedWindow.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RelaxationPausedWindow.hpp"

M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningProgressWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningProgressWindow.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RelaxationRunningProgressWindow.hpp"

M products/BellHybrid/apps/common/CMakeLists.txt => products/BellHybrid/apps/common/CMakeLists.txt +2 -0
@@ 39,6 39,7 @@ target_sources(application-bell-common
        src/models/SettingsModel.cpp
        src/models/BedtimeModel.cpp
        src/models/LowBatteryInfoModel.cpp
        src/models/PreWakeUpModel.cpp
        src/popups/AlarmActivatedWindow.cpp
        src/popups/AlarmActivatedWindow.cpp
        src/popups/BedtimeNotificationWindow.cpp


@@ 116,6 117,7 @@ target_sources(application-bell-common
        include/common/models/LayoutModel.hpp
        include/common/models/LowBatteryInfoModel.hpp
        include/common/models/QuoteModel.hpp
        include/common/models/PreWakeUpModel.hpp
        include/common/popups/presenter/AlarmActivatedPresenter.hpp
        include/common/popups/AlarmActivatedWindow.hpp
        include/common/popups/AlarmDeactivatedWindow.hpp

M products/BellHybrid/apps/common/include/common/layouts/BaseHomeScreenLayoutProvider.hpp => products/BellHybrid/apps/common/include/common/layouts/BaseHomeScreenLayoutProvider.hpp +2 -1
@@ 24,7 24,8 @@ namespace app::home_screen
        AlarmRinging,
        AlarmRingingDeactivatedWait,
        AlarmSnoozedWait,
        AlarmSnoozed
        AlarmSnoozed,
        PreWakeUpActive
    };
};


M products/BellHybrid/apps/common/include/common/models/AbstractAlarmModel.hpp => products/BellHybrid/apps/common/include/common/models/AbstractAlarmModel.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 34,6 34,7 @@ namespace app
        virtual TimePoint getTimeOfNextSnooze()                = 0;
        virtual alarms::AlarmStatus getAlarmStatus()           = 0;
        virtual void activateAlarm(bool state)                 = 0;
        virtual bool turnOffPreWakeUp()                        = 0;
        /// Command model to update its internal data
        virtual void update(AlarmModelReadyHandler callback = AlarmModelReadyHandler()) = 0;
    };

M products/BellHybrid/apps/common/include/common/models/AlarmModel.hpp => products/BellHybrid/apps/common/include/common/models/AlarmModel.hpp +3 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 36,6 36,8 @@ namespace app
        void turnOff() override;
        void snooze() override;
        void activateAlarm(bool state) override;
        bool turnOffPreWakeUp() override;

        std::chrono::seconds getTimeToNextSnooze() override;
        TimePoint getTimeOfNextSnooze() override;
        alarms::AlarmStatus getAlarmStatus() override;

A products/BellHybrid/apps/common/include/common/models/PreWakeUpModel.hpp => products/BellHybrid/apps/common/include/common/models/PreWakeUpModel.hpp +36 -0
@@ 0,0 1,36 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

namespace app
{
    class ApplicationCommon;
}

namespace app
{
    class AbstractPreWakeUpModel
    {
      public:
        virtual ~AbstractPreWakeUpModel() noexcept = default;

        virtual bool isActive() const       = 0;
        virtual void setActive(bool active) = 0;
        virtual bool turnOffPreWakeUp()     = 0;
    };

    class PreWakeUpModel : public AbstractPreWakeUpModel
    {
      public:
        explicit PreWakeUpModel(ApplicationCommon *app);

        bool isActive() const override;
        void setActive(bool active) override;
        bool turnOffPreWakeUp() override;

      private:
        ApplicationCommon *app{};
        bool activity{false};
    };
} // namespace app

M products/BellHybrid/apps/common/src/AlarmModel.cpp => products/BellHybrid/apps/common/src/AlarmModel.cpp +5 -0
@@ 232,6 232,11 @@ namespace app
        update(callback);
    }

    bool AlarmModel::turnOffPreWakeUp()
    {
        return alarms::AlarmServiceAPI::requestTurnOffPreWakeUp(app);
    }

    alarms::AlarmStatus AlarmModel::getAlarmStatus()
    {
        return alarmStatus;

M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassic.cpp => products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassic.cpp +5 -0
@@ 205,6 205,11 @@ namespace gui
            alarm->setEditMode(EditMode::Browse);
            removeTextDescription();
            break;
        case app::home_screen::ViewState::PreWakeUpActive:
            setHeaderViewMode(HeaderViewMode::AlarmIconAndTime);
            alarm->setEditMode(EditMode::Browse);
            removeTextDescription();
            break;
        }
    }


M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutVertical.cpp => products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutVertical.cpp +2 -0
@@ 106,6 106,8 @@ namespace gui
            alarmMainTime->setVisible(false);
            setScreenMode(ScreenMode::Main);
            break;
        case app::home_screen::ViewState::PreWakeUpActive:
            break;
        }
    }


A products/BellHybrid/apps/common/src/models/PreWakeUpModel.cpp => products/BellHybrid/apps/common/src/models/PreWakeUpModel.cpp +27 -0
@@ 0,0 1,27 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "models/PreWakeUpModel.hpp"
#include <apps-common/ApplicationCommon.hpp>
#include <service-time/AlarmServiceAPI.hpp>

namespace app
{
    PreWakeUpModel::PreWakeUpModel(ApplicationCommon *app) : app{app}
    {}

    bool PreWakeUpModel::isActive() const
    {
        return activity;
    }

    void PreWakeUpModel::setActive(bool active)
    {
        activity = active;
    }

    bool PreWakeUpModel::turnOffPreWakeUp()
    {
        return alarms::AlarmServiceAPI::requestTurnOffPreWakeUp(app);
    }
} // namespace app

M products/BellHybrid/apps/common/src/widgets/BellBattery.cpp => products/BellHybrid/apps/common/src/widgets/BellBattery.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <common/data/BatteryUtils.hpp>

M products/BellHybrid/apps/include/Application.hpp => products/BellHybrid/apps/include/Application.hpp +4 -0
@@ 6,6 6,7 @@
#include <ApplicationCommon.hpp>
#include <common/models/AlarmModel.hpp>
#include <common/models/BatteryModel.hpp>
#include <common/models/PreWakeUpModel.hpp>

namespace app
{


@@ 35,6 36,7 @@ namespace app

        std::unique_ptr<app::AlarmModel> alarmModel;
        std::unique_ptr<AbstractBatteryModel> batteryModel;
        std::unique_ptr<AbstractPreWakeUpModel> preWakeUpModel;

      private:
        sys::MessagePointer handleKBDKeyEvent(sys::Message *msgl) override;


@@ 42,6 44,8 @@ namespace app
        sys::MessagePointer handleAppClose(sys::Message *msgl) override;
        sys::MessagePointer handleAppFocusLost(sys::Message *msgl) override;
        void updateStatuses(gui::AppWindow *window) const override;
        sys::MessagePointer handlePreWakeUpChangeState(sys::Message *msgl);
        bool isInputEventToHandlePreWakeUp(const gui::InputEvent inputEvent);

        virtual void onKeyPressed();
        virtual void onStart();

M products/BellHybrid/services/audio/ServiceAudio.cpp => products/BellHybrid/services/audio/ServiceAudio.cpp +22 -17
@@ 13,13 13,13 @@ namespace
    // 4kB is too small because internally drflac_open() uses cache which by default has 4kB.
    // Alternatively smaller DR_FLAC_BUFFER_SIZE could be defined.
    constexpr auto serviceAudioStackSize = 1024 * 8;
    constexpr auto defaultVolume        = "11";
    constexpr auto defaultSnoozeVolume  = "10";
    constexpr auto defaultBedtimeVolume = "12";
    constexpr auto maxVolumeToSet       = 15.f;
    constexpr auto minVolumeToSet       = 0.f;
    constexpr auto profileType          = audio::Profile::Type::PlaybackLoudspeaker;
    constexpr auto volumeSetting        = audio::Setting::Volume;
    constexpr auto defaultVolume         = "11";
    constexpr auto defaultSnoozeVolume   = "10";
    constexpr auto defaultBedtimeVolume  = "12";
    constexpr auto maxVolumeToSet        = 15.f;
    constexpr auto minVolumeToSet        = 0.f;
    constexpr auto profileType           = audio::Profile::Type::PlaybackLoudspeaker;
    constexpr auto volumeSetting         = audio::Setting::Volume;

    namespace initializer
    {


@@ 133,8 133,7 @@ namespace service
    }

    Audio::~Audio()
    {
    }
    {}

    sys::MessagePointer Audio::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msgl,
                                                   [[maybe_unused]] sys::ResponseMessage *resp)


@@ 198,18 197,24 @@ namespace service
        return std::make_unique<AudioStartPlaybackResponse>(retCode, retToken);
    }

    auto Audio::handleStop([[maybe_unused]] const std::vector<audio::PlaybackType> &stopTypes,
                           const audio::Token &token) -> std::unique_ptr<AudioResponseMessage>
    auto Audio::handleStop(const std::vector<audio::PlaybackType> &stopTypes, const audio::Token &token)
        -> std::unique_ptr<AudioResponseMessage>
    {
        std::vector<std::pair<audio::Token, audio::RetCode>> retCodes;

        // if stopType is not provided then stop all inputs, otherwise stop specific ones from stopType
        for (auto &input : audioMux.GetAllInputs()) {
            auto t = input.token;
            if (token.IsValid() && t == token) {
                retCodes.emplace_back(t, stopInput(&input));
            }
            if (token.IsUninitialized()) {
                retCodes.emplace_back(t, stopInput(&input));
            const auto &currentOperation = input.audio->GetCurrentOperation();
            const auto isOperationInStopTypes =
                std::find(stopTypes.begin(), stopTypes.end(), currentOperation.GetPlaybackType()) != stopTypes.end();
            if (stopTypes.empty() || isOperationInStopTypes) {
                auto t = input.token;
                if (token.IsValid() && t == token) {
                    retCodes.emplace_back(t, stopInput(&input));
                }
                if (token.IsUninitialized()) {
                    retCodes.emplace_back(t, stopInput(&input));
                }
            }
        }


M products/BellHybrid/services/time/AlarmOperations.cpp => products/BellHybrid/services/time/AlarmOperations.cpp +40 -10
@@ 1,8 1,9 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <BellAlarmHandler.hpp>

#include <service-time/AlarmMessage.hpp>
#include <time/AlarmOperations.hpp>
#include <time/dateCommon.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>


@@ 143,12 144,17 @@ namespace alarms
        auto snoozeChimeSettingsProvider = std::make_unique<SnoozeChimeSettingsProviderImpl>(service);
        auto onboardingSettingsProvider  = std::make_unique<OnboardingSettingsProviderImpl>(service);
        auto bedtimeSettingsProvider     = std::make_unique<BedtimeSettingsProviderImpl>(service);
        auto alarmOperations             = std::make_unique<AlarmOperations>(std::move(alarmEventsRepo),
        auto onPreWakeUpChangeState      = [service](bool isActive) {
            auto message = std::make_shared<alarms::PreWakeUpChangeState>(isActive);
            service->bus.sendMulticast(std::move(message), sys::BusChannel::AlarmNotifications);
        };
        auto alarmOperations = std::make_unique<AlarmOperations>(std::move(alarmEventsRepo),
                                                                 getCurrentTimeCallback,
                                                                 std::move(preWakeUpSettingsProvider),
                                                                 std::move(snoozeChimeSettingsProvider),
                                                                 std::move(onboardingSettingsProvider),
                                                                 std::move(bedtimeSettingsProvider));
                                                                 std::move(bedtimeSettingsProvider),
                                                                 std::move(onPreWakeUpChangeState));
        alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock,
                                                  std::make_shared<alarms::BellAlarmClockHandler>(service));
        alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::PreWakeUpChime,


@@ 168,10 174,12 @@ namespace alarms
                                     std::unique_ptr<PreWakeUpSettingsProvider> &&preWakeUpSettingsProvider,
                                     std::unique_ptr<SnoozeChimeSettingsProvider> &&snoozeChimeSettings,
                                     std::unique_ptr<OnboardingSettingsProvider> &&onboardingSettings,
                                     std::unique_ptr<AbstractBedtimeSettingsProvider> &&bedtimeSettingsProvider)
                                     std::unique_ptr<AbstractBedtimeSettingsProvider> &&bedtimeSettingsProvider,
                                     PreWakeUp::ChangeStateCallback &&callback)
        : AlarmOperationsCommon{std::move(alarmEventsRepo), std::move(getCurrentTimeCallback)},
          preWakeUp(std::move(preWakeUpSettingsProvider)), snoozeChimeSettings(std::move(snoozeChimeSettings)),
          onboardingSettings(std::move(onboardingSettings)), bedtime(std::move(bedtimeSettingsProvider))
          preWakeUp(std::move(preWakeUpSettingsProvider), std::move(callback)),
          snoozeChimeSettings(std::move(snoozeChimeSettings)), onboardingSettings(std::move(onboardingSettings)),
          bedtime(std::move(bedtimeSettingsProvider))
    {}

    void AlarmOperations::minuteUpdated(TimePoint now)


@@ 224,8 232,8 @@ namespace alarms
    void AlarmOperations::processBedtime(TimePoint now)
    {
        if (bedtime.decide(now)) {
            auto bedtimeEvent           = std::make_shared<AlarmEventRecord>();
            bedtimeEvent->enabled       = true;
            auto bedtimeEvent     = std::make_shared<AlarmEventRecord>();
            bedtimeEvent->enabled = true;
            handleAlarmEvent(bedtimeEvent, alarms::AlarmType::BedtimeReminder, true);
        }
    }


@@ 347,12 355,31 @@ namespace alarms
        AlarmOperationsCommon::handleAlarmEvent(event, alarmType, newStateOn);
    }

    PreWakeUp::PreWakeUp(std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider)
        : settingsProvider{std::move(settingsProvider)}
    void AlarmOperations::turnOffPreWakeUp(IAlarmOperations::OnTurnOffPreWakeUp callback)
    {
        auto nextEvent = getNextPreWakeUpEvent();
        if (nextEvent.isValid()) {
            if (auto event = std::dynamic_pointer_cast<AlarmEventRecord>(nextEvent.parent); event) {
                disablePreWakeUp(event);
                if (callback) {
                    callback(true);
                }
                if (!nextSingleEvents.empty()) {
                    nextSingleEvents.front()->isPreWakeUpAlreadyHandledByUser = true;
                }
            }
        }
    }

    PreWakeUp::PreWakeUp(std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider, ChangeStateCallback &&callback)
        : settingsProvider{std::move(settingsProvider)}, onChangeStateCallback(std::move(callback))
    {}

    auto PreWakeUp::decide(TimePoint now, const SingleEventRecord &event) -> Decision
    {
        if (event.isPreWakeUpAlreadyHandledByUser) {
            return {false, false};
        }
        const auto chimeSettings       = settingsProvider->getChimeSettings();
        const auto frontlightSettings  = settingsProvider->getFrontlightSettings();
        const auto isTimeForChime      = isTimeForPreWakeUp(now, event, chimeSettings);


@@ 375,6 402,9 @@ namespace alarms

    auto PreWakeUp::setActive(bool state) -> void
    {
        if (onChangeStateCallback != nullptr) {
            onChangeStateCallback(state);
        }
        active = state;
    }


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

#pragma once


@@ 64,13 64,14 @@ namespace alarms
    class PreWakeUp
    {
      public:
        using ChangeStateCallback = std::function<void(bool)>;
        struct Decision
        {
            bool timeForChime;
            bool timeForFrontlight;
        };

        explicit PreWakeUp(std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider);
        PreWakeUp(std::unique_ptr<PreWakeUpSettingsProvider> &&settingsProvider, ChangeStateCallback &&callback);
        auto decide(TimePoint now, const SingleEventRecord &event) -> Decision;
        auto isActive() const -> bool;
        auto setActive(bool state) -> void;


@@ 82,6 83,7 @@ namespace alarms

        std::unique_ptr<PreWakeUpSettingsProvider> settingsProvider;
        bool active{false};
        ChangeStateCallback onChangeStateCallback;
    };

    class Bedtime


@@ 104,7 106,10 @@ namespace alarms
                        std::unique_ptr<PreWakeUpSettingsProvider> &&preWakeUpSettingsProvider,
                        std::unique_ptr<SnoozeChimeSettingsProvider> &&snoozeChimeSettingsProvider,
                        std::unique_ptr<OnboardingSettingsProvider> &&onboardingSettingsProvider,
                        std::unique_ptr<AbstractBedtimeSettingsProvider> &&BedtimeModel);
                        std::unique_ptr<AbstractBedtimeSettingsProvider> &&BedtimeModel,
                        PreWakeUp::ChangeStateCallback &&callback);

        void turnOffPreWakeUp(OnTurnOffPreWakeUp callback) override;

      private:
        void minuteUpdated(TimePoint now) override;

M products/BellHybrid/services/time/tests/test-BellAlarmOperations.cpp => products/BellHybrid/services/time/tests/test-BellAlarmOperations.cpp +26 -9
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <AlarmOperations.hpp>


@@ 105,14 105,16 @@ namespace
        std::unique_ptr<alarms::PreWakeUpSettingsProvider> &&preWakeUpSettingsProvider,
        std::unique_ptr<alarms::SnoozeChimeSettingsProvider> &&snoozeChimeSettingsProvider,
        std::unique_ptr<alarms::OnboardingSettingsProvider> &&onboardingSettingsProvider,
        std::unique_ptr<alarms::AbstractBedtimeSettingsProvider> &&bedtimeSettingsProvider)
        std::unique_ptr<alarms::AbstractBedtimeSettingsProvider> &&bedtimeSettingsProvider,
        alarms::PreWakeUp::ChangeStateCallback callback = nullptr)
    {
        return std::make_unique<alarms::AlarmOperations>(std::move(alarmRepo),
                                                         timeInjector,
                                                         std::move(preWakeUpSettingsProvider),
                                                         std::move(snoozeChimeSettingsProvider),
                                                         std::move(onboardingSettingsProvider),
                                                         std::move(bedtimeSettingsProvider));
                                                         std::move(bedtimeSettingsProvider),
                                                         std::move(callback));
    }
} // namespace



@@ 127,9 129,11 @@ std::unique_ptr<alarms::IAlarmOperations> AlarmOperationsFixture::getMockedAlarm
                                      std::make_unique<MockedBedtimeModel>());
}

std::function<void(bool)> changeStateCallback = [](bool state) {};

TEST(PreWakeUp, TooEarlyForPreWakeUp)
{
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>());
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>(), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 6min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());


@@ 141,7 145,7 @@ TEST(PreWakeUp, TooEarlyForPreWakeUp)

TEST(PreWakeUp, TimeToPlayChime)
{
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>());
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>(), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 5min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());


@@ 155,7 159,7 @@ TEST(PreWakeUp, TimeToPlayChimeButDisabled)
{
    auto settingsProvider = std::make_unique<MockedPreWakeUpSettingsProvider>();
    settingsProvider->setChimeSettings(false, std::chrono::minutes::zero());
    alarms::PreWakeUp preWakeUp(std::move(settingsProvider));
    alarms::PreWakeUp preWakeUp(std::move(settingsProvider), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 5min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());


@@ 167,7 171,7 @@ TEST(PreWakeUp, TimeToPlayChimeButDisabled)

TEST(PreWakeUp, TimeToLightFrontlight)
{
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>());
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>(), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 2min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());


@@ 181,7 185,7 @@ TEST(PreWakeUp, TimeToLightFrontlightButDisabled)
{
    auto settingsProvider = std::make_unique<MockedPreWakeUpSettingsProvider>();
    settingsProvider->setFrontlightSettings(false, std::chrono::minutes::zero());
    alarms::PreWakeUp preWakeUp(std::move(settingsProvider));
    alarms::PreWakeUp preWakeUp(std::move(settingsProvider), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 2min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());


@@ 191,6 195,19 @@ TEST(PreWakeUp, TimeToLightFrontlightButDisabled)
    ASSERT_FALSE(decision.timeForFrontlight);
}

TEST(PreWakeUp, CallbackWhenSetActive)
{
    testing::MockFunction<void(bool)> mockCallback;
    std::function<void(bool)> changeCallback = [&](bool state) { mockCallback.Call(state); };
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>(), std::move(changeCallback));
    EXPECT_CALL(mockCallback, Call(true)).Times(2);
    EXPECT_CALL(mockCallback, Call(false)).Times(2);
    preWakeUp.setActive(true);
    preWakeUp.setActive(false);
    preWakeUp.setActive(true);
    preWakeUp.setActive(false);
}

TEST(Bedtime, TimeToBedDisabled)
{
    auto settingsProvider =


@@ 215,7 232,7 @@ TEST(Bedtime, TimeToBedEnabled)

TEST(PreWakeUp, TimePointIsNotRoundedToFullMinute)
{
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>());
    alarms::PreWakeUp preWakeUp(std::make_unique<MockedPreWakeUpSettingsProvider>(), std::move(changeStateCallback));
    auto event           = AlarmEventRecord(1, AlarmTime{5h, 5min}, defMusic, defEnabled, defSnooze, defRRule);
    const auto nextEvent = event.getNextSingleEvent(TimePointFromStringWithShift("2022-11-11 05:00:00"));
    EXPECT_TRUE(static_cast<EventInfo>(nextEvent).isValid());