From 05c8d3117c41c1c3881258942412de5606ff6e77 Mon Sep 17 00:00:00 2001 From: Alek Rudnik Date: Thu, 2 Dec 2021 15:35:02 +0100 Subject: [PATCH] [EGD-7860] Fix for call error flow Make sure it is not possible to request a call twice. Added new error windows for general call error and no network connection. Make sure there are no issues when call is requested from external app e.g. from callog or phonebook. --- cmake/modules/ProjectConfig.cmake | 2 +- image/assets/lang/Deutsch.json | 2 + image/assets/lang/English.json | 2 + image/assets/lang/Espanol.json | 2 + image/assets/lang/Francais.json | 2 + image/assets/lang/Polski.json | 2 + image/assets/lang/Svenska.json | 2 + module-apps/CMakeLists.txt | 2 +- .../application-call/ApplicationCall.cpp | 72 +++++++++++++------ .../application-call/ApplicationCall.hpp | 39 +++++++--- .../application-call/windows/CallWindow.cpp | 1 - .../rt1051/bsp/cellular/rt1051_cellular.cpp | 2 +- module-cellular/at/src/ATFactory.cpp | 2 +- module-cellular/modem/ATCommon.cpp | 6 ++ .../include/service-appmgr/Actions.hpp | 2 + .../service-appmgr/data/CallActionsParams.hpp | 29 ++++++++ .../CellularRequestHandler.cpp | 23 +++--- .../service-cellular/RequestFactory.cpp | 18 ++++- .../service-cellular/ServiceCellular.cpp | 69 ++++++++++++++---- .../service-cellular/CellularMessage.hpp | 37 ++++++++++ .../service-cellular/RequestFactory.hpp | 1 + .../requests/RejectRequest.hpp | 3 +- .../tests/unittest_request_factory.cpp | 58 ++++++++++----- .../services/appmgr/ApplicationManager.cpp | 2 + 24 files changed, 300 insertions(+), 80 deletions(-) diff --git a/cmake/modules/ProjectConfig.cmake b/cmake/modules/ProjectConfig.cmake index 8226df57273783fba87f1f7fbefc6067e8803e90..2d7365035da7970723313d0894b3fc011439ad88 100644 --- a/cmake/modules/ProjectConfig.cmake +++ b/cmake/modules/ProjectConfig.cmake @@ -6,7 +6,7 @@ else() endif() # add LOG_SENSITIVE_DATA enable option -option(LOG_SENSITIVE_DATA "LOG_SENSITIVE_DATA" OFF) +option(LOG_SENSITIVE_DATA "LOG_SENSITIVE_DATA" ON) if (${LOG_SENSITIVE_DATA} STREQUAL "ON") set (LOG_SENSITIVE_DATA_ENABLED 1 CACHE INTERNAL "") else() diff --git a/image/assets/lang/Deutsch.json b/image/assets/lang/Deutsch.json index 61ee74b2d26e4713821189d670ac4bede430d64c..8c2ca3cefa5aaab2bd27e28739fab6f593410c40 100644 --- a/image/assets/lang/Deutsch.json +++ b/image/assets/lang/Deutsch.json @@ -313,6 +313,8 @@ "app_call_speaker_on": "LAUTSPRECHER AN", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "Keine SIM-Karte.\n\nZum Anrufen\nSIM-Karte einsetzen.", + "app_call_no_network_connection": "Keine Netzwerkverbindung.", + "app_call_call_request_failed": "Etwas ist schief gelaufen.", "app_call_offline": "Offline-Modus.\n\nZum Anrufen\n in Online-Modus wechseln.", "app_sms_offline": "Offline-Modus.\n\nZum Senden einer SMS\n in Online-Modus wechseln.", "app_call_emergency_text": "Notruf", diff --git a/image/assets/lang/English.json b/image/assets/lang/English.json index 93a176645341151762517a0956a541d72643f506..79e43d194ed3dff2ffc31794cefa3d7b8a134e76 100644 --- a/image/assets/lang/English.json +++ b/image/assets/lang/English.json @@ -283,6 +283,8 @@ "app_call_speaker_on": "SPEAKER ON", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "No SIM.\n\nTo make a call,\nplease insert a SIM card.", + "app_call_no_network_connection": "No Network Connection.", + "app_call_call_request_failed": "Something went wrong.", "app_call_offline": "You're Offline.\n\nTo make a call,\n switch the mode.", "app_sms_offline": "You're Offline.\n\nTo send message,\n switch the mode.", "app_call_emergency_text": "Emergency call", diff --git a/image/assets/lang/Espanol.json b/image/assets/lang/Espanol.json index 225655b86773b1fd785dfe68909e856211c4778c..eb80b81fd7ee40e818500a5d6ab843b6c50c5b2b 100644 --- a/image/assets/lang/Espanol.json +++ b/image/assets/lang/Espanol.json @@ -313,6 +313,8 @@ "app_call_speaker_on": "ALTAVOZ ACTIVADO", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "No hay SIM.\n\nPara hacer una llamada,\ndebes insertar una tarjeta SIM.", + "app_call_no_network_connection": "No hay conexión de red.", + "app_call_call_request_failed": "Algo salió mal.", "app_call_offline": "No tienes conexión.\n\nPara hacer una llamada,\n cambia al modo Conectado.", "app_sms_offline": "No tienes conexión.\n\nPara enviar un SMS,\n cambia al modo Conectado.", "app_call_emergency_text": "Llamada de emergencia", diff --git a/image/assets/lang/Francais.json b/image/assets/lang/Francais.json index 4a9c652102774dfe1bd9b2d00f76cb3bec7d7b3c..9bf397e145105e60dc08f78031e71b44c44f57d7 100644 --- a/image/assets/lang/Francais.json +++ b/image/assets/lang/Francais.json @@ -282,6 +282,8 @@ "app_call_speaker_on": "HAUT-PARLEUR ACTIVÉ", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "Pas de carte SIM.\n\nPour faire un appel,\nveuillez insérer une carte SIM.", + "app_call_no_network_connection": "Pas de connexion réseau.", + "app_call_call_request_failed": "Quelque chose s'est mal passé.", "app_call_offline": "Tu es hors ligne.\n\nPour faire un appel,\npassez en mode Connecté.", "app_sms_offline": "Vous êtes hors ligne.\n\nPour envoyer un SMS,\npassez en mode Connecté.", "app_call_emergency_text": "Appel d'urgence", diff --git a/image/assets/lang/Polski.json b/image/assets/lang/Polski.json index fbde74d70822504814e1265118d6ed0175b61085..39d04a650bbae02129ae3fb68ea0e4215874672a 100644 --- a/image/assets/lang/Polski.json +++ b/image/assets/lang/Polski.json @@ -317,6 +317,8 @@ "app_call_speaker_on": "GŁOŚNIK", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "Brak SIM.\n\nAby wykonać połączenie,\nwłóż kartę SIM.", + "app_call_no_network_connection": "Brak połączenia sieciowego.", + "app_call_call_request_failed": "Coś poszło nie tak.", "app_call_offline": "Jesteś w trybie offline.\n\nAby wykonać połączenie,\n przejdź w tryb Połączony.", "app_sms_offline": "Jesteś w trybie offline.\n\nAby wysłać SMS,\n przejdź w tryb Połączony.", "app_call_emergency_text": "Połączenie alarmowe", diff --git a/image/assets/lang/Svenska.json b/image/assets/lang/Svenska.json index 4a0f4fd7b41b025843dc782761c9bee1aefac4ef..7bf0e63d0b00932e95798482a04e307abd1594c7 100644 --- a/image/assets/lang/Svenska.json +++ b/image/assets/lang/Svenska.json @@ -257,6 +257,8 @@ "app_call_speaker_on": "HÖGT.PÅ", "app_call_bluetooth": "BLUETOOTH", "app_call_no_sim": "För att ringa,,\nsätt i ett SIM-kort.", + "app_call_no_network_connection": "Ingen nätverksanslutning.", + "app_call_call_request_failed": "Något gick fel.", "app_call_offline": "Du är frånkopplad.\n\nByt till \"ansluten\"\nför att ringa.", "app_call_emergency_text": "Nödsamtal", "app_call_wrong_emergency": "Kan inte ringa..\n$NUMBER är inte ett nödnummer.", diff --git a/module-apps/CMakeLists.txt b/module-apps/CMakeLists.txt index e737342a066aa46d8f0dd0ffdd95f7f586783d01..431af0dc737ede5fc73f8274f98aca6db58be015 100644 --- a/module-apps/CMakeLists.txt +++ b/module-apps/CMakeLists.txt @@ -10,7 +10,7 @@ add_library(${PROJECT_NAME} STATIC) add_subdirectory(apps-common) -option(ENABLE_APP_ANTENNA "Enable application antenna" OFF) +option(ENABLE_APP_ANTENNA "Enable application antenna" OFF) set(APPLICATIONS alarm-clock diff --git a/module-apps/application-call/ApplicationCall.cpp b/module-apps/application-call/ApplicationCall.cpp index 7fb7fc07ef2a3ff930f22d3d1666daaf2a4ed3d9..0612e2329231fd93f1395861788224494c34b320 100644 --- a/module-apps/application-call/ApplicationCall.cpp +++ b/module-apps/application-call/ApplicationCall.cpp @@ -36,7 +36,7 @@ namespace app {Indicator::Signal, Indicator::Time, Indicator::Battery, Indicator::SimCard}); addActionReceiver(manager::actions::Call, [this](auto &&data) { if (auto msg = dynamic_cast(data.get()); msg != nullptr) { - handleCallEvent(msg->getPhoneNumber().getEntered()); + handleCallEvent(msg->getPhoneNumber().getEntered(), ExternalRequest::True); return actionHandled(); } return actionNotHandled(); @@ -50,34 +50,29 @@ namespace app return actionHandled(); }); addActionReceiver(manager::actions::NotAnEmergencyNotification, [this](auto &&data) { - auto buttonAction = [=]() -> bool { - returnToPreviousWindow(); - return true; - }; - constexpr auto iconNoEmergency = "fail_128px_W_G"; - auto textNoEmergency = utils::translate("app_call_wrong_emergency"); + auto textNoEmergency = utils::translate("app_call_wrong_emergency"); utils::findAndReplaceAll(textNoEmergency, "$NUMBER", data->getDescription()); - showNotification(buttonAction, iconNoEmergency, textNoEmergency); + showNotificationAndRestartCallFlow(NotificationType::Info, textNoEmergency); return actionHandled(); }); + addActionReceiver(manager::actions::NoSimNotification, [this](auto &&data) { - auto buttonAction = [=]() -> bool { - returnToPreviousWindow(); - return true; - }; - constexpr auto iconNoSim = "info_128px_W_G"; - const auto textNoSim = utils::translate("app_call_no_sim"); - showNotification(buttonAction, iconNoSim, textNoSim); + showNotificationAndRestartCallFlow(NotificationType::Info, + utils::translate("app_app_call_no_simcall_offline")); + return actionHandled(); + }); + addActionReceiver(manager::actions::NoNetworkConnectionNotification, [this](auto &&data) { + showNotificationAndRestartCallFlow(NotificationType::Info, + utils::translate("app_call_no_network_connection")); + return actionHandled(); + }); + addActionReceiver(manager::actions::CallRequestGeneralErrorNotification, [this](auto &&data) { + showNotificationAndRestartCallFlow(NotificationType::Failure, + utils::translate("app_call_call_request_failed")); return actionHandled(); }); addActionReceiver(manager::actions::CallRejectedByOfflineNotification, [this](auto &&data) { - auto buttonAction = [=]() -> bool { - app::manager::Controller::switchBack(this); - return true; - }; - constexpr auto icon = "info_128px_W_G"; - const auto textOffline = utils::translate("app_call_offline"); - showNotification(buttonAction, icon, textOffline); + showNotificationAndRestartCallFlow(NotificationType::Info, utils::translate("app_call_offline")); return actionHandled(); }); addActionReceiver(manager::actions::AbortCall, [this](auto &&data) { @@ -112,6 +107,17 @@ namespace app }); } + bool ApplicationCall::conditionalReturnToPreviousView() + { + // if external request simply return to previous app + if (externalRequest == ExternalRequest::True) { + app::manager::Controller::switchBack(this); + return true; + } + returnToPreviousWindow(); + return true; + } + bool ApplicationCall::isPopupPermitted(gui::popup::ID popupId) const { if (popupId == gui::popup::ID::Volume) { @@ -174,6 +180,14 @@ namespace app return true; } + auto ApplicationCall::showNotificationAndRestartCallFlow(NotificationType type, const std::string &text) -> bool + { + auto buttonAction = [=]() -> bool { return conditionalReturnToPreviousView(); }; + auto icon = type == NotificationType::Info ? "info_128px_W_G" : "fail_128px_W_G"; + setCallState(call::State::IDLE); + return showNotification(buttonAction, icon, text); + } + void ApplicationCall::destroyUserInterface() {} @@ -206,12 +220,24 @@ namespace app void ApplicationCall::handleEmergencyCallEvent(const std::string &number) { + auto state = getCallState(); + if (state != call::State::IDLE) { + LOG_WARN("Cannot call in %s state", c_str(state)); + return; + } CellularServiceAPI::DialEmergencyNumber(this, utils::PhoneNumber(number)); } - void ApplicationCall::handleCallEvent(const std::string &number) + void ApplicationCall::handleCallEvent(const std::string &number, ExternalRequest isExternalRequest) { + auto state = getCallState(); + if (state != call::State::IDLE) { + LOG_WARN("Cannot call in %s state", c_str(state)); + return; + } CellularServiceAPI::DialNumber(this, utils::PhoneNumber(number)); + setCallState(call::State::OUTGOING_CALL); + externalRequest = isExternalRequest; } void ApplicationCall::handleAddContactEvent(const std::string &number) diff --git a/module-apps/application-call/include/application-call/ApplicationCall.hpp b/module-apps/application-call/include/application-call/ApplicationCall.hpp index 905a35d1ee13fc4c11434ec3d901313ecc6a46f2..1418b343887843d802aefe7e2a09d964eccdf6fb 100644 --- a/module-apps/application-call/include/application-call/ApplicationCall.hpp +++ b/module-apps/application-call/include/application-call/ApplicationCall.hpp @@ -56,20 +56,20 @@ namespace app class EnterNumberWindowInterface { public: - virtual ~EnterNumberWindowInterface() noexcept = default; - virtual void handleCallEvent(const std::string &number) = 0; - virtual void handleEmergencyCallEvent(const std::string &number) = 0; - virtual void handleAddContactEvent(const std::string &number) = 0; + virtual ~EnterNumberWindowInterface() noexcept = default; + enum class ExternalRequest + { + True, + False + }; + virtual void handleCallEvent(const std::string &number, + ExternalRequest isExternalRequest = ExternalRequest::False) = 0; + virtual void handleEmergencyCallEvent(const std::string &number) = 0; + virtual void handleAddContactEvent(const std::string &number) = 0; }; class ApplicationCall : public Application, public CallWindowInterface, public EnterNumberWindowInterface { - private: - sys::TimerHandle callerIdTimer; - - protected: - call::State callState = call::State::IDLE; - public: explicit ApplicationCall(std::string name = name_call, std::string parent = {}, @@ -90,10 +90,16 @@ namespace app void handleIncomingCall(); void handleCallerId(const app::manager::actions::CallParams *params); void handleEmergencyCallEvent(const std::string &number) override; - void handleCallEvent(const std::string &number) override; + void handleCallEvent(const std::string &number, ExternalRequest isExternalRequest) override; void handleAddContactEvent(const std::string &number) override; auto showNotification(std::function action, const std::string &icon, const std::string &text) -> bool; + enum class NotificationType + { + Info, + Failure + }; + auto showNotificationAndRestartCallFlow(NotificationType type, const std::string &text) -> bool; [[nodiscard]] auto getCallState() const noexcept -> call::State override { @@ -121,6 +127,15 @@ namespace app void transmitDtmfTone(uint32_t digit) override; void hangupCall() override; void answerIncomingCall() override; + + private: + sys::TimerHandle callerIdTimer; + + protected: + call::State callState = call::State::IDLE; + ExternalRequest externalRequest = ExternalRequest::False; + + bool conditionalReturnToPreviousView(); }; template <> struct ManifestTraits @@ -133,6 +148,8 @@ namespace app manager::actions::EmergencyDial, manager::actions::NotAnEmergencyNotification, manager::actions::NoSimNotification, + manager::actions::NoNetworkConnectionNotification, + manager::actions::CallRequestGeneralErrorNotification, manager::actions::CallRejectedByOfflineNotification, manager::actions::PhoneModeChanged, manager::actions::ActivateCall, diff --git a/module-apps/application-call/windows/CallWindow.cpp b/module-apps/application-call/windows/CallWindow.cpp index 09c822596f60ae77c0fe1a401a77524b0e12ed01..cc7e6cf297b1a5ed16c11f53335bce70cac10fb3 100644 --- a/module-apps/application-call/windows/CallWindow.cpp +++ b/module-apps/application-call/windows/CallWindow.cpp @@ -440,7 +440,6 @@ namespace gui { switch (callEndType) { case CallEndType::None: - [[fallthrough]]; case CallEndType::Ended: durationLabel->setText(utils::translate(strings::callended)); break; diff --git a/module-bsp/board/rt1051/bsp/cellular/rt1051_cellular.cpp b/module-bsp/board/rt1051/bsp/cellular/rt1051_cellular.cpp index f82e866d3f9ba554e89be76526586b1be0057a3a..97be9b2080f45bcd3cf0e00368d00bca6009a3c5 100644 --- a/module-bsp/board/rt1051/bsp/cellular/rt1051_cellular.cpp +++ b/module-bsp/board/rt1051/bsp/cellular/rt1051_cellular.cpp @@ -279,7 +279,7 @@ namespace bsp } RXfer.resultCode = reason; - logUARTdebug("[RX reason] %s", c_str(reason)); + logUARTdebug("[RX reason] %s", ::c_str(reason)); xMessageBufferSendFromISR(uartRxBuffer, (void *)&RXfer, RXfer.getSize(), &xHigherPriorityTaskWoken); diff --git a/module-cellular/at/src/ATFactory.cpp b/module-cellular/at/src/ATFactory.cpp index c34b5166c6436b831c94a5b22d3e66e46bfd4dd4..7aeb01173893e2ac0f5ce37f208eab88c3a73b81 100644 --- a/module-cellular/at/src/ATFactory.cpp +++ b/module-cellular/at/src/ATFactory.cpp @@ -65,7 +65,7 @@ namespace at {AT::GET_SCANMODE, {"AT+QCFG=\"nwscanmode\""}}, {AT::QGMR, {"AT+QGMR"}}, {AT::STORE_SETTINGS_ATW, {"AT&W"}}, - {AT::CEER, {"AT+CEER"}}, + {AT::CEER, {"AT+CEER", 1s}}, {AT::QIGETERROR, {"AT+QIGETERROR"}}, {AT::VTS, {"AT+VTS=", default_long_timeout}}, {AT::QLDTMF, {"AT+QLDTMF=1,"}}, diff --git a/module-cellular/modem/ATCommon.cpp b/module-cellular/modem/ATCommon.cpp index b9c14bb548bebb1ff41ecb98b2014607038f26ca..275e737ac2f9df799dc960ad5574321125a9d2c9 100644 --- a/module-cellular/modem/ATCommon.cpp +++ b/module-cellular/modem/ATCommon.cpp @@ -65,12 +65,18 @@ std::string Channel::formatCommand(const std::string &cmd) const Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, size_t rxCount) { Result result; + if (cmd.empty()) { + LOG_INFO("Skip empty command"); + result.code = Result::Code::OK; + return result; + } ATStream atStream(rxCount); awaitingResponseFlag.set(); cmdInit(); std::string cmdFixed = formatCommand(cmd); + LOG_DEBUG("start of %s", cmdFixed.c_str()); cmdSend(cmdFixed); auto startTime = std::chrono::steady_clock::now(); diff --git a/module-services/service-appmgr/include/service-appmgr/Actions.hpp b/module-services/service-appmgr/include/service-appmgr/Actions.hpp index bacd2dbfb1cf958d96bbc0c8c40245faea67bfac..86e18aeb552c473ad4604279b6919140bee99d49 100644 --- a/module-services/service-appmgr/include/service-appmgr/Actions.hpp +++ b/module-services/service-appmgr/include/service-appmgr/Actions.hpp @@ -32,6 +32,8 @@ namespace app::manager HandleCallerId, NotAnEmergencyNotification, NoSimNotification, + NoNetworkConnectionNotification, + CallRequestGeneralErrorNotification, Dial, EmergencyDial, ShowCallLog, diff --git a/module-services/service-appmgr/include/service-appmgr/data/CallActionsParams.hpp b/module-services/service-appmgr/include/service-appmgr/data/CallActionsParams.hpp index 0397bfcd129768d207726e6027425c3cc320ea01..7cc1f0560add620d94c6b188b2ba1a97b0bbd699 100644 --- a/module-services/service-appmgr/include/service-appmgr/data/CallActionsParams.hpp +++ b/module-services/service-appmgr/include/service-appmgr/data/CallActionsParams.hpp @@ -19,4 +19,33 @@ namespace app::manager::actions private: utils::PhoneNumber::View number; }; + + class CallRequestGeneralErrorParams : public app::manager::actions::ActionParams + { + public: + struct Error + { + enum class Type + { + Error, + CmeError, + CmsError, + ModemTimeout, + UndefinedError, + TransmissionError, + ChannelNotReadyError + } type; + }; + + explicit CallRequestGeneralErrorParams(Error error) : error{error} + {} + + [[nodiscard]] auto getError() const noexcept + { + return error; + } + + private: + Error error; + }; } // namespace app::manager::actions diff --git a/module-services/service-cellular/CellularRequestHandler.cpp b/module-services/service-cellular/CellularRequestHandler.cpp index 40d1a0dc299b4dbce7e8d4855cdcf00ba9a23cbe..03cf83d5ecb2952188a3cd6072f5c5965274fc31 100644 --- a/module-services/service-cellular/CellularRequestHandler.cpp +++ b/module-services/service-cellular/CellularRequestHandler.cpp @@ -43,6 +43,7 @@ void CellularRequestHandler::handle(cellular::ImeiRequest &request, at::Result & auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, service::name::appmgr); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::UssdRequest &request, at::Result &result) @@ -56,7 +57,7 @@ void CellularRequestHandler::handle(cellular::UssdRequest &request, at::Result & else { sendMmiResult(requestHandled); } - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::CallRequest &request, at::Result &result) @@ -83,28 +84,32 @@ void CellularRequestHandler::handle(cellular::RejectRequest &request, at::Result auto message = std::make_shared(request.getNumber()); cellular.bus.sendUnicast(message, service::name::appmgr); } + else if (request.getRejectReason() == cellular::RejectRequest::RejectReason::NoNetworkConnection) { + auto message = std::make_shared(); + cellular.bus.sendUnicast(message, service::name::appmgr); + } request.setHandled(true); } void CellularRequestHandler::handle(cellular::SupplementaryServicesRequest &request, at::Result &result) { auto requestHandled = request.checkModemResponse(result); - request.setHandled(requestHandled); sendMmiResult(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::PasswordRegistrationRequest &request, at::Result &result) { auto requestHandled = request.checkModemResponse(result); - request.setHandled(requestHandled); sendMmiResult(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::PinChangeRequest &request, at::Result &result) { auto requestHandled = request.checkModemResponse(result); - request.setHandled(requestHandled); sendMmiResult(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::ClirRequest &request, at::Result &result) @@ -136,7 +141,7 @@ void CellularRequestHandler::handle(cellular::ClirRequest &request, at::Result & } auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, ::service::name::appmgr); - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::CallForwardingRequest &request, at::Result &result) @@ -201,7 +206,7 @@ void CellularRequestHandler::handle(cellular::CallForwardingRequest &request, at } auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, ::service::name::appmgr); - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::CallBarringRequest &request, at::Result &result) @@ -250,7 +255,7 @@ void CellularRequestHandler::handle(cellular::CallBarringRequest &request, at::R auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, ::service::name::appmgr); - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::ClipRequest &request, at::Result &result) @@ -288,7 +293,7 @@ void CellularRequestHandler::handle(cellular::ClipRequest &request, at::Result & auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, ::service::name::appmgr); - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::handle(cellular::CallWaitingRequest &request, at::Result &result) @@ -335,7 +340,7 @@ void CellularRequestHandler::handle(cellular::CallWaitingRequest &request, at::R } auto msg = std::make_shared(MMIResultParams::MMIResult::Success, response); cellular.bus.sendUnicast(msg, ::service::name::appmgr); - request.setHandled(requestHandled); + request.setHandled(true); } void CellularRequestHandler::sendMmiResult(bool result) diff --git a/module-services/service-cellular/RequestFactory.cpp b/module-services/service-cellular/RequestFactory.cpp index 0686cefc1adc838fae6360922ccc79a567ea755c..7d9167364201c5f5f8c4830f7ede495a33d5e5b8 100644 --- a/module-services/service-cellular/RequestFactory.cpp +++ b/module-services/service-cellular/RequestFactory.cpp @@ -16,6 +16,7 @@ #include "service-cellular/requests/UssdRequest.hpp" #include "service-cellular/requests/RejectRequest.hpp" +#include #include #include @@ -67,9 +68,21 @@ namespace cellular return nullptr; } + bool RequestFactory::isConnectedToNetwork() + { + at::Cmd buildCmd = at::factory(at::AT::COPS) + "?"; + auto resp = channel.cmd(buildCmd); + at::response::cops::CurrentOperatorInfo ret; + if ((resp.code == at::Result::Code::OK) && (at::response::parseCOPS(resp, ret))) { + return ret.getOperator().has_value(); + } + return false; + } + std::unique_ptr RequestFactory::create() { - if (auto req = emergencyCheck(); req) { + auto isRegisteredToNetwork = isConnectedToNetwork(); + if (auto req = emergencyCheck(); req && isRegisteredToNetwork) { return req; } @@ -119,6 +132,9 @@ namespace cellular if (!simInserted) { return std::make_unique(RejectRequest::RejectReason::NoSim, request); } + if (!isRegisteredToNetwork) { + return std::make_unique(RejectRequest::RejectReason::NoNetworkConnection, request); + } return std::make_unique(request); } diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index a28e81172675ee1d86d7c7db197accd2d7082694..2248c8bc89ce6f8411452904c1ec2912a40479b5 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -1745,22 +1745,63 @@ auto ServiceCellular::handleCellularAnswerIncomingCallMessage(CellularMessage *m return std::make_shared(ret); } +namespace +{ + constexpr auto translate(at::Result::Code code) -> CellularCallRequestGeneralError::ErrorType + { + switch (code) { + case at::Result::Code::ERROR: + case at::Result::Code::CME_ERROR: + case at::Result::Code::CMS_ERROR: + return CellularCallRequestGeneralError::ErrorType::Error; + case at::Result::Code::TIMEOUT: + return CellularCallRequestGeneralError::ErrorType::ModemTimeout; + case at::Result::Code::TOKENS: + case at::Result::Code::PARSING_ERROR: + case at::Result::Code::FULL_MSG_BUFFER: + case at::Result::Code::TRANSMISSION_NOT_STARTED: + case at::Result::Code::RECEIVING_NOT_STARTED: + case at::Result::Code::DATA_NOT_USED: + case at::Result::Code::CMUX_FRAME_ERROR: + return CellularCallRequestGeneralError::ErrorType::TransmissionError; + case at::Result::Code::OK: + case at::Result::Code::NONE: + case at::Result::Code::UNDEFINED: + return CellularCallRequestGeneralError::ErrorType::UndefinedError; + } + return CellularCallRequestGeneralError::ErrorType::UndefinedError; + } +} // namespace + auto ServiceCellular::handleCellularCallRequestMessage(CellularCallRequestMessage *msg) -> std::shared_ptr { LOG_INFO("%s", __PRETTY_FUNCTION__); auto channel = cmux->get(CellularMux::Channel::Commands); if (channel == nullptr) { + LOG_WARN("commands channel not ready"); + auto message = std::make_shared( + CellularCallRequestGeneralError::ErrorType::ChannelNotReadyError); + bus.sendUnicast(message, ::service::name::appmgr); return std::make_shared(false); } cellular::RequestFactory factory( msg->number.getEntered(), *channel, msg->callMode, Store::GSM::get()->simCardInserted()); auto request = factory.create(); - CellularRequestHandler handler(*this); auto result = channel->cmd(request->command()); request->handle(handler, result); + if (!result) { + log_last_AT_error(channel); + } + LOG_INFO("isHandled %d, %s", static_cast(request->isHandled()), utils::enumToString(result.code).c_str()); + if (!request->isHandled()) { + CellularCallRequestGeneralError::ErrorType errorType = translate(result.code); + auto message = std::make_shared(errorType); + bus.sendUnicast(message, ::service::name::appmgr); + } + return std::make_shared(request->isHandled()); } @@ -1961,22 +2002,22 @@ auto ServiceCellular::handleCellularGetFirmwareVersionMessage(sys::Message *msg) auto ServiceCellular::handleEVMStatusMessage(sys::Message *msg) -> std::shared_ptr { using namespace bsp::cellular::status; - auto message = static_cast(msg); - auto status_pin = message->state; - if (priv->modemResetHandler->handleStatusPinEvent(status_pin == value::ACTIVE)) { - return std::make_shared(true); - } + auto message = static_cast(msg); + auto status_pin = message->state; + if (priv->modemResetHandler->handleStatusPinEvent(status_pin == value::ACTIVE)) { + return std::make_shared(true); + } - if (status_pin == value::ACTIVE) { - if (priv->state->get() == State::ST::PowerUpProcedure) { - priv->state->set(State::ST::PowerUpInProgress); // and go to baud detect as usual - } + if (status_pin == value::ACTIVE) { + if (priv->state->get() == State::ST::PowerUpProcedure) { + priv->state->set(State::ST::PowerUpInProgress); // and go to baud detect as usual } - if (status_pin == value::INACTIVE) { - if (priv->state->get() == State::ST::PowerDownWaiting) { - priv->state->set(State::ST::PowerDown); - } + } + if (status_pin == value::INACTIVE) { + if (priv->state->get() == State::ST::PowerDownWaiting) { + priv->state->set(State::ST::PowerDown); } + } return std::make_shared(true); } diff --git a/module-services/service-cellular/service-cellular/CellularMessage.hpp b/module-services/service-cellular/service-cellular/CellularMessage.hpp index 8a7eb9682d7cc684ab021b4d8a738ff742a1e18f..755cc52ce1133fad89466143cbd435b03855b617 100644 --- a/module-services/service-cellular/service-cellular/CellularMessage.hpp +++ b/module-services/service-cellular/service-cellular/CellularMessage.hpp @@ -545,6 +545,43 @@ class CellularNotAnEmergencyNotification : public CellularResponseMessage, } }; +class CellularNoNetworkConenctionNotification : public CellularResponseMessage, + public app::manager::actions::ConvertibleToAction +{ + public: + CellularNoNetworkConenctionNotification() : CellularResponseMessage(false) + {} + + [[nodiscard]] auto toAction() const -> std::unique_ptr + { + return std::make_unique(sender, + app::manager::actions::NoNetworkConnectionNotification, + std::make_unique()); + } +}; + +class CellularCallRequestGeneralError : public CellularResponseMessage, + public app::manager::actions::ConvertibleToAction +{ + public: + using Error = app::manager::actions::CallRequestGeneralErrorParams::Error; + using ErrorType = app::manager::actions::CallRequestGeneralErrorParams::Error::Type; + + CellularCallRequestGeneralError(ErrorType errorType) : CellularResponseMessage(false), error{errorType} + {} + + [[nodiscard]] auto toAction() const -> std::unique_ptr + { + return std::make_unique( + sender, + app::manager::actions::CallRequestGeneralErrorNotification, + std::make_unique(error)); + } + + private: + Error error; +}; + class CellularNewIncomingSMSMessage : public CellularMessage { public: diff --git a/module-services/service-cellular/service-cellular/RequestFactory.hpp b/module-services/service-cellular/service-cellular/RequestFactory.hpp index a71e67d45c144605a316fef5b5864a59c1901239..849fce82eaa57a34aae5e89eebc482ef0256b45e 100644 --- a/module-services/service-cellular/service-cellular/RequestFactory.hpp +++ b/module-services/service-cellular/service-cellular/RequestFactory.hpp @@ -30,6 +30,7 @@ namespace cellular private: void registerRequest(std::string regex, CreateCallback); std::unique_ptr emergencyCheck(); + bool isConnectedToNetwork(); std::string request; std::vector> requestMap; diff --git a/module-services/service-cellular/service-cellular/requests/RejectRequest.hpp b/module-services/service-cellular/service-cellular/requests/RejectRequest.hpp index f7d7f0be045ed8a1348b01d6b88444dd226ff5d7..7289d4b8746d7b7e1efbdc040c2f9e78d7abd87e 100644 --- a/module-services/service-cellular/service-cellular/requests/RejectRequest.hpp +++ b/module-services/service-cellular/service-cellular/requests/RejectRequest.hpp @@ -17,7 +17,8 @@ namespace cellular enum class RejectReason { NoSim, - NotAnEmergencyNumber + NotAnEmergencyNumber, + NoNetworkConnection }; RejectRequest(RejectReason rejectReason, const std::string &number) diff --git a/module-services/service-cellular/tests/unittest_request_factory.cpp b/module-services/service-cellular/tests/unittest_request_factory.cpp index 27ee4f2e99c406434b583ce2eeaa26fc0ea23f43..dae10a20e001cae8616fe68067aac34eb831325b 100644 --- a/module-services/service-cellular/tests/unittest_request_factory.cpp +++ b/module-services/service-cellular/tests/unittest_request_factory.cpp @@ -34,6 +34,8 @@ TEST_CASE("Emergency handling") bool isNumberEmergencyNoSim; // mock that sim is inserted bool insertSim; + // mock that phone is connected to network + bool isConnectedToNetwork; // reject reason if applicable std::optional rejectReason; // expected typeid name of created request @@ -49,42 +51,59 @@ TEST_CASE("Emergency handling") ////// normal request // no SIM and SIM emergency number / sim inserted - {false, true, true, true, std::nullopt, typeid(CallRequest).name()}, + {false, true, true, true, true, std::nullopt, typeid(CallRequest).name()}, + // no SIM and SIM emergency number / sim inserted / no network connection + {false, + true, + true, + true, + false, + RejectRequest::RejectReason::NoNetworkConnection, + typeid(RejectRequest).name(), + ""}, // no SIM emergency number / sim inserted - {false, false, true, true, std::nullopt, typeid(CallRequest).name()}, + {false, false, true, true, true, std::nullopt, typeid(CallRequest).name()}, // SIM emergency number / sim inserted - {false, true, false, true, std::nullopt, typeid(CallRequest).name()}, + {false, true, false, true, true, std::nullopt, typeid(CallRequest).name()}, // no SIM and SIM emergency number / no sim inserted - {false, true, true, false, std::nullopt, typeid(CallRequest).name()}, + {false, true, true, false, true, std::nullopt, typeid(CallRequest).name()}, // no SIM emergency number / no sim inserted - {false, false, true, false, std::nullopt, typeid(CallRequest).name()}, + {false, false, true, false, true, std::nullopt, typeid(CallRequest).name()}, // SIM emergency number / no sim inserted - {false, true, false, false, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, + {false, true, false, false, true, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, // normal number / sim inserted - {false, false, false, true, std::nullopt, typeid(CallRequest).name()}, + {false, false, false, true, true, std::nullopt, typeid(CallRequest).name()}, // normal number / no sim inserted - {false, false, false, false, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, + {false, false, false, false, true, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, ////// emergency request // no SIM and SIM emergency number / sim inserted - {true, true, true, true, std::nullopt, typeid(CallRequest).name()}, + {true, true, true, true, true, std::nullopt, typeid(CallRequest).name()}, // no SIM emergency number / sim inserted - {true, false, true, true, std::nullopt, typeid(CallRequest).name()}, + {true, false, true, true, true, std::nullopt, typeid(CallRequest).name()}, // SIM emergency number / sim inserted - {true, true, false, true, std::nullopt, typeid(CallRequest).name()}, + {true, true, false, true, true, std::nullopt, typeid(CallRequest).name()}, // no SIM and SIM emergency number / no sim inserted - {true, true, true, false, std::nullopt, typeid(CallRequest).name()}, + {true, true, true, false, true, std::nullopt, typeid(CallRequest).name()}, // no SIM emergency number / no sim inserted - {true, false, true, false, std::nullopt, typeid(CallRequest).name()}, + {true, false, true, false, true, std::nullopt, typeid(CallRequest).name()}, // SIM emergency number / no sim inserted - {true, true, false, false, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, + {true, true, false, false, true, RejectRequest::RejectReason::NoSim, typeid(RejectRequest).name(), ""}, // normal number / sim inserted - {true, false, false, true, RejectRequest::RejectReason::NotAnEmergencyNumber, typeid(RejectRequest).name(), ""}, + {true, + false, + false, + true, + true, + RejectRequest::RejectReason::NotAnEmergencyNumber, + typeid(RejectRequest).name(), + ""}, // normal number / no sim inserted {true, false, false, false, + true, RejectRequest::RejectReason::NotAnEmergencyNumber, typeid(RejectRequest).name(), ""}, @@ -106,6 +125,9 @@ TEST_CASE("Emergency handling") if (test.isNumberEmergencySim) { channelMockResponse.emplace_back("+QECCNUM: 1,\"" + test.number + "\""); } + if (test.isConnectedToNetwork) { + channelMockResponse.emplace_back("+COPS: 0,0,\"PLAY\",7"); + } auto dummyChannel = at::GenericChannel(at::Result::Code::OK, channelMockResponse); @@ -443,7 +465,11 @@ TEST_CASE("MMI requests") }; for (auto &testCase : testCases) { - auto mockChannel = at::GenericChannel(at::Result::Code::OK, {}); + std::vector channelMockResponse; + // connected to network + channelMockResponse.emplace_back("+COPS: 0,0,\"PLAY\",7"); + + auto mockChannel = at::GenericChannel(at::Result::Code::OK, channelMockResponse); RequestFactory requestFactory(testCase.requestString, mockChannel, cellular::api::CallMode::Regular, true); auto request = requestFactory.create(); auto requestCommand = request->command(); diff --git a/products/PurePhone/services/appmgr/ApplicationManager.cpp b/products/PurePhone/services/appmgr/ApplicationManager.cpp index 3db8de823b84f5dd3eba8be5b412c82f11bdbcf4..c135f1297720974530a21c82d3ffb92f4e84827c 100644 --- a/products/PurePhone/services/appmgr/ApplicationManager.cpp +++ b/products/PurePhone/services/appmgr/ApplicationManager.cpp @@ -358,6 +358,8 @@ namespace app::manager connect(typeid(CellularMMIPushMessage), convertibleToActionHandler); connect(typeid(CellularNoSimNotification), convertibleToActionHandler); connect(typeid(CellularNotAnEmergencyNotification), convertibleToActionHandler); + connect(typeid(CellularNoNetworkConenctionNotification), convertibleToActionHandler); + connect(typeid(CellularCallRequestGeneralError), convertibleToActionHandler); connect(typeid(CellularSmsNoSimRequestMessage), convertibleToActionHandler); connect(typeid(CellularSMSRejectedByOfflineNotification), convertibleToActionHandler); connect(typeid(CellularCallRejectedByOfflineNotification), convertibleToActionHandler);