M enabled_unittests => enabled_unittests +1 -0
@@ 25,6 25,7 @@ TESTS_LIST["catch2-actions-registry-tests"]="
Given actions registry when enqueue multiple actions at once then count handled actions;
Given actions registry when enqueue multiple actions at once then wait for them to expire.;
Given actions registry when enqueue multiple actions at once then process the specific ones only.;
+ Process the specific actions only and skip others.;
"
#---------
TESTS_LIST["catch2-audio-test"]="
M image/assets/lang/English.json => image/assets/lang/English.json +3 -1
@@ 578,5 578,7 @@
"app_desktop_update_in_progress": "Update in progress...",
"app_desktop_update_ready_for_reset": "Ready for reset...",
"app_desktop_update_success": "MuditaOS has been updated to ver. $VERSION succesfully.",
- "app_call_private_number": "Private number"
+ "app_call_private_number": "Private number",
+ "tethering": "Tethering",
+ "tethering_enable_question": "<text>You're connected to the computer.<br />Turn tethering on?<br /><text color='9'>(some functions may be disabled)</text></text>"
}
M module-apps/Application.cpp => module-apps/Application.cpp +35 -1
@@ 8,6 8,7 @@
#include "MessageType.hpp" // for MessageType
#include "module-sys/Timers/TimerFactory.hpp" // for Timer
#include "TopBar.hpp"
+#include "popups/TetheringConfirmationPopup.hpp"
#include "Translator.hpp" // for KeyInputSim...
#include "common_data/EventStore.hpp" // for Battery
#include "common_data/RawKey.hpp" // for RawKey, key...
@@ 115,6 116,20 @@ namespace app
[&](sys::phone_modes::PhoneMode phoneMode, sys::phone_modes::Tethering tetheringMode) {
handlePhoneModeChanged(phoneMode, tetheringMode);
});
+
+ addActionReceiver(app::manager::actions::ShowPopup, [this](auto &¶ms) {
+ auto popupParams = static_cast<app::PopupRequestParams *>(params.get());
+ if (const auto popupId = popupParams->getPopupId(); isPopupPermitted(popupId)) {
+ switchWindow(gui::popup::resolveWindowName(popupId));
+ }
+ return actionHandled();
+ });
+ addActionReceiver(app::manager::actions::AbortPopup, [this](auto &¶ms) {
+ auto popupParams = static_cast<app::PopupRequestParams *>(params.get());
+ const auto popupId = popupParams->getPopupId();
+ abortPopup(popupId);
+ return actionHandled();
+ });
}
Application::~Application() noexcept
@@ 647,7 662,6 @@ namespace app
void Application::messageCloseApplication(sys::Service *sender, std::string application)
{
-
auto msg = std::make_shared<AppMessage>(MessageType::AppClose);
sender->bus.sendUnicast(msg, application);
}
@@ 698,6 712,13 @@ namespace app
return std::make_unique<gui::VolumeWindow>(app, window::volume_window);
});
break;
+ case ID::Tethering:
+ windowsFactory.attach(window::tethering_confirmation_window,
+ [](Application *app, const std::string &name) {
+ return std::make_unique<gui::TetheringConfirmationPopup>(
+ app, window::tethering_confirmation_window);
+ });
+ break;
case ID::PhoneModes:
windowsFactory.attach(window::phone_modes_window, [](Application *app, const std::string &name) {
return std::make_unique<gui::HomeModesWindow>(app, window::phone_modes_window);
@@ 709,6 730,19 @@ namespace app
}
}
+ void Application::abortPopup(gui::popup::ID id)
+ {
+ const auto popupName = gui::popup::resolveWindowName(id);
+ if (getCurrentWindow()->getName() == popupName) {
+ returnToPreviousWindow();
+ }
+ }
+
+ bool Application::isPopupPermitted([[maybe_unused]] gui::popup::ID popupId) const
+ {
+ return true;
+ }
+
bool Application::popToWindow(const std::string &window)
{
if (window == gui::name::window::no_window) {
M module-apps/Application.hpp => module-apps/Application.hpp +21 -1
@@ 31,6 31,7 @@
#include "popups/Popups.hpp"
#include "WindowsFactory.hpp"
#include "WindowsStack.hpp"
+#include "Popups.hpp"
namespace app
{
@@ 176,6 177,8 @@ namespace app
sys::MessagePointer handleSIMMessage(sys::Message *msgl);
sys::MessagePointer handleAudioKeyMessage(sys::Message *msgl);
+ virtual bool isPopupPermitted(gui::popup::ID popupId) const;
+
std::list<std::unique_ptr<app::GuiTimer>> gui_timers;
std::unordered_map<manager::actions::ActionId, OnActionReceived> receivers;
@@ 331,6 334,7 @@ namespace app
/// Method used to attach popups windows to application
void attachPopups(const std::vector<gui::popup::ID> &popupsList);
+ void abortPopup(gui::popup::ID id);
public:
/// @ingrup AppWindowStack
@@ 399,7 403,7 @@ namespace app
class ApplicationLaunchData : public manager::actions::ActionParams
{
public:
- ApplicationLaunchData(const app::ApplicationName &appName)
+ explicit ApplicationLaunchData(const app::ApplicationName &appName)
: manager::actions::ActionParams{"Application launch parameters"}, targetAppName{appName}
{}
@@ 411,4 415,20 @@ namespace app
private:
ApplicationName targetAppName;
};
+
+ class PopupRequestParams : public manager::actions::ActionParams
+ {
+ public:
+ explicit PopupRequestParams(gui::popup::ID popupId)
+ : manager::actions::ActionParams{"Popup request parameters"}, popupId{popupId}
+ {}
+
+ [[nodiscard]] auto getPopupId() const noexcept
+ {
+ return popupId;
+ }
+
+ private:
+ gui::popup::ID popupId;
+ };
} /* namespace app */
M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +2 -0
@@ 28,9 28,11 @@ set( SOURCES
"windows/NoEvents.cpp"
"widgets/ButtonOnOff.cpp"
"widgets/InputBox.cpp"
+ "popups/Popups.cpp"
"popups/VolumeWindow.cpp"
"popups/WindowWithTimer.cpp"
"popups/HomeModesWindow.cpp"
+ "popups/TetheringConfirmationPopup.cpp"
"windows/BrightnessWindow.cpp"
"widgets/BrightnessBox.cpp"
"widgets/ModesBox.cpp"
M module-apps/application-alarm-clock/ApplicationAlarmClock.cpp => module-apps/application-alarm-clock/ApplicationAlarmClock.cpp +1 -1
@@ 108,7 108,7 @@ namespace app
style::alarmClock::window::name::dialogYesNo,
[](Application *app, const std::string &name) { return std::make_unique<gui::DialogYesNo>(app, name); });
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationAlarmClock::destroyUserInterface()
M module-apps/application-antenna/ApplicationAntenna.cpp => module-apps/application-antenna/ApplicationAntenna.cpp +1 -1
@@ 178,7 178,7 @@ namespace app
return std::make_unique<gui::AlgoParamsWindow>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationAntenna::destroyUserInterface()
M module-apps/application-calculator/ApplicationCalculator.cpp => module-apps/application-calculator/ApplicationCalculator.cpp +1 -1
@@ 43,7 43,7 @@ namespace app
return std::make_unique<gui::CalculatorMainWindow>(app, name);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationCalculator::destroyUserInterface()
M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +1 -1
@@ 143,7 143,7 @@ namespace app
return std::make_unique<gui::EventReminderWindow>(app, event_reminder_window);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationCalendar::destroyUserInterface()
M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +6 -1
@@ 84,6 84,11 @@ namespace app
});
}
+ bool ApplicationCall::isPopupPermitted(gui::popup::ID popupId) const
+ {
+ return getState() == call::State::IDLE;
+ }
+
// number of seconds after end call to switch back to previous application
const inline utils::time::Duration delayToSwitchToPreviousApp = 3;
@@ 232,7 237,7 @@ namespace app
windowsFactory.attach(app::window::name_dialogConfirm, [](Application *app, const std::string &name) {
return std::make_unique<gui::DialogConfirm>(app, name);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
bool ApplicationCall::showNotification(std::function<bool()> action,
M module-apps/application-call/ApplicationCall.hpp => module-apps/application-call/ApplicationCall.hpp +1 -0
@@ 86,6 86,7 @@ namespace app
sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override;
sys::ReturnCodes InitHandler() override;
sys::ReturnCodes DeinitHandler() override;
+ bool isPopupPermitted(gui::popup::ID popupId) const override;
sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override final
{
M module-apps/application-calllog/ApplicationCallLog.cpp => module-apps/application-calllog/ApplicationCallLog.cpp +1 -1
@@ 98,7 98,7 @@ namespace app
return std::make_unique<gui::DialogYesNo>(app, name);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationCallLog::destroyUserInterface()
M module-apps/application-clock/ApplicationClock.cpp => module-apps/application-clock/ApplicationClock.cpp +1 -1
@@ 86,7 86,7 @@ namespace app
return std::make_unique<gui::ClockMainWindow>(app, name);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationClock::destroyUserInterface()
M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +1 -1
@@ 493,7 493,7 @@ namespace app
return std::make_unique<gui::MmiInternalMsgWindow>(app, desktop_mmi_internal);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationDesktop::destroyUserInterface()
M module-apps/application-meditation/ApplicationMeditation.cpp => module-apps/application-meditation/ApplicationMeditation.cpp +1 -1
@@ 53,7 53,7 @@ namespace app
return std::make_unique<gui::PreparationTimeWindow>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationMeditation::destroyUserInterface()
M module-apps/application-meditation/windows/MeditationTimerWindow.cpp => module-apps/application-meditation/windows/MeditationTimerWindow.cpp +0 -1
@@ 75,7 75,6 @@ void MeditationTimerWindow::onBeforeShow(ShowMode mode, SwitchData *data)
timer->start();
application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
};
-
timer->registerTimeoutCallback(onPreparation);
timer->setCounterVisible(timerData->isCounterEnabled());
timer->reset(timerData->getPreparationTime());
M module-apps/application-messages/ApplicationMessages.cpp => module-apps/application-messages/ApplicationMessages.cpp +1 -1
@@ 160,7 160,7 @@ namespace app
return std::make_unique<gui::SearchResults>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationMessages::destroyUserInterface()
M module-apps/application-music-player/ApplicationMusicPlayer.cpp => module-apps/application-music-player/ApplicationMusicPlayer.cpp +1 -1
@@ 69,7 69,7 @@ namespace app
return std::make_unique<gui::MusicPlayerEmptyWindow>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationMusicPlayer::destroyUserInterface()
M module-apps/application-notes/ApplicationNotes.cpp => module-apps/application-notes/ApplicationNotes.cpp +1 -1
@@ 122,7 122,7 @@ namespace app
utils::localize.get("app_phonebook_options_title"),
[](Application *app, const std::string &name) { return std::make_unique<gui::OptionWindow>(app, name); });
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationNotes::destroyUserInterface()
M module-apps/application-onboarding/ApplicationOnBoarding.cpp => module-apps/application-onboarding/ApplicationOnBoarding.cpp +1 -1
@@ 139,7 139,7 @@ namespace app
return std::make_unique<gui::ChangeTimeZone>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationOnBoarding::destroyUserInterface()
M module-apps/application-phonebook/ApplicationPhonebook.cpp => module-apps/application-phonebook/ApplicationPhonebook.cpp +1 -1
@@ 147,7 147,7 @@ namespace app
return std::make_unique<gui::PhonebookNewContact>(app);
});
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationPhonebook::destroyUserInterface()
M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +1 -2
@@ 524,8 524,6 @@ namespace app
windowsFactory.attach(gui::window::name::quote_categories, [](Application *app, const std::string &name) {
return std::make_unique<gui::QuoteCategoriesWindow>(app);
});
-
- attachPopups({gui::popup::ID::Volume});
windowsFactory.attach(gui::window::name::phone_modes, [](Application *app, const std::string &name) {
return std::make_unique<gui::PhoneModesWindow>(
app, static_cast<ApplicationSettingsNew *>(app), static_cast<ApplicationSettingsNew *>(app));
@@ 539,6 537,7 @@ namespace app
windowsFactory.attach(gui::window::name::connection_frequency, [](Application *app, const std::string &name) {
return std::make_unique<gui::ConnectionFrequencyWindow>(app, static_cast<ApplicationSettingsNew *>(app));
});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering});
}
void ApplicationSettingsNew::destroyUserInterface()
M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +1 -1
@@ 163,7 163,7 @@ namespace app
});
}
- attachPopups({gui::popup::ID::Volume, gui::popup::ID::PhoneModes});
+ attachPopups({gui::popup::ID::Volume, gui::popup::ID::Tethering, gui::popup::ID::PhoneModes});
}
void ApplicationSettings::destroyUserInterface()
A => +22 -0
@@ 0,0 1,22 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "Popups.hpp"
namespace gui::popup
{
std::string resolveWindowName(ID id)
{
switch (id) {
case ID::Volume:
return gui::popup::window::volume_window;
case ID::PhoneModes:
return gui::popup::window::phone_modes_window;
case ID::Brightness:
return gui::popup::window::brightness_window;
case ID::Tethering:
return gui::popup::window::tethering_confirmation_window;
}
return {};
}
} // namespace gui::popup
M => +4 -0
@@ 17,6 17,7 @@ namespace gui
Volume,
PhoneModes,
Brightness,
Tethering
};
namespace window
@@ 24,6 25,9 @@ namespace gui
inline constexpr auto volume_window = "VolumePopup";
inline constexpr auto phone_modes_window = "PhoneModesPopup";
inline constexpr auto brightness_window = "BrightnessPopup";
inline constexpr auto tethering_confirmation_window = "TetheringConfirmationPopup";
} // namespace window
std::string resolveWindowName(ID id);
} // namespace popup
} // namespace gui
A => +32 -0
@@ 0,0 1,32 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "TetheringConfirmationPopup.hpp"
#include "DialogMetadataMessage.hpp"
#include "Application.hpp"
#include <module-sys/SystemManager/messages/TetheringQuestionRequest.hpp>
#include <service-appmgr/Controller.hpp>
namespace gui
{
TetheringConfirmationPopup::TetheringConfirmationPopup(app::Application *app, const std::string &name)
: DialogYesNo{app, name}
{}
void TetheringConfirmationPopup::onBeforeShow(ShowMode mode, [[maybe_unused]] SwitchData *data)
{
DialogMetadata metadata;
metadata.title = utils::translateI18("tethering");
metadata.text = utils::translateI18("tethering_enable_question");
metadata.icon = "info_big_circle_W_G";
metadata.action = [this]() {
application->bus.sendUnicast(std::make_shared<sys::TetheringEnabledResponse>(),
service::name::system_manager);
app::manager::Controller::sendAction(application, app::manager::actions::Home);
return true;
};
auto msg = std::make_unique<DialogMetadataMessage>(std::move(metadata));
DialogYesNo::onBeforeShow(mode, msg.get());
}
} // namespace gui
A => +19 -0
@@ 0,0 1,19 @@
// 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 <string>
#include "Dialog.hpp"
namespace gui
{
class TetheringConfirmationPopup : public DialogYesNo
{
public:
TetheringConfirmationPopup(app::Application *app, const std::string &name);
void onBeforeShow(ShowMode mode, SwitchData *data) override;
};
}; // namespace gui
M => +1 -0
@@ 3,6 3,7 @@
#include <module-gui/gui/input/InputEvent.hpp>
#include <i18n/i18n.hpp>
#include "Application.hpp"
#include "VolumeWindow.hpp"
#include "popups/data/PopupData.hpp"
M => +11 -2
@@ 3,9 3,12 @@
#pragma once
#include "Application.hpp"
#include "widgets/BarGraph.hpp"
#include "module-apps/widgets/BarGraph.hpp"
#include "WindowWithTimer.hpp"
#include <module-audio/Audio/AudioCommon.hpp>
#include <module-audio/Audio/Profiles/Profile.hpp>
#include <functional>
namespace style::window::volume
@@ 23,6 26,12 @@ namespace style::window::volume
} // namespace bar
} // namespace style::window::volume
namespace app
{
class Application;
} // namespace app
namespace gui
{
class VolumeWindow : public WindowWithTimer
M module-services/service-appmgr/model/ActionsRegistry.cpp => module-services/service-appmgr/model/ActionsRegistry.cpp +15 -3
@@ 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/model/ActionsRegistry.hpp>
@@ 70,13 70,25 @@ namespace app::manager
void ActionsRegistry::notifyAboutNextAction()
{
- for (auto &action : actions) {
- if (const auto handled = nextActionReady(action); handled) {
+ for (auto it = actions.begin(); it != actions.end();) {
+ auto &action = *it;
+ switch (const auto status = nextActionReady(action); status) {
+ case ActionProcessStatus::Accepted: {
LOG_INFO(
"Pending action %s to %s", magic_enum::enum_name(action.actionId).data(), action.target.c_str());
actionInProgress = &action;
return;
}
+ case ActionProcessStatus::Dropped: {
+ // Drop the action, so it'll not be processed again.
+ it = actions.erase(it);
+ break;
+ }
+ case ActionProcessStatus::Skipped:
+ // Skip the action and check the next one.
+ ++it;
+ break;
+ }
}
}
M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +38 -15
@@ 10,6 10,7 @@
#include <module-sys/Timers/TimerFactory.hpp>
#include <SystemManager/SystemManager.hpp>
#include <SystemManager/messages/SystemManagerMessage.hpp>
+#include <SystemManager/messages/TetheringQuestionRequest.hpp>
#include <application-call/ApplicationCall.hpp>
#include <application-special-input/ApplicationSpecialInput.hpp>
#include <application-desktop/ApplicationDesktop.hpp>
@@ 331,7 332,7 @@ namespace app::manager
});
connect(typeid(ActionHandledResponse), [this](sys::Message *response) {
actionsRegistry.finished();
- return nullptr;
+ return sys::MessageNone{};
});
connect(typeid(GetCurrentDisplayLanguageRequest), [&](sys::Message *request) {
return std::make_shared<GetCurrentDisplayLanguageResponse>(utils::localize.getDisplayLanguage());
@@ 364,6 365,8 @@ namespace app::manager
connect(typeid(sdesktop::passcode::ScreenPasscodeRequest), convertibleToActionHandler);
connect(typeid(CellularSMSRejectedByOfflineNotification), convertibleToActionHandler);
connect(typeid(CellularCallRejectedByOfflineNotification), convertibleToActionHandler);
+ connect(typeid(sys::TetheringQuestionRequest), convertibleToActionHandler);
+ connect(typeid(sys::TetheringQuestionAbort), convertibleToActionHandler);
}
sys::ReturnCodes ApplicationManager::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
@@ 467,15 470,17 @@ namespace app::manager
LOG_INFO("No focused application at the moment. Starting new application...");
onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
startApplication(*app);
- return true;
+ return false;
}
+ onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
if (app->name() == currentlyFocusedApp->name()) {
- LOG_WARN("Failed to return to currently focused application.");
+ // Switch window only.
+ app::Application::messageSwitchApplication(
+ this, app->name(), app->switchWindow, std::move(app->switchData));
return false;
}
- onApplicationSwitch(*app, std::move(msg->getData()), msg->getWindow());
const bool isFocusedAppCloseable =
closeCurrentlyFocusedApp && currentlyFocusedApp->closeable() && !currentlyFocusedApp->blockClosing;
requestApplicationClose(*currentlyFocusedApp, isFocusedAppCloseable);
@@ 514,48 519,65 @@ namespace app::manager
actionsRegistry.enqueue(std::move(entry));
}
- bool ApplicationManager::handleAction(ActionEntry &action)
+ ActionProcessStatus ApplicationManager::handleAction(ActionEntry &action)
{
switch (action.actionId) {
case actions::Home:
return handleHomeAction(action);
case actions::Launch:
return handleLaunchAction(action);
+ case actions::ShowPopup:
+ [[fallthrough]];
+ case actions::AbortPopup:
+ return handlePopupAction(action);
default:
return handleCustomAction(action);
}
}
- auto ApplicationManager::handleHomeAction(ActionEntry &action) -> bool
+ auto ApplicationManager::handleHomeAction(ActionEntry &action) -> ActionProcessStatus
{
action.setTargetApplication(rootApplicationName);
SwitchRequest switchRequest(ServiceName, rootApplicationName, gui::name::window::main_window, nullptr);
- return handleSwitchApplication(&switchRequest);
+ return handleSwitchApplication(&switchRequest) ? ActionProcessStatus::Accepted : ActionProcessStatus::Dropped;
}
- auto ApplicationManager::handleLaunchAction(ActionEntry &action) -> bool
+ auto ApplicationManager::handleLaunchAction(ActionEntry &action) -> ActionProcessStatus
{
auto launchParams = static_cast<ApplicationLaunchData *>(action.params.get());
auto targetApp = getApplication(launchParams->getTargetApplicationName());
if (targetApp == nullptr || !targetApp->handles(actions::Launch)) {
- return false;
+ return ActionProcessStatus::Dropped;
}
action.setTargetApplication(targetApp->name());
SwitchRequest switchRequest(ServiceName, targetApp->name(), gui::name::window::main_window, nullptr);
- return handleSwitchApplication(&switchRequest);
+ return handleSwitchApplication(&switchRequest) ? ActionProcessStatus::Accepted : ActionProcessStatus::Dropped;
}
- auto ApplicationManager::handleCustomAction(ActionEntry &action) -> bool
+ auto ApplicationManager::handlePopupAction(ActionEntry &action) -> ActionProcessStatus
+ {
+ auto targetApp = getFocusedApplication();
+ if (targetApp == nullptr) {
+ return ActionProcessStatus::Skipped;
+ }
+ action.setTargetApplication(targetApp->name());
+
+ auto ¶ms = action.params;
+ app::Application::requestAction(this, targetApp->name(), action.actionId, std::move(params));
+ return ActionProcessStatus::Accepted;
+ }
+
+ auto ApplicationManager::handleCustomAction(ActionEntry &action) -> ActionProcessStatus
{
const auto actionHandlers = applications.findByAction(action.actionId);
if (actionHandlers.empty()) {
LOG_ERROR("No applications handling action #%d.", action.actionId);
- return false;
+ return ActionProcessStatus::Dropped;
}
if (actionHandlers.size() > 1) {
LOG_FATAL("Choosing amongst multiple action handler applications is not yet implemented.");
- return false;
+ return ActionProcessStatus::Dropped;
}
const auto targetApp = actionHandlers.front();
@@ 565,11 587,12 @@ namespace app::manager
const auto focusedAppClose = !(actionParams && actionParams->disableAppClose);
SwitchRequest switchRequest(
ServiceName, targetApp->name(), targetApp->switchWindow, std::move(targetApp->switchData));
- return handleSwitchApplication(&switchRequest, focusedAppClose);
+ return handleSwitchApplication(&switchRequest, focusedAppClose) ? ActionProcessStatus::Accepted
+ : ActionProcessStatus::Skipped;
}
app::Application::requestAction(this, targetApp->name(), action.actionId, std::move(actionParams));
- return true;
+ return ActionProcessStatus::Accepted;
}
auto ApplicationManager::handleSwitchBack(SwitchBackRequest *msg) -> bool
M module-services/service-appmgr/service-appmgr/Actions.hpp => module-services/service-appmgr/service-appmgr/Actions.hpp +2 -0
@@ 60,6 60,8 @@ namespace app::manager
DisplayLogoAtExit,
SMSRejectedByOfflineNotification,
CallRejectedByOfflineNotification,
+ ShowPopup,
+ AbortPopup,
UserAction // The last enumerator in the Action enum.
// All user-defined actions shall have values greater than UserAction.
// All system-wide actions shall have values lesser than UserAction.
M module-services/service-appmgr/service-appmgr/model/ActionsRegistry.hpp => module-services/service-appmgr/service-appmgr/model/ActionsRegistry.hpp +9 -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
#pragma once
@@ 38,10 38,17 @@ namespace app::manager
bool operator==(const ActionEntry &lhs, const ActionEntry &rhs) noexcept;
bool operator!=(const ActionEntry &lhs, const ActionEntry &rhs) noexcept;
+ enum class ActionProcessStatus
+ {
+ Accepted,
+ Skipped,
+ Dropped
+ };
+
class ActionsRegistry
{
public:
- using OnNextActionReadyCallback = std::function<bool(ActionEntry &action)>;
+ using OnNextActionReadyCallback = std::function<ActionProcessStatus(ActionEntry &action)>;
explicit ActionsRegistry(OnNextActionReadyCallback &&callback);
M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp => module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp +5 -4
@@ 116,11 116,12 @@ namespace app::manager
// Message handlers
void registerMessageHandlers();
- bool handleAction(ActionEntry &action);
+ auto handleAction(ActionEntry &action) -> ActionProcessStatus;
void handleActionRequest(ActionRequest *actionMsg);
- auto handleHomeAction(ActionEntry &action) -> bool;
- auto handleLaunchAction(ActionEntry &action) -> bool;
- auto handleCustomAction(ActionEntry &action) -> bool;
+ auto handleHomeAction(ActionEntry &action) -> ActionProcessStatus;
+ auto handleLaunchAction(ActionEntry &action) -> ActionProcessStatus;
+ auto handlePopupAction(ActionEntry &action) -> ActionProcessStatus;
+ auto handleCustomAction(ActionEntry &action) -> ActionProcessStatus;
auto handleSwitchApplication(SwitchRequest *msg, bool closeCurrentlyFocusedApp = true) -> bool;
auto handleCloseConfirmation(CloseConfirmation *msg) -> bool;
auto handleSwitchConfirmation(SwitchConfirmation *msg) -> bool;
M module-services/service-appmgr/tests/test-ActionsRegistry.cpp => module-services/service-appmgr/tests/test-ActionsRegistry.cpp +41 -9
@@ 14,7 14,7 @@ TEST_CASE("Given actions registry when initialise it incorrectly then verify")
TEST_CASE("Given empty actions registry when verify its state then no pending actions")
{
- auto nextActionCallback = [](ActionEntry & /*entry*/) { return true; };
+ auto nextActionCallback = [](ActionEntry & /*entry*/) { return ActionProcessStatus::Accepted; };
ActionsRegistry registry{std::move(nextActionCallback)};
REQUIRE(!registry.hasPendingAction());
@@ 22,7 22,7 @@ TEST_CASE("Given empty actions registry when verify its state then no pending ac
TEST_CASE("Given actions registry when enqueue then check pending action")
{
- auto nextActionCallback = [](ActionEntry & /*entry*/) { return true; };
+ auto nextActionCallback = [](ActionEntry & /*entry*/) { return ActionProcessStatus::Accepted; };
ActionsRegistry registry{std::move(nextActionCallback)};
registry.enqueue(ActionEntry{actions::Launch});
@@ 35,7 35,7 @@ TEST_CASE("Given actions registry when enqueue then check if action was processe
bool handled = false;
auto nextActionCallback = [&handled](ActionEntry & /*entry*/) {
handled = true;
- return true;
+ return ActionProcessStatus::Accepted;
};
ActionsRegistry registry{std::move(nextActionCallback)};
@@ 45,7 45,7 @@ TEST_CASE("Given actions registry when enqueue then check if action was processe
TEST_CASE("Given actions registry when finished queued action then no pending actions")
{
- auto nextActionCallback = [](ActionEntry & /*entry*/) { return true; };
+ auto nextActionCallback = [](ActionEntry & /*entry*/) { return ActionProcessStatus::Accepted; };
ActionsRegistry registry{std::move(nextActionCallback)};
registry.enqueue(ActionEntry{actions::Launch});
@@ 58,7 58,7 @@ TEST_CASE("Given actions registry when enqueue multiple actions sequentially the
int counter = 0;
auto nextActionCallback = [&counter](ActionEntry & /*entry*/) {
++counter;
- return true;
+ return ActionProcessStatus::Accepted;
};
ActionsRegistry registry{std::move(nextActionCallback)};
@@ 79,7 79,7 @@ TEST_CASE("Given actions registry when enqueue multiple actions at once then cou
int counter = 0;
auto nextActionCallback = [&counter](ActionEntry & /*entry*/) {
++counter;
- return true;
+ return ActionProcessStatus::Accepted;
};
ActionsRegistry registry{std::move(nextActionCallback)};
@@ 104,7 104,7 @@ TEST_CASE("Given actions registry when enqueue multiple actions at once then cou
TEST_CASE("Given actions registry when enqueue multiple actions at once then wait for them to expire.")
{
- auto nextActionCallback = [](ActionEntry & /*entry*/) { return true; };
+ auto nextActionCallback = [](ActionEntry & /*entry*/) { return ActionProcessStatus::Accepted; };
ActionsRegistry registry{std::move(nextActionCallback)};
registry.enqueue(ActionEntry{actions::Launch});
@@ 126,9 126,9 @@ TEST_CASE("Given actions registry when enqueue multiple actions at once then pro
auto nextActionCallback = [&counter](ActionEntry &entry) {
if (entry.actionId == actions::UserAction) {
++counter;
- return true;
+ return ActionProcessStatus::Accepted;
}
- return false;
+ return ActionProcessStatus::Skipped;
};
ActionsRegistry registry{std::move(nextActionCallback)};
@@ 143,3 143,35 @@ TEST_CASE("Given actions registry when enqueue multiple actions at once then pro
REQUIRE(counter == 1);
REQUIRE(!registry.hasPendingAction());
}
+
+TEST_CASE("Process the specific actions only and skip others.")
+{
+ int acceptedCounter = 0;
+ int skippedCounter = 0;
+ int droppedCounter = 0;
+ auto nextActionCallback = [&acceptedCounter, &skippedCounter, &droppedCounter](ActionEntry &entry) {
+ if (entry.actionId == actions::UserAction) {
+ ++acceptedCounter;
+ return ActionProcessStatus::Accepted;
+ }
+ if (entry.actionId == actions::Home) {
+ ++skippedCounter;
+ return ActionProcessStatus::Skipped;
+ }
+ ++droppedCounter;
+ return ActionProcessStatus::Dropped;
+ };
+ ActionsRegistry registry{std::move(nextActionCallback)};
+
+ registry.enqueue(ActionEntry{actions::Launch});
+ REQUIRE(droppedCounter == 1);
+ REQUIRE(!registry.hasPendingAction());
+
+ registry.enqueue(ActionEntry{actions::Home});
+ REQUIRE(skippedCounter == 1);
+ REQUIRE(!registry.hasPendingAction());
+
+ registry.enqueue(ActionEntry{actions::UserAction});
+ registry.finished();
+ REQUIRE(acceptedCounter == 1);
+}
M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +3 -0
@@ 211,6 211,9 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
});
connect(sdesktop::usb::USBConfigured(), [&](sys::Message *msg) {
+ bus.sendUnicast(std::make_shared<sys::TetheringStateRequest>(sys::phone_modes::Tethering::On),
+ service::name::system_manager);
+
if (!usbSecurityModel->isSecurityEnabled()) {
LOG_INFO("Endpoint security disabled.");
return sys::MessageNone{};
M module-sys/PhoneModes/Subject.cpp => module-sys/PhoneModes/Subject.cpp +12 -6
@@ 19,18 19,22 @@ namespace sys::phone_modes
}
}
- void Subject::setMode(PhoneMode _phoneMode, Tethering _tetheringMode)
+ bool Subject::setMode(PhoneMode _phoneMode, Tethering _tetheringMode)
{
- if (const bool changed = changePhoneMode(_phoneMode) || changeTetheringMode(_tetheringMode); changed) {
+ const bool changed = changePhoneMode(_phoneMode) || changeTetheringMode(_tetheringMode);
+ if (changed) {
notifyChange();
}
+ return changed;
}
- void Subject::setPhoneMode(PhoneMode mode)
+ bool Subject::setPhoneMode(PhoneMode mode)
{
- if (const auto changed = changePhoneMode(mode); changed) {
+ const auto changed = changePhoneMode(mode);
+ if (changed) {
notifyChange();
}
+ return changed;
}
bool Subject::changePhoneMode(PhoneMode mode) noexcept
@@ 38,11 42,13 @@ namespace sys::phone_modes
return std::exchange(phoneMode, mode) != mode;
}
- void Subject::setTetheringMode(Tethering mode)
+ bool Subject::setTetheringMode(Tethering mode)
{
- if (const auto changed = changeTetheringMode(mode); changed) {
+ const auto changed = changeTetheringMode(mode);
+ if (changed) {
notifyChange();
}
+ return changed;
}
bool Subject::changeTetheringMode(Tethering mode) noexcept
M module-sys/PhoneModes/Subject.hpp => module-sys/PhoneModes/Subject.hpp +21 -3
@@ 17,9 17,27 @@ namespace sys::phone_modes
public:
explicit Subject(Service *owner);
- void setMode(PhoneMode _phoneMode, Tethering _tetheringMode);
- void setPhoneMode(PhoneMode mode);
- void setTetheringMode(Tethering mode);
+ /**
+ * Sets phone and tethering modes
+ * @param _phoneMode Phone mode
+ * @param _tetheringMode Tethering mode
+ * @return true if modes changed, false otherwise
+ */
+ bool setMode(PhoneMode _phoneMode, Tethering _tetheringMode);
+
+ /**
+ * Sets the phone mode
+ * @param mode Phone mode
+ * @return true if phone mode changed, false otherwise
+ */
+ bool setPhoneMode(PhoneMode mode);
+
+ /**
+ * Sets the tethering mode
+ * @param mode Tethering mode
+ * @return true if tethering mode changed, false otherwise
+ */
+ bool setTetheringMode(Tethering mode);
private:
void notifyChange();
M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +23 -1
@@ 27,6 27,7 @@
#include "messages/RequestCpuFrequencyMessage.hpp"
#include "messages/PhoneModeRequest.hpp"
#include "messages/TetheringStateRequest.hpp"
+#include "messages/TetheringQuestionRequest.hpp"
#include <time/ScopedTime.hpp>
#include "Timers/TimerFactory.hpp"
#include <service-appmgr/StartupType.hpp>
@@ 603,6 604,11 @@ namespace sys
return sys::MessageNone{};
});
+ connect(typeid(TetheringEnabledResponse), [this](sys::Message *message) -> sys::MessagePointer {
+ auto response = static_cast<TetheringEnabledResponse *>(message);
+ return enableTethering(response);
+ });
+
deviceManager->RegisterNewDevice(powerManager->getExternalRamDevice());
return ReturnCodes::Success;
@@ 768,7 774,23 @@ namespace sys
MessagePointer SystemManager::handleTetheringStateRequest(TetheringStateRequest *request)
{
LOG_INFO("Tethering state change requested");
- phoneModeSubject->setTetheringMode(request->getTetheringState());
+ if (const auto requestedState = request->getTetheringState(); requestedState == phone_modes::Tethering::On) {
+ bus.sendUnicast(std::make_shared<TetheringQuestionRequest>(),
+ app::manager::ApplicationManager::ServiceName);
+ }
+ else {
+ if (const auto tetheringChanged = phoneModeSubject->setTetheringMode(phone_modes::Tethering::Off);
+ !tetheringChanged) {
+ bus.sendUnicast(std::make_shared<TetheringQuestionAbort>(),
+ app::manager::ApplicationManager::ServiceName);
+ }
+ }
+ return MessageNone{};
+ }
+
+ MessagePointer SystemManager::enableTethering([[maybe_unused]] TetheringEnabledResponse *response)
+ {
+ phoneModeSubject->setTetheringMode(phone_modes::Tethering::On);
return MessageNone{};
}
M module-sys/SystemManager/SystemManager.hpp => module-sys/SystemManager/SystemManager.hpp +2 -0
@@ 41,6 41,7 @@ namespace sys
class PhoneModeRequest; // Forward declaration
class TetheringStateRequest; // Forward declaration
+ class TetheringEnabledResponse; // Forward declaration
enum class Code
{
@@ 191,6 192,7 @@ namespace sys
MessagePointer handlePhoneModeRequest(PhoneModeRequest *request);
MessagePointer handleTetheringStateRequest(TetheringStateRequest *request);
+ MessagePointer enableTethering(TetheringEnabledResponse *response);
void batteryCriticalLevelAction(bool charging);
void batteryNormalLevelAction();
A module-sys/SystemManager/messages/TetheringQuestionRequest.hpp => module-sys/SystemManager/messages/TetheringQuestionRequest.hpp +43 -0
@@ 0,0 1,43 @@
+// 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 <module-sys/Service/Message.hpp>
+
+#include <service-appmgr/Actions.hpp>
+#include <service-appmgr/messages/ActionRequest.hpp>
+
+namespace sys
+{
+ class TetheringQuestionRequest : public sys::DataMessage, public app::manager::actions::ConvertibleToAction
+ {
+ public:
+ TetheringQuestionRequest() : sys::DataMessage(MessageType::MessageTypeUninitialized)
+ {}
+
+ std::unique_ptr<app::manager::ActionRequest> toAction() const override
+ {
+ auto params = std::make_unique<app::PopupRequestParams>(gui::popup::ID::Tethering);
+ return std::make_unique<app::manager::ActionRequest>(
+ sender, app::manager::actions::ShowPopup, std::move(params));
+ }
+ };
+
+ class TetheringQuestionAbort : public sys::DataMessage, public app::manager::actions::ConvertibleToAction
+ {
+ public:
+ TetheringQuestionAbort() : sys::DataMessage(MessageType::MessageTypeUninitialized)
+ {}
+
+ std::unique_ptr<app::manager::ActionRequest> toAction() const override
+ {
+ auto params = std::make_unique<app::PopupRequestParams>(gui::popup::ID::Tethering);
+ return std::make_unique<app::manager::ActionRequest>(
+ sender, app::manager::actions::AbortPopup, std::move(params));
+ }
+ };
+
+ class TetheringEnabledResponse : public sys::ResponseMessage
+ {};
+} // namespace sys