~aleteoryx/muditaos

0f3fb7c1528b8294edc1c85b82795bd2e03fe79a — Michał Kamoń 4 years ago 52d5a35
[EGD-6736] Add app's state dependent autoLock mechanism

This PR provides the implementation of the auto-locking mechanism that
is dependent on an application's current auto-locking policy. Three
auto-lock policies have been introduced:

* DetermineByWindow
* DetermineByAppState
* PreventPermanently

Also changed the AutoLockWindow set/get auto-lock time value to the
message-based approach.
34 files changed, 473 insertions(+), 146 deletions(-)

M image/user/db/settings_v2_002.sql
M module-apps/Application.cpp
M module-apps/Application.hpp
M module-apps/ApplicationLauncher.hpp
M module-apps/application-call/ApplicationCall.hpp
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-meditation/ApplicationMeditation.hpp
M module-apps/application-onboarding/ApplicationOnBoarding.hpp
M module-apps/application-settings-new/ApplicationSettings.cpp
M module-apps/application-settings-new/ApplicationSettings.hpp
A module-apps/application-settings-new/data/AutoLockData.hpp
M module-apps/application-settings-new/windows/AutolockWindow.cpp
M module-apps/application-settings-new/windows/AutolockWindow.hpp
M module-apps/locks/CMakeLists.txt
A module-apps/locks/handlers/LockPolicyHandler.cpp
A module-apps/locks/handlers/LockPolicyHandler.hpp
M module-apps/popups/PowerOffWindow.cpp
M module-apps/windows/AppWindow.cpp
M module-apps/windows/AppWindow.hpp
M module-services/service-appmgr/ApplicationManifest.cpp
M module-services/service-appmgr/doc/auto-lock/README.md
A module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.puml
A module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.svg
M module-services/service-appmgr/model/ApplicationHandle.cpp
M module-services/service-appmgr/model/ApplicationManager.cpp
M module-services/service-appmgr/model/ApplicationsRegistry.cpp
M module-services/service-appmgr/service-appmgr/ApplicationManifest.hpp
A module-services/service-appmgr/service-appmgr/messages/AutoLockRequests.hpp
M module-services/service-appmgr/service-appmgr/model/ApplicationHandle.hpp
M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp
M module-services/service-db/agents/settings/SystemSettings.hpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp
M source/main.cpp
M test/pytest/test_auto_lock.py
M image/user/db/settings_v2_002.sql => image/user/db/settings_v2_002.sql +1 -1
@@ 15,7 15,7 @@ INSERT OR IGNORE INTO settings_tab (path, value) VALUES
    ('gs_active_sim', 'SIM1'),
    ('gs_lock_pass_hash', '3333'),
    ('gs_lock_screen_passcode_is_on', '1'),
    ('gs_lock_time', '0'),
    ('gs_lock_time', '180'),
    ('gs_display_language', 'English'),
    ('gs_input_language', 'English'),
    ('gs_eula_accepted', '0'),

M module-apps/Application.cpp => module-apps/Application.cpp +7 -1
@@ 103,7 103,8 @@ namespace app
          default_window(gui::name::window::main_window), windowsStack(this),
          keyTranslator{std::make_unique<gui::KeyInputSimpleTranslation>()}, startInBackground{startInBackground},
          callbackStorage{std::make_unique<CallbackStorage>()}, topBarManager{std::make_unique<TopBarManager>()},
          settings(std::make_unique<settings::Settings>()), phoneMode{mode}, phoneLockSubject(this)
          settings(std::make_unique<settings::Settings>()), phoneMode{mode}, phoneLockSubject(this),
          lockPolicyHandler(this)
    {
        topBarManager->enableIndicators({gui::top_bar::Indicator::Time});
        using TimeMode = gui::top_bar::TimeConfiguration::TimeMode;


@@ 946,4 947,9 @@ namespace app
        return (utils::getNumericValue<bool>(
            settings->getValue(settings::SystemProperties::lockScreenPasscodeIsOn, settings::SettingsScope::Global)));
    }

    auto Application::getLockPolicyHandler() noexcept -> locks::LockPolicyHandlerInterface &
    {
        return lockPolicyHandler;
    }
} /* namespace app */

M module-apps/Application.hpp => module-apps/Application.hpp +12 -7
@@ 30,6 30,7 @@
#include <TopBarManager.hpp>
#include <popups/Popups.hpp>
#include <locks/handlers/PhoneLockSubject.hpp>
#include <locks/handlers/LockPolicyHandler.hpp>
#include "WindowsFactory.hpp"
#include "WindowsStack.hpp"



@@ 125,7 126,7 @@ namespace app
            NONE,
            /// Application: Object has been created and underlying service is waiting to execute init handler method.
            /// Application Manager: Launcher for the application has been provided. Application can be started using
            /// provided launcher. The other possibility is that Appication Manager received CLOSING_FINISHED message.
            /// provided launcher. The other possibility is that Application Manager received CLOSING_FINISHED message.
            DEACTIVATED,
            /// Application: Set after entering the init handler of the application. In this state application will
            /// request in a blocking way the db configuration of the phone. Before exiting the init handler application


@@ 186,12 187,12 @@ namespace app
        sys::TimerHandle longPressTimer;
        void clearLongPressTimeout();

        Application(std::string name,
                    std::string parent                  = "",
                    sys::phone_modes::PhoneMode mode    = sys::phone_modes::PhoneMode::Connected,
                    StartInBackground startInBackground = {false},
                    uint32_t stackDepth                 = 4096,
                    sys::ServicePriority priority       = sys::ServicePriority::Idle);
        explicit Application(std::string name,
                             std::string parent                  = "",
                             sys::phone_modes::PhoneMode mode    = sys::phone_modes::PhoneMode::Connected,
                             StartInBackground startInBackground = {false},
                             uint32_t stackDepth                 = 4096,
                             sys::ServicePriority priority       = sys::ServicePriority::Idle);

        virtual ~Application() noexcept;



@@ 400,11 401,15 @@ namespace app
        sys::phone_modes::PhoneMode phoneMode;

        locks::PhoneLockSubject phoneLockSubject;
        locks::LockPolicyHandler lockPolicyHandler;

      public:
        [[nodiscard]] auto getPhoneLockSubject() noexcept -> locks::PhoneLockSubject &;

        [[nodiscard]] bool isPhoneLockEnabled() const noexcept;

        [[nodiscard]] auto getLockPolicyHandler() noexcept -> locks::LockPolicyHandlerInterface &;

        const gui::top_bar::Configuration &getTopBarConfiguration() const noexcept;
    };


