~aleteoryx/muditaos

14046eb1892869e61c413c8614fe94a3697ef8ab — Dawid Wojtas 2 years ago 6e1741c
[BH-1745] Fix a deep press crash during popups

Rewrite the popups filter to remove unnecessary popups.
Remove callbacks from activate and deactivate popups
which cause problems when the popups was on the stack.
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 15,6 15,7 @@
* Fixed "Next alarm will ring in 24h" popup on shutdown screen
* Fixed redundant clock face display while shutting down Harmony
* Fixed problem with disabling the frontlight in pre-wake up
* Fixed occasional crash when a deep press occurs during popups

### Added


M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +2 -2
@@ 43,9 43,9 @@ namespace app

        getPopupFilter().addAppDependentFilter([&](const gui::PopupRequestParams &popupParams) {
            if (popupParams.getPopupId() == gui::popup::ID::Volume) {
                return true;
                return gui::popup::FilterType::Show;
            }
            return true;
            return gui::popup::FilterType::Show;
        });
        statusBarManager->enableIndicators(
            {Indicator::Signal, Indicator::Time, Indicator::Battery, Indicator::SimCard});

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +3 -2
@@ 33,8 33,9 @@ namespace app
                              std::make_shared<SIMConfiguration>(SIMConfiguration::DisplayMode::OnlyInactiveState));
        bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);

        getPopupFilter().addAppDependentFilter(
            [&](const gui::PopupRequestParams & /*popupParams*/) { return !blockAllPopups; });
        getPopupFilter().addAppDependentFilter([&](const gui::PopupRequestParams & /*popupParams*/) {
            return blockAllPopups ? gui::popup::FilterType::Ignore : gui::popup::FilterType::Show;
        });

        addActionReceiver(app::manager::actions::ShowMMIResponse, [this](auto &&data) {
            switchWindow(app::window::name::desktop_mmi_pull, std::move(data));

M module-apps/application-onboarding/ApplicationOnBoarding.cpp => module-apps/application-onboarding/ApplicationOnBoarding.cpp +3 -2
@@ 47,7 47,8 @@ namespace app
        bus.channels.push_back(sys::BusChannel::ServiceCellularNotifications);

        getPopupFilter().addAppDependentFilter([&](const gui::PopupRequestParams & /*popupParams*/) {
            return gui::name::window::main_window != getCurrentWindow()->getName();
            return gui::name::window::main_window != getCurrentWindow()->getName() ? gui::popup::FilterType::Show
                                                                                   : gui::popup::FilterType::Ignore;
        });
    }



@@ 146,7 147,7 @@ namespace app
            const auto eulaDirPath  = purefs::dir::getSystemDataDirPath() / "licenses";
            const auto eulaFilename = "eula.txt";
            auto eulaRepository     = std::make_unique<app::onBoarding::EULARepository>(eulaDirPath, eulaFilename);
            auto presenter      = std::make_unique<app::onBoarding::EULALicenseWindowPresenter>([&]() { acceptEULA(); },
            auto presenter = std::make_unique<app::onBoarding::EULALicenseWindowPresenter>([&]() { acceptEULA(); },
                                                                                           std::move(eulaRepository));
            return std::make_unique<app::onBoarding::EULALicenseWindow>(app, std::move(presenter));
        });

M module-apps/apps-common/ApplicationCommon.cpp => module-apps/apps-common/ApplicationCommon.cpp +8 -3
@@ 864,9 864,14 @@ namespace app
            data->setDisposition(gui::popup::Disposition{
                gui::popup::Disposition::Priority::Normal, gui::popup::Disposition::WindowType::Popup, id});
        }
        windowsPopupQueue->pushRequest(gui::popup::Request(id, std::move(data), *blueprint));
        auto result = tryShowPopup();
        LOG_INFO("tryShowPopup %s status: %s", magic_enum::enum_name(id).data(), result ? "shown" : "ignored");
        if (popupFilter->addPopup(gui::PopupRequestParams(id))) {
            windowsPopupQueue->pushRequest(gui::popup::Request(id, std::move(data), *blueprint));
            auto result = tryShowPopup();
            LOG_INFO("Try to show Popup %s status: %s", magic_enum::enum_name(id).data(), result ? "shown" : "ignored");
        }
        else {
            LOG_INFO("Popup %s removed", magic_enum::enum_name(id).data());
        }
    }

    gui::popup::Filter &ApplicationCommon::getPopupFilter() const

