From fde3371558e9517eea92673f0e71fcfe8834e4fa Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 3 May 2023 22:16:52 +0200 Subject: [PATCH 1/6] SystemTask: implement screen locked until button is pressed When the device is woken through pressing the button everything is the same. But when woken through other means like single-tap or raise-to-wake, then the screen is locked (and showing a lock screen on touch input) until the button is pressed. Only exception is when the alarm wakes the screen, then touch input is still valid for the user to be able to press the red "stop alarm" button. Co-authored-by: NeroBurner --- src/CMakeLists.txt | 1 + src/displayapp/DisplayApp.cpp | 6 +++ src/displayapp/DisplayApp.h | 2 + src/displayapp/Messages.h | 2 + src/displayapp/widgets/PopupMessage.cpp | 56 +++++++++++++++++++++++++ src/displayapp/widgets/PopupMessage.h | 20 +++++++++ src/systemtask/SystemTask.cpp | 24 ++++++++++- src/systemtask/SystemTask.h | 2 + 8 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/displayapp/widgets/PopupMessage.cpp create mode 100644 src/displayapp/widgets/PopupMessage.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5cd2e656a4..a9488c8c34 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -403,6 +403,7 @@ list(APPEND SOURCE_FILES displayapp/widgets/PageIndicator.cpp displayapp/widgets/DotIndicator.cpp displayapp/widgets/StatusIcons.cpp + displayapp/widgets/PopupMessage.cpp ## Settings displayapp/screens/settings/QuickSettings.cpp diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index bfd7dbed6d..d4d6e04ca6 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -477,6 +477,12 @@ void DisplayApp::Refresh() { LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); motorController.RunForDuration(35); break; + case Messages::ShowIgnoreTouchPopup: + popupMessage.SetHidden(false); + break; + case Messages::HideIgnoreTouchPopup: + popupMessage.SetHidden(true); + break; } } diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index dabed99ea7..9d25bd4f98 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -15,6 +15,7 @@ #include "components/timer/Timer.h" #include "components/alarm/AlarmController.h" #include "touchhandler/TouchHandler.h" +#include "displayapp/widgets/PopupMessage.h" #include "displayapp/Messages.h" #include "BootErrors.h" @@ -102,6 +103,7 @@ namespace Pinetime { Pinetime::Controllers::FirmwareValidator validator; Pinetime::Components::LittleVgl lvgl; Pinetime::Controllers::Timer timer; + Pinetime::Applications::Widgets::PopupMessage popupMessage; AppControllers controllers; TaskHandle_t taskHandle; diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 1fcd72d278..76750a96e8 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -24,6 +24,8 @@ namespace Pinetime { AlarmTriggered, Chime, BleRadioEnableToggle, + ShowIgnoreTouchPopup, + HideIgnoreTouchPopup }; } } diff --git a/src/displayapp/widgets/PopupMessage.cpp b/src/displayapp/widgets/PopupMessage.cpp new file mode 100644 index 0000000000..ffcecdca4e --- /dev/null +++ b/src/displayapp/widgets/PopupMessage.cpp @@ -0,0 +1,56 @@ +#include "displayapp/widgets/PopupMessage.h" +#include "displayapp/InfiniTimeTheme.h" +#include + +using namespace Pinetime::Applications::Widgets; + +PopupMessage::PopupMessage() { +} + +void PopupMessage::Create() { + popup = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(popup, 90, 90); + lv_obj_align(popup, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_bg_color(popup, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_obj_set_style_local_bg_opa(popup, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_60); + lv_obj_t* lockBody = lv_obj_create(popup, nullptr); + lv_obj_set_size(lockBody, 55, 50); + lv_obj_align(lockBody, popup, LV_ALIGN_CENTER, 0, 10); + + lv_obj_set_style_local_bg_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_bg_opa(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); + lv_obj_set_style_local_border_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_border_width(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 22); + lv_obj_set_style_local_border_side(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); + lv_obj_set_style_local_border_opa(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100); + + lv_obj_t* lockTop = lv_obj_create(popup, nullptr); + lv_obj_set_size(lockTop, 30, 35); + lv_obj_align(lockTop, popup, LV_ALIGN_CENTER, 0, -20); + lv_obj_set_style_local_bg_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_bg_opa(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); + lv_obj_set_style_local_border_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_border_width(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 6); + lv_obj_set_style_local_border_side(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); + lv_obj_set_style_local_border_opa(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100); + + lv_obj_set_hidden(popup, isHidden); +} + +void PopupMessage::SetHidden(bool hidden) { + if (isHidden == hidden) { + return; + } + isHidden = hidden; + // create/delete on demand + if (popup == nullptr && !isHidden) { + Create(); + } else if (popup != nullptr) { + lv_obj_del(popup); + popup = nullptr; + } +} + +bool PopupMessage::IsHidden() { + return isHidden; +} diff --git a/src/displayapp/widgets/PopupMessage.h b/src/displayapp/widgets/PopupMessage.h new file mode 100644 index 0000000000..39e16b2c8f --- /dev/null +++ b/src/displayapp/widgets/PopupMessage.h @@ -0,0 +1,20 @@ +#pragma once +#include + +namespace Pinetime { + namespace Applications { + namespace Widgets { + class PopupMessage { + public: + PopupMessage(); + void Create(); + void SetHidden(bool hidden); + bool IsHidden(); + + private: + lv_obj_t* popup = nullptr; + bool isHidden = true; + }; + } + } +} diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 8e0435e372..d978763b07 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -215,6 +215,7 @@ void SystemTask::Work() { } break; case Messages::SetOffAlarm: + unlockedByButton = true; // unlock so it is possible to press red stop button GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); break; @@ -224,6 +225,7 @@ void SystemTask::Work() { bleDiscoveryTimer = 5; break; case Messages::BleFirmwareUpdateStarted: + unlockedByButton = true; // prevent no screen-locked popup on firmware update GoToRunning(); wakeLocksHeld++; displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted); @@ -251,7 +253,14 @@ void SystemTask::Work() { break; } if (state == SystemTaskState::Running) { - displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); + if (unlockedByButton) { + displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); + } else { + auto gesture = touchHandler.GestureGet(); + if (gesture != Pinetime::Applications::TouchEvents::None) { + displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowIgnoreTouchPopup); + } + } } else { // If asleep, check for touch panel wake triggers auto gesture = touchHandler.GestureGet(); @@ -273,6 +282,7 @@ void SystemTask::Work() { action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Press); // This is for faster wakeup, sacrificing special longpress and doubleclick handling while sleeping if (IsSleeping()) { + unlockedByButton = true; fastWakeUpDone = true; GoToRunning(); break; @@ -314,6 +324,8 @@ void SystemTask::Work() { } else { state = SystemTaskState::AODSleeping; } + // lock when going to sleep + unlockedByButton = false; break; case Messages::OnNewDay: // We might be sleeping (with TWI device disabled. @@ -424,6 +436,8 @@ void SystemTask::GoToSleep() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep); } heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep); + unlockedByButton = false; + displayApp.PushMessage(Pinetime::Applications::Display::Messages::HideIgnoreTouchPopup); state = SystemTaskState::GoingToSleep; }; @@ -473,7 +487,13 @@ void SystemTask::HandleButtonAction(Controllers::ButtonActions action) { case Actions::Click: // If the first action after fast wakeup is a click, it should be ignored. if (!fastWakeUpDone) { - displayApp.PushMessage(Applications::Display::Messages::ButtonPushed); + if (!unlockedByButton) { + // the first button event unlocks the touch input + unlockedByButton = true; + displayApp.PushMessage(Pinetime::Applications::Display::Messages::HideIgnoreTouchPopup); + } else { + displayApp.PushMessage(Applications::Display::Messages::ButtonPushed); + } } break; case Actions::DoubleClick: diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 0060e36096..be0d6e4dea 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -134,6 +134,8 @@ namespace Pinetime { bool stepCounterMustBeReset = false; static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000); + bool unlockedByButton = true; + SystemMonitor monitor; }; } From 79d4978c2cf5a7ed3a9988399b7a6ce2794690f0 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 24 May 2025 21:40:04 +0200 Subject: [PATCH 2/6] PopupMessage: little cleanup, more const --- src/displayapp/widgets/PopupMessage.cpp | 7 ++----- src/displayapp/widgets/PopupMessage.h | 26 +++++++++++-------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/displayapp/widgets/PopupMessage.cpp b/src/displayapp/widgets/PopupMessage.cpp index ffcecdca4e..56545f5143 100644 --- a/src/displayapp/widgets/PopupMessage.cpp +++ b/src/displayapp/widgets/PopupMessage.cpp @@ -4,9 +4,6 @@ using namespace Pinetime::Applications::Widgets; -PopupMessage::PopupMessage() { -} - void PopupMessage::Create() { popup = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_size(popup, 90, 90); @@ -37,7 +34,7 @@ void PopupMessage::Create() { lv_obj_set_hidden(popup, isHidden); } -void PopupMessage::SetHidden(bool hidden) { +void PopupMessage::SetHidden(const bool hidden) { if (isHidden == hidden) { return; } @@ -51,6 +48,6 @@ void PopupMessage::SetHidden(bool hidden) { } } -bool PopupMessage::IsHidden() { +bool PopupMessage::IsHidden() const { return isHidden; } diff --git a/src/displayapp/widgets/PopupMessage.h b/src/displayapp/widgets/PopupMessage.h index 39e16b2c8f..6a43d5525b 100644 --- a/src/displayapp/widgets/PopupMessage.h +++ b/src/displayapp/widgets/PopupMessage.h @@ -1,20 +1,16 @@ #pragma once #include -namespace Pinetime { - namespace Applications { - namespace Widgets { - class PopupMessage { - public: - PopupMessage(); - void Create(); - void SetHidden(bool hidden); - bool IsHidden(); +namespace Pinetime::Applications::Widgets { + class PopupMessage { + public: + PopupMessage() = default; + void Create(); + void SetHidden(bool hidden); + bool IsHidden() const; - private: - lv_obj_t* popup = nullptr; - bool isHidden = true; - }; - } - } + private: + lv_obj_t* popup = nullptr; + bool isHidden = true; + }; } From 3282333632f61c20f40d80157122225b32cea3e0 Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Thu, 29 May 2025 22:32:31 +0200 Subject: [PATCH 3/6] SystemTask: clang-format --- src/systemtask/SystemTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index d978763b07..ea1dc544ce 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -215,7 +215,7 @@ void SystemTask::Work() { } break; case Messages::SetOffAlarm: - unlockedByButton = true; // unlock so it is possible to press red stop button + unlockedByButton = true; // unlock so it is possible to press red stop button GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); break; @@ -225,7 +225,7 @@ void SystemTask::Work() { bleDiscoveryTimer = 5; break; case Messages::BleFirmwareUpdateStarted: - unlockedByButton = true; // prevent no screen-locked popup on firmware update + unlockedByButton = true; // prevent no screen-locked popup on firmware update GoToRunning(); wakeLocksHeld++; displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted); From 10344e5e68898a80a8701acb860b699b296e60ce Mon Sep 17 00:00:00 2001 From: sim Date: Sun, 20 Jul 2025 12:57:45 +0200 Subject: [PATCH 4/6] Always hide lock popup when changing appview It fixes a potential double-free when removing lock popup --- src/displayapp/DisplayApp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index d4d6e04ca6..ad1d961824 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -506,6 +506,11 @@ void DisplayApp::LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direc // This is mainly to fix an issue with receiving two notifications at the same time // and shouldn't happen otherwise. if (app != currentApp) { + // We need to remove the popup + // If we keep the popup linked to the previous view, and this view is deleted, a bug will occur if we try to re-remove the popup. + // Not removing the popup will also prevent the popup to be raised on top of + // the new app + popupMessage.SetHidden(true); returnAppStack.Push(currentApp); appStackDirections.Push(direction); } From 13e216895321f42d70b720ca83da87497ad1b94b Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 22 Jul 2025 12:59:09 +0200 Subject: [PATCH 5/6] Make lock icon less white And increase popup padding --- src/displayapp/widgets/PopupMessage.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/displayapp/widgets/PopupMessage.cpp b/src/displayapp/widgets/PopupMessage.cpp index 56545f5143..cdd5744377 100644 --- a/src/displayapp/widgets/PopupMessage.cpp +++ b/src/displayapp/widgets/PopupMessage.cpp @@ -10,23 +10,23 @@ void PopupMessage::Create() { lv_obj_align(popup, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_bg_color(popup, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); lv_obj_set_style_local_bg_opa(popup, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_60); - lv_obj_t* lockBody = lv_obj_create(popup, nullptr); - lv_obj_set_size(lockBody, 55, 50); - lv_obj_align(lockBody, popup, LV_ALIGN_CENTER, 0, 10); - lv_obj_set_style_local_bg_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_t* lockBody = lv_obj_create(popup, nullptr); + lv_obj_set_size(lockBody, 50, 45); + lv_obj_align(lockBody, popup, LV_ALIGN_CENTER, 0, 9); + lv_obj_set_style_local_bg_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_obj_set_style_local_bg_opa(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); - lv_obj_set_style_local_border_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_obj_set_style_local_border_width(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 22); + lv_obj_set_style_local_border_color(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); + lv_obj_set_style_local_border_width(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 23); lv_obj_set_style_local_border_side(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); lv_obj_set_style_local_border_opa(lockBody, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_t* lockTop = lv_obj_create(popup, nullptr); lv_obj_set_size(lockTop, 30, 35); - lv_obj_align(lockTop, popup, LV_ALIGN_CENTER, 0, -20); - lv_obj_set_style_local_bg_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_align(lockTop, popup, LV_ALIGN_CENTER, 0, -17); + lv_obj_set_style_local_bg_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_obj_set_style_local_bg_opa(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0); - lv_obj_set_style_local_border_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_border_color(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_obj_set_style_local_border_width(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 6); lv_obj_set_style_local_border_side(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL); lv_obj_set_style_local_border_opa(lockTop, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100); From 188fbff230286effa0417bb9764d293c6050eca3 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 22 Jul 2025 13:31:01 +0200 Subject: [PATCH 6/6] Do not show the lock popup on watchface with single tap --- src/displayapp/DisplayApp.cpp | 4 ++++ src/displayapp/DisplayApp.h | 2 ++ src/displayapp/DisplayAppRecovery.h | 4 ++++ src/systemtask/SystemTask.cpp | 8 +++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index ad1d961824..1bc5e137e7 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -729,6 +729,10 @@ void DisplayApp::Register(Pinetime::Controllers::NavigationService* NavigationSe this->controllers.navigationService = NavigationService; } +bool DisplayApp::IsWatchFace() { + return this->currentApp == Apps::Clock; +} + void DisplayApp::ApplyBrightness() { auto brightness = settingsController.GetBrightness(); if (brightness != Controllers::BrightnessController::Levels::Low && brightness != Controllers::BrightnessController::Levels::Medium && diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 9d25bd4f98..1f4cf17b69 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -81,6 +81,8 @@ namespace Pinetime { void Register(Pinetime::Controllers::MusicService* musicService); void Register(Pinetime::Controllers::NavigationService* NavigationService); + bool IsWatchFace(); + private: Pinetime::Drivers::St7789& lcd; const Pinetime::Drivers::Cst816S& touchPanel; diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 162ff2575e..e7ac448af0 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -74,6 +74,10 @@ namespace Pinetime { void Register(Pinetime::Controllers::MusicService* musicService); void Register(Pinetime::Controllers::NavigationService* NavigationService); + bool IsWatchFace() { + return false; + } + private: TaskHandle_t taskHandle; static void Process(void* instance); diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index ea1dc544ce..723b5742be 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -257,7 +257,13 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); } else { auto gesture = touchHandler.GestureGet(); - if (gesture != Pinetime::Applications::TouchEvents::None) { + if ( + displayApp.IsWatchFace() + && (gesture == Pinetime::Applications::TouchEvents::Tap + || gesture == Pinetime::Applications::TouchEvents::DoubleTap) + ) { + // Do not show the lock popup on the watch face with a single tap + } else if (gesture != Pinetime::Applications::TouchEvents::None) { displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowIgnoreTouchPopup); } }