M module-apps/ApplicationLauncher.hpp => module-apps/ApplicationLauncher.hpp +17 -25
@@ 9,11 9,6 @@ namespace app
{
    using ApplicationManifest = app::manager::ApplicationManifest;

    enum class PreventAutoLocking : bool
    {
        False,
        True
    };
    enum class Closeable : bool
    {
        False,


@@ 33,16 28,17 @@ namespace app
        Closeable closeable = Closeable::False;
        /// defines whether application should be run without gaining focus, it will remian in the BACKGROUND state
        bool startBackground = false;
        /// flag defines whether this application can prevent auto-locking mechanism
        PreventAutoLocking preventAutoLocking = PreventAutoLocking::False;

        void setAutoLockPolicy() noexcept
        {
            if (handle != nullptr) {
                handle->getLockPolicyHandler().set(manifest.getAutoLockPolicy());
            }
        }

      public:
        ApplicationLauncher(std::string name,
                            ApplicationManifest &&manifest,
                            Closeable isCloseable,
                            PreventAutoLocking preventAutoLocking = PreventAutoLocking::False)
            : name{std::move(name)}, manifest{std::move(manifest)}, closeable{isCloseable}, preventAutoLocking{
                                                                                                preventAutoLocking} {};
        ApplicationLauncher(std::string name, ApplicationManifest &&manifest, Closeable isCloseable)
            : name{std::move(name)}, manifest{std::move(manifest)}, closeable{isCloseable} {};
        virtual ~ApplicationLauncher() = default;

        [[nodiscard]] std::string getName() const noexcept


@@ 60,9 56,9 @@ namespace app
            return (closeable == Closeable::True);
        }

        [[nodiscard]] bool isPreventAutoLockingOn() const noexcept
        [[nodiscard]] bool preventsAutoLocking() const noexcept
        {
            return (preventAutoLocking == PreventAutoLocking::True);
            return (handle == nullptr || handle->getLockPolicyHandler().preventsAutoLocking());
        }

        virtual bool run(sys::phone_modes::PhoneMode mode, sys::Service *caller = nullptr)


@@ 82,17 78,15 @@ namespace app
    template <class T> class ApplicationLauncherT : public ApplicationLauncher
    {
      public:
        ApplicationLauncherT(std::string name,
                             ApplicationManifest &&manifest,
                             Closeable isCloseable              = Closeable::True,
                             PreventAutoLocking preventBlocking = PreventAutoLocking::True)
            : ApplicationLauncher(name, std::move(manifest), isCloseable, preventBlocking)
        ApplicationLauncherT(std::string name, ApplicationManifest &&manifest, Closeable isCloseable = Closeable::True)
            : ApplicationLauncher(std::move(name), std::move(manifest), isCloseable)
        {}

        bool run(sys::phone_modes::PhoneMode mode, sys::Service *caller) override
        {
            parent = (caller == nullptr ? "" : caller->GetName());
            handle = std::make_shared<T>(name, parent, mode);
            setAutoLockPolicy();
            return sys::SystemManager::RunApplication(handle, caller);
        }



@@ 100,18 94,16 @@ namespace app
        {
            parent = (caller == nullptr ? "" : caller->GetName());
            handle = std::make_shared<T>(name, parent, mode, true);
            setAutoLockPolicy();
            return sys::SystemManager::RunApplication(handle, caller);
        }
    };

    /// creates application launcher per class provided
    template <class T>
    std::unique_ptr<ApplicationLauncherT<T>> CreateLauncher(
        std::string name,
        Closeable isCloseable                 = Closeable::True,
        PreventAutoLocking preventAutoLocking = PreventAutoLocking::False)
    std::unique_ptr<ApplicationLauncherT<T>> CreateLauncher(std::string name, Closeable isCloseable = Closeable::True)
    {
        return std::unique_ptr<ApplicationLauncherT<T>>(
            new ApplicationLauncherT<T>(name, ManifestOf<T>(), isCloseable, preventAutoLocking));
            new ApplicationLauncherT<T>(name, ManifestOf<T>(), isCloseable));
    }
} // namespace app

M module-apps/application-call/ApplicationCall.hpp => module-apps/application-call/ApplicationCall.hpp +2 -1
@@ 142,7 142,8 @@ namespace app
                     manager::actions::NotAnEmergencyNotification,
                     manager::actions::NoSimNotification,
                     manager::actions::CallRejectedByOfflineNotification,
                     manager::actions::PhoneModeChanged}};
                     manager::actions::PhoneModeChanged},
                    locks::AutoLockPolicy::PreventPermanently};
        }
    };
} /* namespace app */

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +0 -20
@@ 127,26 127,6 @@ namespace app
            switchWindow(app::window::name::logo_window, std::move(data));
            return actionHandled();
        });

        addActionReceiver(app::manager::actions::AutoLock, [this](auto &&data) {
            if (lockHandler.isScreenLocked()) {
                return actionHandled();
            }
            if (this->getState() == app::Application::State::ACTIVE_FORGROUND) {
                ///> we cannot block on all windows
                if (getCurrentWindow()->getName() == gui::name::window::main_window ||
                    getCurrentWindow()->getName() == app::window::name::desktop_menu) {
                    lockHandler.lockScreen();
                    switchWindow(app::window::name::desktop_main_window, std::move(data));
                }
            }
            else {
                lockHandler.lockScreen();
                switchWindow(app::window::name::desktop_main_window, std::move(data));
            }

            return actionHandled();
        });
    }

    // Invoked upon receiving data message

M module-apps/application-meditation/ApplicationMeditation.hpp => module-apps/application-meditation/ApplicationMeditation.hpp +2 -1
@@ 33,7 33,8 @@ namespace app
    {
        static auto GetManifest() -> manager::ApplicationManifest
        {
            return {{manager::actions::Launch, manager::actions::PhoneModeChanged}};
            return {{manager::actions::Launch, manager::actions::PhoneModeChanged},
                    locks::AutoLockPolicy::PreventPermanently};
        }
    };
} // namespace app

M module-apps/application-onboarding/ApplicationOnBoarding.hpp => module-apps/application-onboarding/ApplicationOnBoarding.hpp +2 -1
@@ 47,7 47,8 @@ namespace app
    {
        static auto GetManifest() -> manager::ApplicationManifest
        {
            return {{manager::actions::Launch, manager::actions::PhoneModeChanged}};
            return {{manager::actions::Launch, manager::actions::PhoneModeChanged},
                    locks::AutoLockPolicy::PreventPermanently};
        }
    };
} // namespace app

M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +13 -7
@@ 56,6 56,7 @@
#include <application-settings-new/data/PhoneNameData.hpp>
#include <application-settings-new/data/PINSettingsLockStateData.hpp>
#include <application-settings-new/windows/BluetoothCheckPasskeyWindow.hpp>
#include <application-settings-new/data/AutoLockData.hpp>

#include <service-evtmgr/EventManagerServiceAPI.hpp>
#include <service-cellular/CellularServiceAPI.hpp>


@@ 300,6 301,12 @@ namespace app
            return sys::MessageNone{};
        });

        connect(typeid(manager::GetAutoLockTimeoutResponse), [&](sys::Message *msg) {
            auto response = static_cast<manager::GetAutoLockTimeoutResponse *>(msg);
            auto data     = std::make_unique<gui::AutoLockData>(response->getValue());
            updateWindow(gui::window::name::autolock, std::move(data));
            return sys::MessageNone{};
        });
        createUserInterface();

        settings->registerValueChange(settings::operators_on,


@@ 694,17 701,16 @@ namespace app
        CellularServiceAPI::SetConnectionFrequency(this, val);
    }

    auto ApplicationSettingsNew::getAutoLockTime() const noexcept -> std::chrono::milliseconds
    void ApplicationSettingsNew::getAutoLockTime()
    {
        return std::chrono::milliseconds{utils::getNumericValue<unsigned int>(
            settings->getValue(::settings::SystemProperties::lockTime, ::settings::SettingsScope::Global))};
        bus.sendUnicast(std::make_shared<app::manager::GetAutoLockTimeoutRequest>(),
                        app::manager::ApplicationManager::ServiceName);
    }

    void ApplicationSettingsNew::setAutoLockTime(std::chrono::milliseconds lockTime) noexcept
    void ApplicationSettingsNew::setAutoLockTime(std::chrono::seconds lockTime)
    {
        settings->setValue(::settings::SystemProperties::lockTime,
                           std::to_string(lockTime.count()),
                           ::settings::SettingsScope::Global);
        bus.sendUnicast(std::make_shared<app::manager::SetAutoLockTimeoutRequest>(lockTime),
                        app::manager::ApplicationManager::ServiceName);
    }

    void ApplicationSettingsNew::switchToAllDevicesViaBtErrorPrompt(std::shared_ptr<sys::DataMessage> msg,

M module-apps/application-settings-new/ApplicationSettings.hpp => module-apps/application-settings-new/ApplicationSettings.hpp +4 -4
@@ 167,8 167,8 @@ namespace app
        class AutoLockSettings
        {
          public:
            virtual auto getAutoLockTime() const noexcept -> std::chrono::milliseconds = 0;
            virtual void setAutoLockTime(std::chrono::milliseconds lockTime) noexcept  = 0;
            virtual void getAutoLockTime()                              = 0;
            virtual void setAutoLockTime(std::chrono::seconds lockTime) = 0;
        };

    }; // namespace settingsInterface