M module-apps/apps-common/WindowsPopupFilter.cpp => module-apps/apps-common/WindowsPopupFilter.cpp +12 -2
@@ 16,7 16,7 @@ namespace gui::popup
    bool Filter::isPermitted(const gui::PopupRequestParams &params) const
    {
        for (const auto &filter : appDependentFilter) {
            if (filter != nullptr && not filter(params)) {
            if (filter != nullptr && filter(params) != FilterType::Show) {
                return false;
            }
        }


@@ 40,7 40,17 @@ namespace gui::popup
        return true;
    }

    void Filter::addAppDependentFilter(std::function<bool(const gui::PopupRequestParams &)> f)
    bool Filter::addPopup(const gui::PopupRequestParams &params) const
    {
        for (const auto &filter : appDependentFilter) {
            if (filter == nullptr || filter(params) == FilterType::Remove) {
                return false;
            }
        }
        return true;
    }

    void Filter::addAppDependentFilter(std::function<FilterType(const gui::PopupRequestParams &)> f)
    {
        appDependentFilter.push_back(f);
    }

M module-apps/apps-common/WindowsPopupFilter.hpp => module-apps/apps-common/WindowsPopupFilter.hpp +12 -3
@@ 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,12 16,20 @@ namespace app
}
namespace gui::popup
{

    enum class FilterType
    {
        Show = 0, // Show popup
        Ignore,   // Ignore popup but add to the popup's queue
        Remove    // Remove and don't add to the popup's queue
    };

    /// This filter class is used just to filter next popup to handle if any
    /// it can and should be overriden to filter out only desired ones at the time
    class Filter
    {
      private:
        std::list<std::function<bool(const gui::PopupRequestParams &)>> appDependentFilter;
        std::list<std::function<FilterType(const gui::PopupRequestParams &)>> appDependentFilter;
        /// non-owning pointer to existing stack - @see attachWindowsStack()
        app::WindowsStack *stack = nullptr;



@@ 29,7 37,8 @@ namespace gui::popup
        virtual ~Filter() = default;

        void attachWindowsStack(app::WindowsStack *stack);
        void addAppDependentFilter(std::function<bool(const gui::PopupRequestParams &)> f);
        void addAppDependentFilter(std::function<FilterType(const gui::PopupRequestParams &)> f);
        virtual bool isPermitted(const gui::PopupRequestParams &params) const;
        virtual bool addPopup(const gui::PopupRequestParams &params) const;
    };
} // namespace gui::popup

M module-apps/tests/windows/test-WindowsPopupFilter.cpp => module-apps/tests/windows/test-WindowsPopupFilter.cpp +5 -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 "WindowsPopupFilter.hpp"


@@ 14,7 14,8 @@ TEST_CASE("WindowsPopupQueue::isPermitted", "[!mayfail]")
    gui::popup::Filter filter;
    SECTION("filter is ok, there is not stack")
    {
        filter.addAppDependentFilter([](const gui::PopupRequestParams &) -> bool { return true; });
        filter.addAppDependentFilter(
            [](const gui::PopupRequestParams &) -> gui::popup::FilterType { return gui::popup::FilterType::Show; });
        REQUIRE(filter.isPermitted(prp));
    }



@@ 84,6 85,7 @@ TEST_CASE("WindowsPopupQueue::addAppDependentFilter")
    gui::popup::Filter filter;
    auto prp = gui::PopupRequestParams(gui::popup::ID::Alarm);
    // create filter that accepts nothing
    filter.addAppDependentFilter([](const gui::PopupRequestParams &) -> bool { return false; });
    filter.addAppDependentFilter(
        [](const gui::PopupRequestParams &) -> gui::popup::FilterType { return gui::popup::FilterType::Ignore; });
    REQUIRE(not filter.isPermitted(prp));
}

