mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-10-26 00:18:31 -04:00
Due to vfs deprecation there is need to remove all vfs calls from code. This PR covers module gui. There are some modifications in other modules included which are necessary because of build system issues.
713 lines
28 KiB
C++
713 lines
28 KiB
C++
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include <service-appmgr/model/ApplicationManager.hpp>
|
|
#include <service-appmgr/Controller.hpp>
|
|
|
|
#include <module-apps/messages/AppMessage.hpp>
|
|
#include <Common.hpp>
|
|
#include <Common/Common.hpp>
|
|
#include <Service/Bus.hpp>
|
|
#include <Service/Message.hpp>
|
|
#include <Service/Timer.hpp>
|
|
#include <SystemManager/SystemManager.hpp>
|
|
#include <application-call/ApplicationCall.hpp>
|
|
#include <application-special-input/ApplicationSpecialInput.hpp>
|
|
#include <i18n/i18n.hpp>
|
|
#include <log/log.hpp>
|
|
#include <service-appmgr/messages/Message.hpp>
|
|
#include <service-db/DBServiceAPI.hpp>
|
|
#include <service-evtmgr/EventManager.hpp>
|
|
#include <service-gui/ServiceGUI.hpp>
|
|
#include <service-eink/Common.hpp>
|
|
#include <service-eink/ServiceEink.hpp>
|
|
#include <service-gui/Common.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <utility>
|
|
|
|
#include <module-utils/Utils.hpp>
|
|
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
|
|
// Auto phone lock disabled for now till the times when it's debugged
|
|
// #define AUTO_PHONE_LOCK_ENABLED
|
|
|
|
namespace app::manager
|
|
{
|
|
namespace
|
|
{
|
|
constexpr auto default_application_locktime_ms = 30000;
|
|
}; // namespace
|
|
|
|
ApplicationManagerBase::ApplicationManagerBase(std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers)
|
|
: applications{std::move(launchers)}
|
|
{}
|
|
|
|
void ApplicationManagerBase::setState(State _state) noexcept
|
|
{
|
|
state = _state;
|
|
}
|
|
|
|
void ApplicationManagerBase::pushApplication(const ApplicationName &name)
|
|
{
|
|
stack.push_front(name);
|
|
}
|
|
|
|
void ApplicationManagerBase::popApplication()
|
|
{
|
|
if (!stack.empty()) {
|
|
stack.pop_front();
|
|
}
|
|
}
|
|
|
|
void ApplicationManagerBase::clearStack()
|
|
{
|
|
stack.clear();
|
|
}
|
|
|
|
auto ApplicationManagerBase::getFocusedApplication() const noexcept -> ApplicationHandle *
|
|
{
|
|
for (const auto &appName : stack) {
|
|
if (auto app = getApplication(appName);
|
|
app != nullptr && app->state() == app::Application::State::ACTIVE_FORGROUND) {
|
|
return app;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
auto ApplicationManagerBase::getLaunchingApplication() const noexcept -> ApplicationHandle *
|
|
{
|
|
if (stack.empty()) {
|
|
return nullptr;
|
|
}
|
|
auto app = getApplication(stack.front());
|
|
return app->state() != app::Application::State::ACTIVE_FORGROUND ? app : nullptr;
|
|
}
|
|
|
|
auto ApplicationManagerBase::getPreviousApplication() const noexcept -> ApplicationHandle *
|
|
{
|
|
if (stack.size() < 2) {
|
|
return nullptr;
|
|
}
|
|
return getApplication(stack[1]);
|
|
}
|
|
|
|
auto ApplicationManagerBase::getApplication(const ApplicationName &name) const noexcept -> ApplicationHandle *
|
|
{
|
|
return applications.findByName(name);
|
|
}
|
|
|
|
ApplicationManager::ApplicationManager(const ApplicationName &serviceName,
|
|
std::vector<std::unique_ptr<app::ApplicationLauncher>> &&launchers,
|
|
const ApplicationName &_rootApplicationName)
|
|
: Service{serviceName}, ApplicationManagerBase(std::move(launchers)), rootApplicationName{_rootApplicationName},
|
|
blockingTimer{std::make_unique<sys::Timer>(
|
|
"BlockTimer", this, std::numeric_limits<sys::ms>::max(), sys::Timer::Type::SingleShot)},
|
|
settings(std::make_unique<settings::Settings>(this))
|
|
{
|
|
registerMessageHandlers();
|
|
blockingTimer->connect([this](sys::Timer &) { onPhoneLocked(); });
|
|
settings->registerValueChange(settings::SystemProperties::displayLanguage,
|
|
[this](std::string value) { displayLanguageChanged(value); });
|
|
settings->registerValueChange(settings::SystemProperties::inputLanguage,
|
|
[this](std::string value) { inputLanguageChanged(value); });
|
|
settings->registerValueChange(settings::SystemProperties::lockTime,
|
|
[this](std::string value) { lockTimeChanged(value); });
|
|
}
|
|
|
|
sys::ReturnCodes ApplicationManager::InitHandler()
|
|
{
|
|
blockingTimer->setInterval(default_application_locktime_ms);
|
|
utils::localize.setFallbackLanguage(utils::localize.DefaultLanguage);
|
|
utils::localize.setDisplayLanguage(displayLanguage);
|
|
utils::localize.setInputLanguage(inputLanguage);
|
|
|
|
startSystemServices();
|
|
startBackgroundApplications();
|
|
if (auto app = getApplication(rootApplicationName); app != nullptr) {
|
|
Controller::sendAction(this, actions::Home);
|
|
}
|
|
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
void ApplicationManager::startSystemServices()
|
|
{
|
|
if (bool ret = sys::SystemManager::CreateService(
|
|
std::make_shared<sgui::ServiceGUI>(service::name::gui, GetName(), 480, 600), this);
|
|
!ret) {
|
|
LOG_ERROR("Failed to initialize GUI service");
|
|
}
|
|
if (bool ret =
|
|
sys::SystemManager::CreateService(std::make_shared<ServiceEink>(service::name::eink, GetName()), this);
|
|
!ret) {
|
|
LOG_ERROR("Failed to initialize EInk service");
|
|
}
|
|
}
|
|
|
|
void ApplicationManager::suspendSystemServices()
|
|
{
|
|
sys::SystemManager::SuspendService(service::name::gui, this);
|
|
sys::SystemManager::SuspendService(service::name::eink, this);
|
|
}
|
|
|
|
void ApplicationManager::startBackgroundApplications()
|
|
{
|
|
for (const auto &name : std::vector<ApplicationName>{app::name_call, app::special_input}) {
|
|
if (auto app = getApplication(name); app != nullptr) {
|
|
app->runInBackground(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
sys::ReturnCodes ApplicationManager::DeinitHandler()
|
|
{
|
|
closeApplications();
|
|
closeServices();
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
auto ApplicationManager::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msgl,
|
|
[[maybe_unused]] sys::ResponseMessage *resp) -> sys::MessagePointer
|
|
{
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
}
|
|
|
|
void ApplicationManager::registerMessageHandlers()
|
|
{
|
|
connect(typeid(ApplicationStatusRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<ApplicationStatusRequest *>(request);
|
|
return std::make_shared<ApplicationStatusResponse>(msg->checkAppName,
|
|
getApplication(msg->checkAppName) != nullptr);
|
|
});
|
|
connect(typeid(PowerSaveModeInitRequest), [this](sys::Message *) {
|
|
handlePowerSavingModeInit();
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(PreventBlockingRequest), [this](sys::Message *) {
|
|
blockingTimer->reload();
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(SwitchRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<SwitchRequest *>(request);
|
|
handleSwitchApplication(msg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(SwitchBackRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<SwitchBackRequest *>(request);
|
|
handleSwitchBack(msg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(SwitchConfirmation), [this](sys::Message *request) {
|
|
auto msg = static_cast<SwitchConfirmation *>(request);
|
|
handleSwitchConfirmation(msg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(CloseConfirmation), [this](sys::Message *request) {
|
|
auto msg = static_cast<CloseConfirmation *>(request);
|
|
handleCloseConfirmation(msg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(ApplicationCloseRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<ApplicationCloseRequest *>(request);
|
|
closeApplication(applications.findByName(msg->getApplication()));
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(ApplicationInitialised), [this](sys::Message *request) {
|
|
auto msg = static_cast<ApplicationInitialised *>(request);
|
|
handleInitApplication(msg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(DisplayLanguageChangeRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<DisplayLanguageChangeRequest *>(request);
|
|
handleDisplayLanguageChange(msg);
|
|
return msgHandled();
|
|
});
|
|
connect(typeid(InputLanguageChangeRequest), [this](sys::Message *request) {
|
|
auto msg = static_cast<InputLanguageChangeRequest *>(request);
|
|
handleInputLanguageChange(msg);
|
|
return msgHandled();
|
|
});
|
|
connect(typeid(ShutdownRequest), [this](sys::Message *) {
|
|
closeApplications();
|
|
closeServices();
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
connect(typeid(ActionRequest), [this](sys::Message *request) {
|
|
auto actionMsg = static_cast<ActionRequest *>(request);
|
|
handleAction(actionMsg);
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
});
|
|
|
|
auto convertibleToActionHandler = [this](sys::Message *request) { return handleMessageAsAction(request); };
|
|
connect(typeid(CellularSimRequestPinMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularSimRequestPukMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularUnlockSimMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularBlockSimMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularDisplayCMEMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularMMIResultMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularMMIResponseMessage), convertibleToActionHandler);
|
|
connect(typeid(CellularMMIPushMessage), convertibleToActionHandler);
|
|
}
|
|
|
|
sys::ReturnCodes ApplicationManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
|
|
{
|
|
LOG_INFO("Power mode: %s", c_str(mode));
|
|
|
|
switch (mode) {
|
|
case sys::ServicePowerMode ::Active:
|
|
sys::SystemManager::ResumeService(service::name::eink, this);
|
|
sys::SystemManager::ResumeService(service::name::gui, this);
|
|
break;
|
|
case sys::ServicePowerMode ::SuspendToRAM:
|
|
[[fallthrough]];
|
|
case sys::ServicePowerMode ::SuspendToNVM:
|
|
suspendSystemServices();
|
|
break;
|
|
}
|
|
return sys::ReturnCodes::Success;
|
|
}
|
|
|
|
auto ApplicationManager::startApplication(ApplicationHandle &app) -> bool
|
|
{
|
|
if (app.state() == ApplicationHandle::State::ACTIVE_BACKGROUND) {
|
|
LOG_INFO("Switching focus to application [%s] (window [%s])", app.name().c_str(), app.switchWindow.c_str());
|
|
setState(State::AwaitingFocusConfirmation);
|
|
app::Application::messageSwitchApplication(this, app.name(), app.switchWindow, std::move(app.switchData));
|
|
}
|
|
else {
|
|
LOG_INFO("Starting application %s", app.name().c_str());
|
|
app.run(this);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::closeServices() -> bool
|
|
{
|
|
closeService(service::name::gui);
|
|
closeService(service::name::eink);
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::closeApplications() -> bool
|
|
{
|
|
for (const auto &app : getApplications()) {
|
|
if (app->started()) {
|
|
LOG_INFO("Closing application %s", app->name().c_str());
|
|
closeApplication(app.get());
|
|
app->setState(ApplicationHandle::State::DEACTIVATED);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ApplicationManager::closeService(const std::string &name)
|
|
{
|
|
bool ret = sys::SystemManager::DestroyService(name, this);
|
|
if (ret) {
|
|
LOG_INFO("Service/Application %s closed", name.c_str());
|
|
}
|
|
else {
|
|
LOG_FATAL("Service/Application %s is still running", name.c_str());
|
|
}
|
|
}
|
|
|
|
void ApplicationManager::closeApplication(ApplicationHandle *application)
|
|
{
|
|
if (application == nullptr) {
|
|
return;
|
|
}
|
|
|
|
closeService(application->name());
|
|
application->close();
|
|
}
|
|
|
|
auto ApplicationManager::handlePowerSavingModeInit() -> bool
|
|
{
|
|
LOG_INFO("Going to suspend mode");
|
|
suspendSystemServices();
|
|
sys::SystemManager::SuspendSystem(this);
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::handleSwitchApplication(SwitchRequest *msg, bool closeCurrentlyFocusedApp) -> bool
|
|
{
|
|
auto app = getApplication(msg->getName());
|
|
if (app == nullptr) {
|
|
LOG_ERROR("Failed to switch to application %s: No such application.", msg->getName().c_str());
|
|
return false;
|
|
}
|
|
|
|
auto currentlyFocusedApp = getFocusedApplication();
|
|
if (currentlyFocusedApp == nullptr) {
|
|
LOG_INFO("No focused application at the moment. Starting new application...");
|
|
onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
|
|
startApplication(*app);
|
|
return true;
|
|
}
|
|
|
|
if (app->name() == currentlyFocusedApp->name()) {
|
|
LOG_WARN("Failed to return to currently focused application.");
|
|
return false;
|
|
}
|
|
|
|
onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
|
|
const bool isFocusedAppCloseable =
|
|
closeCurrentlyFocusedApp && currentlyFocusedApp->closeable() && !currentlyFocusedApp->blockClosing;
|
|
requestApplicationClose(*currentlyFocusedApp, isFocusedAppCloseable);
|
|
return true;
|
|
}
|
|
|
|
void ApplicationManager::onApplicationSwitch(ApplicationHandle &app,
|
|
std::unique_ptr<gui::SwitchData> &&data,
|
|
std::string targetWindow)
|
|
{
|
|
if (app.name() == rootApplicationName) {
|
|
clearStack();
|
|
}
|
|
pushApplication(app.name());
|
|
app.switchData = std::move(data);
|
|
app.switchWindow = std::move(targetWindow);
|
|
}
|
|
|
|
void ApplicationManager::requestApplicationClose(ApplicationHandle &app, bool isCloseable)
|
|
{
|
|
if (isCloseable) {
|
|
LOG_INFO("Closing application %s", app.name().c_str());
|
|
setState(State::AwaitingCloseConfirmation);
|
|
app::Application::messageCloseApplication(this, app.name());
|
|
}
|
|
else {
|
|
LOG_INFO("Application %s is about to lose focus.", app.name().c_str());
|
|
setState(State::AwaitingLostFocusConfirmation);
|
|
app::Application::messageApplicationLostFocus(this, app.name());
|
|
}
|
|
}
|
|
|
|
auto ApplicationManager::handleAction(ActionRequest *actionMsg) -> bool
|
|
{
|
|
switch (const auto action = actionMsg->getAction(); action) {
|
|
case actions::Home:
|
|
return handleHomeAction();
|
|
case actions::Launch: {
|
|
auto params = static_cast<ApplicationLaunchData *>(actionMsg->getData().get());
|
|
return handleLaunchAction(params);
|
|
}
|
|
default: {
|
|
auto &actionParams = actionMsg->getData();
|
|
return handleCustomAction(action, std::move(actionParams));
|
|
}
|
|
}
|
|
}
|
|
|
|
auto ApplicationManager::handleHomeAction() -> bool
|
|
{
|
|
SwitchRequest switchRequest(ServiceName, rootApplicationName, gui::name::window::main_window, nullptr);
|
|
return handleSwitchApplication(&switchRequest);
|
|
}
|
|
|
|
auto ApplicationManager::handleLaunchAction(ApplicationLaunchData *launchParams) -> bool
|
|
{
|
|
auto targetApp = getApplication(launchParams->getTargetApplicationName());
|
|
if (targetApp == nullptr || !targetApp->handles(actions::Launch)) {
|
|
return false;
|
|
}
|
|
|
|
SwitchRequest switchRequest(ServiceName, targetApp->name(), gui::name::window::main_window, nullptr);
|
|
return handleSwitchApplication(&switchRequest);
|
|
}
|
|
|
|
auto ApplicationManager::handleCustomAction(actions::ActionId action, actions::ActionParamsPtr &&actionParams)
|
|
-> bool
|
|
{
|
|
const auto actionHandlers = applications.findByAction(action);
|
|
if (actionHandlers.empty()) {
|
|
LOG_ERROR("No applications handling action #%d.", action);
|
|
return false;
|
|
}
|
|
if (actionHandlers.size() > 1) {
|
|
LOG_FATAL("Choosing amongst multiple action handler applications is not yet implemented.");
|
|
return false;
|
|
}
|
|
|
|
const auto targetApp = actionHandlers.front();
|
|
if (targetApp->state() != ApplicationHandle::State::ACTIVE_FORGROUND) {
|
|
const auto focusedAppClose = !(actionParams && actionParams->disableAppClose);
|
|
pendingAction = std::make_tuple(targetApp->name(), action, std::move(actionParams));
|
|
|
|
SwitchRequest switchRequest(
|
|
ServiceName, targetApp->name(), targetApp->switchWindow, std::move(targetApp->switchData));
|
|
return handleSwitchApplication(&switchRequest, focusedAppClose);
|
|
}
|
|
|
|
app::Application::requestAction(this, targetApp->name(), action, std::move(actionParams));
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::handleSwitchBack(SwitchBackRequest *msg) -> bool
|
|
{
|
|
auto previousApp = getPreviousApplication();
|
|
if (previousApp == nullptr) {
|
|
LOG_WARN("Failed to switch to the previous application: No such application.");
|
|
return false;
|
|
}
|
|
|
|
auto currentlyFocusedApp = getFocusedApplication();
|
|
if (currentlyFocusedApp == nullptr) {
|
|
LOG_INFO("No focused application at the moment. Starting previous application...");
|
|
onApplicationSwitchToPrev(*previousApp, std::move(msg->getData()));
|
|
startApplication(*previousApp);
|
|
return true;
|
|
}
|
|
|
|
if (previousApp->name() == currentlyFocusedApp->name()) {
|
|
LOG_WARN("Failed to return to currently focused application.");
|
|
return false;
|
|
}
|
|
|
|
LOG_DEBUG("Switch applications: [%s][%s](%s) -> [%s][%s](%s)",
|
|
currentlyFocusedApp->name().c_str(),
|
|
currentlyFocusedApp->switchWindow.c_str(),
|
|
app::Application::stateStr(currentlyFocusedApp->state()),
|
|
previousApp->name().c_str(),
|
|
previousApp->switchWindow.c_str(),
|
|
app::Application::stateStr(previousApp->state()));
|
|
|
|
onApplicationSwitchToPrev(*previousApp, std::move(msg->getData()));
|
|
requestApplicationClose(*currentlyFocusedApp, currentlyFocusedApp->closeable());
|
|
return true;
|
|
}
|
|
|
|
void ApplicationManager::onApplicationSwitchToPrev(ApplicationHandle &previousApp,
|
|
std::unique_ptr<gui::SwitchData> &&data)
|
|
{
|
|
popApplication();
|
|
previousApp.switchData = std::move(data);
|
|
}
|
|
|
|
auto ApplicationManager::handleInitApplication(ApplicationInitialised *msg) -> bool
|
|
{
|
|
auto app = getApplication(msg->getSenderName());
|
|
if (app == nullptr) {
|
|
LOG_ERROR("Failed to register %s: No such application.", msg->getSenderName().c_str());
|
|
return false;
|
|
}
|
|
|
|
if (msg->getStatus() == StartupStatus::Success) {
|
|
onApplicationInitialised(*app, msg->isBackgroundApplication());
|
|
}
|
|
else {
|
|
onApplicationInitFailure(*app);
|
|
}
|
|
|
|
auto notification = std::make_shared<ApplicationStatusRequest>(GetName(), app->name());
|
|
sys::Bus::SendMulticast(notification, sys::BusChannels::AppManagerNotifications, this);
|
|
return true;
|
|
}
|
|
|
|
void ApplicationManager::onApplicationInitialised(ApplicationHandle &app, StartInBackground startInBackground)
|
|
{
|
|
LOG_DEBUG("Application %s initialised successfully.", app.name().c_str());
|
|
|
|
auto launchingApp = getLaunchingApplication();
|
|
if (launchingApp == nullptr || launchingApp->name() != app.name()) {
|
|
app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
|
|
return;
|
|
}
|
|
|
|
if (startInBackground) {
|
|
setState(State::Running);
|
|
app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
|
|
}
|
|
else {
|
|
LOG_INFO("Switch application to %s", app.name().c_str());
|
|
app.setState(ApplicationHandle::State::ACTIVATING);
|
|
setState(State::AwaitingFocusConfirmation);
|
|
app::Application::messageSwitchApplication(this, app.name(), app.switchWindow, std::move(app.switchData));
|
|
}
|
|
}
|
|
|
|
void ApplicationManager::onApplicationInitFailure(ApplicationHandle &app)
|
|
{
|
|
LOG_ERROR("Failed to initialise %s: Application internal error.", app.name().c_str());
|
|
Controller::switchBack(this);
|
|
}
|
|
|
|
auto ApplicationManager::handleDisplayLanguageChange(app::manager::DisplayLanguageChangeRequest *msg) -> bool
|
|
{
|
|
const auto &requestedLanguage = msg->getLanguage();
|
|
|
|
if (requestedLanguage == displayLanguage) {
|
|
LOG_WARN("The selected language is already set. Ignore.");
|
|
return false;
|
|
}
|
|
displayLanguage = requestedLanguage;
|
|
settings->setValue(settings::SystemProperties::displayLanguage, displayLanguage);
|
|
utils::localize.setDisplayLanguage(displayLanguage);
|
|
rebuildActiveApplications();
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::handleInputLanguageChange(app::manager::InputLanguageChangeRequest *msg) -> bool
|
|
{
|
|
const auto &requestedLanguage = msg->getLanguage();
|
|
|
|
if (requestedLanguage == inputLanguage) {
|
|
LOG_WARN("The selected language is already set. Ignore.");
|
|
return false;
|
|
}
|
|
inputLanguage = requestedLanguage;
|
|
settings->setValue(settings::SystemProperties::inputLanguage, inputLanguage);
|
|
utils::localize.setInputLanguage(inputLanguage);
|
|
return true;
|
|
}
|
|
|
|
void ApplicationManager::rebuildActiveApplications()
|
|
{
|
|
for (const auto &app : getApplications()) {
|
|
if (app && app->valid()) {
|
|
if (const auto appState = app->state(); appState == ApplicationHandle::State::ACTIVE_FORGROUND ||
|
|
appState == ApplicationHandle::State::ACTIVE_BACKGROUND) {
|
|
app::Application::messageRebuildApplication(this, app->name());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto ApplicationManager::handleSwitchConfirmation(SwitchConfirmation *msg) -> bool
|
|
{
|
|
auto senderApp = getApplication(msg->getSenderName());
|
|
if (senderApp == nullptr) {
|
|
LOG_ERROR("Failed to switch to %s. No such application.", msg->getSenderName().c_str());
|
|
return false;
|
|
}
|
|
LOG_INFO(
|
|
"Switch confirmed by %s (%s).", senderApp->name().c_str(), app::Application::stateStr(senderApp->state()));
|
|
return onSwitchConfirmed(*senderApp);
|
|
}
|
|
|
|
auto ApplicationManager::onSwitchConfirmed(ApplicationHandle &app) -> bool
|
|
{
|
|
if (getState() == State::AwaitingFocusConfirmation || getState() == State::Running) {
|
|
app.blockClosing = false;
|
|
app.setState(ApplicationHandle::State::ACTIVE_FORGROUND);
|
|
setState(State::Running);
|
|
EventManager::messageSetApplication(this, app.name());
|
|
|
|
auto &[appName, action, data] = pendingAction;
|
|
if (appName == app.name()) {
|
|
app::Application::requestAction(this, appName, action, std::move(data));
|
|
pendingAction = std::make_tuple(ApplicationName{}, 0, nullptr);
|
|
}
|
|
return true;
|
|
}
|
|
if (getState() == State::AwaitingLostFocusConfirmation) {
|
|
if (auto launchingApp = getLaunchingApplication(); launchingApp != nullptr) {
|
|
LOG_INFO("Lost focus confirmed by %s. Starting %s application.",
|
|
app.name().c_str(),
|
|
launchingApp->name().c_str());
|
|
app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
|
|
app.switchWindow.clear();
|
|
startApplication(*launchingApp);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
auto ApplicationManager::handleCloseConfirmation(CloseConfirmation *msg) -> bool
|
|
{
|
|
auto senderApp = getApplication(msg->getSenderName());
|
|
if (senderApp == nullptr) {
|
|
LOG_ERROR("Failed to handle close confirmation from %s: No such application.",
|
|
msg->getSenderName().c_str());
|
|
return false;
|
|
}
|
|
return onCloseConfirmed(*senderApp);
|
|
}
|
|
|
|
auto ApplicationManager::onCloseConfirmed(ApplicationHandle &app) -> bool
|
|
{
|
|
if (app.closeable()) {
|
|
app.setState(ApplicationHandle::State::DEACTIVATED);
|
|
Controller::closeApplication(this, app.name());
|
|
}
|
|
else {
|
|
app.setState(ApplicationHandle::State::ACTIVE_BACKGROUND);
|
|
}
|
|
|
|
if (const auto launchingApp = getLaunchingApplication();
|
|
launchingApp != nullptr && getState() == State::AwaitingCloseConfirmation) {
|
|
startApplication(*launchingApp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
auto ApplicationManager::handleMessageAsAction(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>
|
|
{
|
|
auto actionMsg = dynamic_cast<manager::actions::ConvertibleToAction *>(request);
|
|
if (!actionMsg) {
|
|
return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Failure);
|
|
}
|
|
auto action = actionMsg->toAction();
|
|
handleAction(action.get());
|
|
|
|
return std::make_shared<sys::ResponseMessage>();
|
|
}
|
|
|
|
void ApplicationManager::onPhoneLocked()
|
|
{
|
|
#ifdef AUTO_PHONE_LOCK_ENABLED
|
|
LOG_INFO("Screen lock timer triggered.");
|
|
blockingTimer->stop();
|
|
|
|
auto focusedApp = getFocusedApplication();
|
|
if (focusedApp == nullptr || focusedApp->preventsBlocking()) {
|
|
blockingTimer->reload();
|
|
return;
|
|
}
|
|
|
|
if (focusedApp->name() == rootApplicationName) {
|
|
app::Application::messageSwitchApplication(
|
|
this,
|
|
rootApplicationName,
|
|
gui::name::window::main_window,
|
|
std::make_unique<gui::LockPhoneData>(gui::LockPhoneData::Request::NoPin));
|
|
}
|
|
else {
|
|
focusedApp->blockClosing = true;
|
|
std::unique_ptr<gui::LockPhoneData> data =
|
|
std::make_unique<gui::LockPhoneData>(gui::LockPhoneData::Request::NoPin);
|
|
data->setPrevApplication(focusedApp->name());
|
|
Controller::switchApplication(this, rootApplicationName, gui::name::window::main_window, std::move(data));
|
|
}
|
|
#endif
|
|
}
|
|
void ApplicationManager::displayLanguageChanged(std::string value)
|
|
{
|
|
if (value.empty()) {
|
|
return;
|
|
}
|
|
displayLanguage = value;
|
|
utils::localize.setDisplayLanguage(displayLanguage);
|
|
rebuildActiveApplications();
|
|
}
|
|
void ApplicationManager::lockTimeChanged(std::string value)
|
|
{
|
|
if (value.empty()) {
|
|
return;
|
|
}
|
|
blockingTimer->setInterval(utils::getNumericValue<unsigned int>(value));
|
|
//?any additional action needed here?
|
|
}
|
|
void ApplicationManager::inputLanguageChanged(std::string value)
|
|
{
|
|
if (value.empty()) {
|
|
return;
|
|
}
|
|
inputLanguage = value;
|
|
utils::localize.setInputLanguage(value);
|
|
}
|
|
} // namespace app::manager
|