diff --git a/src/components/ble/AlertNotificationClient.h b/src/components/ble/AlertNotificationClient.h index fa10456c..d49205e3 100644 --- a/src/components/ble/AlertNotificationClient.h +++ b/src/components/ble/AlertNotificationClient.h @@ -83,4 +83,4 @@ namespace Pinetime { bool isDescriptorFound = false; }; } -} \ No newline at end of file +} diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp index 3156470c..9b9b4e9e 100644 --- a/src/components/ble/AlertNotificationService.cpp +++ b/src/components/ble/AlertNotificationService.cpp @@ -9,6 +9,7 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t AlertNotificationService::ansUuid; constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; +constexpr ble_uuid16_t AlertNotificationService::ansEventUuid; int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { @@ -33,6 +34,13 @@ AlertNotificationService::AlertNotificationService ( System::SystemTask& systemT .arg = this, .flags = BLE_GATT_CHR_F_WRITE }, + { + .uuid = (ble_uuid_t *) &ansEventUuid, + .access_cb = AlertNotificationCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_NOTIFY, + .val_handle = &eventHandle + }, { 0 } @@ -61,14 +69,36 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle const auto dbgPacketLen = OS_MBUF_PKTLEN(ctxt->om); size_t bufferSize = std::min(dbgPacketLen + stringTerminatorSize, maxBufferSize); auto messageSize = std::min(maxMessageSize, (bufferSize-headerSize)); + uint8_t* category = new uint8_t[1]; NotificationManager::Notification notif; os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data()); + os_mbuf_copydata(ctxt->om, 0, 1, category); notif.message[messageSize-1] = '\0'; notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; - notificationManager.Push(std::move(notif)); + Pinetime::System::SystemTask::Messages event = Pinetime::System::SystemTask::Messages::OnNewNotification; - systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification); + switch(*category) { + case (uint8_t) 0x05: + notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall; + event = Pinetime::System::SystemTask::Messages::OnNewCall; + break; + } + + notificationManager.Push(std::move(notif)); + systemTask.PushMessage(event); } return 0; } + +void AlertNotificationService::event(char event) { + auto *om = ble_hs_mbuf_from_flat(&event, 1); + + uint16_t connectionHandle = systemTask.nimble().connHandle(); + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + + ble_gattc_notify_custom(connectionHandle, eventHandle, om); +} diff --git a/src/components/ble/AlertNotificationService.h b/src/components/ble/AlertNotificationService.h index 120312d2..558cdf54 100644 --- a/src/components/ble/AlertNotificationService.h +++ b/src/components/ble/AlertNotificationService.h @@ -24,10 +24,28 @@ namespace Pinetime { int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt); + void event(char event); + + static const char EVENT_HANG_UP_CALL = 0x00; + static const char EVENT_ANSWER_CALL = 0x01; + private: + static const char ALERT_UNKNOWN = 0x01; + static const char ALERT_SIMPLE_ALERT = 0x02; + static const char ALERT_EMAIL = 0x03; + static const char ALERT_NEWS = 0x04; + static const char ALERT_INCOMING_CALL = 0x05; + static const char ALERT_MISSED_CALL = 0x06; + static const char ALERT_SMS = 0x07; + static const char ALERT_VOICE_MAIL = 0x08; + static const char ALERT_SCHEDULE = 0x09; + static const char ALERT_HIGH_PRIORITY_ALERT = 0x0a; + static const char ALERT_INSTANT_MESSAGE = 0x0b; + static constexpr uint16_t ansId {0x1811}; static constexpr uint16_t ansCharId {0x2a46}; + static constexpr uint16_t ansEventCharId = {0x2a47}; static constexpr ble_uuid16_t ansUuid { .u { .type = BLE_UUID_TYPE_16 }, @@ -39,11 +57,18 @@ namespace Pinetime { .value = ansCharId }; - struct ble_gatt_chr_def characteristicDefinition[2]; + static constexpr ble_uuid16_t ansEventUuid { + .u { .type = BLE_UUID_TYPE_16 }, + .value = ansEventCharId + }; + + struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_svc_def serviceDefinition[2]; Pinetime::System::SystemTask &systemTask; NotificationManager ¬ificationManager; + + uint16_t eventHandle; }; } } diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index a109800c..7bb135da 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -58,6 +58,7 @@ namespace Pinetime { Pinetime::Controllers::MusicService& music() {return musicService;}; Pinetime::Controllers::NavigationService& navigation() {return navService;}; + Pinetime::Controllers::AlertNotificationService& alertService() {return anService;}; uint16_t connHandle(); diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index b6ad90b4..879b5f22 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -128,6 +128,9 @@ void DisplayApp::Refresh() { } } break; + case Messages::NewCall: + modal->NewNotification(notificationManager, &systemTask.nimble().alertService()); + break; case Messages::TouchEvent: { if (state != States::Running) break; auto gesture = OnTouchEvent(); diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index da5a7b22..b79df51a 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -34,7 +34,7 @@ namespace Pinetime { public: enum class States {Idle, Running}; enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent, ButtonPushed, - NewNotification, BleFirmwareUpdateStarted }; + NewNotification, NewCall, BleFirmwareUpdateStarted }; enum class FullRefreshDirections { None, Up, Down }; enum class TouchModes { Gestures, Polling }; diff --git a/src/displayapp/screens/Modal.cpp b/src/displayapp/screens/Modal.cpp index d1a110ea..6d6768dc 100644 --- a/src/displayapp/screens/Modal.cpp +++ b/src/displayapp/screens/Modal.cpp @@ -6,10 +6,7 @@ using namespace Pinetime::Applications::Screens; extern lv_font_t jetbrains_mono_extrabold_compressed; extern lv_font_t jetbrains_mono_bold_20; -Modal::Modal(Pinetime::Applications::DisplayApp *app) : Screen(app) { - - -} +Modal::Modal(Pinetime::Applications::DisplayApp *app) : Screen(app), alertNotificationService(nullptr) {} Modal::~Modal() { lv_obj_clean(lv_scr_act()); @@ -41,13 +38,46 @@ void Modal::OnEvent(lv_obj_t *event_obj, lv_event_t evt) { if(evt == LV_EVENT_DELETE && event_obj == mbox) { Hide(); } else if(evt == LV_EVENT_VALUE_CHANGED) { - /* A button was clicked */ - lv_mbox_start_auto_close(mbox, 0); -// Hide(); + if(event_obj == mbox) { + if(strcmp(lv_mbox_get_active_btn_text(event_obj), this->positiveButton.c_str()) == 0) { + if(alertNotificationService != nullptr) { + alertNotificationService->event(Pinetime::Controllers::AlertNotificationService::EVENT_ANSWER_CALL); + } + } else { + if(alertNotificationService != nullptr) { + alertNotificationService->event(Pinetime::Controllers::AlertNotificationService::EVENT_HANG_UP_CALL); + } + } + lv_mbox_start_auto_close(mbox, 0); + } } } -void Modal::Show(const char* msg) { +void Modal::NewNotification(Pinetime::Controllers::NotificationManager ¬ificationManager, Pinetime::Controllers::AlertNotificationService* alertService) { + alertNotificationService = alertService; + auto notification = notificationManager.GetLastNotification(); + std::string msg; + if(notification.valid) { + switch(notification.category) { + case Pinetime::Controllers::NotificationManager::Categories::IncomingCall: + this->positiveButton = "Answer"; + this->negativeButton = "Hang up"; + msg += "Incoming call from:\n"; + msg += notification.message.data(); + break; + default: + this->positiveButton = "Ok"; + this->negativeButton = "Cancel"; + msg = notification.message.data(); + break; + } + + static const char *btns[] = {this->positiveButton.c_str(), this->negativeButton.c_str(), ""}; + this->Show(msg.c_str(), btns); + } +} + +void Modal::Show(const char* msg, const char *btns[]) { if(isVisible) return; isVisible = true; lv_style_copy(&modal_style, &lv_style_plain_color); @@ -60,11 +90,9 @@ void Modal::Show(const char* msg) { lv_obj_set_size(obj, LV_HOR_RES, LV_VER_RES); lv_obj_set_opa_scale_enable(obj, true); /* Enable opacity scaling for the animation */ - static const char * btns2[] = {"Ok", ""}; - /* Create the message box as a child of the modal background */ mbox = lv_mbox_create(obj, nullptr); - lv_mbox_add_btns(mbox, btns2); + lv_mbox_add_btns(mbox, btns); lv_mbox_set_text(mbox, msg); lv_obj_align(mbox, nullptr, LV_ALIGN_CENTER, 0, 0); lv_obj_set_event_cb(mbox, Modal::mbox_event_cb); diff --git a/src/displayapp/screens/Modal.h b/src/displayapp/screens/Modal.h index 9cc177f0..de7575a8 100644 --- a/src/displayapp/screens/Modal.h +++ b/src/displayapp/screens/Modal.h @@ -3,6 +3,8 @@ #include "Screen.h" #include #include +#include +#include namespace Pinetime { namespace Applications { @@ -13,7 +15,9 @@ namespace Pinetime { Modal(DisplayApp* app); ~Modal() override; - void Show(const char* msg); + + void NewNotification(Pinetime::Controllers::NotificationManager ¬ificationManager, Pinetime::Controllers::AlertNotificationService* alertService); + void Show(const char* msg, const char *btns[]); void Hide(); bool Refresh() override; @@ -23,6 +27,11 @@ namespace Pinetime { private: void OnEvent(lv_obj_t *event_obj, lv_event_t evt); + Pinetime::Controllers::AlertNotificationService* alertNotificationService = nullptr; + + std::string positiveButton; + std::string negativeButton; + lv_style_t modal_style; lv_obj_t *obj; lv_obj_t *mbox; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 13a84c26..2fbc8cf0 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -161,6 +161,10 @@ void SystemTask::Work() { if(isSleeping && !isWakingUp) GoToRunning(); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewNotification); break; + case Messages::OnNewCall: + if(isSleeping && !isWakingUp) GoToRunning(); + displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewCall); + break; case Messages::BleConnected: ReloadIdleTimer(); isBleDiscoveryTimerRunning = true; diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index cf3f1021..7e031b52 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -27,7 +27,7 @@ namespace Pinetime { namespace System { class SystemTask { public: - enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, BleConnected, + enum class Messages {GoToSleep, GoToRunning, OnNewTime, OnNewNotification, OnNewCall, BleConnected, BleFirmwareUpdateStarted, BleFirmwareUpdateFinished, OnTouchEvent, OnButtonEvent, OnDisplayTaskSleeping };