M products/BellHybrid/apps/Application.cpp => products/BellHybrid/apps/Application.cpp +1 -1
@@ 34,7 34,7 @@ namespace app
            if (val == true) {
                LOG_ERROR("block popup - as curent window is in higher order popup");
            }
            return !val;
            return val ? gui::popup::FilterType::Ignore : gui::popup::FilterType::Show;
        });
    }


M products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp => products/BellHybrid/apps/application-bell-main/ApplicationBellMain.cpp +8 -2
@@ 42,9 42,10 @@ namespace app
            const auto popupId = params.getPopupId();
            if (popupId == gui::popup::ID::Alarm || popupId == gui::popup::ID::AlarmActivated ||
                popupId == gui::popup::ID::AlarmDeactivated) {
                return gui::name::window::main_window != getCurrentWindow()->getName();
                return gui::name::window::main_window != getCurrentWindow()->getName() ? gui::popup::FilterType::Show
                                                                                       : gui::popup::FilterType::Remove;
            }
            return true;
            return gui::popup::FilterType::Show;
        });

        bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);


@@ 84,6 85,11 @@ namespace app
        });
        connect(typeid(AlarmDeactivated), [this](sys::Message *request) -> sys::MessagePointer {
            alarmModel->turnOff();
            alarmModel->activateAlarm(false);
            return sys::msgHandled();
        });
        connect(typeid(AlarmActivated), [this](sys::Message *request) -> sys::MessagePointer {
            alarmModel->activateAlarm(true);
            return sys::msgHandled();
        });
    }

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-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


@@ 33,6 33,7 @@ namespace app
        virtual std::chrono::seconds getTimeToNextSnooze()     = 0;
        virtual TimePoint getTimeOfNextSnooze()                = 0;
        virtual alarms::AlarmStatus getAlarmStatus()           = 0;
        virtual void activateAlarm(bool state)                 = 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 +2 -1
@@ 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


@@ 37,6 37,7 @@ namespace app
        bool isSnoozeActive() override;
        void turnOff() override;
        void snooze() override;
        void activateAlarm(bool state) override;
        std::chrono::seconds getTimeToNextSnooze() override;
        TimePoint getTimeOfNextSnooze() override;
        alarms::AlarmStatus getAlarmStatus() override;

M products/BellHybrid/apps/common/include/common/popups/AlarmDeactivatedWindow.hpp => products/BellHybrid/apps/common/include/common/popups/AlarmDeactivatedWindow.hpp +1 -1
@@ 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

M products/BellHybrid/apps/common/include/common/popups/presenter/AlarmActivatedPresenter.hpp => products/BellHybrid/apps/common/include/common/popups/presenter/AlarmActivatedPresenter.hpp +1 -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


@@ 36,11 36,8 @@ namespace app::popup
        {
          public:
            virtual ~Presenter() noexcept                                  = default;
            virtual void updateAlarmModel(AlarmModelReadyHandler callback) = 0;
            virtual time_t getAlarmTime() const noexcept                   = 0;
            virtual bool isAlarmActive() const noexcept                    = 0;
            virtual void activate()                                        = 0;
            virtual void deactivate()                                      = 0;
        };
    };



@@ 49,11 46,8 @@ namespace app::popup
      public:
        AlarmActivatedPresenter(AbstractAlarmModel &alarmModel);

        void updateAlarmModel(AlarmModelReadyHandler callback);
        time_t getAlarmTime() const noexcept;
        bool isAlarmActive() const noexcept;
        void activate();
        void deactivate();

      private:
        AbstractAlarmModel &alarmModel;

M products/BellHybrid/apps/common/src/AlarmModel.cpp => products/BellHybrid/apps/common/src/AlarmModel.cpp +9 -1
@@ 153,7 153,9 @@ namespace app
    {
        snoozeCount    = 0;
        nextSnoozeTime = TIME_POINT_INVALID;
        alarms::AlarmServiceAPI::requestTurnOffRingingAlarm(app, cachedRecord.parent->ID);
        if (cachedRecord.parent != nullptr) {
            alarms::AlarmServiceAPI::requestTurnOffRingingAlarm(app, cachedRecord.parent->ID);
        }
    }

    void AlarmModel::snooze()


