From 3cc558b02add43fa90c548ca220665d84f0c49ca Mon Sep 17 00:00:00 2001 From: Hubert Chrzaniuk Date: Wed, 3 Feb 2021 17:55:46 +0100 Subject: [PATCH] [EGD-2931] Fix private number incoming calls The change adjusts both cellular service as well as call and call log applications to handle properly incoming calls from private numbers. --- image/assets/lang/English.json | 3 +- .../application-call/ApplicationCall.cpp | 78 +++++++++++-------- .../application-call/ApplicationCall.hpp | 9 ++- .../application-call/data/CallAppStyle.hpp | 1 + .../application-call/windows/CallWindow.cpp | 48 ++++++++---- .../application-calllog/CalllogModel.cpp | 37 ++++++--- .../application-calllog/data/CallLogStyle.hpp | 6 +- .../widgets/CalllogItem.cpp | 7 +- .../windows/CallLogDetailsWindow.cpp | 18 ++++- .../windows/CallLogMainWindow.cpp | 11 ++- .../windows/CallLogMainWindow.hpp | 2 +- .../windows/CallLogOptionsWindow.cpp | 25 +++--- module-apps/windows/AppWindow.hpp | 2 +- module-cellular/CMakeLists.txt | 1 + module-cellular/at/UrcHandler.hpp | 4 +- module-cellular/at/UrcRing.hpp | 42 ++++++++++ module-cellular/at/src/Urc.cpp | 4 +- module-cellular/at/src/UrcFactory.cpp | 9 ++- module-cellular/at/src/UrcRing.cpp | 39 ++++++++++ module-cellular/test/unittest_URC.cpp | 42 ++++++++-- module-db/Interface/CalllogRecord.cpp | 70 ++++++++++++----- .../model/ApplicationManager.cpp | 2 + .../service-appmgr/service-appmgr/Actions.hpp | 4 +- .../service-cellular/CellularCall.cpp | 10 ++- .../CellularRequestHandler.cpp | 14 ++++ .../service-cellular/CellularUrcHandler.cpp | 11 ++- .../service-cellular/CellularUrcHandler.hpp | 2 + .../service-cellular/RequestFactory.cpp | 17 +--- .../service-cellular/ServiceCellular.cpp | 17 ++-- .../service-cellular/CellularCall.hpp | 5 +- .../service-cellular/CellularMessage.hpp | 50 ++++++++---- .../CellularRequestHandler.hpp | 1 + .../service-cellular/RequestFactory.hpp | 2 - .../service-cellular/RequestHandler.hpp | 2 + .../service-cellular/ServiceCellular.hpp | 1 + .../requests/RejectRequest.hpp | 48 ++++++++++++ .../tests/unittest_request_factory.cpp | 42 +++++----- .../service-fota/FotaUrcHandler.hpp | 3 +- 38 files changed, 500 insertions(+), 189 deletions(-) create mode 100644 module-cellular/at/UrcRing.hpp create mode 100644 module-cellular/at/src/UrcRing.cpp create mode 100644 module-services/service-cellular/service-cellular/requests/RejectRequest.hpp diff --git a/image/assets/lang/English.json b/image/assets/lang/English.json index b7b152085..363252e06 100644 --- a/image/assets/lang/English.json +++ b/image/assets/lang/English.json @@ -503,5 +503,6 @@ "app_desktop_update_start": "Update start", "app_desktop_update_size": "size", "app_desktop_update_bytes": "bytes", - "app_desktop_update_unpacking": "Unpacking" + "app_desktop_update_unpacking": "Unpacking", + "app_call_private_number": "Private number" } diff --git a/module-apps/application-call/ApplicationCall.cpp b/module-apps/application-call/ApplicationCall.cpp index b62cf5405..a2d2078f3 100644 --- a/module-apps/application-call/ApplicationCall.cpp +++ b/module-apps/application-call/ApplicationCall.cpp @@ -50,40 +50,27 @@ namespace app switchWindow(app::window::name_emergencyCall, std::forward(data)); return msgHandled(); }); - - auto convertibleToActionHandler = [this](sys::Message *request) { return HandleMessageAsAction(request); }; - connect(typeid(CellularActionResponseMessage), convertibleToActionHandler); - } - - auto ApplicationCall::HandleMessageAsAction(sys::Message *request) -> std::shared_ptr - { - auto actionMsg = dynamic_cast(request); - if (!actionMsg) { - return std::make_shared(sys::ReturnCodes::Failure); - } - - auto buttonAction = [=]() -> bool { - returnToPreviousWindow(); - return true; - }; - - constexpr auto iconNoEmergency = "emergency_W_G"; - auto textNoEmergency = utils::localize.get("app_call_wrong_emergency"); - constexpr auto iconNoSim = "info_big_circle_W_G"; - const auto textNoSim = utils::localize.get("app_call_no_sim"); - - auto action = actionMsg->toAction(); - - switch (const auto actionId = action->getAction(); actionId) { - case app::manager::actions::CallRejectNotEmergency: - utils::findAndReplaceAll(textNoEmergency, "$NUMBER", action->getData()->getDescription()); + addActionReceiver(manager::actions::NotAnEmergencyNotification, [this](auto &&data) { + auto buttonAction = [=]() -> bool { + returnToPreviousWindow(); + return true; + }; + constexpr auto iconNoEmergency = "emergency_W_G"; + auto textNoEmergency = utils::localize.get("app_call_wrong_emergency"); + utils::findAndReplaceAll(textNoEmergency, "$NUMBER", data->getDescription()); showNotification(buttonAction, iconNoEmergency, textNoEmergency); - break; - case app::manager::actions::CallRejectNoSim: + return msgHandled(); + }); + addActionReceiver(manager::actions::NoSimNotification, [this](auto &&data) { + auto buttonAction = [=]() -> bool { + returnToPreviousWindow(); + return true; + }; + constexpr auto iconNoSim = "info_big_circle_W_G"; + const auto textNoSim = utils::localize.get("app_call_no_sim"); showNotification(buttonAction, iconNoSim, textNoSim); - break; - } - return std::make_shared(); + return msgHandled(); + }); } // number of seconds after end call to switch back to previous application @@ -99,14 +86,34 @@ namespace app manager::Controller::sendAction(this, manager::actions::Call, std::make_unique()); } - void ApplicationCall::IncomingCallHandler(const CellularCallMessage *const msg) + void ApplicationCall::CallerIdHandler(const CellularCallMessage *const msg) { - if (state == call::State::IDLE) { + if (getState() == call::State::IDLE) { + if (callerIdTimer) { + callerIdTimer->stop(); + callerIdTimer.reset(nullptr); + } manager::Controller::sendAction( this, manager::actions::Call, std::make_unique(msg->number)); } } + void ApplicationCall::IncomingCallHandler(const CellularCallMessage *const msg) + { + if (getState() == call::State::IDLE) { + constexpr sys::ms callerIdTimeout = 1000; + callerIdTimer = + std::make_unique("CallerIdTimer", this, callerIdTimeout, sys::Timer::Type::SingleShot); + callerIdTimer->connect([=](sys::Timer &) { + callerIdTimer->stop(); + manager::Controller::sendAction( + this, + manager::actions::Call, + std::make_unique(utils::PhoneNumber().getView())); + }); + } + } + void ApplicationCall::RingingHandler(const CellularCallMessage *const msg) { manager::Controller::sendAction( @@ -153,6 +160,9 @@ namespace app case CellularCallMessage::Type::IncomingCall: { IncomingCallHandler(msg); } break; + case CellularCallMessage::Type::CallerId: { + CallerIdHandler(msg); + } break; } } diff --git a/module-apps/application-call/ApplicationCall.hpp b/module-apps/application-call/ApplicationCall.hpp index b66cd536d..bbfdf4ba0 100644 --- a/module-apps/application-call/ApplicationCall.hpp +++ b/module-apps/application-call/ApplicationCall.hpp @@ -32,6 +32,7 @@ namespace app class CallWindowInterface { public: + using NumberChangeCallback = std::function; virtual ~CallWindowInterface() noexcept = default; virtual void setState(app::call::State state) noexcept = 0; @@ -70,8 +71,10 @@ namespace app void CallAbortHandler(); void CallActiveHandler(); void IncomingCallHandler(const CellularCallMessage *const msg); + void CallerIdHandler(const CellularCallMessage *const msg); void RingingHandler(const CellularCallMessage *const msg); - auto HandleMessageAsAction(sys::Message *request) -> std::shared_ptr; + + std::unique_ptr callerIdTimer; protected: call::State state = call::State::IDLE; @@ -124,7 +127,9 @@ namespace app return {{manager::actions::Launch, manager::actions::Call, manager::actions::Dial, - manager::actions::EmergencyDial}}; + manager::actions::EmergencyDial, + manager::actions::NotAnEmergencyNotification, + manager::actions::NoSimNotification}}; } }; } /* namespace app */ diff --git a/module-apps/application-call/data/CallAppStyle.hpp b/module-apps/application-call/data/CallAppStyle.hpp index 7bd3902d5..383e372de 100644 --- a/module-apps/application-call/data/CallAppStyle.hpp +++ b/module-apps/application-call/data/CallAppStyle.hpp @@ -25,6 +25,7 @@ namespace callAppStyle inline constexpr auto speaker = "app_call_speaker"; inline constexpr auto speakeron = "app_call_speaker_on"; inline constexpr auto bluetooth = "app_call_bluetooth"; + inline constexpr auto privateNumber = "app_call_private_number"; } // namespace strings namespace numberLabel diff --git a/module-apps/application-call/windows/CallWindow.cpp b/module-apps/application-call/windows/CallWindow.cpp index c7cd4cfd5..d909af529 100644 --- a/module-apps/application-call/windows/CallWindow.cpp +++ b/module-apps/application-call/windows/CallWindow.cpp @@ -162,15 +162,22 @@ namespace gui switch (state) { case State::INCOMING_CALL: { interface->startAudioRinging(); - bottomBar->setActive(gui::BottomBar::Side::CENTER, true); bottomBar->setText(gui::BottomBar::Side::LEFT, utils::localize.get(strings::answer), true); bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(strings::reject), true); durationLabel->setText(utils::localize.get(strings::iscalling)); durationLabel->setVisible(true); - sendSmsIcon->setVisible(true); speakerIcon->setVisible(false); microphoneIcon->setVisible(false); - setFocusItem(sendSmsIcon); + if (phoneNumber.getFormatted().empty()) { + bottomBar->setActive(gui::BottomBar::Side::CENTER, false); + sendSmsIcon->setVisible(false); + setFocusItem(nullptr); + } + else { + bottomBar->setActive(gui::BottomBar::Side::CENTER, true); + sendSmsIcon->setVisible(true); + setFocusItem(sendSmsIcon); + } } break; case State::CALL_ENDED: { interface->stopAudio(); @@ -222,6 +229,7 @@ namespace gui stopCallTimer(); [[fallthrough]]; default: + numberLabel->clear(); bottomBar->setActive(gui::BottomBar::Side::LEFT, false); bottomBar->setActive(gui::BottomBar::Side::CENTER, false); bottomBar->setActive(gui::BottomBar::Side::RIGHT, false); @@ -249,22 +257,27 @@ namespace gui void CallWindow::onBeforeShow(ShowMode mode, SwitchData *data) { if (auto callData = dynamic_cast(data); callData != nullptr) { - phoneNumber = callData->getPhoneNumber(); - auto contact = DBServiceAPI::MatchContactByPhoneNumber(this->application, phoneNumber); - auto displayName = phoneNumber.getFormatted(); - if (contact) { - LOG_INFO("number = %s recognized as contact id = %" PRIu32 ", name = %s", - phoneNumber.getEntered().c_str(), - contact->ID, - contact->getFormattedName().c_str()); - displayName = contact->getFormattedName(); + phoneNumber = callData->getPhoneNumber(); + if (!callData->getPhoneNumber().getFormatted().empty()) { + auto contact = DBServiceAPI::MatchContactByPhoneNumber(this->application, phoneNumber); + auto displayName = phoneNumber.getFormatted(); + if (contact) { + LOG_INFO("number = %s recognized as contact id = %" PRIu32 ", name = %s", + phoneNumber.getEntered().c_str(), + contact->ID, + contact->getFormattedName().c_str()); + displayName = contact->getFormattedName(); + } + else { + LOG_INFO("number = %s was not recognized as any valid contact", phoneNumber.getEntered().c_str()); + } + + numberLabel->setText(displayName); } else { - LOG_INFO("number = %s was not recognized as any valid contact", phoneNumber.getEntered().c_str()); + numberLabel->setText(utils::localize.get(strings::privateNumber)); } - numberLabel->setText(displayName); - if (dynamic_cast(data) != nullptr) { if (getState() == State::INCOMING_CALL) { LOG_DEBUG("ignoring IncomingCallData message"); @@ -317,8 +330,8 @@ namespace gui case State::CALL_IN_PROGRESS: interface->hangupCall(); return true; - break; - default: + case State::IDLE: + case State::CALL_ENDED: break; } @@ -411,4 +424,5 @@ namespace gui callDuration = std::chrono::seconds().zero(); stop_timer = true; } + } /* namespace gui */ diff --git a/module-apps/application-calllog/CalllogModel.cpp b/module-apps/application-calllog/CalllogModel.cpp index 99175e6d3..a9f224de3 100644 --- a/module-apps/application-calllog/CalllogModel.cpp +++ b/module-apps/application-calllog/CalllogModel.cpp @@ -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 "CalllogModel.hpp" @@ -61,20 +61,11 @@ gui::ListItem *CalllogModel::getItem(gui::Order order) auto item = new gui::CalllogItem(this, !(application->isTimeFormat12())); - item->setCall(call); - item->activatedCallback = [=](gui::Item &item) { - LOG_INFO("activatedCallback"); - std::unique_ptr data = std::make_unique(*call); - application->switchWindow(calllog::settings::DetailsWindowStr, std::move(data)); - return true; - }; - - item->inputCallback = [this, item](gui::Item &, const gui::InputEvent &event) { + auto callCallback = [this, item](gui::Item &, const gui::InputEvent &event) { if (event.state != gui::InputEvent::State::keyReleasedShort) { return false; } if (event.keyCode == gui::KeyCode::KEY_LF) { - LOG_DEBUG("calling"); return app::manager::Controller::sendAction( application, app::manager::actions::Dial, @@ -82,5 +73,29 @@ gui::ListItem *CalllogModel::getItem(gui::Order order) } return false; }; + + item->focusChangedCallback = [=](gui::Item &item) { + if (item.focus == true) { + auto &callLogItem = dynamic_cast(item); + if (callLogItem.getCall().presentation == PresentationType::PR_UNKNOWN) { + // disable call button since the number is unknown + application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::LEFT, false); + item.inputCallback = nullptr; + } + else { + application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::LEFT, true); + item.inputCallback = callCallback; + } + } + return true; + }; + + item->setCall(call); + item->activatedCallback = [=](gui::Item &item) { + std::unique_ptr data = std::make_unique(*call); + application->switchWindow(calllog::settings::DetailsWindowStr, std::move(data)); + return true; + }; + return item; } diff --git a/module-apps/application-calllog/data/CallLogStyle.hpp b/module-apps/application-calllog/data/CallLogStyle.hpp index f4fd3329d..e2a403a4c 100644 --- a/module-apps/application-calllog/data/CallLogStyle.hpp +++ b/module-apps/application-calllog/data/CallLogStyle.hpp @@ -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 @@ -7,6 +7,10 @@ // CALL LOG STYLE namespace callLogStyle { + namespace strings + { + inline constexpr auto privateNumber = "app_call_private_number"; + } // DETAILS WINDOW namespace detailsWindow { diff --git a/module-apps/application-calllog/widgets/CalllogItem.cpp b/module-apps/application-calllog/widgets/CalllogItem.cpp index 3dcc707dd..5ba5a8b6c 100644 --- a/module-apps/application-calllog/widgets/CalllogItem.cpp +++ b/module-apps/application-calllog/widgets/CalllogItem.cpp @@ -63,7 +63,12 @@ namespace gui void CalllogItem::setCall(std::shared_ptr &call) { this->call = call; - text->setText(call->name); + if (call->presentation == PresentationType::PR_UNKNOWN) { + text->setText(utils::localize.get(callLogStyle::strings::privateNumber)); + } + else { + text->setText(call->name); + } auto callType = calllog::toCallLogCallType(call->type); if (callType == calllog::CallLogCallType::MISSED) { diff --git a/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp b/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp index 054388da0..ef56fe93b 100644 --- a/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp +++ b/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp @@ -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 "CallLogDetailsWindow.hpp" @@ -206,8 +206,6 @@ namespace gui setTitle(record.name); - number->setText(record.phoneNumber.getFormatted()); - auto callType = toCallLogCallType(record.type); for (auto &img : callTypeImg) { img->setVisible(false); @@ -243,6 +241,20 @@ namespace gui if (mode == ShowMode::GUI_SHOW_INIT) setFocusItem(rects[static_cast(FocusRects::Call)]); + + if (record.presentation == PresentationType::PR_UNKNOWN) { + rects[FocusRects::Call]->setVisible(false); + rects[FocusRects::Call]->activatedCallback = nullptr; + rects[FocusRects::Call]->focusChangedCallback = nullptr; + rects[FocusRects::Sms]->setVisible(false); + rects[FocusRects::Sms]->activatedCallback = nullptr; + rects[FocusRects::Sms]->focusChangedCallback = nullptr; + number->setText(utils::localize.get(callLogStyle::strings::privateNumber)); + bottomBar->setActive(BottomBar::Side::CENTER, false); + } + else { + number->setText(record.phoneNumber.getFormatted()); + } } bool CallLogDetailsWindow::onInput(const InputEvent &inputEvent) diff --git a/module-apps/application-calllog/windows/CallLogMainWindow.cpp b/module-apps/application-calllog/windows/CallLogMainWindow.cpp index 7872835e7..ef11871d5 100644 --- a/module-apps/application-calllog/windows/CallLogMainWindow.cpp +++ b/module-apps/application-calllog/windows/CallLogMainWindow.cpp @@ -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 "CallLogMainWindow.hpp" @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -75,8 +76,10 @@ namespace gui bool CallLogMainWindow::onDatabaseMessage(sys::Message *msgl) { - DBCalllogResponseMessage *msg = reinterpret_cast(msgl); - return calllogModel->updateRecords(std::move(*msg->records)); + auto *msg = dynamic_cast(msgl); + if (msg != nullptr) { + return calllogModel->updateRecords(std::move(*msg->records)); + } + return false; } - } /* namespace gui */ diff --git a/module-apps/application-calllog/windows/CallLogMainWindow.hpp b/module-apps/application-calllog/windows/CallLogMainWindow.hpp index 08333ed0b..a0c8dcc08 100644 --- a/module-apps/application-calllog/windows/CallLogMainWindow.hpp +++ b/module-apps/application-calllog/windows/CallLogMainWindow.hpp @@ -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 diff --git a/module-apps/application-calllog/windows/CallLogOptionsWindow.cpp b/module-apps/application-calllog/windows/CallLogOptionsWindow.cpp index f913fc06d..537e7a441 100644 --- a/module-apps/application-calllog/windows/CallLogOptionsWindow.cpp +++ b/module-apps/application-calllog/windows/CallLogOptionsWindow.cpp @@ -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 "CallLogOptionsWindow.hpp" @@ -10,19 +10,20 @@ std::list calllogWindowOptions(app::ApplicationCallLog *app, const CalllogRecord &record) { - auto searchResults = DBServiceAPI::ContactGetByIDWithTemporary(app, record.getContactId()); - std::list options; + if (record.presentation != PresentationType::PR_UNKNOWN) { + auto searchResults = DBServiceAPI::ContactGetByIDWithTemporary(app, record.getContactId()); - if (searchResults->empty() || !searchResults->front().isValid() || searchResults->front().isTemporary()) { - // add option - add contact - options.emplace_back(gui::Option{ - std::make_unique(app, gui::option::ContactOperation::Add, searchResults->front())}); - } - else { - // add option - contact details - options.emplace_back(gui::Option{std::make_unique( - app, gui::option::ContactOperation::Details, searchResults->front())}); + if (searchResults->empty() || !searchResults->front().isValid() || searchResults->front().isTemporary()) { + // add option - add contact + options.emplace_back(gui::Option{std::make_unique( + app, gui::option::ContactOperation::Add, searchResults->front())}); + } + else { + // add option - contact details + options.emplace_back(gui::Option{std::make_unique( + app, gui::option::ContactOperation::Details, searchResults->front())}); + } } // add option delete call option diff --git a/module-apps/windows/AppWindow.hpp b/module-apps/windows/AppWindow.hpp index 7ce32a1bb..15187e473 100644 --- a/module-apps/windows/AppWindow.hpp +++ b/module-apps/windows/AppWindow.hpp @@ -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 diff --git a/module-cellular/CMakeLists.txt b/module-cellular/CMakeLists.txt index 9288eaa7f..83c8a30d4 100644 --- a/module-cellular/CMakeLists.txt +++ b/module-cellular/CMakeLists.txt @@ -34,6 +34,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCpin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcQiurc.cpp ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcPoweredDown.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcRing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcResponse.cpp ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcFactory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/at/src/Commands.cpp diff --git a/module-cellular/at/UrcHandler.hpp b/module-cellular/at/UrcHandler.hpp index decea6dd7..bd64350f0 100644 --- a/module-cellular/at/UrcHandler.hpp +++ b/module-cellular/at/UrcHandler.hpp @@ -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 @@ -13,6 +13,7 @@ namespace at::urc class Qind; class Cpin; class Qiurc; + class Ring; class PoweredDown; class UrcResponse; @@ -27,6 +28,7 @@ namespace at::urc virtual void Handle(Qind &urc) = 0; virtual void Handle(Cpin &urc) = 0; virtual void Handle(Qiurc &urc) = 0; + virtual void Handle(Ring &urc) = 0; virtual void Handle(PoweredDown &urc) = 0; virtual void Handle(UrcResponse &urc) = 0; }; diff --git a/module-cellular/at/UrcRing.hpp b/module-cellular/at/UrcRing.hpp new file mode 100644 index 000000000..ee2270f39 --- /dev/null +++ b/module-cellular/at/UrcRing.hpp @@ -0,0 +1,42 @@ +// 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 "Urc.hpp" + +namespace at::urc +{ + class Ring : public Urc + { + public: + enum RingType + { + Normal, + Async, + Sync, + RelAsync, + RelSync, + Fax, + Voice + }; + + static constexpr std::string_view headUnsolicited = "+CRING"; + static constexpr std::string_view headNormal = "RING"; + + static auto isURC(const std::string &uHead) -> bool + { + return uHead.find(Ring::headUnsolicited) == 0 || uHead.find(Ring::headNormal) == 0; + } + + using Urc::Urc; + + [[nodiscard]] auto isValid() const noexcept -> bool override; + [[nodiscard]] auto getType() const -> std::optional; + + void Handle(UrcHandler &h) final + { + h.Handle(*this); + } + }; +} // namespace at::urc diff --git a/module-cellular/at/src/Urc.cpp b/module-cellular/at/src/Urc.cpp index 83250fb48..0560005de 100644 --- a/module-cellular/at/src/Urc.cpp +++ b/module-cellular/at/src/Urc.cpp @@ -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 @@ -6,7 +6,7 @@ namespace at::urc { - Urc::Urc(const std::string &urcBody, const std::string &urcHead) : urcBody(urcBody), urcHead(urcHead) + Urc::Urc(const std::string &urcBody, const std::string &urcHead) : urcBody(utils::trim(urcBody)), urcHead(urcHead) { split(urcBody); } diff --git a/module-cellular/at/src/UrcFactory.cpp b/module-cellular/at/src/UrcFactory.cpp index 7a24f1461..d68ce0cfd 100644 --- a/module-cellular/at/src/UrcFactory.cpp +++ b/module-cellular/at/src/UrcFactory.cpp @@ -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 @@ -13,6 +13,8 @@ #include #include #include +#include + using namespace at::urc; std::unique_ptr UrcFactory::Create(const std::string &urcMessage) @@ -22,7 +24,7 @@ std::unique_ptr UrcFactory::Create(const std::string &urcMessage) } const char headDelimiter = ':'; auto it = std::find(urcMessage.begin(), urcMessage.end(), headDelimiter); - std::string head = std::string(urcMessage.begin(), it); + std::string head = utils::trim(std::string(urcMessage.begin(), it)); std::string body = std::string(it == urcMessage.end() ? urcMessage.begin() : it + 1, urcMessage.end()); if (Ctze::isURC(head)) { @@ -49,6 +51,9 @@ std::unique_ptr UrcFactory::Create(const std::string &urcMessage) else if (PoweredDown::isURC(head)) { return std::make_unique(body); } + else if (Ring::isURC(head)) { + return std::make_unique(body); + } else if (auto type = UrcResponse::isURC(head)) { return std::make_unique(type.value()); } diff --git a/module-cellular/at/src/UrcRing.cpp b/module-cellular/at/src/UrcRing.cpp new file mode 100644 index 000000000..b8c15e581 --- /dev/null +++ b/module-cellular/at/src/UrcRing.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include + +auto at::urc::Ring::isValid() const noexcept -> bool +{ + if (getType() == std::nullopt) { + return false; + } + return Urc::isValid(); +} + +auto at::urc::Ring::getType() const -> std::optional +{ + if (urcBody == at::urc::Ring::headNormal) { + return at::urc::Ring::RingType::Normal; + } + else if (urcBody == "ASYNC") { + return at::urc::Ring::RingType::Async; + } + else if (urcBody == "SYNC") { + return at::urc::Ring::RingType::Sync; + } + else if (urcBody == "REL ASYNC") { + return at::urc::Ring::RingType::RelAsync; + } + else if (urcBody == "REL SYNC") { + return at::urc::Ring::RingType::RelSync; + } + else if (urcBody == "FAX") { + return at::urc::Ring::RingType::Fax; + } + else if (urcBody == "VOICE") { + return at::urc::Ring::RingType::Voice; + } + + return std::nullopt; +} diff --git a/module-cellular/test/unittest_URC.cpp b/module-cellular/test/unittest_URC.cpp index d55aae66e..f10f594d8 100644 --- a/module-cellular/test/unittest_URC.cpp +++ b/module-cellular/test/unittest_URC.cpp @@ -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 "Utils.hpp" @@ -18,6 +18,7 @@ #include "UrcClip.hpp" #include "UrcCpin.hpp" #include "UrcQiurc.hpp" +#include "UrcRing.hpp" #include "UrcPoweredDown.hpp" #include "UrcResponse.hpp" #include "UrcFactory.hpp" @@ -753,11 +754,6 @@ TEST_CASE("Urc RESPONSE") REQUIRE(rsp); REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Connect); - urc = at::urc::UrcFactory::Create("RING"); - rsp = getURC(urc); - REQUIRE(rsp); - REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Ring); - urc = at::urc::UrcFactory::Create("NO CARRIER"); rsp = getURC(urc); REQUIRE(rsp); @@ -841,3 +837,37 @@ TEST_CASE("+Qiurc: TCP Context and connection message") REQUIRE(qiurc->getType() == std::nullopt); } } + +TEST_CASE("RING") +{ + struct RingTest + { + std::string body; + std::optional ringType; + }; + + std::vector testCases = { + {"RING", at::urc::Ring::Normal}, + {"+CRING: ASYNC", at::urc::Ring::Async}, + {"+CRING: SYNC", at::urc::Ring::Sync}, + {"+CRING: REL ASYNC", at::urc::Ring::RelAsync}, + {"\r\n+CRING: REL SYNC", at::urc::Ring::RelSync}, + {"+CRING: FAX", at::urc::Ring::Fax}, + {"+CRING: VOICE", at::urc::Ring::Voice}, + {"+CRING: BUMMER", std::nullopt}, + }; + + for (auto &test : testCases) { + auto urc = at::urc::UrcFactory::Create(test.body); + auto ring = getURC(urc); + REQUIRE(ring); + if (test.ringType) { + REQUIRE(ring->getType()); + REQUIRE(ring->getType().value() == test.ringType); + } + else { + REQUIRE(!ring->isValid()); + REQUIRE(!ring->getType()); + } + } +} diff --git a/module-db/Interface/CalllogRecord.cpp b/module-db/Interface/CalllogRecord.cpp index 5303d042d..632c9f6c7 100644 --- a/module-db/Interface/CalllogRecord.cpp +++ b/module-db/Interface/CalllogRecord.cpp @@ -47,19 +47,29 @@ CalllogRecordInterface::CalllogRecordInterface(CalllogDB *calllogDb, ContactsDB bool CalllogRecordInterface::Add(const CalllogRecord &rec) { - ContactRecordInterface contactInterface(contactsDB); - auto contactMatch = - contactInterface.MatchByNumber(rec.phoneNumber, ContactRecordInterface::CreateTempContact::True); - if (!contactMatch) { - LOG_ERROR("Cannot get contact, for number %s", rec.phoneNumber.getNonEmpty().c_str()); - return false; - } - auto &contactRec = contactMatch->contact; - auto localRec = rec; - localRec.contactId = contactRec.ID; - localRec.name = contactRec.getFormattedName(); - LOG_DEBUG("Adding calllog record %s", utils::to_string(localRec).c_str()); + if (!rec.phoneNumber.getFormatted().empty()) { + ContactRecordInterface contactInterface(contactsDB); + auto contactMatch = + contactInterface.MatchByNumber(rec.phoneNumber, ContactRecordInterface::CreateTempContact::True); + if (!contactMatch) { + LOG_ERROR("Cannot get contact, for number %s", rec.phoneNumber.getNonEmpty().c_str()); + return false; + } + auto &contactRec = contactMatch->contact; + + localRec.contactId = contactRec.ID; + localRec.name = contactRec.getFormattedName(); + if (localRec.presentation == PresentationType::PR_UNKNOWN) { + localRec.presentation = PresentationType::PR_ALLOWED; + } + LOG_DEBUG("Adding call log record %s", utils::to_string(localRec).c_str()); + } + else { + // private number so do not add contact just call log entry + localRec.presentation = PresentationType::PR_UNKNOWN; + LOG_DEBUG("Adding private call entry to call log record."); + } return calllogDB->calls.add(CalllogTableRow{{.ID = localRec.ID}, // this is only to remove warning .number = localRec.phoneNumber.getEntered(), @@ -71,7 +81,6 @@ bool CalllogRecordInterface::Add(const CalllogRecord &rec) .name = localRec.name, .contactId = localRec.contactId, .isRead = localRec.isRead}); - ; } uint32_t CalllogRecordInterface::GetLastID() @@ -119,21 +128,37 @@ std::unique_ptr> CalllogRecordInterface::GetLimitOffs bool CalllogRecordInterface::Update(const CalllogRecord &rec) { - auto call = calllogDB->calls.getById(rec.ID); if (!call.isValid()) { return false; } + auto contactID = rec.contactId; + auto presentation = rec.presentation; + if (call.presentation == PresentationType::PR_UNKNOWN && rec.phoneNumber.isValid()) { + // entry added as private was updated with phone number + ContactRecordInterface contactInterface(contactsDB); + auto contactMatch = + contactInterface.MatchByNumber(rec.phoneNumber, ContactRecordInterface::CreateTempContact::True); + if (!contactMatch) { + LOG_ERROR("Cannot get or create temporary contact for number %s", rec.phoneNumber.getNonEmpty().c_str()); + return false; + } + contactID = contactMatch->contact.ID; + if (presentation == PresentationType::PR_UNKNOWN) { + presentation = PresentationType::PR_ALLOWED; + } + } + return calllogDB->calls.update(CalllogTableRow{{.ID = rec.ID}, .number = rec.phoneNumber.getEntered(), .e164number = rec.phoneNumber.getE164(), - .presentation = rec.presentation, + .presentation = presentation, .date = rec.date, .duration = rec.duration, .type = rec.type, .name = rec.name, - .contactId = rec.contactId, + .contactId = contactID, .isRead = rec.isRead}); } @@ -165,13 +190,16 @@ CalllogRecord CalllogRecordInterface::GetByID(uint32_t id) { auto call = calllogDB->calls.getById(id); - auto contactRec = GetContactRecordByID(call.contactId); - if (contactRec.ID == DB_ID_NONE) { - LOG_ERROR("Cannot find contact for ID %" PRIu32, call.contactId); - return CalllogRecord(); + if (call.contactId != DB_ID_NONE) { + auto contactRec = GetContactRecordByID(call.contactId); + if (contactRec.ID == DB_ID_NONE) { + LOG_ERROR("Cannot find contact for ID %" PRIu32, call.contactId); + return CalllogRecord(); + } + + call.name = contactRec.getFormattedName(); } - call.name = contactRec.getFormattedName(); return CalllogRecord(call); } diff --git a/module-services/service-appmgr/model/ApplicationManager.cpp b/module-services/service-appmgr/model/ApplicationManager.cpp index 9a3eb41e0..7f7612b85 100644 --- a/module-services/service-appmgr/model/ApplicationManager.cpp +++ b/module-services/service-appmgr/model/ApplicationManager.cpp @@ -295,6 +295,8 @@ namespace app::manager connect(typeid(CellularMMIResultMessage), convertibleToActionHandler); connect(typeid(CellularMMIResponseMessage), convertibleToActionHandler); connect(typeid(CellularMMIPushMessage), convertibleToActionHandler); + connect(typeid(CellularNoSimNotification), convertibleToActionHandler); + connect(typeid(CellularNotAnEmergencyNotification), convertibleToActionHandler); connect(typeid(sys::CriticalBatteryLevelNotification), convertibleToActionHandler); connect(typeid(sys::SystemBrownoutMesssage), convertibleToActionHandler); } diff --git a/module-services/service-appmgr/service-appmgr/Actions.hpp b/module-services/service-appmgr/service-appmgr/Actions.hpp index 140f23bd5..1ed174963 100644 --- a/module-services/service-appmgr/service-appmgr/Actions.hpp +++ b/module-services/service-appmgr/service-appmgr/Actions.hpp @@ -26,8 +26,8 @@ namespace app::manager Launch, CloseSystem, Call, - CallRejectNotEmergency, - CallRejectNoSim, + NotAnEmergencyNotification, + NoSimNotification, Dial, EmergencyDial, ShowCallLog, diff --git a/module-services/service-cellular/CellularCall.cpp b/module-services/service-cellular/CellularCall.cpp index e20251eed..1c0a65435 100644 --- a/module-services/service-cellular/CellularCall.cpp +++ b/module-services/service-cellular/CellularCall.cpp @@ -29,8 +29,8 @@ namespace CellularCall CalllogRecord callRec; callRec.type = type; callRec.date = utils::time::Timestamp().getTime(); - callRec.name = number.getFormatted(); // temporary set name to entered number - callRec.phoneNumber = number; + callRec.presentation = PresentationType::PR_UNKNOWN; + callRec.phoneNumber = number; call = startCallAction ? startCallAction(callRec) : CalllogRecord(); if (!call.isValid()) { LOG_ERROR("startCallAction failed"); @@ -95,4 +95,10 @@ namespace CellularCall return true; } + + void CellularCall::setNumber(const utils::PhoneNumber::View &number) + { + call.presentation = number.getFormatted().empty() ? PresentationType::PR_UNKNOWN : PresentationType::PR_ALLOWED; + call.phoneNumber = number; + } } // namespace CellularCall diff --git a/module-services/service-cellular/CellularRequestHandler.cpp b/module-services/service-cellular/CellularRequestHandler.cpp index 8b8586ec0..611bf7ebd 100644 --- a/module-services/service-cellular/CellularRequestHandler.cpp +++ b/module-services/service-cellular/CellularRequestHandler.cpp @@ -19,6 +19,7 @@ #include "service-cellular/requests/ClirRequest.hpp" #include "service-cellular/requests/ClipRequest.hpp" #include "service-cellular/requests/CallWaitingRequest.hpp" +#include "service-cellular/requests/RejectRequest.hpp" #include @@ -72,6 +73,19 @@ void CellularRequestHandler::handle(cellular::CallRequest &request, at::Result & request.setHandled(true); } +void CellularRequestHandler::handle(cellular::RejectRequest &request, at::Result &result) +{ + if (request.getRejectReason() == cellular::RejectRequest::RejectReason::NoSim) { + auto message = std::make_shared(request.getNumber()); + cellular.bus.sendUnicast(message, app::manager::ApplicationManager::ServiceName); + } + else if (request.getRejectReason() == cellular::RejectRequest::RejectReason::NotAnEmergencyNumber) { + auto message = std::make_shared(request.getNumber()); + cellular.bus.sendUnicast(message, app::manager::ApplicationManager::ServiceName); + } + request.setHandled(true); +} + void CellularRequestHandler::handle(cellular::SupplementaryServicesRequest &request, at::Result &result) { auto requestHandled = request.checkModemResponse(result); diff --git a/module-services/service-cellular/CellularUrcHandler.cpp b/module-services/service-cellular/CellularUrcHandler.cpp index 35b02fb34..adc3236d1 100644 --- a/module-services/service-cellular/CellularUrcHandler.cpp +++ b/module-services/service-cellular/CellularUrcHandler.cpp @@ -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 "CellularUrcHandler.hpp" @@ -25,8 +25,13 @@ void CellularUrcHandler::Handle(Clip &urc) if (urc.isValid()) { phoneNumber = urc.getNumber(); } - // continue without number - response = std::make_unique(CellularCallMessage::Type::IncomingCall, phoneNumber); + response = std::make_unique(CellularCallMessage::Type::CallerId, phoneNumber); + urc.setHandled(true); +} + +void CellularUrcHandler::Handle(Ring &urc) +{ + response = std::make_unique(CellularCallMessage::Type::IncomingCall, ""); urc.setHandled(true); } diff --git a/module-services/service-cellular/CellularUrcHandler.hpp b/module-services/service-cellular/CellularUrcHandler.hpp index d48f411f3..3e6fb405d 100644 --- a/module-services/service-cellular/CellularUrcHandler.hpp +++ b/module-services/service-cellular/CellularUrcHandler.hpp @@ -17,6 +17,7 @@ #include #include #include +#include /** * ServiceCellular helper for handling Urc messages @@ -35,6 +36,7 @@ class CellularUrcHandler : public at::urc::UrcHandler void Handle(at::urc::Qind &urc) final; void Handle(at::urc::Cpin &urc) final; void Handle(at::urc::Qiurc &urc) final; + void Handle(at::urc::Ring &urc) final; void Handle(at::urc::PoweredDown &urc) final; void Handle(at::urc::UrcResponse &urc) final; diff --git a/module-services/service-cellular/RequestFactory.cpp b/module-services/service-cellular/RequestFactory.cpp index d95b8ea80..ee2b91a51 100644 --- a/module-services/service-cellular/RequestFactory.cpp +++ b/module-services/service-cellular/RequestFactory.cpp @@ -14,6 +14,7 @@ #include "service-cellular/requests/PinChangeRequest.hpp" #include "service-cellular/requests/ImeiRequest.hpp" #include "service-cellular/requests/UssdRequest.hpp" +#include "service-cellular/requests/RejectRequest.hpp" #include #include @@ -57,11 +58,11 @@ namespace cellular return std::make_unique(request); } else { - actionRequest = app::manager::actions::Action::CallRejectNoSim; + return std::make_unique(RejectRequest::RejectReason::NoSim, request); } } else if (requestMode == CellularCallRequestMessage::RequestMode::Emergency) { - actionRequest = app::manager::actions::Action::CallRejectNotEmergency; + return std::make_unique(RejectRequest::RejectReason::NotAnEmergencyNumber, request); } return nullptr; } @@ -72,10 +73,6 @@ namespace cellular return req; } - if (actionRequest) { - return nullptr; - } - std::string groupA, groupB, groupC, groupD, groupE, groupF; GroupMatch matchPack = {groupA, groupB, groupC, groupD, groupE, groupF}; @@ -120,15 +117,9 @@ namespace cellular } if (simStatus == SimStatus::SimSlotEmpty) { - actionRequest = app::manager::actions::Action::CallRejectNoSim; - return nullptr; + return std::make_unique(RejectRequest::RejectReason::NoSim, request); } return std::make_unique(request); } - std::optional &RequestFactory::getActionRequest() - { - return actionRequest; - } - } // namespace cellular diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index a5fbe1ae3..f2fa2215c 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -768,6 +768,10 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, responseMsg = std::make_shared(ret); break; } + case CellularCallMessage::Type::CallerId: { + ongoingCall.setNumber(msg->number); + break; + } } } break; // Incoming notifications from Notification Virtual Channel @@ -932,15 +936,10 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, auto request = factory.create(); - if (auto action = factory.getActionRequest(); action) { - responseMsg = std::make_shared(action.value(), msg->number.getEntered()); - } - else { - CellularRequestHandler handler(*this); - auto result = channel->cmd(request->command(), at::default_doc_timeout); - request->handle(handler, result); - responseMsg = std::make_shared(request->isHandled()); - } + CellularRequestHandler handler(*this); + auto result = channel->cmd(request->command(), at::default_doc_timeout); + request->handle(handler, result); + responseMsg = std::make_shared(request->isHandled()); } break; case MessageType::DBServiceNotification: { diff --git a/module-services/service-cellular/service-cellular/CellularCall.hpp b/module-services/service-cellular/service-cellular/CellularCall.hpp index 09b114126..d6460d237 100644 --- a/module-services/service-cellular/service-cellular/CellularCall.hpp +++ b/module-services/service-cellular/service-cellular/CellularCall.hpp @@ -8,6 +8,7 @@ #include #include