@@ 236,8 236,8 @@ namespace app
        auto getConnectionFrequency() const noexcept -> uint8_t override;
        void setConnectionFrequency(uint8_t val) noexcept override;

        auto getAutoLockTime() const noexcept -> std::chrono::milliseconds override;
        void setAutoLockTime(std::chrono::milliseconds lockTime) noexcept override;
        void getAutoLockTime() override;
        void setAutoLockTime(std::chrono::seconds lockTime) override;

      private:
        void attachQuotesWindows();

A module-apps/application-settings-new/data/AutoLockData.hpp => module-apps/application-settings-new/data/AutoLockData.hpp +25 -0
@@ 0,0 1,25 @@
// 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 <SwitchData.hpp>
#include <service-appmgr/messages/AutoLockRequests.hpp>

namespace gui
{
    class AutoLockData : public gui::SwitchData
    {
        std::chrono::seconds value;

      public:
        explicit AutoLockData(std::chrono::seconds value) : value{value}
        {}

        [[nodiscard]] auto getValue() const noexcept
        {
            return value;
        }
    };

} // namespace gui

M module-apps/application-settings-new/windows/AutolockWindow.cpp => module-apps/application-settings-new/windows/AutolockWindow.cpp +24 -12
@@ 2,22 2,22 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AutolockWindow.hpp"
#include "OptionSetting.hpp"

#include <application-settings-new/data/AutoLockData.hpp>
#include <OptionSetting.hpp>
#include <i18n/i18n.hpp>

namespace gui
{
    namespace
    {
        const std::vector<std::pair<std::string, std::chrono::milliseconds>> autoLockTimes = {
            {"15s", std::chrono::milliseconds{15000}},
            {"30s", std::chrono::milliseconds{30000}},
            {"1m", std::chrono::milliseconds{60000}},
            {"2m", std::chrono::milliseconds{120000}},
            {"5m", std::chrono::milliseconds{300000}},
            {"10m", std::chrono::milliseconds{600000}},
            {"20m", std::chrono::milliseconds{1200000}}};
        const std::vector<std::pair<std::string, std::chrono::seconds>> autoLockTimes = {
            {"15s", std::chrono::seconds{15}},
            {"30s", std::chrono::seconds{30}},
            {"1m", std::chrono::minutes{1}},
            {"2m", std::chrono::minutes{2}},
            {"5m", std::chrono::minutes{5}},
            {"10m", std::chrono::minutes{10}},
            {"20m", std::chrono::minutes{20}}};
    } // namespace

    AutolockWindow::AutolockWindow(app::Application *app, app::settingsInterface::AutoLockSettings *autoLockSettings)


@@ 34,6 34,7 @@ namespace gui
                timeString,
                [=](gui::Item &item) {
                    autoLockSettings->setAutoLockTime(time);
                    currentAutoLockTimeout = time;
                    refreshOptionsList();
                    return true;
                },


@@ 45,11 46,22 @@ namespace gui
                    return true;
                },
                this,
                autoLockSettings->getAutoLockTime() == time ? gui::option::SettingRightItem::Checked
                                                            : gui::option::SettingRightItem::Disabled));
                currentAutoLockTimeout == time ? gui::option::SettingRightItem::Checked
                                               : gui::option::SettingRightItem::Disabled));
        }

        return optionsList;
    }

    void AutolockWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        if (auto autoLockData = dynamic_cast<const AutoLockData *>(data); data != nullptr) {
            currentAutoLockTimeout = autoLockData->getValue();
        }
        else if (mode == ShowMode::GUI_SHOW_INIT) {
            autoLockSettings->getAutoLockTime();
        }
        BaseSettingsWindow::onBeforeShow(mode, data);
    }

} // namespace gui

M module-apps/application-settings-new/windows/AutolockWindow.hpp => module-apps/application-settings-new/windows/AutolockWindow.hpp +2 -1
@@ 13,10 13,11 @@ namespace gui
    {
      public:
        AutolockWindow(app::Application *app, app::settingsInterface::AutoLockSettings *autoLockSettings);
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        auto buildOptionsList() -> std::list<Option> override;

        std::chrono::seconds currentAutoLockTimeout{0};
        app::settingsInterface::AutoLockSettings *autoLockSettings;
    };
} // namespace gui

M module-apps/locks/CMakeLists.txt => module-apps/locks/CMakeLists.txt +2 -0
@@ 17,6 17,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PinLockHandler.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PhoneLockHandler.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PhoneLockSubject.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/LockPolicyHandler.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/LockWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockBaseWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockWindow.cpp"


@@ 33,6 34,7 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PinLockHandler.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PhoneLockHandler.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/PhoneLockSubject.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/handlers/LockPolicyHandler.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/LockWindow.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockBaseWindow.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockWindow.hpp"

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

#include "LockPolicyHandler.hpp"
#include <log/log.hpp>
#include <Application.hpp>
#include <gsl_assert>

using namespace locks;

AutoLockPolicy LockPolicyAccessInterface::get() const noexcept
{
    return autoLockingPolicy;
}

void LockPolicyAccessInterface::set(AutoLockPolicy policy) noexcept
{
    if (autoLockingPolicy != AutoLockPolicy::PreventPermanently) {
        autoLockingPolicy = policy;
    }
    else {
        LOG_ERROR("AutoLocking is prevented permanently");
    }
}

bool LockPolicyHandlerInterface::preventsAutoLocking()
{
    if (const auto policy = get(); policy == AutoLockPolicy::DetermineByWindow) {
        return preventsAutoLockByWindow();
    }
    else if (policy == AutoLockPolicy::DetermineByAppState) {
        return preventsAutoLockByState() || preventsAutoLockByWindow();
    }
    return true;
}

LockPolicyHandler::LockPolicyHandler(app::Application *owner,
                                     std::function<bool()> preventsAutoLockByStateCallback) noexcept
    : owner{owner}, preventsAutoLockByStateCallback(std::move(preventsAutoLockByStateCallback))
{
    Expects(owner != nullptr);
}

void LockPolicyHandler::setPreventsAutoLockByStateCallback(
    std::function<bool()> _preventsAutoLockByStateCallback) noexcept
{
    preventsAutoLockByStateCallback = std::move(_preventsAutoLockByStateCallback);
}
bool LockPolicyHandler::preventsAutoLockByWindow()
{
    return owner->getCurrentWindow()->preventsAutoLocking();
}
bool LockPolicyHandler::preventsAutoLockByState() const
{
    Expects(preventsAutoLockByStateCallback != nullptr);
    return preventsAutoLockByStateCallback();
}

