【健康服务】UI
authorCaisking <Casiking@zhihuishixun.com>
Fri, 18 Apr 2025 03:54:43 +0000 (11:54 +0800)
committerCaisking <Casiking@zhihuishixun.com>
Fri, 18 Apr 2025 03:54:43 +0000 (11:54 +0800)
19 files changed:
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/defult_health.json [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.h [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.cpp [new file with mode: 0644]
code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.h [new file with mode: 0644]

diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.cpp
new file mode 100644 (file)
index 0000000..12aee59
--- /dev/null
@@ -0,0 +1,236 @@
+\r
+#include "heart_blood/BloodCardView.h"\r
+#include "common/image_cache_manager.h"\r
+#include "UiConfig.h"\r
+#include "ui_resource_image.h"\r
+#include <ui_scroll_view.h>\r
+#include "components/ui_button.h"\r
+#include "MainViewSample.h"\r
+#include "components/ui_view_group.h"\r
+#include "DialModelSPO2.h"\r
+#include "DialModelHeartRate.h"\r
+\r
+#include "UiConfig.h"\r
+#include "uicomponents/UIComponents.h"\r
+#include "MainPresenterSample.h"\r
+\r
+#include "bloodoxygen/include/BloodResultPresenter.h"\r
+#include "bloodoxygen/include/BloodOxygenModel.h"\r
+namespace OHOS\r
+{\r
+    static BloodCardView *g_pBloodCardView{nullptr};\r
+\r
+    BloodCardView::BloodCardView()\r
+    {\r
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "BloodCardView::BloodCardView");\r
+        SetPosition(0, 0, HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);\r
+        g_pBloodCardView = this;\r
+    }\r
+\r
+    BloodCardView::~BloodCardView()\r
+    {\r
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "BloodCardView::~BloodCardView");\r
+        DeInit();\r
+        g_pBloodCardView = nullptr;\r
+    }\r
+\r
+    BloodCardView *BloodCardView::GetInstance()\r
+    {\r
+        return g_pBloodCardView;\r
+    }\r
+\r
+    /* -------------------------------------------------------------------------- */\r
+    void BloodCardView::UpSPO2Text()\r
+    {\r
+        if (bloodLabel == nullptr || timeLabel == nullptr)\r
+            return;\r
+            \r
+        // 更新血氧数据\r
+        uint16_t spo2 = BloodOxygenModel::GetInstance()->GetSPO2data();\r
+        if (spo2 != 0) // 判断是否为默认数据\r
+        {\r
+            // 更新数据\r
+            std::string bloodoxygenStr = std::to_string(spo2) + "%";\r
+            bloodLabel->SetText(bloodoxygenStr.c_str());\r
+\r
+            // 获取时间差\r
+            uint32_t time = BloodResultPresenter::GetInstance()->GetCurrentTime();\r
+            uint32_t check_time = BloodOxygenModel::GetInstance()->GetCheckTime();\r
+            int time_diff = BloodResultPresenter::GetInstance()->GetTDOA(time, check_time);\r
+\r
+            if (time_diff == 0)\r
+            {\r
+                timeLabel->SetTextId(STR_CHECKNEW);\r
+            }\r
+            else if (time_diff <= 60)\r
+            {\r
+                UpdateLabel(timeLabel, time_diff, STR_CHECKTIME);\r
+            }\r
+            else\r
+            {\r
+                timeLabel->SetTextId(STR_CHECKLONG);\r
+            }\r
+        }\r
+        else\r
+        {\r
+            bloodLabel->SetText("--");\r
+            timeLabel->SetTextId(STR_CHECKNO);\r
+        }\r
+    }\r
+\r
+    /* -------------------------------------------------------------------------- */\r
+    /***\r
+     * @description:\r
+     * @return 添加按键是否成功\r
+     */\r
+    bool BloodCardView::AddButton()\r
+    {\r
+        InitButtonExt(checkButton, 118, 336, 230, 80, MAIN_CLICK_BLOOD, STR_CHECK, 30);\r
+        checkButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xffFF5A36); // 设置按键颜色\r
+        // 设置按键监听\r
+        UIView::OnClickListener *clickListener = (UIView::OnClickListener *)OHOS::MainPresenterSample::GetInstance();\r
+        checkButton->SetOnClickListener(clickListener);\r
+\r
+        Add(checkButton);\r
+        return true;\r
+    }\r
+    /***\r
+     * @description:\r
+     * @return 初始化标签是否成功\r
+     */\r
+    bool BloodCardView::InitLable()\r
+    {\r
+        /*初始化title*/\r
+        InitRollLabel(titleLabel, 83, 50, 300, 35, "title", STR_BLOOD, DEFAULT_VECTOR_FONT_FILENAME, 30);\r
+        /*初始化血氧值label*/\r
+        InitUILabel(bloodLabel, 83, 22, 300, 300, "bloodtext", "--", DEFAULT_VECTOR_FONT_FILENAME, 120);\r
+        /*初始化检测时间*/\r
+        InitRollLabel(timeLabel, 53, 260, 360, 35, "time", STR_CHECKNO, DEFAULT_VECTOR_FONT_FILENAME, 30);\r
+        // 设置来回滚动属性\r
+        timeLabel->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);\r
+        timeLabel->SetRollSpeed(23);\r
+\r
+        UpSPO2Text();\r
+\r
+        Add(titleLabel);\r
+        Add(bloodLabel);\r
+        Add(timeLabel);\r
+\r
+        return true;\r
+    }\r
+    /***\r
+     * @description:\r
+     * @return 初始化背景是否成功\r
+     */\r
+    bool BloodCardView::Initbackground()\r
+    {\r
+\r
+        background = new UIImageView();\r
+\r
+        background->SetPosition(0, 0);   // widget's left position and top position\r
+        background->Resize(466, 466);    // widget's width and height\r
+        background->SetViewId("image1"); // Set style\r
+\r
+        Add(background);\r
+        return true;\r
+    }\r
+    /***\r
+     * @description:\r
+     * @return 是否初始化成功\r
+     */\r
+    bool BloodCardView::InitView()\r
+    {\r
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "bool BloodCardView::InitView()");\r
+        if (!Initbackground())\r
+        {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Initbackground error!\n");\r
+        };\r
+        if (!InitLable())\r
+        {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "InitLable error!\n");\r
+        };\r
+        if (!AddButton())\r
+        {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AddButton error!\n");\r
+        };\r
+        // SetCoverable(true);\r
+        return true;\r
+    }\r
+    /***\r
+     * @description:\r
+     * @return 删除组件\r
+     */\r
+    void BloodCardView::DeInit()\r
+    {\r
+        UnLoadBloodImageRes();\r
+        RemoveAll();\r
+        if (background != nullptr)\r
+        {\r
+            delete background;\r
+            background = nullptr;\r
+        }\r
+        if (bloodLabel != nullptr)\r
+        {\r
+            delete bloodLabel;\r
+            bloodLabel = nullptr;\r
+        }\r
+        if (timeLabel != nullptr)\r
+        {\r
+            delete timeLabel;\r
+            timeLabel = nullptr;\r
+        }\r
+        if (titleLabel != nullptr)\r
+        {\r
+            delete titleLabel;\r
+            titleLabel = nullptr;\r
+        }\r
+    }\r
+    /* -------------------------------------------------------------------------- */\r
+    /*预加载血氧图片资源*/\r
+    void BloodCardView::PreLoadBloodImageRes(void)\r
+    {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodCardView::PreLoadBloodImageRes");\r
+        if (!resLoadStatus)\r
+        {\r
+            ImageInfo *image = ImageCacheManager::GetInstance().LoadOneInMultiRes(BLOODOXYGEN_BACKGOUND, BLOOD_IAMGES);\r
+            if (image == nullptr)\r
+            {\r
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "TraingView::LoadTrainingImage  fail");\r
+                return;\r
+            }\r
+            background->SetSrc(image);\r
+            resLoadStatus = true;\r
+        }\r
+    }\r
+\r
+    /*卸载血氧图片资源*/\r
+    void BloodCardView::UnLoadBloodImageRes(void)\r
+    {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodCardView::UnLoadBloodImageRes");\r
+        if (resLoadStatus)\r
+        {\r
+            ImageInfo *img = nullptr;\r
+            background->SetSrc(img);\r
+            ImageCacheManager::GetInstance().UnloadOneInMultiRes(BLOODOXYGEN_BACKGOUND, BLOOD_IAMGES);\r
+            resLoadStatus = false;\r
+        }\r
+    }\r
+\r
+    void BloodCardView::PreLoad(void)\r
+    {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodCardView::PreLoad");\r
+        if (!viewiInitStatus)\r
+        {\r
+            InitView();\r
+            viewiInitStatus = true;\r
+        }\r
+        PreLoadBloodImageRes();\r
+    }\r
+\r
+    void BloodCardView::UnLoad(void)\r
+    {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodCardView::UnLoad");\r
+        UnLoadBloodImageRes();\r
+    }\r
+    /* -------------------------------------------------------------------------- */\r
+}\r
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/BloodCardView.h
new file mode 100644 (file)
index 0000000..d0c6f34
--- /dev/null
@@ -0,0 +1,79 @@
+/***\r
+ * @Date: 2024-06-28 16:08:09\r
+ * @LastEditors: Caisking 3449750381@qq.com\r
+ * @LastEditTime: 2024-07-29 11:48:50\r
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/BloodCardView.h\r
+ */\r
+/***\r
+ * @Date: 2024-06-26 16:13:19\r
+ * @LastEditors: Caisking 3449750381@qq.com\r
+ * @LastEditTime: 2024-06-26 16:52:01\r
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/BloodCardView.h\r
+ */\r
+\r
+#ifndef _Blood_CARD_VIEW_H\r
+#define _Blood_CARD_VIEW_H\r
+\r
+\r
+#include "View.h"\r
+#include <ui_scroll_view.h>\r
+#include "components/ui_view_group.h"\r
+#include "components/ui_label.h"\r
+#include "components/ui_label_ext.h"\r
+#include "components/ui_image_view.h"\r
+#include "components/ui_button.h"\r
+#include "components/ui_image_animator.h"\r
+#include "components/ui_label_button_ext.h"\r
+#include "components/ui_card_page.h"\r
+#include "components/ui_label_button_ext.h"\r
+\r
+namespace OHOS\r
+{\r
+\r
+#define CHECK "buttoncheck"\r
+\r
+    class BloodCardView : public UICardPage\r
+    {\r
+\r
+    public:\r
+        BloodCardView();\r
+        virtual ~BloodCardView();\r
+        static BloodCardView *GetInstance(void);\r
+\r
+        bool InitView();\r
+        void DeInit();\r
+\r
+        bool AddButton();\r
+        bool InitLable();\r
+        bool Initbackground();\r
+\r
+        void PreLoad(void) override;\r
+        void UnLoad(void) override;\r
+\r
+        void UpSPO2Text();\r
+\r
+    private:\r
+        void PreLoadBloodImageRes(void);\r
+        void UnLoadBloodImageRes(void);\r
+\r
+    private:\r
+        UIView::OnDragListener *draglistener{nullptr};\r
+        BloodCardView(BloodCardView &&) = delete;\r
+        BloodCardView &operator=(BloodCardView &&) = delete;\r
+\r
+        UIImageView *background = nullptr;\r
+        UIButton *warnButton = nullptr;\r
+        UILabelButton *monitorButton = nullptr;\r
+        UILabelExt *titleLabel = nullptr;\r
+        UILabelExt *timeLabel = nullptr;\r
+        UILabel *bloodLabel = nullptr;\r
+\r
+        UILabelButtonExt *checkButton{nullptr};\r
+\r
+        bool viewiInitStatus{false};\r
+        bool resLoadStatus{false};\r
+\r
+        int bloodoxygen;\r
+    };\r
+} // namespace OHOS\r
+#endif // Blood_PRESENTER_H\r
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.cpp
new file mode 100644 (file)
index 0000000..13462f4
--- /dev/null
@@ -0,0 +1,127 @@
+/***
+ * @Date: 2024-07-30 11:22:00
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-08-16 15:59:09
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckAbnormalPresenter.cpp
+ */
+/*
+ * Copyright (c) CompanyNameMagicTag 2021-2021. All rights reserved.
+ * Description: bloodOxygen view
+ * Author:
+ * Create: 2021-08-01
+ */
+
+#include "heart_blood/CheckAbnormalPresenter.h"
+#include "common/task_manager.h"
+#include "BloodOxygenModel.h"
+
+#include "bloodoxygen/include/BloodDetectionView.h"
+#include "heart_blood/CheckAbnormalView.h"
+
+#include "components/ui_label.h"
+#include "components/ui_label_ext.h"
+
+#include "ChangeSliceListener.h"
+#include "broadcast_service.h"
+#include <fstream>
+#include "iostream"
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "wearable_log.h"
+#include "cmsis_os.h"
+#include "securec.h"
+#include "broadcast_service.h"
+#include "graphic_service.h"
+#include <chrono>
+#include <thread>
+#include <sys/time.h>
+
+#ifdef PPG_HX3695
+#include "ppg_service.h"
+#endif
+
+// #include "displaybrightness/include/DisplayBrightnessModel.h"
+#include "power_display_service.h"
+#include "custom_utils.h"
+
+#ifdef ENABLE_CYWEE
+#include "cywee_service.h"
+#endif
+
+#include "MainModel.h"
+#include "heart_blood/health_service/health_service.h"
+
+// #include "battery_hal.h"
+
+#include "NativeRegisterManager.h"
+
+namespace OHOS
+{
+
+    REGIST_SLICE(VIEW_CODED_LOCK, CheckAbnormalView, CheckAbnormalPresenter);
+
+
+    static CheckAbnormalPresenter *g_pCheckAbnormalPresenter;
+
+    CheckAbnormalPresenter::CheckAbnormalPresenter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CheckAbnormalPresenter::new CheckAbnormalPresenter");
+        g_pCheckAbnormalPresenter = this;
+    }
+    CheckAbnormalPresenter::~CheckAbnormalPresenter()
+    {
+        g_pCheckAbnormalPresenter = nullptr;
+    }
+    CheckAbnormalPresenter *CheckAbnormalPresenter::GetInstance()
+    {
+        return g_pCheckAbnormalPresenter;
+    }
+    void CheckAbnormalPresenter::OnStart()
+    {
+        Presenter<CheckAbnormalView>::OnStart();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CheckAbnormalPresenter::On Start ");
+    }
+    void CheckAbnormalPresenter::OnPause(void) {}
+
+    void CheckAbnormalPresenter::OnResume(void) {}
+
+    void CheckAbnormalPresenter::OnStop(void) {}
+
+    bool CheckAbnormalPresenter::OnClick(UIView &view, const ClickEvent &event)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodPresenter::OnClick");
+
+        if (strcmp(view.GetViewId(), CLICK_BLOOD_STOP) == 0)
+        {
+            NativeAbility::GetInstance().Back();
+        }
+        if (strcmp(view.GetViewId(), CLICK_BLOOD_RE) == 0)
+        {
+            // 检测过程中充电 失败可以弹窗
+            // bool isCharging = get_charge_stat(); // 获取充电状态
+            bool isCharging = false;
+
+            if (isCharging)
+            {
+                HealthState highHealthState;
+                highHealthState.checkType = CHARGE;
+                HealthService::GetInstance()->SetHealthCurrent(highHealthState);
+                NativeAbility::GetInstance().ChangeSlice(VIEW_CHECK_INVALID);
+                return true;
+            }
+            // 回到上一个检测界面
+            uint16 preSlice = NativeAbility::GetInstance().GetPreSliceId();
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "preSlice %d", preSlice);
+
+            if (preSlice == VIEW_MAIN) {
+                MainModel::GetInstance().SetFromSetCardView(true);
+                MainModel::GetInstance().SetFromCardId(HEART_RATE);
+              }
+            NativeAbility::GetInstance().ChangeSlice(preSlice);
+        }
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalPresenter.h
new file mode 100644 (file)
index 0000000..a420c9b
--- /dev/null
@@ -0,0 +1,44 @@
+/***
+ * @Date: 2024-07-30 11:22:09
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 16:39:17
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckAbnormalPresenter.h
+ */
+
+#ifndef CHECK_ABNORMAL_PRESENTER_H
+#define CHECK_ABNORMAL_PRESENTER_H
+
+#include "Presenter.h"
+#include "ModelListenerSample.h"
+#include "components/ui_circle_progress.h"
+#include "ohos_types.h"
+#include "KeyInputListener.h"
+#include "common/key_code.h"
+#include "heart_blood/CheckAbnormalView.h"
+
+namespace OHOS
+{
+    static constexpr const char *CLICK_BLOOD_STOP = "clickbloodstop"; // 血氧检测暂停
+    static constexpr const char *CLICK_BLOOD_RE = "clickbloodre";     // 血氧检测重新
+
+    class CheckAbnormalView;
+    class CheckAbnormalPresenter : public Presenter<CheckAbnormalView>,
+                                   public UIView::OnClickListener,
+
+                                   public UIView::OnDragListener
+    {
+    public:
+        CheckAbnormalPresenter();
+        virtual ~CheckAbnormalPresenter();
+        static CheckAbnormalPresenter *GetInstance(void);
+
+        void OnStart() override;
+        void OnPause() override;
+        void OnResume() override;
+        void OnStop() override;
+
+        bool OnClick(UIView &view, const ClickEvent &event) override;
+    };
+}
+
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.cpp
new file mode 100644 (file)
index 0000000..0a59025
--- /dev/null
@@ -0,0 +1,176 @@
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 16:39:56
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/src/CheckAbnormalView.cpp
+ */
+
+#include "common/image_cache_manager.h"
+#include "ui_resource_image.h"
+#include <ui_scroll_view.h>
+#include "components/ui_button.h"
+#include "MainViewSample.h"
+#include "components/ui_view_group.h"
+#include "DialModelSPO2.h"
+#include "DialModelHeartRate.h"
+#include "BloodOxygenModel.h"
+
+#include "UiConfig.h"
+#include "uicomponents/UIComponents.h"
+#include "MainPresenterSample.h"
+
+#include "heart_blood/CheckAbnormalPresenter.h"
+#include "heart_blood/CheckAbnormalView.h"
+
+#include "vibrator_service.h"
+#include "custom_runtime.h"
+
+namespace OHOS
+{
+    static CheckAbnormalView *g_pCheckAbnormalView{nullptr};
+    static const char *BLOOD_PATH_NOTE = "/user/res/Blood/Error.bin";
+
+    CheckAbnormalView::CheckAbnormalView()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckAbnormalView::CheckAbnormalView");
+        g_pCheckAbnormalView = this;
+    }
+
+    CheckAbnormalView::~CheckAbnormalView()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckAbnormalView::~CheckAbnormalView");
+        DeInit();
+        g_pCheckAbnormalView = nullptr;
+    }
+
+    CheckAbnormalView *CheckAbnormalView::GetInstance()
+    {
+        return g_pCheckAbnormalView;
+    }
+
+    /* -------------------------------------------------------------------------- */
+    /***
+     * @description:
+     * @return 添加按键是否成功
+     */
+    bool CheckAbnormalView::AddButton()
+    {
+        InitButtonExt(StButton, 58, 320, 170, 90, CLICK_BLOOD_STOP, STR_STOP, 30);
+        StButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xff191919); // 设置按键颜色
+        StButton->SetOnClickListener(presenter_);
+
+        InitButtonExt(ReButton, 238, 320, 170, 90, CLICK_BLOOD_RE, STR_RECHECK, 30);
+        ReButton->SetStyle(STYLE_BACKGROUND_COLOR, 0xffFF8A36); // 设置按键颜色
+        ReButton->SetOnClickListener(presenter_);
+
+        AddViewToRootContainer(StButton);
+        AddViewToRootContainer(ReButton);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 初始化标签是否成功
+     */
+    bool CheckAbnormalView::InitLable()
+    {
+        /*初始化title*/
+        InitRollLabel(titleLabel, 83, 50, 300, 35, "title", STR_CHECKERROR, DEFAULT_VECTOR_FONT_FILENAME, 30);
+
+        InitLabelExt(noteLabel, 53, 230, 360, 70, "time", STR_PWUWC, DEFAULT_VECTOR_FONT_FILENAME, 30);
+        // 设置来回滚动属性
+        noteLabel->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);
+        noteLabel->SetRollSpeed(23);
+
+        AddViewToRootContainer(titleLabel);
+        AddViewToRootContainer(noteLabel);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 初始化背景是否成功
+     */
+    bool CheckAbnormalView::Initbackground()
+    {
+
+        noteimage = new UIImageView();
+        noteimage->SetPosition(193, 120, 80, 80);
+        noteimage->SetSrc(BLOOD_PATH_NOTE);
+
+        AddViewToRootContainer(noteimage);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 是否初始化成功
+     */
+    bool CheckAbnormalView::CheckAbnormalViewInit()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "bool CheckAbnormalView::InitView()");
+        if (!Initbackground())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Initbackground error!");
+        };
+        if (!InitLable())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "InitLable error!");
+        };
+        if (!AddButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddButton error!");
+        };
+        return true;
+    }
+    /***
+     * @description:
+     * @return 删除组件
+     */
+    void CheckAbnormalView::DeInit()
+    {
+        if (StButton != nullptr)
+        {
+            delete StButton;
+            StButton = nullptr;
+        }
+        if (ReButton != nullptr)
+        {
+            delete ReButton;
+            ReButton = nullptr;
+        }
+        if (noteLabel != nullptr)
+        {
+            delete noteLabel;
+            noteLabel = nullptr;
+        }
+        if (titleLabel != nullptr)
+        {
+            delete titleLabel;
+            titleLabel = nullptr;
+        }
+        if (noteimage != nullptr)
+        {
+            delete noteimage;
+            noteimage = nullptr;
+        }
+    }
+
+    void CheckAbnormalView::OnStart()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckAbnormalView::OnStart");
+
+        if (!CheckAbnormalViewInit())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckAbnormalView::InitBloodView fail");
+        }
+        
+        if(true != OHOS::ConfigModel::GetInstance()->GetDnotdisturb() && (!uapi_sleep_mode_flag_get()))
+        {
+            ui_api_vibrate_once_func();
+        }
+        
+
+        GetRootContainer()->SetDraggable(true);
+        GetRootContainer()->SetTouchable(true);
+        GetRootContainer()->SetOnDragListener(presenter_);     
+        // GetRootContainer()->SetOnKeyActListener(presenter_);
+    }
+}
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckAbnormalView.h
new file mode 100644 (file)
index 0000000..7f6246d
--- /dev/null
@@ -0,0 +1,70 @@
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 11:46:23
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/include/CheckAbnormalView.h
+ */
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-05-07 18:51:13
+ * @FilePath: /XTS_FD230/FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/include/CheckAbnormalView.h
+ */
+/*
+ * Copyright (c) CompanyNameMagicTag 2021-2021. All rights reserved.
+ * Description: bloodResult view
+ * Author:
+ * Create: 2021-08-01
+ */
+
+#ifndef CHECK_ABNORMAL_VIEW_H
+#define CHECK_ABNORMAL_VIEW_H
+
+#include "View.h"
+
+#include "wearable_log.h"
+#include "UiConfig.h"
+#include "components/ui_label.h"
+#include "components/ui_label_ext.h"
+#include "components/ui_button.h"
+#include "components/ui_label_button.h"
+#include "components/ui_image_animator.h"
+#include "components/ui_circle_progress.h"
+#include "components/ui_view_group.h"
+#include "heart_blood/CheckAbnormalPresenter.h"
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_button_ext.h"
+namespace OHOS
+{
+    class CheckAbnormalPresenter;
+    class CheckAbnormalView : public View<CheckAbnormalPresenter>
+    {
+    public:
+        CheckAbnormalView();
+        virtual ~CheckAbnormalView();
+        static CheckAbnormalView *GetInstance(void);
+
+
+        void OnStart() override;
+
+        bool CheckAbnormalViewInit();
+
+        void DeInit();
+        bool AddButton();
+        bool InitLable();
+        bool Initbackground();
+
+    private:
+        // 提醒图标
+        UIImageView *noteimage = nullptr;
+        // 按键
+        UILabelButtonExt *StButton = nullptr;
+        UILabelButtonExt *ReButton = nullptr;
+        // 提醒label
+        UILabelExt *titleLabel = nullptr;
+        UILabelExt *noteLabel = nullptr;
+    };
+}
+
+#endif // 血氧主界面
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.cpp
new file mode 100644 (file)
index 0000000..f13bf69
--- /dev/null
@@ -0,0 +1,100 @@
+/*** 
+ * @Date: 2024-07-30 11:22:44
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-31 15:22:17
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckInvalidPresenter.cpp
+ */
+/*
+ * Copyright (c) CompanyNameMagicTag 2021-2021. All rights reserved.
+ * Description: bloodOxygen view
+ * Author:
+ * Create: 2021-08-01
+ */
+
+#include "heart_blood/CheckInvalidPresenter.h"
+#include "common/task_manager.h"
+#include "BloodOxygenModel.h"
+
+#include "bloodoxygen/include/BloodDetectionView.h"
+#include "heart_blood/CheckInvalidView.h"
+
+#include "components/ui_label.h"
+#include "components/ui_label_ext.h"
+
+#include "ChangeSliceListener.h"
+#include "broadcast_service.h"
+#include <fstream>
+#include "iostream"
+#include <sstream>
+#include <string>
+#include <cstdlib>
+#include <ctime>
+#include "wearable_log.h"
+#include "cmsis_os.h"
+#include "securec.h"
+#include "broadcast_service.h"
+#include "graphic_service.h"
+#include <chrono>
+#include <thread>
+#include <sys/time.h>
+
+#ifdef PPG_HX3695
+#include "ppg_service.h"
+#endif
+
+// #include "displaybrightness/include/DisplayBrightnessModel.h"
+#include "power_display_service.h"
+#include "custom_utils.h"
+
+#ifdef ENABLE_CYWEE
+#include "cywee_service.h"
+#endif
+
+#include "MainModel.h"
+
+#include "NativeRegisterManager.h"
+
+namespace OHOS
+{
+
+    REGIST_SLICE(VIEW_CHECK_INVALID, CheckInvalidView, CheckInvalidPresenter);
+
+
+    static CheckInvalidPresenter *g_pCheckInvalidPresenter;
+
+    CheckInvalidPresenter::CheckInvalidPresenter()
+    {
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CheckInvalidPresenter::new CheckInvalidPresenter");
+        g_pCheckInvalidPresenter = this;
+    }
+    CheckInvalidPresenter::~CheckInvalidPresenter()
+    {
+        g_pCheckInvalidPresenter = nullptr;
+    }
+    CheckInvalidPresenter *CheckInvalidPresenter::GetInstance()
+    {
+        return g_pCheckInvalidPresenter;
+    }
+    void CheckInvalidPresenter::OnStart()
+    {
+        Presenter<CheckInvalidView>::OnStart();
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CheckInvalidPresenter::On Start ");
+    }
+    void CheckInvalidPresenter::OnPause(void) {}
+
+    void CheckInvalidPresenter::OnResume(void) {}
+
+    void CheckInvalidPresenter::OnStop(void) {}
+
+    bool CheckInvalidPresenter::OnClick(UIView &view, const ClickEvent &event)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BloodPresenter::OnClick");
+
+        if (strcmp(view.GetViewId(), CLICK_HEALTH_KONW) == 0)
+        {
+            NativeAbility::GetInstance().Back();
+        }
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidPresenter.h
new file mode 100644 (file)
index 0000000..ef24ac1
--- /dev/null
@@ -0,0 +1,43 @@
+/***
+ * @Date: 2024-07-30 11:22:09
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 16:39:17
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckInvalidPresenter.h
+ */
+
+#ifndef CHECK_Invalid_PRESENTER_H
+#define CHECK_Invalid_PRESENTER_H
+
+#include "Presenter.h"
+#include "ModelListenerSample.h"
+#include "components/ui_circle_progress.h"
+#include "ohos_types.h"
+#include "KeyInputListener.h"
+#include "common/key_code.h"
+#include "heart_blood/CheckInvalidView.h"
+
+namespace OHOS
+{
+    static constexpr const char *CLICK_HEALTH_KONW = "clickbloodkown";     // 检测重新
+
+    class CheckInvalidView;
+    class CheckInvalidPresenter : public Presenter<CheckInvalidView>,
+                                   public UIView::OnClickListener,
+
+                                   public UIView::OnDragListener
+    {
+    public:
+        CheckInvalidPresenter();
+        virtual ~CheckInvalidPresenter();
+        static CheckInvalidPresenter *GetInstance(void);
+
+        void OnStart() override;
+        void OnPause() override;
+        void OnResume() override;
+        void OnStop() override;
+
+        bool OnClick(UIView &view, const ClickEvent &event) override;
+    };
+}
+
+#endif
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.cpp
new file mode 100644 (file)
index 0000000..a0a99d2
--- /dev/null
@@ -0,0 +1,227 @@
+/***
+ * @Date: 2024-07-30 11:20:16
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-31 15:16:05
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckInvalidView.cpp
+ */
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 16:39:56
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/src/CheckInvalidView.cpp
+ */
+
+#include "common/image_cache_manager.h"
+#include "ui_resource_image.h"
+#include <ui_scroll_view.h>
+#include "components/ui_button.h"
+#include "MainViewSample.h"
+#include "components/ui_view_group.h"
+#include "DialModelSPO2.h"
+#include "DialModelHeartRate.h"
+#include "BloodOxygenModel.h"
+
+#include "UiConfig.h"
+#include "uicomponents/UIComponents.h"
+#include "MainPresenterSample.h"
+
+#include "heart_blood/CheckInvalidPresenter.h"
+#include "heart_blood/CheckInvalidView.h"
+
+#include "heart_blood/health_service/health_service.h"
+
+#include "vibrator_service.h"
+#include "custom_runtime.h"
+
+namespace OHOS
+{
+    static CheckInvalidView *g_pCheckInvalidView{nullptr};
+    static const char *BLOOD_PATH_NOTE = "/user/res/Blood/Error.bin";
+
+    CheckInvalidView::CheckInvalidView()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckInvalidView::CheckInvalidView");
+        g_pCheckInvalidView = this;
+    }
+
+    CheckInvalidView::~CheckInvalidView()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckInvalidView::~CheckInvalidView");
+        DeInit();
+        g_pCheckInvalidView = nullptr;
+    }
+
+    CheckInvalidView *CheckInvalidView::GetInstance()
+    {
+        return g_pCheckInvalidView;
+    }
+
+    void CheckInvalidView::SetViewData()
+    {
+        HealthState healthState = HealthService::GetInstance()->GetHealthCurrent();
+
+        // 判断类型
+        if (healthState.checkType == BLOOD_CHECK)
+        {
+            titleLabel->SetTextId(STR_CHECKEWARN);
+
+            if (healthState.resultStatus == LOW)
+            {
+                SetNoteLabel(STR_BLOODSHORT, healthState.checkResult);
+            }
+        }
+        else if (healthState.checkType == HEART_CHECK)
+        {
+            titleLabel->SetTextId(STR_HEARTTITLE);
+            // 处理心率状态
+            switch (healthState.resultStatus)
+            {
+            case HIGH:
+                SetNoteLabel(STR_HEARTMAX, healthState.checkResult);
+                break;
+            case LOW:
+                SetNoteLabel(STR_HEARTMIN, healthState.checkResult);
+                break;
+            default:
+                SetNoteLabel(STR_HEARTMAX, healthState.checkResult);
+                break;
+            }
+        }
+        else if (healthState.checkType == CHARGE)
+        {
+            titleLabel->SetTextId(STR_CHARGE);
+            noteLabel->SetTextId(STR_CHARGE_NOTE);
+            remindLabel->SetVisible(false);
+        }
+    }
+
+    void CheckInvalidView::SetNoteLabel(UIResourceTextId viewId, int checkResult)
+    {
+        noteLabel->SetTextId(viewId);
+        UpdateLabel(noteLabel, checkResult, viewId);
+    }
+    /* -------------------------------------------------------------------------- */
+    /***
+     * @description:
+     * @return 添加按键是否成功
+     */
+    bool CheckInvalidView::AddButton()
+    {
+        /*初始化按键*/
+        InitButtonExt(kownButton, 0, 366, 466, 100, CLICK_HEALTH_KONW, STR_KONW, 30);
+        kownButton->SetImageSrc(PNG_466x100BUTTON_IMAGE, PNG_466x100BUTTON_IMAGE);
+        kownButton->SetOnClickListener(presenter_);
+
+        AddViewToRootContainer(kownButton);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 初始化标签是否成功
+     */
+    bool CheckInvalidView::InitLable()
+    {
+        /*初始化title*/
+        InitRollLabel(titleLabel, 83, 50, 300, 35, "title", STR_CHECKEWARN, DEFAULT_VECTOR_FONT_FILENAME, 30);
+        InitRollLabel(remindLabel, 53, 270, 360, 70, "remindLabel", STR_HEARTNOTE, DEFAULT_VECTOR_FONT_FILENAME, 30);
+        // 设置来回滚动属性
+        InitLabelExt(noteLabel, 53, 230, 360, 70, "time", STR_HEARTNOTE, DEFAULT_VECTOR_FONT_FILENAME, 30);
+        noteLabel->SetLineBreakMode(UILabel::LINE_BREAK_OSCILLATION);
+        noteLabel->SetRollSpeed(23);
+
+        AddViewToRootContainer(titleLabel);
+        AddViewToRootContainer(remindLabel);
+        AddViewToRootContainer(noteLabel);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 初始化背景是否成功
+     */
+    bool CheckInvalidView::Initbackground()
+    {
+
+        noteimage = new UIImageView();
+        noteimage->SetPosition(193, 120, 80, 80);
+        noteimage->SetSrc(BLOOD_PATH_NOTE);
+
+        AddViewToRootContainer(noteimage);
+        return true;
+    }
+    /***
+     * @description:
+     * @return 是否初始化成功
+     */
+    bool CheckInvalidView::CheckInvalidViewInit()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "bool CheckInvalidView::InitView()");
+        if (!Initbackground())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Initbackground error!");
+        };
+        if (!InitLable())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "InitLable error!");
+        };
+        if (!AddButton())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AddButton error!");
+        };
+        return true;
+    }
+    /***
+     * @description:
+     * @return 删除组件
+     */
+    void CheckInvalidView::DeInit()
+    {
+        if (kownButton != nullptr)
+        {
+            delete kownButton;
+            kownButton = nullptr;
+        }
+        if (noteLabel != nullptr)
+        {
+            delete noteLabel;
+            noteLabel = nullptr;
+        }
+        if (titleLabel != nullptr)
+        {
+            delete titleLabel;
+            titleLabel = nullptr;
+        }
+        if (remindLabel != nullptr)
+        {
+            delete remindLabel;
+            remindLabel = nullptr;
+        }
+        if (noteimage != nullptr)
+        {
+            delete noteimage;
+            noteimage = nullptr;
+        }
+    }
+
+    void CheckInvalidView::OnStart()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckInvalidView::OnStart");
+        View<CheckInvalidPresenter>::OnStart();
+
+        if (!CheckInvalidViewInit())
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckInvalidView::InitBloodView fail");
+        }
+        SetViewData();
+
+        if(true != OHOS::ConfigModel::GetInstance()->GetDnotdisturb() && (!uapi_sleep_mode_flag_get()))
+        {
+            // 震动提醒
+            ui_api_vibrate_once_func();
+        }
+
+        // 增加按键监听
+        RootView::OnKeyActListener *keyactListener = (RootView::OnKeyActListener *)OHOS::CheckInvalidPresenter::GetInstance();
+        RootView::GetInstance()->SetOnKeyActListener(keyactListener);
+    }
+   
+}
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/CheckInvalidView.h
new file mode 100644 (file)
index 0000000..f3b2b6a
--- /dev/null
@@ -0,0 +1,82 @@
+/***
+ * @Date: 2024-07-30 11:22:29
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 17:39:46
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/CheckInvalidView.h
+ */
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 11:46:23
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/include/CheckInvalidView.h
+ */
+/***
+ * @Date: 2024-04-15 10:55:58
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-05-07 18:51:13
+ * @FilePath: /XTS_FD230/FD230/code/sdk/application/wearable/fd230app/nativeui/bloodoxygen/include/CheckInvalidView.h
+ */
+/*
+ * Copyright (c) CompanyNameMagicTag 2021-2021. All rights reserved.
+ * Description: bloodResult view
+ * Author:
+ * Create: 2021-08-01
+ */
+
+#ifndef CHECK_Invalid_VIEW_H
+#define CHECK_Invalid_VIEW_H
+
+#include "View.h"
+
+#include "wearable_log.h"
+#include "UiConfig.h"
+
+#include "components/ui_label.h"
+#include "components/ui_label_ext.h"
+#include"ui_resource_string.h"
+
+#include "components/ui_button.h"
+#include "components/ui_label_button.h"
+#include "components/ui_image_animator.h"
+#include "components/ui_circle_progress.h"
+#include "components/ui_view_group.h"
+#include "heart_blood/CheckInvalidPresenter.h"
+
+#include "components/ui_scroll_view.h"
+#include "components/ui_label_button_ext.h"
+namespace OHOS
+{
+    class CheckInvalidPresenter;
+    class CheckInvalidView : public View<CheckInvalidPresenter>
+    {
+    public:
+        CheckInvalidView();
+        virtual ~CheckInvalidView();
+        static CheckInvalidView *GetInstance(void);
+
+ 
+        void OnStart() override;
+
+        bool CheckInvalidViewInit();
+
+        void DeInit();
+        bool AddButton();
+        bool InitLable();
+        bool Initbackground();
+
+        void SetViewData();
+        void SetNoteLabel(UIResourceTextId viewId, int checkResult);
+
+    private:
+        // 提醒图标
+        UIImageView *noteimage = nullptr;
+        // 按键
+        UILabelButtonExt *kownButton = nullptr;
+        // 提醒label
+        UILabelExt *titleLabel = nullptr;
+        UILabelExt *noteLabel = nullptr;
+        UILabelExt *remindLabel = nullptr;
+    };
+}
+
+#endif // 血氧主界面
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/defult_health.json b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/defult_health.json
new file mode 100644 (file)
index 0000000..0abdbde
--- /dev/null
@@ -0,0 +1,12 @@
+data{
+    "heart_latest_data": {
+        "value": 0,
+        "timestamp": 0
+    },
+    "heart_data_list": [
+        {
+            "value": 0,
+            "timestamp": 0
+        }
+    ]
+}
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.cpp
new file mode 100644 (file)
index 0000000..cea17e9
--- /dev/null
@@ -0,0 +1,692 @@
+#include "health_service.h"
+#include "bloodoxygen/include/BloodOxygenModel.h"
+#include "cJSON.h"
+#include "heartrate/include/HeartModel.h"
+#include "kv_store.h"
+#include "wearable_log.h"
+
+#include <cstdint>
+#include <ctime>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "custom_runtime.h"
+#include "custom_utils.h"
+
+// #include "safemodemanager/include/SafeModeManagerModelC.h"
+
+namespace OHOS {
+extern "C" {
+void uapi_dev_runtime_set_bloodoxygen_storage_status(uint8_t status);
+void uapi_dev_runtime_set_heartrate_storage_status(uint8_t status);
+
+void save_heart_data() {
+  // printf("save_heart_data\r\n");
+  OHOS::HealthService::GetInstance()->SaveDailyHeartRate();
+  return;
+}
+
+void save_heart_maxmin() {
+  // printf("save_heart_maxmin\r\n");
+  uint16_t max_heart_data =
+      OHOS::HeartModel::GetInstance()->GetShowMaxHeartdata();
+  uint16_t min_heart_data =
+      OHOS::HeartModel::GetInstance()->GetShowMinHeartdata();
+
+  OHOS::HealthService::GetInstance()->SaveHeartMaxMin(max_heart_data,
+                                                      min_heart_data);
+  return;
+}
+void save_blood_oxygen_data() {
+  OHOS::BloodOxygenData data;
+  data.SPO2 = OHOS::BloodOxygenModel::GetInstance()->GetSPO2data();
+  data.timestamp = OHOS::BloodOxygenModel::GetInstance()->GetCheckTime();
+  // 进行血氧存储 如果处于读取
+  if (uapi_dev_runtime_get_bloodoxygen_storage_status()) {
+    // printf("save_blood_oxygen_data is reading\n");
+    //进行延迟
+    LOS_Msleep(100);
+    if (uapi_dev_runtime_get_bloodoxygen_storage_status()) {
+      // printf("save_blood_oxygen_data is reading again\n");
+      //重新发送该消息
+      do_custom_fileoperate_service_check_msg(
+          CUSTOM_FILEOPERATE_MSG_TYPE_BLOODXYGEN_SAVE, nullptr, 0);
+      return;
+    }
+  }
+  HealthService::GetInstance()->UpdateHealthData(data);
+  // printf("save_blood_oxygen_data success\n");
+  return;
+}
+
+void save_heart_rate_data() {
+  OHOS::HeartRateData data;
+  data.Heart = OHOS::HeartModel::GetInstance()->GetHeartdata();
+  data.timestamp = OHOS::HeartModel::GetInstance()->GetCheckTime();
+  // 进行心率存储 如果处于读取
+  if (uapi_dev_runtime_get_heartrate_storage_status()) {
+    // printf("save_heart_rate_data is reading\n");
+    //进行延迟
+    LOS_Msleep(100);
+    if (uapi_dev_runtime_get_heartrate_storage_status()) {
+      // printf("save_heart_rate_data is reading again\n");
+      //重新发送该消息
+      do_custom_fileoperate_service_check_msg(
+          CUSTOM_FILEOPERATE_MSG_TYPE_HEARTRATE_SAVE, nullptr, 0);
+      return;
+    }
+  }
+  HealthService::GetInstance()->UpdateHealthData(data);
+  // printf("save_heart_rate_data success\n");
+  return;
+}
+//进行心率列表保存
+void save_heart_list() { HealthService::GetInstance()->SaveDailyHeartRate(); }
+}
+
+//判断时间戳是否为今日
+bool IsTimestampToday(uint32_t timestamp) {
+  // 获取当前时间
+  struct tm currentTm;
+  time_t seconds;
+  time(&seconds);
+  localtime_r(&seconds, &currentTm);
+  // 将给定时间戳转换为 tm 结构
+  struct tm *timestampTm =
+      localtime(reinterpret_cast<const time_t *>(&timestamp));
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "当前年月日:%d-%d-%d",
+                currentTm.tm_year + 1900, currentTm.tm_mon + 1,
+                currentTm.tm_mday);
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "给定时间戳:%d-%d-%d",
+                timestampTm->tm_year + 1900, timestampTm->tm_mon + 1,
+                timestampTm->tm_mday);
+  // 比较年、月和日
+  if ((currentTm.tm_year == timestampTm->tm_year &&
+       currentTm.tm_mon == timestampTm->tm_mon &&
+       currentTm.tm_mday == timestampTm->tm_mday)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static HealthService *g_pHealthService = nullptr;
+/*获取日期*/
+std::string GetCurrentDate() {
+  char date[9];
+  uapi_get_YYMMDD_Time(date, '\0');
+  return std::string(date);
+#if 0
+        time_t now = time(0);
+        tm *ltm = localtime(&now);
+        char date[9];                                // MM/DD/YYYY format
+        strftime(date, sizeof(date), "%m%d%Y", ltm); // Use "%m%d%Y" for MMDDYYYY format
+        return std::string(date);
+#endif
+}
+// static char *JSON_F_buf=NULL;
+
+HealthService::HealthService() {
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "HealthService::HealthService");
+  g_pHealthService = this;
+}
+HealthService::~HealthService() { g_pHealthService = nullptr; }
+HealthService *HealthService::GetInstance() {
+  static HealthService instance;
+  return &instance;
+}
+
+static constexpr const char *HEALTH_JSON_PATH = "/user/userdata/health/";
+static constexpr const char *HEALTH_JSON_PATH_HEART =
+    "/user/userdata/health/heart/";
+static constexpr const char *HEALTH_JSON_PATH_OXYGEN =
+    "/user/userdata/health/oxygen/";
+const char *GET_HEALTH_JSON_PATH_C_STR_HEART() {
+  return HEALTH_JSON_PATH_HEART;
+}
+const char *GET_HEALTH_JSON_PATH_C_STR_OXYGEN() {
+  return HEALTH_JSON_PATH_OXYGEN;
+}
+/* --------------------------------- 文件IO操作
+ * --------------------------------- */
+/*创建文件夹*/
+bool HealthService::CreateHealthFolder() {
+  struct stat info;
+  if (stat(HEALTH_JSON_PATH, &info) != 0) {
+    if (mkdir(HEALTH_JSON_PATH, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "mkdir HEALTH_JSON_PATH is error");
+      return false;
+    }
+  }
+  if (stat(HEALTH_JSON_PATH_HEART, &info) != 0) {
+    if (mkdir(HEALTH_JSON_PATH_HEART, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) !=
+        0) {
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                    "mkdir HEALTH_JSON_PATH_HEART is error");
+      return false;
+    }
+  }
+  if (stat(HEALTH_JSON_PATH_OXYGEN, &info) != 0) {
+    if (mkdir(HEALTH_JSON_PATH_OXYGEN, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) !=
+        0) {
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                    "mkdir HEALTH_JSON_PATH_OXYGEN is error");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/*生成bin*/
+std::string GetBinFilePath(uint8_t type) {
+  std::string currentDate = GetCurrentDate();
+  const char *healthTypePath = (type == HEALTH_TYPE_HEART)
+                                   ? HEALTH_JSON_PATH_HEART
+                                   : HEALTH_JSON_PATH_OXYGEN;
+
+  return healthTypePath + currentDate + ".bin";
+}
+
+/* --------------------------------- json操作 ---------------------------------
+ */
+static constexpr const char *HEART_JSON_PATH =
+    "/user/userdata/health/heart.json";
+static constexpr const char *BLOOD_JSON_PATH =
+    "/user/userdata/health/blood.json";
+
+// 读取血氧数据
+BloodOxygenData *HealthService::ReadBloodOxygenData() {
+  // 判断文件夹是否存在
+  if (!CreateHealthFolder()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to create health folder");
+    return nullptr;
+  }
+
+  // 读取文件
+  std::ifstream inFile(BLOOD_JSON_PATH);
+  if (!inFile.is_open()) {
+    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Failed to open JSON file");
+    return nullptr;
+  }
+
+  // 读取文件内容到字符串
+  std::stringstream buffer;
+  buffer << inFile.rdbuf();
+  std::string jsonDataString = buffer.str();
+  const char *jsonData = jsonDataString.c_str();
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "jsonData: %s", jsonData);
+
+  // 关闭文件
+  inFile.close();
+
+  if (jsonDataString.empty()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "jsonDataString is empty");
+    return nullptr;
+  }
+
+  cJSON *oxygen_root = cJSON_Parse(jsonData);
+  if (oxygen_root == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to parse JSON data");
+    return nullptr;
+  }
+
+  BloodOxygenData *data = new BloodOxygenData();
+
+  cJSON *value_item = cJSON_GetObjectItem(oxygen_root, "value");
+  cJSON *timestamp_item = cJSON_GetObjectItem(oxygen_root, "timestamp");
+
+  // 检查是否存在必要字段,并验证数据类型
+  if (value_item && cJSON_IsNumber(value_item) && timestamp_item &&
+      cJSON_IsNumber(timestamp_item)) {
+    data->SPO2 = value_item->valueint;
+    data->timestamp = timestamp_item->valuedouble;
+
+    // 进一步验证数据的合理性
+    if (data->SPO2 < 0 || data->SPO2 > 100) // 血氧饱和度范围是0-100
+    {
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid SPO2 value: %d",
+                    data->SPO2);
+      cJSON_Delete(oxygen_root);
+      delete data;
+      return nullptr;
+    }
+  } else {
+    // 读取的数据异常
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Missing or invalid data fields");
+    cJSON_Delete(oxygen_root);
+    delete data;
+    return nullptr;
+  }
+
+  cJSON_Delete(oxygen_root);
+  return data;
+}
+
+// 读取心率数据
+void HealthService::ReadHeartRateData(HeartRateData &data) {
+  data.timestamp = heart_time;
+  data.Heart = heart_rate;
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "heart_time: %d, heart_rate: %d",
+                data.timestamp, data.Heart);
+}
+
+// 保存血氧数据X
+bool HealthService::UpdateHealthData(const BloodOxygenData &data) {
+  // 配置血氧存储状态
+  uapi_dev_runtime_set_bloodoxygen_storage_status(1);
+
+  // 判断文件夹是否存在
+  if (!CreateHealthFolder()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CreateHealthFolder file");
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  // 判断文件是否存在,不存在即创建并打开以输出模式
+  std::ofstream outFile(BLOOD_JSON_PATH, std::ios::trunc);
+  if (!outFile.is_open()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to create or open JSON file for writing");
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  // 创建一个 JSON 对象
+  cJSON *oxygen_root = cJSON_CreateObject();
+  if (oxygen_root == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to create JSON object");
+    outFile.close();
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  cJSON_AddItemToObject(oxygen_root, "value", cJSON_CreateNumber(data.SPO2));
+  cJSON_AddItemToObject(oxygen_root, "timestamp",
+                        cJSON_CreateNumber(data.timestamp));
+
+  char *jsonData = cJSON_Print(oxygen_root);
+  if (jsonData == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to generate JSON data");
+    cJSON_Delete(oxygen_root); // 释放内存
+    outFile.close();
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  // 写入 JSON 数据到文件
+  outFile << jsonData;
+
+  // 释放资源
+  cJSON_Delete(oxygen_root);
+  free(jsonData);
+  outFile.close();
+  WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateHealthData SPO2 JSON is ok");
+
+  /* 存储bin文件[协议使用] */
+  std::string binFilePath = GetBinFilePath(HEALTH_TYPE_OXYGEN);
+  FILE *fp = fopen(binFilePath.c_str(), "ab+");
+  if (fp == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to open binary file for writing");
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  // 写入数据
+  if (fwrite(&data.timestamp, sizeof(data.timestamp), 1, fp) != 1 ||
+      fwrite(&data.SPO2, sizeof(data.SPO2), 1, fp) != 1) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to write data to binary file");
+    fclose(fp);
+    uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  fclose(fp);
+
+  uapi_dev_runtime_set_bloodoxygen_storage_status(0); // 恢复状态
+  return true;
+}
+
+// 清空健康数据
+bool HealthService::CleanHealthData() {
+  //清空心率数组
+  ClearHourlyHeartRates();
+  //进行数据存储
+  do_custom_fileoperate_service_check_msg(
+      CUSTOM_FILEOPERATE_MSG_TYPE_HEART_DATA_LIST, nullptr, 0);
+  // SaveDailyHeartRate();
+
+  HeartModel::GetInstance()->ClearDisplayData();
+  // BloodOxygenModel::GetInstance()->ClearDisplayData();
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "CleanHealthData  is ok");
+  return true;
+}
+
+HealthState HealthService::GetHealthCurrent() { return healthState_; }
+void HealthService::SetHealthCurrent(HealthState healthState) {
+  healthState_ = healthState;
+}
+/* ------------------------------- 心率当天历史数据处理
+ * ------------------------------ */
+static constexpr const char *HEART_DATA_PATH =
+    "/user/userdata/health/heart_history.bin";
+
+//清空数组
+void HealthService::ClearHourlyHeartRates() {
+  for (int i = 0; i < MAX_HOURS; ++i) {
+    dailyHeartRates[i].Heart = 0;
+    dailyHeartRates[i].timestamp = 0;
+  }
+}
+
+// 更新心率列表项
+void HealthService::UpdateHourlyHeartRate(time_t timestamp,
+                                          uint16_t heartRate) {
+  struct tm *timeInfo = localtime(&timestamp);
+  uint16_t hour = static_cast<uint16_t>(timeInfo->tm_hour);
+
+  if (hour < MAX_HOURS && heartRate > 0) {
+
+    // 更新当前小时的心率和时间戳
+    dailyHeartRates[hour].Heart = heartRate;
+    dailyHeartRates[hour].timestamp = timestamp;
+
+    currenthour = hour;
+
+    // 从当前小时的下一个小时开始,清除后续所有已记录的值
+    if (hour != 23) {
+      for (int i = hour + 1; i < MAX_HOURS; ++i) {
+        dailyHeartRates[i].Heart = 0;
+        dailyHeartRates[i].timestamp = 0;
+      }
+    }
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateHourlyHeartRate is ok");
+  } else {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Invalid hour or heart rate value %d", hour);
+  }
+}
+
+// 获取指定小时的心率
+uint16_t HealthService::GetHourlyHeartRate(uint16_t hour) {
+  if (hour < MAX_HOURS) {
+    return dailyHeartRates[hour].Heart; // 默认为 0 如果未更新
+  }
+  return 0; // 或者返回一个异常值
+}
+//获取指定小时的时间戳
+time_t HealthService::GetHourlyTimestamp(uint16_t hour) {
+  if (hour < MAX_HOURS) {
+    return dailyHeartRates[hour].timestamp; // 默认为 0 如果未更新
+  }
+  return 0; // 或者返回一个异常值
+}
+
+// 获取当前小时
+uint16_t HealthService::GetCurrentHour() { return currenthour; }
+/*
+心率最大最小值存储
+关机存储
+*/
+#define HEART_MAX_MIN_PATH "/user/userdata/health/heart_max_min.bin"
+// 保存最大最小值
+bool HealthService::SaveHeartMaxMin(uint16_t max, uint16_t min) {
+  std::ofstream outFile(HEART_MAX_MIN_PATH, std::ios::binary | std::ios::trunc);
+  if (!outFile.is_open()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file");
+    return false;
+  }
+
+  outFile.write(reinterpret_cast<const char *>(&max), sizeof(max));
+  if (!outFile) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to write max value");
+    return false;
+  }
+
+  outFile.write(reinterpret_cast<const char *>(&min), sizeof(min));
+  if (!outFile) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to write min value");
+    return false;
+  }
+
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SaveHeartMaxMin is ok max %d, min %d",
+                max, min);
+  return true;
+}
+// 加载最大最小值
+void HealthService::LoadHeartMaxMin(uint16_t &max, uint16_t &min) {
+  max = heart_max;
+  if (heart_min == 255)
+    min = 0;
+  else
+    min = heart_min;
+}
+
+//进行消息发送
+void HealthService::send_heart_save() {
+  do_custom_fileoperate_service_check_msg(
+      CUSTOM_FILEOPERATE_MSG_TYPE_HEARTRATE_SAVE, nullptr, 0);
+}
+void HealthService::send_blood_save() {
+  do_custom_fileoperate_service_check_msg(
+      CUSTOM_FILEOPERATE_MSG_TYPE_BLOODXYGEN_SAVE, nullptr, 0);
+}
+
+//获取list文件
+uint32_t HealthService::GetListTime() { return lastLoadTime; }
+
+std::string HealthService::formatTime(uint32_t time) {
+  char labelTime[20];
+  if (uapi_get_TIME_STR(time, labelTime, '.', ':', DATE_TIME_DEFULL) !=
+      ERRCODE_SUCC) {
+    return "--"; // 默认值
+  }
+  return labelTime; // 成功获取时间
+}
+
+/********************************************************************************************/
+/*******************************************************************************************
+ */
+//存储心率
+bool HealthService::UpdateHealthData(const HeartRateData &data) {
+  // 配置心率存储状态
+  uapi_dev_runtime_set_heartrate_storage_status(1);
+
+  // 判断文件夹是否存在
+  if (!CreateHealthFolder()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CreateHealthFolder file");
+    uapi_dev_runtime_set_heartrate_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  if (data.timestamp < 0 || (!IsTimestampToday(data.timestamp))) {
+    uapi_dev_runtime_set_heartrate_storage_status(0); // 恢复状态
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid timestamp %d",
+                  data.timestamp);
+    return false;
+  }
+  if (!save_bin_heart(data)) { // 存储bin文件[协议使用]
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveDailyHeartRate failed");
+    uapi_dev_runtime_set_heartrate_storage_status(0); // 恢复状态
+    return false;
+  }
+
+  uapi_dev_runtime_set_heartrate_storage_status(0); // 恢复状态
+  return true;
+}
+//存储bin文件
+bool HealthService::save_bin_heart(const HeartRateData &data) {
+  /* 存储 bin 文件 [协议使用] */
+  std::string binFilePath = GetBinFilePath(HEALTH_TYPE_HEART);
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "save_bin_heart binFilePath %s",
+                binFilePath.c_str());
+  FILE *fp = fopen(binFilePath.c_str(), "ab+");
+  if (fp == NULL) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to open binary file for writing");
+    return false;
+  }
+
+  // 写入数据
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "sizeof(HeartRateData) %d", sizeof(HeartRateData));
+  if ((fwrite(&data.timestamp, sizeof(data.timestamp), 1, fp) != 1) || (fwrite(&data.Heart, sizeof(data.Heart), 1, fp) != 1)) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to write data to binary file");
+    fclose(fp);
+    return false;
+  }
+
+  fclose(fp);
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+                "Saved heart data: timestamp = %d, Heart = %d", data.timestamp,
+                data.Heart);
+  return true;
+}
+// 加载心率数据 24小时数据
+bool HealthService::LoadDailyHeartRate() {  
+  ClearHourlyHeartRates(); // 清空数组 赋0操作  
+  std::string binFilePath = GetBinFilePath(HEALTH_TYPE_HEART);  
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "LoadDailyHeartRate");  
+  WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "binFilePath %s", binFilePath.c_str());  
+
+  // 配置心率存储状态  
+  uapi_dev_runtime_set_heartrate_storage_status(1);  
+
+  std::ifstream ifs(binFilePath, std::ios::binary);  
+  if (!ifs.is_open()) {  
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,  
+                  "Failed to open binary file for reading");  
+    uapi_dev_runtime_set_heartrate_storage_status(0);  
+    return false;  
+  }  
+
+  HeartRateData data;  
+
+  // 选取每个小时的最新数据  
+  while (true) {  
+    // 先读取时间戳  
+    if (!ifs.read(reinterpret_cast<char *>(&data.timestamp), sizeof(data.timestamp))) {  
+      break; // 如果读取失败,退出循环  
+    }  
+
+    // 再读取心率值  
+    if (!ifs.read(reinterpret_cast<char *>(&data.Heart), sizeof(data.Heart))) {  
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,  
+                    "Failed to read heart rate value");  
+      break; // 如果读取失败,退出循环  
+    }  
+
+    // 检查时间戳是否为当天  
+    if (IsTimestampToday(data.timestamp)) {  
+      // 计算当前小时  
+      time_t rawTime = static_cast<time_t>(data.timestamp);  
+      struct tm *timeInfo = localtime(&rawTime);  
+      int hour = timeInfo->tm_hour; // 获取小时数  
+
+      // 更新每小时最新心率数据  
+      if (dailyHeartRates[hour].timestamp < data.timestamp) {  
+        dailyHeartRates[hour].Heart = data.Heart; // 更新最新数据  
+        dailyHeartRates[hour].timestamp = data.timestamp;  
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "hour %d %d %d", hour,  
+                      data.timestamp, data.Heart);  
+      }  
+
+      // 更新最高、最低心率  
+      if (data.Heart > heart_max) {  
+        heart_max = data.Heart;  
+      }  
+      if (data.Heart < heart_min) {  
+        heart_min = data.Heart;  
+      }  
+      // 更新最新心率数据  
+      heart_time = data.timestamp;  
+      heart_rate = data.Heart;  
+      WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,  
+                    "Loaded heart data: timestamp = %d, Heart = %d",  
+                    data.timestamp, data.Heart);  
+    } else {  
+      WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,  
+                    "error data: timestamp = %d, Heart = %d", data.timestamp,  
+                    data.Heart);  
+    }  
+  }
+
+  // 打印list内容
+  // for (int i = 0; i < MAX_HOURS; i++) {
+  //   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dailyHeartRates[%d] %d %d", i,
+  //                 dailyHeartRates[i].timestamp, dailyHeartRates[i].Heart);
+  // }
+  
+  uapi_dev_runtime_set_heartrate_storage_status(0);  
+  return true;  
+}
+std::string HealthService::get_heart_data() {
+  std::string binFilePath = GetBinFilePath(HEALTH_TYPE_HEART);
+  WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "binFilePath %s", binFilePath.c_str());
+
+  std::ifstream ifs(binFilePath, std::ios::binary); // 以二进制读取模式打开文件
+  if (!ifs.is_open()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Failed to open binary file for reading");
+    return "Error: Unable to open file \n"; // 返回错误信息
+  }
+
+  std::stringstream result;
+  result << "file: " << binFilePath << "\n";
+  HeartRateData data;
+
+  // 读取数据直到文件结束
+  while (ifs.read(reinterpret_cast<char *>(&data), sizeof(HeartRateData))) {
+    // 检查时间戳的有效性
+    if (data.timestamp < 0) {
+      WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid timestamp read: %d",
+                    data.timestamp);
+      continue; // 跳过无效的数据
+    }
+
+    // 将数据格式化为字符串,拼接到结果中
+    result << formatTime(data.timestamp) << "," << std::to_string(data.Heart)
+           << "\n";
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "get_heart_data %d %d",
+                  data.timestamp, data.Heart);
+  }
+
+  if (ifs.bad()) {
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                  "Error reading data from binary file");
+    return "Error: Reading error \n"; // 返回读取错误信息
+  }
+
+  return result.str().empty() ? "No data found \n"
+                              : result.str(); // 检查是否读取到数据
+}
+
+// 存储血氧数据
+// bool HealthService::save_bin_blood(const BloodOxygenData &bloodoxygen) {
+//   /* 存储bin文件[协议使用] */
+//   std::string binFilePath = GetBinFilePath(HEALTH_TYPE_HEART);
+//   FILE *fp = fopen(binFilePath.c_str(), "ab+");
+//   if (fp == NULL) {
+//     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+//                   "Failed to open binary file for writing");
+//     return false;
+//   }
+//   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "binFilePath %s",
+//   binFilePath.c_str());
+
+//   if (fwrite(&bloodoxygen, sizeof(bloodoxygen), 1, fp) != 1) {
+//     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+//                   "Failed to write data to binary file");
+//     fclose(fp);
+//     return false;
+//   }
+//   fclose(fp);
+//   WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "save_bin_blood is ok");
+//   return true;
+// }
+} // namespace OHOS
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/health_service/health_service.h
new file mode 100644 (file)
index 0000000..9028f39
--- /dev/null
@@ -0,0 +1,131 @@
+/***
+ * @Date: 2024-06-14 11:34:19
+ * @LastEditors: Caisking 3449750381@qq.com
+ * @LastEditTime: 2024-07-30 17:45:59
+ * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/heart_blood/health_service/health_service.h
+ */
+
+#ifndef HEART_SERVICE_H
+#define HEART_SERVICE_H
+
+#include "stdio.h"
+#include "string"
+
+#include <fstream>
+#include <ctime>
+#include <cstdint>
+#include <string>
+
+#define HEART_MAX_POINTS 360
+#define MSG_SAVE_TEST 0
+namespace OHOS
+{
+    const char *GET_HEALTH_JSON_PATH_C_STR_HEART();
+    const char *GET_HEALTH_JSON_PATH_C_STR_OXYGEN();
+
+    typedef enum {
+      HEALTH_TYPE_HEART,
+      HEALTH_TYPE_OXYGEN,
+    } HEALTH_TYPE;
+
+#pragma pack(push, 1) // 设置对齐为1字节  
+    typedef struct
+    {
+        uint32_t timestamp; // 最近一次检测时间
+        uint8_t SPO2;       // 血氧值
+    } BloodOxygenData;
+    typedef struct
+    {
+        uint32_t timestamp; // 最近一次检测时间
+        uint8_t Heart;      // 心率值
+    }  HeartRateData;
+#pragma pack(pop) // 恢复默认对齐
+    // 检查类
+    typedef enum
+    {
+        BLOOD_CHECK,
+        HEART_CHECK,
+        CHARGE,
+    } CheckClass;
+
+    // 检查结果
+    typedef enum
+    {
+        HIGH,
+        LOW
+    } CheckResult;
+
+    // 健康状态
+    typedef struct
+    {
+        CheckClass checkType;     // 检查类型
+        CheckResult resultStatus; // 结果状态
+        uint16_t checkResult;     // 检查结果
+    } HealthState;
+
+    class HealthService
+    {
+    public:
+        HealthService();
+        ~HealthService();
+        static HealthService *GetInstance(void);
+        bool CreateHealthFolder();
+        bool LoadJsonData(uint8_t type);                  // 加载json
+        BloodOxygenData *ReadBloodOxygenData();           // 读取血氧数据
+        void ReadHeartRateData( HeartRateData &data);               // 读取心率数据
+        bool UpdateHealthData(const HeartRateData &data); // 更新心率数据
+        bool UpdateHealthData(const BloodOxygenData &data);
+        void ReleaseJsonData(uint8_t type); // 释放json
+        bool UpdateJsonData(uint8_t type);  // 更新json
+        bool CleanHealthData();
+
+        /*健康状态*/
+        HealthState GetHealthCurrent();
+        void SetHealthCurrent(HealthState healthState);
+
+        /*
+            当天24个小时的心率处理
+            -心率数组 每个小时存储最新的值 但是没有小时只有一个值
+            -开机读取
+            -关机存储
+        */
+        bool SaveDailyHeartRate();
+        bool LoadDailyHeartRate();
+        void UpdateHourlyHeartRate(time_t timestamp, uint16_t heartRate);
+        uint16_t GetHourlyHeartRate(uint16_t hour);
+        time_t GetHourlyTimestamp(uint16_t hour); 
+        void ClearHourlyHeartRates();
+        uint16_t GetCurrentHour();
+        uint32_t GetListTime();
+
+        bool SaveHeartMaxMin(uint16_t max, uint16_t min);
+        void LoadHeartMaxMin(uint16_t &max, uint16_t &min);
+
+        void send_heart_save();
+        void send_blood_save();
+
+        std::string get_heart_data();
+        std::string get_blood_data();
+        std::string formatTime(uint32_t time);
+
+        bool save_bin_heart(const HeartRateData &heart);
+        bool save_bin_blood(const BloodOxygenData &bloodoxygen);
+
+      private:
+        //曲线显示数据
+        static const int MAX_HOURS = 24;
+        HeartRateData dailyHeartRates[MAX_HOURS];
+        //最大最小心率
+        uint8_t heart_max = 0;
+        uint8_t heart_min = 255;
+        //最新一次检测的时间与心率值
+        uint32_t heart_time = 0;
+        uint8_t heart_rate = 0;
+
+        //健康状态
+        HealthState healthState_;
+        time_t lastLoadTime; // 记录最后加载的时间
+        uint16_t currenthour = 0;
+    };
+}
+#endif // HEALTH_MODEL_H
\ No newline at end of file
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartModel.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartPresenter.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.cpp b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.h b/code/sdk/application/wearable/fd230/nativeapp/nativeui/heart_blood/set_heart/SetHeartView.h
new file mode 100644 (file)
index 0000000..e69de29