@@ 220,6 222,12 @@ namespace app
        updateAlarm(*alarmEventPtr);
    }

    void AlarmModel::activateAlarm(bool state)
    {
        auto callback = [this, state]() { activate(state); };
        update(callback);
    }

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

M products/BellHybrid/apps/common/src/popups/AlarmActivatedWindow.cpp => products/BellHybrid/apps/common/src/popups/AlarmActivatedWindow.cpp +1 -4
@@ 28,10 28,6 @@ namespace gui
                                                                           std::move(presenter))
    {
        getPresenter()->attach(this);
        getPresenter()->updateAlarmModel([&]() {
            setAlarmTime(getPresenter()->getAlarmTime());
            getPresenter()->activate();
        });
        buildInterface();

        timerCallback = [this](Item &, sys::Timer &) {


@@ 56,6 52,7 @@ namespace gui

    void AlarmActivatedWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        setAlarmTime(getPresenter()->getAlarmTime());
        WindowWithTimer::onBeforeShow(mode, data);
    }


M products/BellHybrid/apps/common/src/popups/AlarmDeactivatedWindow.cpp => products/BellHybrid/apps/common/src/popups/AlarmDeactivatedWindow.cpp +0 -1
@@ 23,7 23,6 @@ namespace gui
    {
        getPresenter()->attach(this);
        buildInterface();
        getPresenter()->updateAlarmModel([&]() { getPresenter()->deactivate(); });

        timerCallback = [this](Item &, sys::Timer &) {
            returnToPreviousWindow();

M products/BellHybrid/apps/common/src/popups/presenter/AlarmActivatedPresenter.cpp => products/BellHybrid/apps/common/src/popups/presenter/AlarmActivatedPresenter.cpp +1 -15
@@ 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 <common/popups/presenter/AlarmActivatedPresenter.hpp>


@@ 21,18 21,4 @@ namespace app::popup
        return alarmModel.getAlarmTime();
    }

    void AlarmActivatedPresenter::activate()
    {
        return alarmModel.activate(true);
    }

    void AlarmActivatedPresenter::deactivate()
    {
        return alarmModel.activate(false);
    }

    void AlarmActivatedPresenter::updateAlarmModel(AlarmModelReadyHandler callback)
    {
        alarmModel.update(callback);
    }
} // namespace app::popup

M products/BellHybrid/services/time/AlarmOperations.cpp => products/BellHybrid/services/time/AlarmOperations.cpp +4 -4
@@ 181,10 181,6 @@ namespace alarms

    bool AlarmOperations::processPreWakeUp(TimePoint now)
    {
        if (nextSingleEvents.empty()) {
            return false;
        }

        auto nextEvent = getNextPreWakeUpEvent();
        if (!nextEvent.isValid()) {
            return false;


@@ 209,6 205,10 @@ namespace alarms

    SingleEventRecord AlarmOperations::getNextPreWakeUpEvent()
    {
        if (nextSingleEvents.empty()) {
            return {};
        }

        const auto event = *(nextSingleEvents.front());
        if (getAlarmEventType(event) != alarms::AlarmType::Clock) {
            return {};

M products/BellHybrid/sys/SystemManager.cpp => products/BellHybrid/sys/SystemManager.cpp +1 -1
@@ 32,7 32,7 @@ namespace sys
    {
        switch (request->getStatus()) {
        case AlarmActivationStatus::ACTIVATED:
            bus.sendUnicast(std::make_shared<AlarmActivated>(), service::name::appmgr);
            bus.sendMulticast(std::make_shared<AlarmActivated>(), sys::BusChannel::AlarmNotifications);
            break;
        case AlarmActivationStatus::DEACTIVATED:
            bus.sendMulticast(std::make_shared<AlarmDeactivated>(), sys::BusChannel::AlarmNotifications);