A module-apps/locks/handlers/LockPolicyHandler.hpp => module-apps/locks/handlers/LockPolicyHandler.hpp +62 -0
@@ 0,0 1,62 @@
// 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 <functional>
namespace app
{
    class ApplicationLauncher;
    class Application;
} // namespace app

namespace locks
{

    enum class AutoLockPolicy
    {
        DetermineByWindow,   /// Default value causing an application to be locked automatically if currently displayed
                             /// window does not prevent it.
        DetermineByAppState, /// Policy that checks if both window and current application state allows for autolock.
        PreventPermanently   /// Permanent state in which an application cannot be locked automatically. Once set it
                             /// cannot be unset.
    };

    class LockPolicyAccessInterface
    {
        friend class app::ApplicationLauncher;
        AutoLockPolicy autoLockingPolicy = AutoLockPolicy::DetermineByWindow;
        void set(AutoLockPolicy policy) noexcept;

      protected:
        [[nodiscard]] AutoLockPolicy get() const noexcept;

      public:
        virtual ~LockPolicyAccessInterface() = default;
    };

    class LockPolicyHandlerInterface : public LockPolicyAccessInterface
    {
      protected:
        [[nodiscard]] virtual bool preventsAutoLockByWindow()      = 0;
        [[nodiscard]] virtual bool preventsAutoLockByState() const = 0;

      public:
        [[nodiscard]] bool preventsAutoLocking();
    };

    class LockPolicyHandler : public LockPolicyHandlerInterface
    {
        app::Application *owner = nullptr;
        std::function<bool()> preventsAutoLockByStateCallback;

        [[nodiscard]] bool preventsAutoLockByWindow() final;
        [[nodiscard]] bool preventsAutoLockByState() const final;

      public:
        explicit LockPolicyHandler(app::Application *owner,
                                   std::function<bool()> preventsAutoLockByStateCallback = nullptr) noexcept;

        void setPreventsAutoLockByStateCallback(std::function<bool()> _preventsAutoLockByStateCallback) noexcept;
    };

} // namespace locks

M module-apps/popups/PowerOffWindow.cpp => module-apps/popups/PowerOffWindow.cpp +2 -1
@@ 11,7 11,7 @@ namespace gui
    PowerOffWindow::PowerOffWindow(app::Application *app, std::unique_ptr<PowerOffPresenter> &&presenter)
        : DialogYesNo(app, popup::window::power_off_window), presenter(std::move(presenter))
    {
        topBar->configure(std::move(configureTopBar(application->getTopBarConfiguration())));
        topBar->configure(configureTopBar(application->getTopBarConfiguration()));
    }

    top_bar::Configuration PowerOffWindow::configureTopBar(top_bar::Configuration appConfiguration)


@@ 29,6 29,7 @@ namespace gui
        DialogMetadata metadata;
        metadata.action = [=]() -> bool {
            LOG_INFO("User call close system");
            preventsAutoLock = true;
            presenter->powerOff();
            return true;
        };

M module-apps/windows/AppWindow.cpp => module-apps/windows/AppWindow.cpp +5 -0
@@ 114,6 114,11 @@ namespace gui
        applyToTopBar(std::move(fn));
    }

    bool AppWindow::preventsAutoLocking() const noexcept
    {
        return preventsAutoLock;
    }

    bool AppWindow::updateTime()
    {
        applyToTopBar([](top_bar::Configuration configuration) {

M module-apps/windows/AppWindow.hpp => module-apps/windows/AppWindow.hpp +6 -0
@@ 51,6 51,11 @@ namespace gui
         */
        using TopBarConfigurationChangeFunction = std::function<top_bar::Configuration(top_bar::Configuration)>;

        /**
         * A flag that is set if current window state requires the phone to stay unlocked
         */
        bool preventsAutoLock = false;

      public:
        AppWindow() = delete;
        AppWindow(app::Application *app, std::string name);


@@ 67,6 72,7 @@ namespace gui
        bool updateSignalStrength();
        bool updateNetworkAccessTechnology();
        void updatePhoneMode(sys::phone_modes::PhoneMode mode);
        [[nodiscard]] bool preventsAutoLocking() const noexcept;
        virtual bool updateTime();
        void setTitle(const UTF8 &text);


M module-services/service-appmgr/ApplicationManifest.cpp => module-services/service-appmgr/ApplicationManifest.cpp +8 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "service-appmgr/Actions.hpp"


@@ 8,7 8,8 @@

namespace app::manager
{
    ApplicationManifest::ApplicationManifest(actions::ActionFilter _actions) : actions{std::move(_actions)}
    ApplicationManifest::ApplicationManifest(actions::ActionFilter _actions, AutoLockPolicy _startupAutoLockPolicy)
        : actions{std::move(_actions)}, startupAutoLockPolicy{_startupAutoLockPolicy}
    {}

    auto ApplicationManifest::contains(actions::ActionId action) const noexcept -> bool


@@ 16,4 17,9 @@ namespace app::manager
        auto it = std::find(actions.begin(), actions.end(), action);
        return it != actions.end();
    }

    [[nodiscard]] auto ApplicationManifest::getAutoLockPolicy() const noexcept -> AutoLockPolicy
    {
        return startupAutoLockPolicy;
    }
} // namespace app::manager

M module-services/service-appmgr/doc/auto-lock/README.md => module-services/service-appmgr/doc/auto-lock/README.md +10 -4
@@ 18,10 18,16 @@ The message is used as a trigger to restart the auto-lock timer, as shown on the

In some situations the phone cannot be locked automatically and thus the auto-locking mechanism provides the ability to detect
such cases. It is determined by a state of the currently focused application. There are three auto-lock policies that 
manage the state an application:
* `AllowAutoLocking` - the default value allowing an application to be locked automatically 
* `PreventTemporarily` - a non-permanent (usually tied to same window) state in which an application cannot be locked automatically
* `PreventPermanently` - a permanent state (usually tied to application's manifest) in which an application cannot be locked automatically. Once set, it cannot be changed.
manage the state an application, that should be stated in the Application's manifest:
* `DetermineByWindow` - the default value causing an application to be locked automatically if currently displayed window does not prevent it.
* `DetermineByAppState` - a policy that checks if both window and current application state allows for autolock.
* `PreventPermanently` - a permanent state in which an application cannot be locked automatically. Once set it cannot be unset.

Each Application has the `LockPolicyHandler` class that manages and enforces policies. In case of `DetermineByAppState` policy, 
an application should provide its own implementation of  the `preventsAutoLockByStateCallback` to the `LockPolicyHandler`. 
The policy, determined in the manifest, is set by `app::ApplicationLauncher` using `LockPolicyHandlerInterface`.

![](auto_lock_policy_handler_interface.svg)

## Locked-Phone interactions


A module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.puml => module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.puml +37 -0
@@ 0,0 1,37 @@
@startuml

skinparam linetype ortho

interface "LockPolicyHandlerInterface" as handlerInt
{
    {method}{abstract} # bool preventsAutoLockByWindow()
    {method}{abstract} # bool preventsAutoLockByState()
    {method} + bool preventsAutoLocking()
}

interface "LockPolicyAccessInterface" as access
{
    {field} - AutoLockPolicy policy
    {method} - void set()
    {method} + void get()
}

class "LockPolicyHandler" as handler
{
    {field} - preventsAutoLockByStateCallback
    {method} + void setPreventsAutoLockByStateCallback(...)
}

class "app::ApplicationLauncher" as launcher

class "app::Application" as app

access <|-- handlerInt
handlerInt <|-- handler

launcher..>app : <<creates>>
launcher-->access : <<friend>>
launcher-->handlerInt : <<use>>
app..>handler : <<creates>>

@enduml

A module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.svg => module-services/service-appmgr/doc/auto-lock/auto_lock_policy_handler_interface.svg +50 -0
@@ 0,0 1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="558px" preserveAspectRatio="none" style="width:408px;height:558px;" version="1.1" viewBox="0 0 408 558" width="408px" zoomAndPan="magnify"><defs><filter height="300%" id="f17wzgsgh6vm0a" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--class handlerInt--><rect fill="#FEFECE" filter="url(#f17wzgsgh6vm0a)" height="86.4141" id="handlerInt" style="stroke: #A80036; stroke-width: 1.5;" width="222" x="39" y="327"/><ellipse cx="63" cy="343" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M58.9219,338.7656 L58.9219,336.6094 L66.3125,336.6094 L66.3125,338.7656 L63.8438,338.7656 L63.8438,346.8438 L66.3125,346.8438 L66.3125,349 L58.9219,349 L58.9219,346.8438 L61.3906,346.8438 L61.3906,338.7656 L58.9219,338.7656 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="170" x="79" y="347.1543">LockPolicyHandlerInterface</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="40" x2="260" y1="359" y2="359"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="40" x2="260" y1="367" y2="367"/><polygon fill="#FFFF44" points="50,373.9023,54,377.9023,50,381.9023,46,377.9023" style="stroke: #B38D22; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="196" x="59" y="381.2104">bool preventsAutoLockByWindow()</text><polygon fill="#FFFF44" points="50,386.707,54,390.707,50,394.707,46,390.707" style="stroke: #B38D22; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="181" x="59" y="394.0151">bool preventsAutoLockByState()</text><ellipse cx="50" cy="404.5117" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="153" x="59" y="406.8198">bool preventsAutoLocking()</text><!--class access--><rect fill="#FEFECE" filter="url(#f17wzgsgh6vm0a)" height="86.4141" id="access" style="stroke: #A80036; stroke-width: 1.5;" width="195" x="82.5" y="133"/><ellipse cx="97.5" cy="149" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M93.4219,144.7656 L93.4219,142.6094 L100.8125,142.6094 L100.8125,144.7656 L98.3438,144.7656 L98.3438,152.8438 L100.8125,152.8438 L100.8125,155 L93.4219,155 L93.4219,152.8438 L95.8906,152.8438 L95.8906,144.7656 L93.4219,144.7656 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="163" x="111.5" y="153.1543">LockPolicyAccessInterface</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="83.5" x2="276.5" y1="165" y2="165"/><rect fill="none" height="6" style="stroke: #C82930; stroke-width: 1.0;" width="6" x="90.5" y="173.9023"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="118" x="102.5" y="179.2104">AutoLockPolicy policy</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="83.5" x2="276.5" y1="185.8047" y2="185.8047"/><rect fill="#F24D5C" height="6" style="stroke: #C82930; stroke-width: 1.0;" width="6" x="90.5" y="194.707"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="53" x="102.5" y="200.0151">void set()</text><ellipse cx="93.5" cy="210.5117" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="53" x="102.5" y="212.8198">void get()</text><!--class handler--><rect fill="#FEFECE" filter="url(#f17wzgsgh6vm0a)" height="73.6094" id="handler" style="stroke: #A80036; stroke-width: 1.5;" width="282" x="99" y="474"/><ellipse cx="179.75" cy="490" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M182.7188,495.6406 Q182.1406,495.9375 181.5,496.0781 Q180.8594,496.2344 180.1563,496.2344 Q177.6563,496.2344 176.3281,494.5938 Q175.0156,492.9375 175.0156,489.8125 Q175.0156,486.6875 176.3281,485.0313 Q177.6563,483.375 180.1563,483.375 Q180.8594,483.375 181.5,483.5313 Q182.1563,483.6875 182.7188,483.9844 L182.7188,486.7031 Q182.0938,486.125 181.5,485.8594 Q180.9063,485.5781 180.2813,485.5781 Q178.9375,485.5781 178.25,486.6563 Q177.5625,487.7188 177.5625,489.8125 Q177.5625,491.9063 178.25,492.9844 Q178.9375,494.0469 180.2813,494.0469 Q180.9063,494.0469 181.5,493.7813 Q182.0938,493.5 182.7188,492.9219 L182.7188,495.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="112" x="200.25" y="494.1543">LockPolicyHandler</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="100" x2="380" y1="506" y2="506"/><rect fill="none" height="6" style="stroke: #C82930; stroke-width: 1.0;" width="6" x="107" y="514.9023"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="191" x="119" y="520.2104">preventsAutoLockByStateCallback</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="100" x2="380" y1="526.8047" y2="526.8047"/><ellipse cx="110" cy="538.707" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="256" x="119" y="541.0151">void setPreventsAutoLockByStateCallback(...)</text><!--class launcher--><rect fill="#FEFECE" filter="url(#f17wzgsgh6vm0a)" height="48" id="launcher" style="stroke: #A80036; stroke-width: 1.5;" width="191" x="84.5" y="8"/><ellipse cx="99.5" cy="24" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M102.4688,29.6406 Q101.8906,29.9375 101.25,30.0781 Q100.6094,30.2344 99.9063,30.2344 Q97.4063,30.2344 96.0781,28.5938 Q94.7656,26.9375 94.7656,23.8125 Q94.7656,20.6875 96.0781,19.0313 Q97.4063,17.375 99.9063,17.375 Q100.6094,17.375 101.25,17.5313 Q101.9063,17.6875 102.4688,17.9844 L102.4688,20.7031 Q101.8438,20.125 101.25,19.8594 Q100.6563,19.5781 100.0313,19.5781 Q98.6875,19.5781 98,20.6563 Q97.3125,21.7188 97.3125,23.8125 Q97.3125,25.9063 98,26.9844 Q98.6875,28.0469 100.0313,28.0469 Q100.6563,28.0469 101.25,27.7813 Q101.8438,27.5 102.4688,26.9219 L102.4688,29.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="159" x="113.5" y="28.1543">app::ApplicationLauncher</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="85.5" x2="274.5" y1="40" y2="40"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="85.5" x2="274.5" y1="48" y2="48"/><!--class app--><rect fill="#FEFECE" filter="url(#f17wzgsgh6vm0a)" height="48" id="app" style="stroke: #A80036; stroke-width: 1.5;" width="133" x="264.5" y="249"/><ellipse cx="279.5" cy="265" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M282.4688,270.6406 Q281.8906,270.9375 281.25,271.0781 Q280.6094,271.2344 279.9063,271.2344 Q277.4063,271.2344 276.0781,269.5938 Q274.7656,267.9375 274.7656,264.8125 Q274.7656,261.6875 276.0781,260.0313 Q277.4063,258.375 279.9063,258.375 Q280.6094,258.375 281.25,258.5313 Q281.9063,258.6875 282.4688,258.9844 L282.4688,261.7031 Q281.8438,261.125 281.25,260.8594 Q280.6563,260.5781 280.0313,260.5781 Q278.6875,260.5781 278,261.6563 Q277.3125,262.7188 277.3125,264.8125 Q277.3125,266.9063 278,267.9844 Q278.6875,269.0469 280.0313,269.0469 Q280.6563,269.0469 281.25,268.7813 Q281.8438,268.5 282.4688,267.9219 L282.4688,270.6406 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="101" x="293.5" y="269.1543">app::Application</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="265.5" x2="396.5" y1="281" y2="281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="265.5" x2="396.5" y1="289" y2="289"/><!--link access to handlerInt--><path d="M171.75,239.05 C171.75,239.05 171.75,326.73 171.75,326.73 " fill="none" id="access-handlerInt" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="164.75,239.05,171.75,219.05,178.75,239.05,164.75,239.05" style="stroke: #A80036; stroke-width: 1.0;"/><!--link handlerInt to handler--><path d="M180,433.07 C180,433.07 180,473.91 180,473.91 " fill="none" id="handlerInt-handler" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="173,433.07,180,413.07,187,433.07,173,433.07" style="stroke: #A80036; stroke-width: 1.0;"/><!--link launcher to app--><path d="M275.7,32 C308.68,32 337.5,32 337.5,32 C337.5,32 337.5,243.57 337.5,243.57 " fill="none" id="launcher-app" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><polygon fill="#A80036" points="337.5,248.57,341.5,239.57,337.5,243.57,333.5,239.57,337.5,248.57" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="64" x="332" y="99.0669">«creates»</text><!--link launcher to access--><path d="M180,56.1 C180,56.1 180,127.87 180,127.87 " fill="none" id="launcher-access" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="180,132.87,184,123.87,180,127.87,176,123.87,180,132.87" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="52" x="181" y="99.0669">«friend»</text><!--link launcher to handlerInt--><path d="M84.31,32 C70.45,32 60.75,32 60.75,32 C60.75,32 60.75,321.85 60.75,321.85 " fill="none" id="launcher-handlerInt" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#A80036" points="60.75,326.85,64.75,317.85,60.75,321.85,56.75,317.85,60.75,326.85" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="39" x="7" y="180.5669">«use»</text><!--link app to handler--><path d="M322.75,297.13 C322.75,297.13 322.75,468.58 322.75,468.58 " fill="none" id="app-handler" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><polygon fill="#A80036" points="322.75,473.58,326.75,464.58,322.75,468.58,318.75,464.58,322.75,473.58" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="64" x="332" y="374.5669">«creates»</text><!--
@startuml

skinparam linetype ortho

interface "LockPolicyHandlerInterface" as handlerInt
{
    {method}{abstract} # bool preventsAutoLockByWindow()
    {method}{abstract} # bool preventsAutoLockByState()
    {method} + bool preventsAutoLocking()
}

interface "LockPolicyAccessInterface" as access
{
    {field} - AutoLockPolicy policy
    {method} - void set()
    {method} + void get()
}

class "LockPolicyHandler" as handler
{
    {field} - preventsAutoLockByStateCallback
    {method} + void setPreventsAutoLockByStateCallback(...)
}

class "app::ApplicationLauncher" as launcher

class "app::Application" as app

access <|- - handlerInt
handlerInt <|- - handler

launcher..>app : <<creates>>
launcher- ->access : <<friend>>
launcher- ->handlerInt : <<use>>
app..>handler : <<creates>>

@enduml

PlantUML version 1.2018.13(Mon Nov 26 18:11:51 CET 2018)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Java Version: 11.0.11+9-Ubuntu-0ubuntu2.20.04
Operating System: Linux
OS Version: 5.8.0-53-generic
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>
\ No newline at end of file

M module-services/service-appmgr/model/ApplicationHandle.cpp => module-services/service-appmgr/model/ApplicationHandle.cpp +2 -1
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-appmgr/model/ApplicationHandle.hpp>
#include <module-apps/ApplicationLauncher.hpp>

namespace app::manager
{


@@ 37,7 38,7 @@ namespace app::manager

    auto ApplicationHandle::preventsAutoLocking() const noexcept -> bool
    {
        return launcher->isPreventAutoLockingOn();
        return launcher->preventsAutoLocking();
    }

    auto ApplicationHandle::closeable() const noexcept -> bool

M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +51 -29
@@ 37,6 37,7 @@
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
#include <service-appmgr/messages/DOMRequest.hpp>
#include <service-appmgr/messages/GetAllNotificationsRequest.hpp>
#include <service-appmgr/messages/AutoLockRequests.hpp>
#include <service-db/DBNotificationMessage.hpp>
#include <module-db/queries/notifications/QueryNotificationsGetAll.hpp>



@@ 47,7 48,7 @@ namespace app::manager
    namespace
    {
        constexpr auto ApplicationManagerStackDepth = 3072;
        constexpr auto timerBlock                   = "BlockTimer";
        constexpr auto autoLockTimerName            = "AutoLockTimer";
    } // namespace

    ApplicationManagerBase::ApplicationManagerBase(std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers)


@@ 135,15 136,16 @@ namespace app::manager
        : Service{serviceName, {}, ApplicationManagerStackDepth},
          ApplicationManagerBase(std::move(launchers)), rootApplicationName{_rootApplicationName},
          actionsRegistry{[this](ActionEntry &action) { return handleAction(action); }}, notificationProvider(this),
          autoLockEnabled(false), settings(std::make_unique<settings::Settings>()),
          settings(std::make_unique<settings::Settings>()),
          phoneModeObserver(std::make_unique<sys::phone_modes::Observer>()),
          phoneLockHandler(locks::PhoneLockHandler(this, settings))
    {
        autoLockTimer = sys::TimerFactory::createSingleShotTimer(
            this, timerBlock, sys::timer::InfiniteTimeout, [this](sys::Timer &) { onPhoneLocked(); });
            this, autoLockTimerName, sys::timer::InfiniteTimeout, [this](sys::Timer &) { onPhoneLocked(); });
        bus.channels.push_back(sys::BusChannel::PhoneModeChanges);
        bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);
        bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);
        bus.channels.push_back(sys::BusChannel::PhoneLockChanges);
        bus.channels.push_back(sys::BusChannel::ServiceCellularNotifications);
        registerMessageHandlers();
    }


@@ 172,15 174,15 @@ namespace app::manager

        settings->registerValueChange(
            settings::SystemProperties::displayLanguage,
            [this](std::string value) { displayLanguageChanged(value); },
            [this](std::string value) { displayLanguageChanged(std::move(value)); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::inputLanguage,
            [this](std::string value) { inputLanguageChanged(value); },
            [this](std::string value) { inputLanguageChanged(std::move(value)); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::lockTime,
            [this](std::string value) { lockTimeChanged(value); },
            settings::SystemProperties::autoLockTimeInSec,
            [this](std::string value) { lockTimeChanged(std::move(value)); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            ::settings::SystemProperties::automaticDateAndTimeIsOn,


@@ 313,12 315,12 @@ namespace app::manager
            return std::make_shared<ApplicationStatusResponse>(msg->checkAppName,
                                                               getApplication(msg->checkAppName) != nullptr);
        });
        connect(typeid(PowerSaveModeInitRequest), [this](sys::Message *) {
        connect(typeid(PowerSaveModeInitRequest), [this]([[maybe_unused]] sys::Message *msg) {
            handlePowerSavingModeInit();
            return std::make_shared<sys::ResponseMessage>();
        });
        connect(typeid(PreventBlockingRequest), [this](sys::Message *) {
            if (autoLockEnabled) {
        connect(typeid(PreventBlockingRequest), [this]([[maybe_unused]] sys::Message *msg) {
            if (!phoneLockHandler.isPhoneLocked()) {
                autoLockTimer.start();
            }
            return std::make_shared<sys::ResponseMessage>();


@@ 423,7 425,6 @@ namespace app::manager
            handleDBResponse(response);
            return sys::msgHandled();
        });

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


@@ 440,6 441,10 @@ namespace app::manager
        connect(typeid(locks::DisablePhoneLock), [&](sys::Message *request) -> sys::MessagePointer {
            return phoneLockHandler.handleDisablePhoneLock();
        });
        connect(typeid(locks::UnlockedPhone), [&](sys::Message *request) -> sys::MessagePointer {
            autoLockTimer.start();
            return sys::msgHandled();
        });
        connect(typeid(locks::ChangePhoneLock),
                [&](sys::Message *request) -> sys::MessagePointer { return phoneLockHandler.handleChangePhoneLock(); });
        connect(typeid(locks::SetPhoneLock),


@@ 447,6 452,14 @@ namespace app::manager
        connect(typeid(locks::SkipSetPhoneLock), [&](sys::Message *request) -> sys::MessagePointer {
            return phoneLockHandler.handleSkipSetPhoneLock();
        });
        connect(typeid(GetAutoLockTimeoutRequest), [&](sys::Message *request) -> sys::MessagePointer {
            auto req = static_cast<GetAutoLockTimeoutRequest *>(request);
            return handleAutoLockGetRequest(req);
        });
        connect(typeid(SetAutoLockTimeoutRequest), [&](sys::Message *request) -> sys::MessagePointer {
            auto req = static_cast<SetAutoLockTimeoutRequest *>(request);
            return handleAutoLockSetRequest(req);
        });

        connect(typeid(sdesktop::developerMode::DeveloperModeRequest),
                [&](sys::Message *request) -> sys::MessagePointer { return handleDeveloperModeRequest(request); });


@@ 1125,10 1138,10 @@ namespace app::manager

    void ApplicationManager::onPhoneLocked()
    {
        if (!autoLockEnabled) {
        if (phoneLockHandler.isPhoneLocked()) {
            autoLockTimer.stop();
            return;
        }

        auto focusedApp = getFocusedApplication();
        if (focusedApp == nullptr || focusedApp->preventsAutoLocking()) {
            autoLockTimer.start();


@@ 1138,11 1151,7 @@ namespace app::manager
            autoLockTimer.start();
            return;
        }
        std::unique_ptr<gui::SwitchData> appSwitchData = std::make_unique<gui::SwitchData>("AutoLock");
        std::unique_ptr<ActionRequest> actionRequest =
            std::make_unique<ActionRequest>(rootApplicationName, actions::AutoLock, std::move(appSwitchData));
        handleActionRequest(actionRequest.get());
        autoLockTimer.start();
        phoneLockHandler.handleLockRequest();
    }

    void ApplicationManager::displayLanguageChanged(std::string value)


@@ 1154,22 1163,35 @@ namespace app::manager

    void ApplicationManager::lockTimeChanged(std::string value)
    {
        autoLockTimer.stop();
        /// It should not be allowed to set this timeout to less then 1s.
        if (utils::getNumericValue<unsigned int>(value) < 1000) {
            autoLockEnabled = false;
            LOG_ERROR("Auto-locking is disabled due to lock time setting %s\n", value.c_str());
        if (value.empty()) {
            LOG_ERROR("No value for auto-locking time period, request ignored");
            return;
        }
        ///> Something went wrong - reload timer
        if (value.empty()) {
            autoLockTimer.start();
        const auto interval = std::chrono::seconds{utils::getNumericValue<unsigned int>(value)};
        if (interval.count() == 0) {
            LOG_ERROR("Invalid auto-locking time period of 0s, request ignored");
            return;
        }
        autoLockEnabled     = true;
        const auto interval = std::chrono::milliseconds{utils::getNumericValue<unsigned int>(value)};
        autoLockTimer.restart(interval);
        //?any additional action needed here?
    }

    auto ApplicationManager::handleAutoLockGetRequest([[maybe_unused]] GetAutoLockTimeoutRequest *request)
        -> std::shared_ptr<sys::ResponseMessage>
    {
        auto intervalValue =
            settings->getValue(settings::SystemProperties::autoLockTimeInSec, settings::SettingsScope::Global);
        const auto interval = std::chrono::seconds{utils::getNumericValue<unsigned int>(intervalValue)};
        return std::make_shared<GetAutoLockTimeoutResponse>(interval);
    }
    auto ApplicationManager::handleAutoLockSetRequest(SetAutoLockTimeoutRequest *request)
        -> std::shared_ptr<sys::ResponseMessage>
    {
        auto interval = request->getValue();
        settings->setValue(settings::SystemProperties::autoLockTimeInSec,
                           utils::to_string(interval.count()),
                           settings::SettingsScope::Global);
        autoLockTimer.restart(interval);
        return std::make_shared<sys::ResponseMessage>();
    }

    void ApplicationManager::inputLanguageChanged(std::string value)

M module-services/service-appmgr/model/ApplicationsRegistry.cpp => module-services/service-appmgr/model/ApplicationsRegistry.cpp +2 -1
@@ 1,7 1,8 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-appmgr/model/ApplicationsRegistry.hpp>
#include <module-apps/ApplicationLauncher.hpp>

namespace app::manager
{

M module-services/service-appmgr/service-appmgr/ApplicationManifest.hpp => module-services/service-appmgr/service-appmgr/ApplicationManifest.hpp +9 -3
@@ 1,19 1,25 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// 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 "service-appmgr/Actions.hpp"
#include <locks/handlers/LockPolicyHandler.hpp>

namespace app::manager
{
    struct ApplicationManifest
    {
        ApplicationManifest(actions::ActionFilter _actions = {});
        using AutoLockPolicy = locks::AutoLockPolicy;
        ApplicationManifest(actions::ActionFilter _actions        = {},
                            AutoLockPolicy _startupAutoLockPolicy = AutoLockPolicy::DetermineByWindow);

        auto contains(actions::ActionId action) const noexcept -> bool;
        [[nodiscard]] auto contains(actions::ActionId action) const noexcept -> bool;
        [[nodiscard]] auto getAutoLockPolicy() const noexcept -> AutoLockPolicy;

      private:
        /// Actions the application can respond to.
        actions::ActionFilter actions;
        AutoLockPolicy startupAutoLockPolicy = AutoLockPolicy::DetermineByWindow;
    };
} // namespace app::manager

A module-services/service-appmgr/service-appmgr/messages/AutoLockRequests.hpp => module-services/service-appmgr/service-appmgr/messages/AutoLockRequests.hpp +44 -0
@@ 0,0 1,44 @@
// 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 "BaseMessage.hpp"

namespace app::manager
{

    class GetAutoLockTimeoutRequest : public BaseMessage
    {
      public:
    };

    class GetAutoLockTimeoutResponse : public sys::ResponseMessage
    {
        std::chrono::seconds value;

      public:
        explicit GetAutoLockTimeoutResponse(std::chrono::seconds value) : value{value}
        {}

        [[nodiscard]] auto getValue() const noexcept
        {
            return value;
        }
    };

    class SetAutoLockTimeoutRequest : public BaseMessage
    {
        std::chrono::seconds value;

      public:
        explicit SetAutoLockTimeoutRequest(std::chrono::seconds value) : value{value}
        {}

        [[nodiscard]] auto getValue() const noexcept
        {
            return value;
        }
    };

} // namespace app::manager

M module-services/service-appmgr/service-appmgr/model/ApplicationHandle.hpp => module-services/service-appmgr/service-appmgr/model/ApplicationHandle.hpp +0 -1
@@ 4,7 4,6 @@
#pragma once

#include <module-apps/Application.hpp>
#include <module-apps/ApplicationLauncher.hpp>

#include <memory>
#include <string>

M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp => module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp +4 -3
@@ 46,6 46,8 @@ namespace app
        class APMRegister;
        class APMSwitch;
        class APMSwitchPrevApp;
        class GetAutoLockTimeoutRequest;
        class SetAutoLockTimeoutRequest;
    } // namespace manager
} // namespace app



@@ 158,6 160,8 @@ namespace app::manager
        /// handles dom request by passing this request to application which should provide the dom
        auto handleDOMRequest(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;
        void handleStart(StartAllowedMessage *msg);
        auto handleAutoLockGetRequest(GetAutoLockTimeoutRequest *request) -> std::shared_ptr<sys::ResponseMessage>;
        auto handleAutoLockSetRequest(SetAutoLockTimeoutRequest *request) -> std::shared_ptr<sys::ResponseMessage>;

        void requestApplicationClose(ApplicationHandle &app, bool isCloseable);
        void onApplicationSwitch(ApplicationHandle &app,


@@ 180,9 184,6 @@ namespace app::manager
        ActionsRegistry actionsRegistry;
        notifications::NotificationProvider notificationProvider;

        bool autoLockEnabled; ///< a flag which indicates whether the autoLockTimer should be armed.
                              /// @note: The flag value depends on database settings "gs_lock_time". If the
                              /// "gs_lock_time" is set to less than 1000 ms, it will be false, otherwise true.
        sys::TimerHandle autoLockTimer; //< auto-lock timer to count time from last user's activity.
                                        // If it reaches time defined in settings database application
                                        // manager is sending signal to Application Desktop in order to

M module-services/service-db/agents/settings/SystemSettings.hpp => module-services/service-db/agents/settings/SystemSettings.hpp +1 -1
@@ 12,7 12,7 @@ namespace settings
        constexpr inline auto usbSecurity              = "gs_usb_security";
        constexpr inline auto usbDevices               = "gs_usb_devices";
        constexpr inline auto lockScreenPasscodeIsOn   = "gs_lock_screen_passcode_is_on";
        constexpr inline auto lockTime                 = "gs_lock_time";
        constexpr inline auto autoLockTimeInSec        = "gs_lock_time";
        constexpr inline auto displayLanguage          = "gs_display_language";
        constexpr inline auto inputLanguage            = "gs_input_language";
        constexpr inline auto automaticDateAndTimeIsOn = "gs_automatic_date_and_time_is_on";

M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp +1 -1
@@ 79,7 79,7 @@ auto DeveloperModeHelper::processPut(Context &context) -> ProcessResult
    else if (body[json::developerMode::changeAutoLockTimeout].is_string()) {
        auto value = body[json::developerMode::changeAutoLockTimeout].string_value();
        settings::EntryPath path;
        path.variable = settings::SystemProperties::lockTime;
        path.variable = settings::SystemProperties::autoLockTimeInSec;
        path.service  = service::name::db;
        path.scope    = settings::SettingsScope::Global;
        auto msg      = std::make_shared<settings::Messages::SetVariable>(std::move(path), std::move(value));

M source/main.cpp => source/main.cpp +3 -5
@@ 26,7 26,6 @@
#include <service-audio/ServiceAudio.hpp>
#include <service-bluetooth/ServiceBluetooth.hpp>
#include <service-db/ServiceDB.hpp>
#include <service-evtmgr/Constants.hpp>
#include <service-evtmgr/EventManager.hpp>
#include <service-lwip/ServiceLwIP.hpp>
#include <service-time/ServiceTime.hpp>


@@ 127,8 126,7 @@ int main()
                app::CreateLauncher<app::ApplicationDesktop>(app::name_desktop, app::Closeable::False));
#endif
#ifdef ENABLE_APP_CALL
            applications.push_back(app::CreateLauncher<app::ApplicationCall>(
                app::name_call, app::Closeable::False, app::PreventAutoLocking::True));
            applications.push_back(app::CreateLauncher<app::ApplicationCall>(app::name_call, app::Closeable::False));
#endif
#ifdef ENABLE_APP_SETTINGS
            applications.push_back(app::CreateLauncher<app::ApplicationSettings>(app::name_settings));


@@ 162,8 160,8 @@ int main()
            applications.push_back(app::CreateLauncher<app::ApplicationMusicPlayer>(app::name_music_player));
#endif
#ifdef ENABLE_APP_MEDITATION
            applications.push_back(app::CreateLauncher<app::ApplicationMeditation>(
                app::name_meditation, app::Closeable::True, app::PreventAutoLocking::True));
            applications.push_back(
                app::CreateLauncher<app::ApplicationMeditation>(app::name_meditation, app::Closeable::True));
#endif
#ifdef ENABLE_APP_CALCULATOR
            applications.push_back(app::CreateLauncher<app::ApplicationCalculator>(app::name_calculator));

M test/pytest/test_auto_lock.py => test/pytest/test_auto_lock.py +6 -13
@@ 17,7 17,7 @@ def change_auto_lock_timer(harness, value: str):
@pytest.fixture(scope='function')
def phone_ends_with_default_auto_lock(harness):
    yield
    timeout = str(30000)
    timeout = str(180)
    log.info("Setting back default timeout to {}ms".format(timeout))
    change_auto_lock_timer(harness, timeout)



@@ 83,13 83,14 @@ def get_dom(harness):
    assert 'Window' in result['body']['dom']
    return result

@pytest.mark.skip("not fully implemented - should work after EGD-5884")
@pytest.mark.rt1051
@pytest.mark.usefixtures("phone_ends_test_in_desktop")
@pytest.mark.usefixtures("phone_in_desktop")
@pytest.mark.usefixtures("phone_ends_with_default_auto_lock")
@pytest.mark.usefixtures("phone_unlocked")
def test_auto_lock(harness):
    # change timer lock value
    change_auto_lock_timer(harness, str(5000))
    change_auto_lock_timer(harness, str(5))
    assert harness.get_application_name() == "ApplicationDesktop"

    time.sleep(6)


@@ 103,22 104,14 @@ def test_auto_lock(harness):
    # we should go back to previously chosen application
    assert harness.get_application_name() == app

    # go back
    harness.connection.send_key_code(key_codes["fnRight"])
    time.sleep(1)
    res = get_dom(harness)
    assert contains_value_recursively(res, 'WindowName', 'MenuWindow') is True

    # go back to main screen
    harness.connection.send_key_code(key_codes["fnRight"], Keytype.long_press)


@pytest.mark.rt1051
@pytest.mark.usefixtures("phone_ends_test_in_desktop")
@pytest.mark.usefixtures("phone_ends_with_default_auto_lock")
@pytest.mark.usefixtures("phone_unlocked")
def test_no_auto_lock_for_meditation_app(harness):
    # change timer lock value
    change_auto_lock_timer(harness, str(5000))
    change_auto_lock_timer(harness, str(5))
    assert harness.get_application_name() == "ApplicationDesktop"

    time.sleep(6)