From: 袁清梦 <3449750381@qq.com> Date: Wed, 25 Sep 2024 14:07:35 +0000 (+0000) Subject: Merge #1017 into sdk602patch0626 from refs/changes/1017/head X-Git-Url: http://git.snicker.com.cn/css/static/gitweb.css?a=commitdiff_plain;h=e1c99a9ad4c320d3796caf6f0a4260ebff1ba225;p=mirrors%2FFD230.git Merge #1017 into sdk602patch0626 from refs/changes/1017/head Code review from 袁清梦 * refs/changes/1017/head: (29 commits squashed) - 修改心率曲线图Y轴数字 - #144 手表,心率测量开始测量的时候显示的心率值太大,需要优化开始显示的心率值 - #678 心率初始出值不稳定,偏差太大。 - #560 运动,徒步运动设置目标1KM,实际放桌子上未动,提示我目标达成 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - #446 运动界面,上下滑,下界面是覆盖式的,优化为U6那种滑动式界面 - #667 运动结束界面,数据不完整,数据内容不丰富,没有设置目标也会显示目标完成度 - #700 运动时间显示花屏,显示逻辑不对(两台测试样机都有) - #687 省电模式-有长按不起反应现象 - #819 手表,表盘步数显示-31441,实际步数99631 - 修改表盘距离数据为uint32_t - #448 运动结束训练记录滑动会遮挡,并且运动结束会显示训练历史记录 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - 修改运动获取实时数据traningauto为1 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - #314 手表,消息通知,长消息超出框外显示 - 移除训练的uapi_add_sport_vote()修改运动结束逻辑 - 增加新表盘原文件 - Merge branch 'sdk602patch0626' of https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230 into sdk602patch0626 - #592 APP iOS 自定义表盘不能删除 - #624 短信消息推送有显示空白现象(使用的是IOS手机) - #605 APP iOS/安卓 手表切换表盘,APP上不同步 - #343 APP安卓4.5.8 手表端切换表盘,APP设备界面的手表显示的表盘不会变,一直都是默认的表盘 - 增加消息json解析的错误预防处理 - 增加心率血氧json解析的错误预防处理 - 增加训练记录json解析错误预防 - 修改默认表盘配置;具体方案还需要商讨 Signed-off-by: Caisking <3449750381@qq.com> Reviewed-by: snickersun@163.com Merged-by: snickersun@163.com CR-link: https://codeup.aliyun.com/64191456b9581d62e8f81ac0/FD230/change/1017 --- diff --git a/code/sdk/application/wearable/fd230app/nativeui/heart_blood/health_service/health_service.cpp b/code/sdk/application/wearable/fd230app/nativeui/heart_blood/health_service/health_service.cpp index 6d9550e4f..4067f5226 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/heart_blood/health_service/health_service.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/heart_blood/health_service/health_service.cpp @@ -113,128 +113,167 @@ namespace OHOS 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, "CreateHealthFolder file"); - return nullptr; - } - - // 读取文件 - std::ifstream inFile(BLOOD_JSON_PATH); - if (!inFile.is_open()) - { - WEARABLE_LOGE(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_LOGE(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, "oxygen_root is empty"); - 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 && timestamp_item) - { - data->SPO2 = value_item->valueint; - data->timestamp = timestamp_item->valuedouble; - } - else - { - // 读取的数据异常 - cJSON_Delete(oxygen_root); - delete data; - return nullptr; - } - cJSON_Delete(oxygen_root); - return data; + // 读取血氧数据 + 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_LOGE(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_LOGE(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; } - // 读取心率数据 - HeartRateData *HealthService::ReadHeartRateData() - { - // 判断文件夹是否存在 - if (!CreateHealthFolder()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CreateHealthFolder file"); - return nullptr; - } - - // 读取文件 - std::ifstream inFile(HEART_JSON_PATH); - if (!inFile.is_open()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open JSON file"); - // 创建一个默认值为 0的数据 存储到json里面 ? - return nullptr; - } - - // 读取文件内容到字符串 - std::stringstream buffer; - buffer << inFile.rdbuf(); - std::string jsonDataString = buffer.str(); - const char *jsonData = jsonDataString.c_str(); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "jsonData: %s", jsonData); - - // 关闭文件 - inFile.close(); - - if (jsonDataString.empty()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "jsonDataString is empty"); - return nullptr; - } - - cJSON *heart_root = cJSON_Parse(jsonData); - if (heart_root == NULL) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "heart_root is empty"); - return nullptr; - } - HeartRateData *data = new HeartRateData(); - - cJSON *value_item = cJSON_GetObjectItem(heart_root, "value"); - cJSON *timestamp_item = cJSON_GetObjectItem(heart_root, "timestamp"); - - if (value_item && timestamp_item) - { - data->Heart = value_item->valueint; - data->timestamp = timestamp_item->valuedouble; - } - else - { - // 读取的数据异常 - cJSON_Delete(heart_root); - delete data; - return nullptr; - } - cJSON_Delete(heart_root); - return data; + // 读取心率数据 + HeartRateData *HealthService::ReadHeartRateData() + { + // 判断文件夹是否存在 + if (!CreateHealthFolder()) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to create health folder"); + return nullptr; + } + + // 读取文件 + std::ifstream inFile(HEART_JSON_PATH); + if (!inFile.is_open()) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open JSON file, creating default data"); + + // 创建默认值为 0 的数据并存储到 JSON 文件 + HeartRateData defaultData; + defaultData.Heart = 0; // 默认心率值 + defaultData.timestamp = static_cast(time(nullptr)); // 当前时间戳 + + // 创建 JSON 对象并写入文件 + cJSON *defaultRoot = cJSON_CreateObject(); + cJSON_AddNumberToObject(defaultRoot, "value", defaultData.Heart); + cJSON_AddNumberToObject(defaultRoot, "timestamp", defaultData.timestamp); + + // 写入 JSON 文件 + FILE *file = fopen(HEART_JSON_PATH, "w"); + if (file) + { + char *jsonString = cJSON_Print(defaultRoot); + fprintf(file, "%s", jsonString); + fclose(file); + free(jsonString); + } + cJSON_Delete(defaultRoot); + + // 返回默认数据 + HeartRateData *data = new HeartRateData(defaultData); + return data; + } + + // 读取文件内容到字符串 + std::stringstream buffer; + buffer << inFile.rdbuf(); + std::string jsonDataString = buffer.str(); + const char *jsonData = jsonDataString.c_str(); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "jsonData: %s", jsonData); + + // 关闭文件 + inFile.close(); + + if (jsonDataString.empty()) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "jsonDataString is empty"); + return nullptr; + } + + cJSON *heart_root = cJSON_Parse(jsonData); + if (heart_root == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to parse JSON data"); + return nullptr; + } + + HeartRateData *data = new HeartRateData(); + + cJSON *value_item = cJSON_GetObjectItem(heart_root, "value"); + cJSON *timestamp_item = cJSON_GetObjectItem(heart_root, "timestamp"); + + // 检查是否存在必要字段,并验证数据类型 + if (value_item && cJSON_IsNumber(value_item) && timestamp_item && cJSON_IsNumber(timestamp_item)) + { + data->Heart = value_item->valueint; + data->timestamp = timestamp_item->valuedouble; + } + else + { + // 读取的数据异常 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Missing or invalid data fields"); + cJSON_Delete(heart_root); + delete data; + return nullptr; + } + + cJSON_Delete(heart_root); + return data; } // 保存血氧数据 bool HealthService::UpdateHealthData(const BloodOxygenData &data) diff --git a/code/sdk/application/wearable/fd230app/nativeui/message/src/MessageModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/message/src/MessageModel.cpp index 7ed7bff6c..5b83e40c1 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/message/src/MessageModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/message/src/MessageModel.cpp @@ -171,74 +171,95 @@ namespace OHOS } // 加载Message文件 - bool MessageModel::LoadMessagesFromStorage() - { - // 加载消息过滤文件 - filtration_file_read(); - std::ifstream file(MESSAGE_JSON_FILE); - if (!file.is_open()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file for reading"); - return false; - } - - std::string fileContent((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - file.close(); - - cJSON *root = cJSON_Parse(fileContent.c_str()); - if (!root) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error parsing JSON file"); - return false; - } - - cJSON *messageArray = cJSON_GetObjectItem(root, "messages"); - if (!messageArray || !cJSON_IsArray(messageArray)) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid data format in JSON file"); - cJSON_Delete(root); - return false; - } - - // 清空现有数据 - // MessageVector.clear(); - - // 将JSON数据转换为MessageData并添加到消息数组中 - int dataCount = cJSON_GetArraySize(messageArray); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dataCount is %d", dataCount); - for (int i = 0; i < dataCount; i++) - { - cJSON *item = cJSON_GetArrayItem(messageArray, i); - - cJSON *isRead = cJSON_GetObjectItem(item, "isRead"); - cJSON *labelDetails = cJSON_GetObjectItem(item, "labelDetails"); - cJSON *labelTitle = cJSON_GetObjectItem(item, "labelTitle"); - cJSON *timestamp = cJSON_GetObjectItem(item, "timestamp"); - - MessageData data; - data.isRead = cJSON_IsTrue(isRead) ? true : false; - data.labelDetails = labelDetails->valuestring; - data.labelTitle = labelTitle->valuestring; - data.timestamp = timestamp->valuedouble; - - char labelTime[20]; - if (uapi_get_TIME_STR(data.timestamp, labelTime, '.', ':', DATE_Y_M_D_H_M) != ERRCODE_SUCC) - { - data.labelTime = std::string("--"); - } - else - { - data.labelTime = std::string(labelTime); - } - - MessageVector.push_back(data); - } - - cJSON_Delete(root); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Messages loaded from storage successfully"); - return true; + bool MessageModel::LoadMessagesFromStorage() + { + // 加载消息过滤文件 + filtration_file_read(); + + std::ifstream file(MESSAGE_JSON_FILE); + if (!file.is_open()) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file for reading"); + return false; + } + + std::string fileContent((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); + + cJSON *root = cJSON_Parse(fileContent.c_str()); + if (!root) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error parsing JSON file"); + return false; // JSON 解析失败,直接返回 + } + + cJSON *messageArray = cJSON_GetObjectItem(root, "messages"); + if (!messageArray || !cJSON_IsArray(messageArray)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid data format in JSON file"); + cJSON_Delete(root); + return false; // 无效的消息数组,直接返回 + } + + // 清空现有数据 + MessageVector.clear(); + + // 将JSON数据转换为MessageData并添加到消息数组中 + int dataCount = cJSON_GetArraySize(messageArray); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dataCount is %d", dataCount); + + for (int i = 0; i < dataCount; i++) + { + cJSON *item = cJSON_GetArrayItem(messageArray, i); + if (!item) // 检查数组项是否有效 + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid item at index %d", i); + cJSON_Delete(root); + return false; // 找到无效项,直接返回 + } + + // 验证并获取各字段 + cJSON *isRead = cJSON_GetObjectItem(item, "isRead"); + cJSON *labelDetails = cJSON_GetObjectItem(item, "labelDetails"); + cJSON *labelTitle = cJSON_GetObjectItem(item, "labelTitle"); + cJSON *timestamp = cJSON_GetObjectItem(item, "timestamp"); + + // 检查必要字段是否存在 + if (!isRead || !cJSON_IsBool(isRead) || + !timestamp || !cJSON_IsNumber(timestamp)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid message format at index %d", i); + cJSON_Delete(root); + return false; // 找到无效数据格式,直接返回 + } + + // 如果所有必要字段有效,则解析并构造 MessageData + MessageData data; + data.isRead = cJSON_IsTrue(isRead); + + // 允许 labelDetails 和 labelTitle 字段为空字符串 + data.labelDetails = (labelDetails && cJSON_IsString(labelDetails)) ? labelDetails->valuestring : ""; + data.labelTitle = (labelTitle && cJSON_IsString(labelTitle)) ? labelTitle->valuestring : ""; + data.timestamp = timestamp->valuedouble; + + // 处理时间字符串 + char labelTime[20]; + if (uapi_get_TIME_STR(data.timestamp, labelTime, '.', ':', DATE_Y_M_D_H_M) != ERRCODE_SUCC) + { + data.labelTime = std::string("--"); + } + else + { + data.labelTime = std::string(labelTime); + } + + MessageVector.push_back(data); + } + + cJSON_Delete(root); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Messages loaded from storage successfully"); + return true; // 所有消息成功加载 } - // 保存Message文件 bool MessageModel::SaveMessagesToStorage() { diff --git a/code/sdk/application/wearable/fd230app/nativeui/set_dial/include/SetDialModel.h b/code/sdk/application/wearable/fd230app/nativeui/set_dial/include/SetDialModel.h index 533dc0a3c..42556841d 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/set_dial/include/SetDialModel.h +++ b/code/sdk/application/wearable/fd230app/nativeui/set_dial/include/SetDialModel.h @@ -37,6 +37,7 @@ namespace OHOS void PrintRegisteredDials(const std::unordered_map &dials); int GetAllDialIDs(char *allidStr); + /*表盘map文件*/ bool readDialfile(); bool saveDialfile(); @@ -51,7 +52,11 @@ namespace OHOS bool CheckFileExists(const std::string &filePath); /*获取自定义表盘名*/ std::string GetCustomName(int Id); + /*删除自定义表盘*/ + bool DeleteCustomDial(uint16_t Id); void TestDialConfig(void); + std::string GetSaveDir(int Id,uint8_t type); + void RegisterDial(uint16_t ID, const char *dialname,uint8_t type); private: void LoadAllDialFromRam(void); diff --git a/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialModel.cpp index 365c179e1..92d248de6 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialModel.cpp @@ -1,700 +1,862 @@ -#include -#include "MainModel.h" #include "SetDialModel.h" -#include "kv_store.h" -#include "securec.h" -#include "dirent.h" #include "DialBinParser.h" +#include "MainModel.h" +#include "NativeAbility.h" +#include "clock/include/MainClockView.h" #include "custom_utils.h" +#include "dirent.h" +#include "kv_store.h" +#include "securec.h" #include "wearable_log.h" -#include -#include +#include +#include +#include +#include #include #include -#include -#include +#include #include +#include #include #include -#include "NativeAbility.h" -#include "clock/include/MainClockView.h" -namespace OHOS -{ - // 定义特殊Id - constexpr uint16_t DEFAULT_DIAL_ID_1 = 1028; - constexpr uint16_t DEFAULT_DIAL_ID_2 = 1052; - constexpr uint16_t DEFAULT_DIAL_ID_3 = 101; - constexpr uint16_t DEFAULT_DIAL_ID_4 = 106; - constexpr uint16_t MAX_DEFAULT_DIAL_ID = 111; +namespace OHOS { +// 定义特殊Id +constexpr uint16_t DEFAULT_DIAL_ID_0 = 1028; +constexpr uint16_t DEFAULT_DIAL_ID_1 = 111; +constexpr uint16_t DEFAULT_DIAL_ID_2 = 112; +constexpr uint16_t DEFAULT_DIAL_ID_3 = 113; +constexpr uint16_t DEFAULT_DIAL_ID_4 = 114; +constexpr uint16_t MAX_DEFAULT_DIAL_ID = 115; +// 定义自定义表盘 +constexpr uint16_t CUSTOM_DIAL_ID_1 = 1; +constexpr uint16_t CUSTOM_DIAL_ID_2 = 2; +constexpr uint16_t CUSTOM_DIAL_ID_3 = 3; +constexpr uint16_t CUSTOM_DIAL_ID_4 = 4; +constexpr uint16_t CUSTOM_DIAL_ID_5 = 5; #define DIAL_ID_LENGTH 2 #define DIAL_NAME_LENGTH 50 #define DIAL_ID_PATH "user/userdata/dial_id.bin" - // 表盘map[Id--dialname] 前5个ID固定 - std::unordered_map registeredDials{ +// 表盘map[Id--dialname] 前5个ID固定 +std::unordered_map registeredDials{ #ifdef CUSTOM_Z1 - {DEFAULT_DIAL_ID_1, "Z1"}, + {DEFAULT_DIAL_ID_0, "Z1"}, #else - {DEFAULT_DIAL_ID_1, "KUMI"}, + {DEFAULT_DIAL_ID_0, "KUMI"}, // 为了预防显示 + {DEFAULT_DIAL_ID_4, "obsidianrhythm"}, //默认表盘修改为 黑耀律动 TODO:ID需要更改 DEFAULT_DIAL_ID_3 #endif - {DEFAULT_DIAL_ID_2, "classic"}, // 经典表盘 - {DEFAULT_DIAL_ID_3, "sport"}, // 运动表盘 - {DEFAULT_DIAL_ID_4, "galaxy"}, // 星空表盘 - {MAX_DEFAULT_DIAL_ID, "satellite"}, // 卫星表盘 - }; - // 表盘市场UID 对应表盘name - bool SetDialModel::saveDialfile() - { - FILE *fp = fopen(DIAL_ID_PATH, "wb+"); - - for (const auto &entry : registeredDials) - { - char buf[DIAL_ID_LENGTH + DIAL_NAME_LENGTH] = {0}; - memcpy_s(buf, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, &entry.first, 2); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %d", entry.first); - memcpy_s(buf + DIAL_ID_LENGTH, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, entry.second.c_str(), entry.second.length()); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %s", entry.second.c_str()); - int size = fwrite(buf, 1, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, fp); - if (DIAL_ID_LENGTH + DIAL_NAME_LENGTH != size) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fwrite is fail! %d", size); - return false; - } - else - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fwrite is succ %d !", entry.first); - } - } - fclose(fp); - return true; - } + {DEFAULT_DIAL_ID_1, "satellite"}, // 卫星表盘 + {DEFAULT_DIAL_ID_2, "birdie"}, // 飞鸟表盘 - bool SetDialModel::readDialfile() - { - FILE *fp = fopen(DIAL_ID_PATH, "rb+"); - if (fp == NULL) - return false; - fseek(fp, 0, SEEK_END); - int size = ftell(fp); - fseek(fp, 0, SEEK_SET); - // char * buf=(char *)malloc(size); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " readDialfile size is %d !", size); - - while (size) - { - uint16_t uid = 0; - if (DIAL_ID_LENGTH != fread((void *)&uid, 1, DIAL_ID_LENGTH, fp)) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fread is fail!"); - } - - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %d", uid); - - char name_buf[DIAL_NAME_LENGTH] = {0}; - if (DIAL_NAME_LENGTH != fread((void *)name_buf, 1, DIAL_NAME_LENGTH, fp)) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fread is fail!"); - } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "name_buf %s", name_buf); - - if (uid != 0) - { - if (!IsDialInstalled(uid)) - { - RegisterDial(uid, name_buf); - } - } - size -= (DIAL_ID_LENGTH + DIAL_NAME_LENGTH); - } - - fclose(fp); - return true; + /* + TODO:增加表盘 + {DEFAULT_DIAL_ID_4, "smart_payment"}, // 智能支付表盘 + {MAX_DEFAULT_DIAL_ID, "kumi_point"}, // kumi指针表盘 + */ + +}; +// 表盘市场UID 对应表盘name +bool SetDialModel::saveDialfile() { + FILE *fp = fopen(DIAL_ID_PATH, "wb+"); + + for (const auto &entry : registeredDials) { + char buf[DIAL_ID_LENGTH + DIAL_NAME_LENGTH] = {0}; + memcpy_s(buf, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, &entry.first, 2); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %d", entry.first); + memcpy_s(buf + DIAL_ID_LENGTH, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, + entry.second.c_str(), entry.second.length()); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %s", entry.second.c_str()); + int size = fwrite(buf, 1, DIAL_ID_LENGTH + DIAL_NAME_LENGTH, fp); + if (DIAL_ID_LENGTH + DIAL_NAME_LENGTH != size) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fwrite is fail! %d", size); + return false; + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fwrite is succ %d !", + entry.first); } + } + fclose(fp); + return true; +} - SetDialModel::SetDialModel() - { - readDialfile(); // 读取表盘map配置文件 - LoadAllDial(); // 更新表盘个数 当前表盘 - char idBuffer[10]; // 读取表盘Id配置文件 - int len = UtilsGetValue("dial_id", idBuffer, sizeof(idBuffer)); - if (len >= 0) - { - currentDialID = std::stoi(idBuffer); // 将字符串转换为整数 - } +bool SetDialModel::readDialfile() { + FILE *fp = fopen(DIAL_ID_PATH, "rb+"); + if (fp == NULL) + return false; + fseek(fp, 0, SEEK_END); + int size = ftell(fp); + fseek(fp, 0, SEEK_SET); + // char * buf=(char *)malloc(size); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " readDialfile size is %d !", size); + + while (size) { + uint16_t uid = 0; + if (DIAL_ID_LENGTH != fread((void *)&uid, 1, DIAL_ID_LENGTH, fp)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fread is fail!"); } - SetDialModel::~SetDialModel() {} + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uid %d", uid); - SetDialModel &SetDialModel::GetInstance() - { - static SetDialModel instance; - return instance; + char name_buf[DIAL_NAME_LENGTH] = {0}; + if (DIAL_NAME_LENGTH != fread((void *)name_buf, 1, DIAL_NAME_LENGTH, fp)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " fread is fail!"); } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "name_buf %s", name_buf); - /* 注册表盘map */ - void SetDialModel::RegisterDial(uint16_t ID, const char *dialname) - { - if (ID == 0 || strlen(dialname) == 0) - return; + if (uid != 0) { + if (!IsDialInstalled(uid)) { + RegisterDial(uid, name_buf); + } + } + size -= (DIAL_ID_LENGTH + DIAL_NAME_LENGTH); + } - registeredDials[ID] = std::string(dialname); // 唯一性 + fclose(fp); + return true; +} - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "RegisterDial %d %s is ok!", ID, dialname); +SetDialModel::SetDialModel() { + readDialfile(); // 读取表盘map配置文件 + LoadAllDial(); // 更新表盘个数 当前表盘 + char idBuffer[10]; // 读取表盘Id配置文件 + int len = UtilsGetValue("dial_id", idBuffer, sizeof(idBuffer)); + if (len >= 0) { + currentDialID = std::stoi(idBuffer); // 将字符串转换为整数 + } +} - LoadAllDial(); +SetDialModel::~SetDialModel() {} - saveDialfile(); - } +SetDialModel &SetDialModel::GetInstance() { + static SetDialModel instance; + return instance; +} + +/* 注册表盘map */ +void SetDialModel::RegisterDial(uint16_t ID, const char *dialname) { + + if (ID == 0 || strlen(dialname) == 0) + return; + + registeredDials[ID] = std::string(dialname); // 唯一性 + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "RegisterDial %d %s is ok!", ID, + dialname); + + LoadAllDial(); + saveDialfile(); +} + +/* 注册表盘map_ble*/ +void SetDialModel::RegisterDial(uint16_t ID, const char *dialname, + uint8_t type) { + // 增加 ID 对应 + if (ID <= 4) { + ID++; + } + + if (ID == 0 || strlen(dialname) == 0) + return; + + registeredDials[ID] = std::string(dialname); // 唯一性 + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "RegisterDial %d %s is ok!", ID, + dialname); + + LoadAllDial(); + saveDialfile(); +} + +/* 打印map */ +void SetDialModel::PrintRegisteredDials( + const std::unordered_map &dials) { + printf("Registered Dials:\n"); + for (const auto &entry : dials) { + printf("ID: %u | Name: %s\n", entry.first, entry.second.c_str()); + } +} - /* 打印map */ - void SetDialModel::PrintRegisteredDials(const std::unordered_map &dials) - { - printf("Registered Dials:\n"); - for (const auto &entry : dials) - { - printf("ID: %u | Name: %s\n", entry.first, entry.second.c_str()); - } +/* 通过名字查询Id */ +uint16_t SetDialModel::GetDialIdFromName(const std::string &dialName) { + for (const auto &entry : registeredDials) { + if (entry.second == dialName) { + return entry.first; // 找到对应的表盘名称,返回对应ID } + } + return 0; // 如果未找到对应的表盘名称,返回0或者其他适当的默认值 +} - /* 通过名字查询Id */ - uint16_t SetDialModel::GetDialIdFromName(const std::string &dialName) - { - for (const auto &entry : registeredDials) - { - if (entry.second == dialName) - { - return entry.first; // 找到对应的表盘名称,返回对应ID - } - } - return 0; // 如果未找到对应的表盘名称,返回0或者其他适当的默认值 +/* 获取当前表盘Id */ +uint16_t SetDialModel::GetCurrentDialID() { + if (registeredDials.find(currentDialID) != registeredDials.end()) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "currentDialID is %d,name is %s", + currentDialID, registeredDials[currentDialID].c_str()); + } + uint16_t id = currentDialID; + if (currentDialID <= 5) { + id--; + } + return id; +} +/* 获取所有表盘Id 每个表盘Id 2个字节 拼接为字符串 */ +int SetDialModel::GetAllDialIDs(char *allidStr) { + std::string allIDs; + int length = 0; + for (const auto &entry : registeredDials) { + uint16_t id = entry.first; + if (id <= 5) { + id--; } + memcpy_s(allidStr + length, 512, &id, 2); + length += 2; + } - /* 获取当前表盘Id */ - uint16_t SetDialModel::GetCurrentDialID() - { - if (registeredDials.find(currentDialID) != registeredDials.end()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "currentDialID is %d,name is %s", currentDialID, registeredDials[currentDialID].c_str()); - } - uint16_t id=currentDialID; - if(currentDialID<=5) - { - id--; - } - return id; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "allidStr is %s %d", allIDs.c_str(), + length); + return length; +} +/* 判断表盘是否存在*/ +bool SetDialModel::IsDialInstalled(uint16_t ID) { + if (ID <= 4) { + ID++; + } + + if (registeredDials.find(ID) != registeredDials.end()) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dial %d is install!", ID); + return true; + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dial %d is not install!", ID); + return false; + } +} +/*删除自定义表盘*/ +bool SetDialModel::DeleteCustomDial(uint16_t Id) { + // 删除配置文件 + std::string filename = GetSaveDir(Id) + "/" + std::to_string(Id) + ".bin"; + if (!uapi_delete_files(filename.c_str())) { + WEARABLE_LOGE( + WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete the dial configuration file: %s", + filename.c_str()); + return false; + } + + // 删除资源文件 + switch (Id) { + case CUSTOM_DIAL_ID_1: + if (!uapi_delete_files(CUSTOM_CLOCK1_DIALPER_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial percentage file " + "for ID 1: %s", + CUSTOM_CLOCK1_DIALPER_PATH); + return false; } - /* 获取所有表盘Id 每个表盘Id 2个字节 拼接为字符串 */ - int SetDialModel::GetAllDialIDs(char *allidStr) - { - std::string allIDs; - int length = 0; - for (const auto &entry : registeredDials) - { - uint16_t id = entry.first; - if (id <= 5) - { - id--; - } - memcpy_s(allidStr + length, 512, &id, 2); - length += 2; - } - - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "allidStr is %s %d", allIDs.c_str(), length); - return length; + if (!uapi_delete_files(CUSTOM_CLOCK1_DIALBACK_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial background file " + "for ID 1: %s", + CUSTOM_CLOCK1_DIALBACK_PATH); + return false; } - /* 判断表盘是否存在*/ - bool SetDialModel::IsDialInstalled(uint16_t ID) - { - if(ID<=4) - { - ID++; - } - - if (registeredDials.find(ID) != registeredDials.end()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dial %d is install!", ID); - return true; - } - else - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dial %d is not install!", ID); - return false; - } + break; + + case CUSTOM_DIAL_ID_2: + if (!uapi_delete_files(CUSTOM_CLOCK2_DIALPER_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial percentage file " + "for ID 2: %s", + CUSTOM_CLOCK2_DIALPER_PATH); + return false; } - /* 删除表盘 */ - bool SetDialModel::UninstallDial(uint16_t ID) - { - if(ID<=4) - { - ID++; - } - if (registeredDials.find(ID) != registeredDials.end()) - { - // 默认表盘不删除[日志提醒] - switch (ID) - { - case MAX_DEFAULT_DIAL_ID: - case DEFAULT_DIAL_ID_1: - case DEFAULT_DIAL_ID_2: - case DEFAULT_DIAL_ID_3: - case DEFAULT_DIAL_ID_4: - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UninstallDial default dial %d fail", ID); - return false; - default: - break; - } - - /*删除文件操作 目前只删除下载表盘*/ - std::string dialFullName = APP_DOWNLOAD_DIAL_PATH; - dialFullName += "/"; - dialFullName += registeredDials[ID]; - dialFullName += ".bin"; - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UninstallDial %s", dialFullName.c_str()); - if (uapi_delete_files(dialFullName.c_str())) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UninstallDial the dial %d is ok", ID); - - registeredDials.erase(ID); - LoadAllDial(); - return true; - } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "uapi_delete_files the dial %d is false", ID); - return false; - } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Couldn't find the dial %d", ID); - return false; + if (!uapi_delete_files(CUSTOM_CLOCK2_DIALBACK_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial background file " + "for ID 2: %s", + CUSTOM_CLOCK2_DIALBACK_PATH); + return false; } - /*更新表盘*/ - void SetDialModel::UpdateDialSetting(uint16_t ID) - { - if(ID<=4) - { - ID++; - } - - if (registeredDials.find(ID) != registeredDials.end()) - { - std::string dialname = registeredDials[ID]; // 根据ID找到对应的表盘名称 - // 在dialInfoList中查找同名表盘 - for (size_t i = 0; i < dialInfoList.size(); i++) - { - if (dialInfoList[i].dialName == dialname) - { - DialSetting diagSetting; - SetDialInfo &info = dialInfoList[i]; - diagSetting.dialFlag = info.dialFlag; - diagSetting.dialId = info.id; - diagSetting.dialFullName = info.dialFullName; - currentDialID = ID; // 更新当前表盘Id - MainModel::GetInstance().AddDialSetting(diagSetting, currentDialID); // 更新表盘设置 - NativeAbility::GetInstance().ChangeSlice(VIEW_MAIN); - return; // 更新成功后直接返回 - } - } - NativeAbility::GetInstance().ChangeSlice(VIEW_MAIN); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetDialModel UpdateDialSetting: Cannot find dial with name %s", dialname.c_str()); - } + break; + + case CUSTOM_DIAL_ID_3: + if (!uapi_delete_files(CUSTOM_CLOCK3_DIALPER_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial percentage file " + "for ID 3: %s", + CUSTOM_CLOCK3_DIALPER_PATH); + return false; } - - /*加载所有表盘*/ - void SetDialModel::LoadAllDial() - { - dialInfoList.clear(); - // 加载自定义表盘 - LoadAllDialFromRam(); - size_t dialSize = dialInfoList.size(); - // 加载默认表盘 - LoadAllDialFromDefult(); - // 加载离线表盘 - LoadAllDialFromFs(); - /* 排序离线表盘 */ - std::sort(dialInfoList.begin() + dialSize, dialInfoList.end(), [](const SetDialInfo &f, const SetDialInfo &n) - { return f.dialName < n.dialName; }); - - // 表盘Id以及表盘map打印 - char dialId[128]; - GetAllDialIDs(dialId); - PrintRegisteredDials(registeredDials); + if (!uapi_delete_files(CUSTOM_CLOCK3_DIALBACK_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial background file " + "for ID 3: %s", + CUSTOM_CLOCK3_DIALBACK_PATH); + return false; + } + break; + + case CUSTOM_DIAL_ID_4: + if (!uapi_delete_files(CUSTOM_CLOCK4_DIALPER_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial percentage file " + "for ID 4: %s", + CUSTOM_CLOCK4_DIALPER_PATH); + return false; + } + if (!uapi_delete_files(CUSTOM_CLOCK4_DIALBACK_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial background file " + "for ID 4: %s", + CUSTOM_CLOCK4_DIALBACK_PATH); + return false; } - /*加载离线表盘*/ - void SetDialModel::LoadAllDialFromFs() - { - int ret; - struct dirent *direntp; - - // 打开目录 - DIR *dirp = opendir(APP_DOWNLOAD_DIAL_PATH); - // 遍历文件 - if (dirp != nullptr) - { - while ((direntp = readdir(dirp)) != nullptr) - { - SetDialInfo dialInfo{0}; - int ret = ParseDialHeader(DOWNLOADDIAL, direntp->d_name, dialInfo); - if (ret == 0) - { - dialInfoList.push_back(dialInfo); - } - } - } - // 关闭目录 - closedir(dirp); - return; + break; + + case CUSTOM_DIAL_ID_5: + if (!uapi_delete_files(CUSTOM_CLOCK5_DIALPER_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial percentage file " + "for ID 5: %s", + CUSTOM_CLOCK5_DIALPER_PATH); + return false; } - /*加载默认表盘*/ - void SetDialModel::LoadAllDialFromDefult(void) - { - int ret; - struct dirent *direntp; - - // 打开目录 - DIR *dirp = opendir(APP_DEFAULT_DIAL_PATH); - // 遍历文件 - if (dirp != nullptr) - { - while ((direntp = readdir(dirp)) != nullptr) - { - SetDialInfo dialInfo{0}; - int ret = ParseDialHeader(DEFULTDIAL, direntp->d_name, dialInfo); - if (ret == 0) - { - dialInfoList.push_back(dialInfo); - } - } - } - // 关闭目录 - closedir(dirp); - return; + if (!uapi_delete_files(CUSTOM_CLOCK5_DIALBACK_PATH)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Failed to delete dial background file " + "for ID 5: %s", + CUSTOM_CLOCK5_DIALBACK_PATH); + return false; } - /*通过表盘名称解析表盘 [离线表盘]*/ - int32_t SetDialModel::ParseDialHeader(int type, const std::string &dialFileName, SetDialInfo &dialInfo) - { - std::string dialFullName; - if (type == DEFULTDIAL) - { - dialFullName = APP_DEFAULT_DIAL_PATH; - } - else if (type == DOWNLOADDIAL) - { - dialFullName = APP_DOWNLOAD_DIAL_PATH; - } - dialFullName += "/"; - dialFullName += dialFileName; - FILE *fp = fopen(dialFullName.c_str(), "rb"); - if (fp == nullptr) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ParseDialHeader cannot open file: %s", - dialFullName.c_str()); - return -1; - } - DialPreviewInfo preInfo{0}; - bool ret = DialBinParser::GetInstance()->GetDialPreviewInfo(fp, &preInfo); - if (!ret) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetDialPreviewInfo %s fail", - dialFullName.c_str()); - fclose(fp); - return -1; - } - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader dialFullName: %s", - dialFullName.c_str()); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader dialName: %s", - preInfo.dialName); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader description: %s", - preInfo.description); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader previewImgId: %u", - preInfo.imgId); - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader imageOffset: %u", - preInfo.offset); - ImageInfo *info = ImageCacheManager::GetInstance().LoadOneInMultiRes( - preInfo.imgId, dialFullName, fp, false, preInfo.offset); - if (info == nullptr) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ParseDialHeader loadimage fail"); - fclose(fp); - return -1; - } - - dialInfo.dialFlag = 1; - dialInfo.id = 0; - dialInfo.dialFullName = dialFullName; - dialInfo.dialName = preInfo.dialName; - dialInfo.description = preInfo.description; - dialInfo.preImageInfo = info; - - fclose(fp); - return 0; + break; + + default: + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Invalid dial ID: %d", Id); + return false; // ID 不合法 + } + + // 所有操作成功 重新加载list + registeredDials.erase(Id); + LoadAllDial(); + WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, + "DeleteCustomDial: Successfully deleted custom dial with ID %d", + Id); + return true; +} + +/* 删除表盘 */ +bool SetDialModel::UninstallDial(uint16_t ID) { + // 增加 ID 对应 + if (ID <= 4) { + ID++; + } + + if (registeredDials.find(ID) != registeredDials.end()) { + // 默认表盘不删除 + switch (ID) { + case MAX_DEFAULT_DIAL_ID: + case DEFAULT_DIAL_ID_1: + case DEFAULT_DIAL_ID_2: + case DEFAULT_DIAL_ID_3: + case DEFAULT_DIAL_ID_4: + case DEFAULT_DIAL_ID_0: // TODO: 后续修改 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Default dial %d cannot be uninstalled", ID); + return false; + + // 删除自定义表盘 + case CUSTOM_DIAL_ID_1: + case CUSTOM_DIAL_ID_2: + case CUSTOM_DIAL_ID_3: + case CUSTOM_DIAL_ID_4: + case CUSTOM_DIAL_ID_5: + if (DeleteCustomDial(ID)) { + return true; + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Failed to uninstall custom dial %d", ID); + return false; + default: + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UninstallDial: dial ID %d is offline dial", ID); + break; } - /*设置当前表盘*/ - void SetDialModel::SaveDialSetting(uint8_t pageIndex) - { - if (pageIndex >= dialInfoList.size()) - { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetDialModel SaveDialSetting [%u %u]", - pageIndex, dialInfoList.size()); - return; - } + // 删除文件操作 + std::string dialFullName = APP_DOWNLOAD_DIAL_PATH; + dialFullName += "/"; + dialFullName += registeredDials[ID]; + dialFullName += ".bin"; + WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Attempting to delete %s", + dialFullName.c_str()); + + if (uapi_delete_files(dialFullName.c_str())) { + WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Successfully deleted dial %d", ID); + registeredDials.erase(ID); + LoadAllDial(); + return true; + } + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Failed to delete dial file %s", + dialFullName.c_str()); + return false; + } + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UninstallDial: Couldn't find the dial %d", ID); + return false; +} +/*更新表盘*/ +void SetDialModel::UpdateDialSetting(uint16_t ID) { + if (ID <= 4) { + ID++; + } + /*判断是否为当前表盘*/ + if (currentDialID == ID) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UpdateDialSetting: Current dial cannot be updated"); + return; + } + + if (registeredDials.find(ID) != registeredDials.end()) { + std::string dialname = registeredDials[ID]; // 根据ID找到对应的表盘名称 + // 在dialInfoList中查找同名表盘 + for (size_t i = 0; i < dialInfoList.size(); i++) { + if (dialInfoList[i].dialName == dialname) { DialSetting diagSetting; - SetDialInfo &info = dialInfoList[pageIndex]; + SetDialInfo &info = dialInfoList[i]; diagSetting.dialFlag = info.dialFlag; diagSetting.dialId = info.id; diagSetting.dialFullName = info.dialFullName; - currentDialID = GetDialIdFromName(info.dialName); // 更新表盘Id - - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "info.dialName %s info.id %d ", info.dialName.c_str(), info.id); - MainModel::GetInstance().AddDialSetting(diagSetting, currentDialID); + currentDialID = ID; + uapi_set_screen_on_api(); // 更新当前表盘Id + MainModel::GetInstance().AddDialSetting(diagSetting, + currentDialID); // 更新表盘设置 + NativeAbility::GetInstance().ChangeSlice(VIEW_MAIN); + WEARABLE_LOGE( + WEARABLE_LOG_MODULE_APP, + "SetDialModel UpdateDialSetting: Cannot find dial with name %s", + dialname.c_str()); + return; // 更新成功后直接返回 + } } + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "UpdateDialSetting: dial ID %d is offline dial", ID); + } +} - /*获取表盘的总数*/ - size_t SetDialModel::GetDialCount(void) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " %d ", dialInfoList.size()); - return dialInfoList.size(); +/*加载所有表盘*/ +void SetDialModel::LoadAllDial() { + dialInfoList.clear(); + // 加载自定义表盘 + LoadAllDialFromRam(); + size_t dialSize = dialInfoList.size(); + // 加载默认表盘 + LoadAllDialFromDefult(); + // 加载离线表盘 + LoadAllDialFromFs(); + /* 排序离线表盘 */ + std::sort(dialInfoList.begin() + dialSize, dialInfoList.end(), + [](const SetDialInfo &f, const SetDialInfo &n) { + return f.dialName < n.dialName; + }); + + // 表盘Id以及表盘map打印 + char dialId[128]; + GetAllDialIDs(dialId); + PrintRegisteredDials(registeredDials); +} +/*加载离线表盘*/ +void SetDialModel::LoadAllDialFromFs() { + int ret; + struct dirent *direntp; + + // 打开目录 + DIR *dirp = opendir(APP_DOWNLOAD_DIAL_PATH); + // 遍历文件 + if (dirp != nullptr) { + while ((direntp = readdir(dirp)) != nullptr) { + SetDialInfo dialInfo{0}; + int ret = ParseDialHeader(DOWNLOADDIAL, direntp->d_name, dialInfo); + if (ret == 0) { + dialInfoList.push_back(dialInfo); + } } - - /*获取表盘列表*/ - std::vector &SetDialModel::GetDialInfo(void) - { - return dialInfoList; + } + // 关闭目录 + closedir(dirp); + return; +} +/*加载默认表盘*/ +void SetDialModel::LoadAllDialFromDefult(void) { + int ret; + struct dirent *direntp; + + // 打开目录 + DIR *dirp = opendir(APP_DEFAULT_DIAL_PATH); + // 遍历文件 + if (dirp != nullptr) { + while ((direntp = readdir(dirp)) != nullptr) { + SetDialInfo dialInfo{0}; + int ret = ParseDialHeader(DEFULTDIAL, direntp->d_name, dialInfo); + if (ret == 0) { + dialInfoList.push_back(dialInfo); + } } + } + // 关闭目录 + closedir(dirp); + return; +} +/*通过表盘名称解析表盘 [离线表盘]*/ +int32_t SetDialModel::ParseDialHeader(int type, const std::string &dialFileName, + SetDialInfo &dialInfo) { + std::string dialFullName; + if (type == DEFULTDIAL) { + dialFullName = APP_DEFAULT_DIAL_PATH; + } else if (type == DOWNLOADDIAL) { + dialFullName = APP_DOWNLOAD_DIAL_PATH; + } + dialFullName += "/"; + dialFullName += dialFileName; + FILE *fp = fopen(dialFullName.c_str(), "rb"); + if (fp == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "ParseDialHeader cannot open file: %s", dialFullName.c_str()); + return -1; + } + DialPreviewInfo preInfo{0}; + bool ret = DialBinParser::GetInstance()->GetDialPreviewInfo(fp, &preInfo); + if (!ret) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetDialPreviewInfo %s fail", + dialFullName.c_str()); + fclose(fp); + return -1; + } + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader dialFullName: %s", + dialFullName.c_str()); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader dialName: %s", + preInfo.dialName); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader description: %s", + preInfo.description); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader previewImgId: %u", + preInfo.imgId); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ParseDialHeader imageOffset: %u", + preInfo.offset); + ImageInfo *info = ImageCacheManager::GetInstance().LoadOneInMultiRes( + preInfo.imgId, dialFullName, fp, false, preInfo.offset); + if (info == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ParseDialHeader loadimage fail"); + fclose(fp); + return -1; + } + + dialInfo.dialFlag = 1; + dialInfo.id = 0; + dialInfo.dialFullName = dialFullName; + dialInfo.dialName = preInfo.dialName; + dialInfo.description = preInfo.description; + dialInfo.preImageInfo = info; + + fclose(fp); + return 0; +} - uint8_t SetDialModel::GetPageIndex(void) - { - uint8_t index = 0; - DialSetting dialSetting = MainModel::GetInstance().GetDialSetting(); - for (auto iter : dialInfoList) - { - if (dialSetting.dialFlag) - { - if (strcmp(iter.dialFullName.c_str(), dialSetting.dialFullName.c_str()) == 0) - { - return index; - } - } - else - { - if ((!iter.dialFlag) && (iter.id == dialSetting.dialId)) - { - return index; - } - } - index++; - } - return 0; - } - /* --------------------------------- 自定义表盘配置 -------------------------------- */ - /*加载自定义表盘*/ - void SetDialModel::LoadAllDialFromRam() - { - for (uint8_t i = DIAL_CLOCK; i < DIAL_MAX; i++) - { - // 获取表盘列表 读取自定义表盘配置 - const DialInfo *info = MainModel::GetInstance().GetDialInfo((DialId)i); - if (info == nullptr) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadAllDialFromRam: Dial info for ID %u is nullptr", i); - continue; - } - - // 处理自定义配置文件 - if (i != DIAL_CLOCK) - { - std::string customFilePath = GetSaveDir(i) + "/" + std::to_string(i) + ".bin"; - if (!CheckFileExists(customFilePath)) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Custom config file does not exist for ID: %u, filename: %s", i, customFilePath.c_str()); - continue; - } - } - - // 初始化表盘信息 - SetDialInfo dialInfo; - dialInfo.dialFlag = 0; - dialInfo.id = i; - dialInfo.dialName = info->dialName; - dialInfo.imageFullName = info->dialImg; - - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Processing Dial ID %u: Name: %s", i, dialInfo.dialName.c_str()); - - // 加载图像资源 - ImageInfo *imageInfo = ImageCacheManager::GetInstance().LoadSingleRes(info->dialImg, false); - if (imageInfo == nullptr) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadAllDialFromRam load image %s failed", info->dialImg); - continue; - } - - // 设置图像信息 - dialInfo.preImageInfo = imageInfo; - - // 添加到表盘列表 - dialInfoList.push_back(dialInfo); - - // 注册到map - // RegisterDial(dialInfo.id, dialInfo.dialName.c_str()); - - // 日志输出 - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Parsed Dial: ID: %u, Name: %s, Image: %s", - dialInfo.id, dialInfo.dialName.c_str(), dialInfo.imageFullName.c_str()); - } - } +/*设置当前表盘*/ +void SetDialModel::SaveDialSetting(uint8_t pageIndex) { + if (pageIndex >= dialInfoList.size()) { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, + "SetDialModel SaveDialSetting [%u %u]", pageIndex, + dialInfoList.size()); + return; + } + DialSetting diagSetting; + SetDialInfo &info = dialInfoList[pageIndex]; + diagSetting.dialFlag = info.dialFlag; + diagSetting.dialId = info.id; + diagSetting.dialFullName = info.dialFullName; + currentDialID = GetDialIdFromName(info.dialName); // 更新表盘Id + + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "info.dialName %s info.id %d ", + info.dialName.c_str(), info.id); + MainModel::GetInstance().AddDialSetting(diagSetting, currentDialID); +} - // 检查文件是否存在的辅助函数 - bool SetDialModel::CheckFileExists(const std::string &filePath) - { - std::ifstream file(filePath); - return file.is_open(); - } - // 测试表盘配置写文件 - void SetDialModel::TestDialConfig() - { - DialLayout dialconfig; - - /*设置表盘参数*/ - dialconfig.dialId = 1; - dialconfig.batteryDisplay = 1; - dialconfig.timeDisplay = 0; - dialconfig.colorTypeSet = 5; - - if (!saveDialConfig(dialconfig)) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to save dial config"); - } +/*获取表盘的总数*/ +size_t SetDialModel::GetDialCount(void) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " %d ", dialInfoList.size()); + return dialInfoList.size(); +} + +/*获取表盘列表*/ +std::vector &SetDialModel::GetDialInfo(void) { + return dialInfoList; +} + +uint8_t SetDialModel::GetPageIndex(void) { + uint8_t index = 0; + DialSetting dialSetting = MainModel::GetInstance().GetDialSetting(); + for (auto iter : dialInfoList) { + if (dialSetting.dialFlag) { + if (strcmp(iter.dialFullName.c_str(), dialSetting.dialFullName.c_str()) == + 0) { + return index; + } + } else { + if ((!iter.dialFlag) && (iter.id == dialSetting.dialId)) { + return index; + } } - // 保存自定义表盘配置到文件 - bool SetDialModel::saveDialConfig(const DialLayout &layout) - { - - std::string filename = GetSaveDir(layout.dialId) + "/" + std::to_string(layout.dialId) + ".bin"; - - // 创建或打开文件 - std::ofstream configFile(filename, std::ios::binary | std::ios::out | std::ios::trunc); - if (!configFile.is_open()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Unable to open config file for writing: %s", filename.c_str()); - return false; // 文件打开失败 - } - - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "saveDialConfig: %d %d %d", layout.batteryDisplay, layout.timeDisplay, layout.colorTypeSet); - - // 将结构体的三个数据按1个字节的存储到文件 - configFile.put(static_cast(layout.batteryDisplay)); // 第一字节:电池图标样式 - configFile.put(static_cast(layout.timeDisplay)); // 第二字节:时间label位置 - configFile.put(static_cast(layout.colorTypeSet)); // 第三字节:字体颜色 - - // 关闭文件 - configFile.close(); - return true; // 成功写入配置 + index++; + } + return 0; +} +/* --------------------------------- 自定义表盘配置 + * -------------------------------- */ +/*加载自定义表盘*/ +void SetDialModel::LoadAllDialFromRam() { + for (uint8_t i = DIAL_CLOCK; i < DIAL_MAX; i++) { + // 获取表盘列表 读取自定义表盘配置 + const DialInfo *info = MainModel::GetInstance().GetDialInfo((DialId)i); + if (info == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "LoadAllDialFromRam: Dial info for ID %u is nullptr", i); + continue; } - /* - 从配置文件读取设置 - 配置文件名:表盘ID - 第一个字节:电池图标样式 - 第二个字节:时间label位置 - 第三个字节:字体颜色 - */ - bool SetDialModel::loadDialConfig(int Id, DialLayout &layout) - { - std::string filename = GetSaveDir(Id) + "/" + std::to_string(Id) + ".bin"; - // 打开文件 - std::ifstream configFile(filename, std::ios::binary); - if (!configFile.is_open()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Unable to open config file for reading: %s", filename.c_str()); - return false; // 文件打开失败 - } - - // 读取配置 - std::array settings; - configFile.read(settings.data(), settings.size()); - - if (configFile.gcount() != settings.size()) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to read configuration: %s", filename.c_str()); - return false; // 读取失败 - } - - // 为成员变量赋值 - layout.batteryDisplay = static_cast(settings[0]); // 电池图标样式 - layout.timeDisplay = static_cast(settings[1]); // 时间label位置 - layout.colorTypeSet = static_cast(settings[2]); // 字体颜色 - - // 关闭文件 - configFile.close(); - return true; // 成功读取配置 + // 处理自定义配置文件 + if (i != DIAL_CLOCK) { + std::string customFilePath = + GetSaveDir(i) + "/" + std::to_string(i) + ".bin"; + if (!CheckFileExists(customFilePath)) { + WEARABLE_LOGE( + WEARABLE_LOG_MODULE_APP, + "Custom config file does not exist for ID: %u, filename: %s", i, + customFilePath.c_str()); + continue; + } } - /*创建文件夹*/ - void SetDialModel::CreateDirectoryIfNotExists(const std::string &path) - { - struct stat info; - if (stat(path.c_str(), &info) != 0) - { - if (mkdir(path.c_str(), 0755) != 0) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error: Could not create directory %s. Errno: %d", path.c_str(), errno); - } - else - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Created directory: %s", path.c_str()); - } - } - else if (info.st_mode & S_IFDIR) - { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory already exists: %s", path.c_str()); - } + // 初始化表盘信息 + SetDialInfo dialInfo; + dialInfo.dialFlag = 0; + dialInfo.id = i; + dialInfo.dialName = info->dialName; + dialInfo.imageFullName = info->dialImg; + + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Processing Dial ID %u: Name: %s", i, + dialInfo.dialName.c_str()); + + // 加载图像资源 + ImageInfo *imageInfo = + ImageCacheManager::GetInstance().LoadSingleRes(info->dialImg, false); + if (imageInfo == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "LoadAllDialFromRam load image %s failed", info->dialImg); + continue; } - /* - 获取存储文件夹 - Id(0~4)通过ID返回对应的文件夹路径 - 0 {已经被用} - 1 - 2 - 3 - 4 - */ - std::string SetDialModel::GetSaveDir(int Id) - { - // 首先检查Id是否在0~4的范围内 - if (Id <= 0 || Id > 4) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error: Id must be between 1 and 4."); - return ""; // 或者返回一个空字符串 - } - // 检查 APP_CUSTOM_DIAL_PATH 是否存在 - CreateDirectoryIfNotExists(APP_CUSTOM_DIAL_PATH); - - std::string folderPath = std::string(APP_CUSTOM_DIAL_PATH) + "/" + std::to_string(Id); - CreateDirectoryIfNotExists(folderPath); // 确保目录存在 - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Directory is %s", folderPath.c_str()); - - return folderPath; // 返回目录路径 - } - /*获取自定义表盘名*/ - std::string SetDialModel::GetCustomName(int Id) - { - // 首先检查Id是否在0~4的范围内 - if (Id <= 0 || Id > 4) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Error: Id must be between 1 and 4."); - return ""; // 或者返回一个空字符串 - } - - // 获取表盘列表 读取自定义表盘配置 - const DialInfo *info = MainModel::GetInstance().GetDialInfo((DialId)Id); - - if (info == nullptr) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadAllDialFromRam: Dial info for ID %u is nullptr", Id); - return ""; - } - - return (info->dialName); + // 设置图像信息 + dialInfo.preImageInfo = imageInfo; + + // 添加到表盘列表 + dialInfoList.push_back(dialInfo); + + // 注册到map + // RegisterDial(dialInfo.id, dialInfo.dialName.c_str()); + + // 日志输出 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Parsed Dial: ID: %u, Name: %s, Image: %s", dialInfo.id, + dialInfo.dialName.c_str(), dialInfo.imageFullName.c_str()); + } +} + +// 检查文件是否存在的辅助函数 +bool SetDialModel::CheckFileExists(const std::string &filePath) { + std::ifstream file(filePath); + return file.is_open(); +} +// 测试表盘配置写文件 +void SetDialModel::TestDialConfig() { + DialLayout dialconfig; + + /*设置表盘参数*/ + dialconfig.dialId = 1; + dialconfig.batteryDisplay = 1; + dialconfig.timeDisplay = 0; + dialconfig.colorTypeSet = 5; + + if (!saveDialConfig(dialconfig)) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to save dial config"); + } +} +// 保存自定义表盘配置到文件 +bool SetDialModel::saveDialConfig(const DialLayout &layout) { + + std::string filename = + GetSaveDir(layout.dialId) + "/" + std::to_string(layout.dialId) + ".bin"; + + // 创建或打开文件 + std::ofstream configFile(filename, + std::ios::binary | std::ios::out | std::ios::trunc); + if (!configFile.is_open()) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Unable to open config file for writing: %s", + filename.c_str()); + return false; // 文件打开失败 + } + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "saveDialConfig: %d %d %d", + layout.batteryDisplay, layout.timeDisplay, layout.colorTypeSet); + + // 将结构体的三个数据按1个字节的存储到文件 + configFile.put( + static_cast(layout.batteryDisplay)); // 第一字节:电池图标样式 + configFile.put( + static_cast(layout.timeDisplay)); // 第二字节:时间label位置 + configFile.put(static_cast(layout.colorTypeSet)); // 第三字节:字体颜色 + + // 关闭文件 + configFile.close(); + return true; // 成功写入配置 +} + +/* + 从配置文件读取设置 + 配置文件名:表盘ID + 第一个字节:电池图标样式 + 第二个字节:时间label位置 + 第三个字节:字体颜色 +*/ +bool SetDialModel::loadDialConfig(int Id, DialLayout &layout) { + std::string filename = GetSaveDir(Id) + "/" + std::to_string(Id) + ".bin"; + // 打开文件 + std::ifstream configFile(filename, std::ios::binary); + if (!configFile.is_open()) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Unable to open config file for reading: %s", + filename.c_str()); + return false; // 文件打开失败 + } + + // 读取配置 + std::array settings; + configFile.read(settings.data(), settings.size()); + + if (configFile.gcount() != settings.size()) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to read configuration: %s", + filename.c_str()); + return false; // 读取失败 + } + + // 为成员变量赋值 + layout.batteryDisplay = + static_cast(settings[0]); // 电池图标样式 + layout.timeDisplay = + static_cast(settings[1]); // 时间label位置 + layout.colorTypeSet = static_cast(settings[2]); // 字体颜色 + + // 关闭文件 + configFile.close(); + return true; // 成功读取配置 +} + +/*创建文件夹*/ +void SetDialModel::CreateDirectoryIfNotExists(const std::string &path) { + struct stat info; + if (stat(path.c_str(), &info) != 0) { + if (mkdir(path.c_str(), 0755) != 0) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Error: Could not create directory %s. Errno: %d", + path.c_str(), errno); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Created directory: %s", + path.c_str()); } + } else if (info.st_mode & S_IFDIR) { + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory already exists: %s", + path.c_str()); + } +} + +/* + 获取存储文件夹 + Id(0~4)通过ID返回对应的文件夹路径 + 0 {已经被用} + 1 + 2 + 3 + 4 +*/ +std::string SetDialModel::GetSaveDir(int Id) { + // 首先检查Id是否在0~5的范围内 + if (Id <= 0 || Id > 5) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Error: Id must be between 1 and 4."); + return ""; // 或者返回一个空字符串 + } + // 检查 APP_CUSTOM_DIAL_PATH 是否存在 + CreateDirectoryIfNotExists(APP_CUSTOM_DIAL_PATH); + + std::string folderPath = + std::string(APP_CUSTOM_DIAL_PATH) + "/" + std::to_string(Id); + CreateDirectoryIfNotExists(folderPath); // 确保目录存在 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Directory is %s", folderPath.c_str()); + + return folderPath; // 返回目录路径 +} +std::string SetDialModel::GetSaveDir(int Id, uint8_t type) { + // 首先检查Id是否在0~4的范围内 + if (Id <= 4) { + Id++; + } + + if (Id <= 0 || Id > 4) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Error: Id must be between 1 and 4."); + return ""; // 或者返回一个空字符串 + } + // 检查 APP_CUSTOM_DIAL_PATH 是否存在 + CreateDirectoryIfNotExists(APP_CUSTOM_DIAL_PATH); + + std::string folderPath = + std::string(APP_CUSTOM_DIAL_PATH) + "/" + std::to_string(Id); + CreateDirectoryIfNotExists(folderPath); // 确保目录存在 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Directory is %s", folderPath.c_str()); + + return folderPath; // 返回目录路径 } + +/*获取自定义表盘名*/ +std::string SetDialModel::GetCustomName(int Id) { + // 首先检查Id是否在0~4的范围内 + if (Id <= 4) { + Id++; + } + + if (Id <= 0 || Id > 4) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "Error: Id must be between 1 and 4."); + return ""; // 或者返回一个空字符串 + } + + // 获取表盘列表 读取自定义表盘配置 + const DialInfo *info = MainModel::GetInstance().GetDialInfo((DialId)Id); + + if (info == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "LoadAllDialFromRam: Dial info for ID %u is nullptr", Id); + return ""; + } + + return (info->dialName); +} + +} // namespace OHOS diff --git a/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialPresenter.cpp b/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialPresenter.cpp index a62750de3..90d7d5211 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialPresenter.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/set_dial/src/SetDialPresenter.cpp @@ -18,7 +18,8 @@ #include "KeyInputListener.h" #include "custom_utils.h" #include "common/key_code.h" - +#include "bleService.h" +#include "bleEvent.h" namespace OHOS { SetDialPresenter::SetDialPresenter() @@ -55,8 +56,13 @@ namespace OHOS bool SetDialPresenter::OnClick(UIView &view, const ClickEvent &event) { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetDialPresenter::OnClick"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetDialPresenter::OnClick"); OnClickAction(); + + //具有延迟 更新表盘 + svr_ble_read_data_value_updata_noyify(); + Watch_SendDial_ToAppCmd(); + return true; } diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h b/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h index 2e88ece22..2231fc5ed 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/include/TraingModel.h @@ -234,7 +234,7 @@ namespace OHOS // 训练存储相关配置 bool CheckDataJson(); /*判断json文件是否存在*/ bool SaveDataToJson(SportData *data); /*保存训练记录到json文件*/ - std::vector LoadDataFormJson(); /*加载json文件*/ + bool LoadDataFormJson(std::vector& sportDataVector); /*加载json文件*/ void RecordSportData(); /*保存数据*/ // 训练数据相关配置 diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp index dc2b49db9..3998ebb47 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp @@ -1627,10 +1627,18 @@ namespace OHOS return false; } + // 解析json + std::vector sportDataVector; + if(!LoadDataFormJson(sportDataVector)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadDataFormJson is error"); + file.close(); + return false; + } + // 关闭文件 file.close(); - - // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckDataJson is ok"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "CheckDataJson is ok"); return true; } #if 1 @@ -1780,51 +1788,141 @@ namespace OHOS return true; } #endif - /* 加载训练数据函数 */ - std::vector TraingModel::LoadDataFormJson() + /* 加载训练数据函数 */ + bool TraingModel::LoadDataFormJson(std::vector& sportDataVector) { std::ifstream file(TRAINING_RECORD_FILE); if (!file.is_open()) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file"); - return std::vector(); + return false; } std::string jsonData((std::istreambuf_iterator(file)), std::istreambuf_iterator()); file.close(); cJSON *root = cJSON_Parse(jsonData.c_str()); + if (root == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to parse JSON: %s", cJSON_GetErrorPtr()); + return false; + } + cJSON *dataArray = cJSON_GetObjectItem(root, "data"); + if (dataArray == NULL ||!cJSON_IsArray(dataArray)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid or missing 'data' array in JSON"); + cJSON_Delete(root); + return false; + } int dataCount = cJSON_GetArraySize(dataArray); + if (dataCount == 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "error dataCount is 0"); + cJSON_Delete(root); + return false; + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dataCount is %d", dataCount); - std::vector sportDataVector; for (int i = 0; i < dataCount; i++) { cJSON *item = cJSON_GetArrayItem(dataArray, i); + if (item == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid item at index %d", i); + continue; // 跳过无效项目 + } + SportData sportData; - sportData.sportType = (Exercisetype)cJSON_GetObjectItem(item, "sportTypeId")->valueint; - sportData.sportId = (UIResourceTextId)cJSON_GetObjectItem(item, "sportId")->valueint; - sportData.start_date = cJSON_GetObjectItem(item, "startDate")->valuestring; - sportData.start_time = cJSON_GetObjectItem(item, "startTime")->valuestring; - sportData.end_time = cJSON_GetObjectItem(item, "endTime")->valuestring; - sportData.goaldegree = cJSON_GetObjectItem(item, "goalDegree")->valueint; - sportData.duration = cJSON_GetObjectItem(item, "duration")->valueint; - sportData.distance = cJSON_GetObjectItem(item, "distance")->valueint; - sportData.avgheart = cJSON_GetObjectItem(item, "avgHeartRate")->valueint; - sportData.steps = cJSON_GetObjectItem(item, "steps")->valueint; - sportData.intensity = cJSON_GetObjectItem(item, "intensity")->valueint; + bool isValid = true; // 用于标记 sportData 是否有效 + + // 检查并获取每个字段,确保其存在且类型正确 + if (cJSON *sportTypeIdItem = cJSON_GetObjectItem(item, "sportTypeId"); sportTypeIdItem && cJSON_IsNumber(sportTypeIdItem)) + sportData.sportType = (Exercisetype)sportTypeIdItem->valueint; + else + isValid = false; - sportData.apc = cJSON_GetObjectItem(item, "apc")->valueint; - sportData.cdc = cJSON_GetObjectItem(item, "cdc")->valueint; - sportData.std = cJSON_GetObjectItem(item, "std")->valueint; + if (cJSON *sportIdItem = cJSON_GetObjectItem(item, "sportId"); sportIdItem && cJSON_IsNumber(sportIdItem)) + sportData.sportId = (UIResourceTextId)sportIdItem->valueint; + else + isValid = false; + + if (cJSON *startDateItem = cJSON_GetObjectItem(item, "startDate"); startDateItem && cJSON_IsString(startDateItem)) + sportData.start_date = startDateItem->valuestring; + else + isValid = false; - sportDataVector.push_back(sportData); + if (cJSON *startTimeItem = cJSON_GetObjectItem(item, "startTime"); startTimeItem && cJSON_IsString(startTimeItem)) + sportData.start_time = startTimeItem->valuestring; + else + isValid = false; + + if (cJSON *endTimeItem = cJSON_GetObjectItem(item, "endTime"); endTimeItem && cJSON_IsString(endTimeItem)) + sportData.end_time = endTimeItem->valuestring; + else + isValid = false; + + if (cJSON *goalDegreeItem = cJSON_GetObjectItem(item, "goalDegree"); goalDegreeItem && cJSON_IsNumber(goalDegreeItem)) + sportData.goaldegree = goalDegreeItem->valueint; + else + isValid = false; + + if (cJSON *durationItem = cJSON_GetObjectItem(item, "duration"); durationItem && cJSON_IsNumber(durationItem)) + sportData.duration = durationItem->valueint; + else + isValid = false; + + if (cJSON *distanceItem = cJSON_GetObjectItem(item, "distance"); distanceItem && cJSON_IsNumber(distanceItem)) + sportData.distance = distanceItem->valueint; + else + isValid = false; + + if (cJSON *avgHeartRateItem = cJSON_GetObjectItem(item, "avgHeartRate"); avgHeartRateItem && cJSON_IsNumber(avgHeartRateItem)) + sportData.avgheart = avgHeartRateItem->valueint; + else + isValid = false; + + if (cJSON *stepsItem = cJSON_GetObjectItem(item, "steps"); stepsItem && cJSON_IsNumber(stepsItem)) + sportData.steps = stepsItem->valueint; + else + isValid = false; + + if (cJSON *intensityItem = cJSON_GetObjectItem(item, "intensity"); intensityItem && cJSON_IsNumber(intensityItem)) + sportData.intensity = intensityItem->valueint; + else + isValid = false; + + if (cJSON *apcItem = cJSON_GetObjectItem(item, "apc"); apcItem && cJSON_IsNumber(apcItem)) + sportData.apc = apcItem->valueint; + else + isValid = false; + + if (cJSON *cdcItem = cJSON_GetObjectItem(item, "cdc"); cdcItem && cJSON_IsNumber(cdcItem)) + sportData.cdc = cdcItem->valueint; + else + isValid = false; + + if (cJSON *stdItem = cJSON_GetObjectItem(item, "std"); stdItem && cJSON_IsNumber(stdItem)) + sportData.std = stdItem->valueint; + else + isValid = false; + + // 只有在所有字段都有效的情况下才添加 sportData 到向量中 + if (isValid) + { + sportDataVector.push_back(sportData); + } + else + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid data in item %d", i); + } } cJSON_Delete(root); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadDataFormJson is ok"); - return sportDataVector; + return true; } + } \ No newline at end of file diff --git a/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordModel.cpp index 6c82ded6d..a43fb9002 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordModel.cpp @@ -60,7 +60,12 @@ namespace OHOS void TraingRecordModel::InitTraingRecordListItem() { // 1.读取json数据 - std::vector sportDataVector = TraingModel::GetInstance()->LoadDataFormJson(); + std::vector sportDataVector; + if (!TraingModel::GetInstance()->LoadDataFormJson(sportDataVector)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadDataFormJson failed"); + return; + } if (!sportDataVector.empty()) { ArrayNum = sportDataVector.size(); diff --git a/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordPresenter.cpp b/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordPresenter.cpp index 09f7070c5..8f96de0c9 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordPresenter.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traingrecord/src/TraingRecordPresenter.cpp @@ -133,7 +133,12 @@ namespace OHOS int index = p_TraingRecordItemView->GetTraingRecordIndex(); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "the index is %d", index); // 读取json数据 - std::vector sportDataVector = TraingModel::GetInstance()->LoadDataFormJson(); + std::vector sportDataVector; + if (!TraingModel::GetInstance()->LoadDataFormJson(sportDataVector)) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadDataFormJson failed"); + return false; + } if (!sportDataVector.empty()) { // 选择点击按键的历史数据 diff --git a/code/sdk/application/wearable/service/ble_service/blemoder/bletest.cpp b/code/sdk/application/wearable/service/ble_service/blemoder/bletest.cpp index dd64745d9..b118cfad7 100644 --- a/code/sdk/application/wearable/service/ble_service/blemoder/bletest.cpp +++ b/code/sdk/application/wearable/service/ble_service/blemoder/bletest.cpp @@ -834,7 +834,7 @@ void get_sedent_param( msg_sedent_set_param_info_t * data) void ble_get_dial_path(char * buf,uint16_t id) { - char *path= (char*)OHOS::SetDialModel::GetInstance().GetSaveDir(id).c_str(); + char *path= (char*)OHOS::SetDialModel::GetInstance().GetSaveDir(id,0).c_str(); memcpy(buf,path,strlen(path)+1); return; } diff --git a/code/sdk/application/wearable/service/ble_service/bleservice/bleANCS.c b/code/sdk/application/wearable/service/ble_service/bleservice/bleANCS.c index 1bafd01d5..18e083e8c 100644 --- a/code/sdk/application/wearable/service/ble_service/bleservice/bleANCS.c +++ b/code/sdk/application/wearable/service/ble_service/bleservice/bleANCS.c @@ -312,24 +312,24 @@ static void ble_ancs_client_notification_attr_rsp_cbk(uint8_t client_id, uint16_ ble_ancs_attr_rsp_t *node = (ble_ancs_attr_rsp_t *)notify_attr_rsp->attr_rsp_lst.head; uint16_t att_num = 1; - char title_buf[256]={0}; - char msg_buf[256]={0}; - char app_buf[32]={0}; + char title_buf[300]={0}; + char msg_buf[300]={0}; + char app_buf[70]={0}; while (node != NULL) { if (node != NULL) { printf("[ANCSClientNotifyATTRSPCBK]att id:%d length:%lu att_value:%s\r\n", node->att_id, node->att_length, node->att); if( node->att_id==1) { - sprintf_s(title_buf,256,"%s",node->att); + sprintf_s(title_buf,300,"%s",node->att); } if(node->att_id==3) { - sprintf_s(msg_buf,256,"%s",node->att); + sprintf_s(msg_buf,300,"%s",node->att); } if(node->att_id==0) { - sprintf_s(app_buf,64,"%s",node->att); + sprintf_s(app_buf,70,"%s",node->att); } } node = lnext(node); diff --git a/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.c b/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.c index afa09591c..5e3553aab 100644 --- a/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.c +++ b/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.c @@ -4006,6 +4006,15 @@ static void GetSportPasueResetCmd(uint16_t cmd,uint8_t *data,uint16_t len,uint8_ } //发送当前表盘到app + +void Watch_SendDial_ToAppCmd(void) +{ + + uint16_t dialNum =ble_get_dial_id(); + ble_data_type type_={0x01,0x17,2,1,1}; + send_big_data(type_,(char *)&dialNum,2); +} + static void SendDialToAppCmd(uint16_t cmd,uint8_t *data,uint16_t len,uint8_t *totaldata,uint8_t crcvalue) { uint8_t value[20]; @@ -6872,8 +6881,8 @@ errcode_t decode_single_dial_info(ble_read_data *buffer_handle) uapi_dev_runtime_set_dialname(filename); //存表盘id ble_dial_uid = dialinfo.dial_uid; - if(ble_dial_uid<=4) - ble_dial_uid++; + // if(ble_dial_uid<=4) + // ble_dial_uid++; diff --git a/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.h b/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.h index f2e2caeef..0304681ee 100644 --- a/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.h +++ b/code/sdk/application/wearable/service/ble_service/bleservice/bleEvent.h @@ -818,6 +818,8 @@ void GetCurDataCmd(uint16_t cmd,uint8_t *data,uint16_t len,uint8_t *totaldata,ui bool get_ctkd_flag(void); +void Watch_SendDial_ToAppCmd(void); + uint8_t parse_jsonCheck_weather(uint8_t *buf,uint8_t *check);//json 格式解析 天气数据 uint8_t read_jsonHistory_weather(void); void GetwatchSaveMac(uint8_t *mac,uint8_t *mactype); diff --git a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/birdie.bin b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/birdie.bin new file mode 100644 index 000000000..f9fdfab46 --- /dev/null +++ b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/birdie.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5509eb40b25f2839bff6dd4496ae740308e17e12c36cd470db502ca0ac8dcbcb +size 1523772 diff --git a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/classic.bin b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/classic.bin deleted file mode 100644 index 77b4b4ce4..000000000 --- a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/classic.bin +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:65c0d4472d9bb822d678a16f460e53b833f8a1c7e41bbee39c6d6506403a39a0 -size 205120 diff --git a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/galaxy.bin b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/galaxy.bin deleted file mode 100644 index 5aa7299da..000000000 --- a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/galaxy.bin +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5e73fb1b366d0ec5c5ba33d1c290fbd94ace6d0f654ea7d411512bd2fe65cef -size 209925 diff --git a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/obsidianrhythm.bin b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/obsidianrhythm.bin new file mode 100644 index 000000000..48dd46e04 --- /dev/null +++ b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/obsidianrhythm.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53d1a6626429f4ea7d0219f7d9637e2cc59979557f9424221ec95381cd0fea22 +size 1399839 diff --git a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/sport.bin b/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/sport.bin deleted file mode 100644 index 739609ea8..000000000 --- a/code/sdk/build/config/target_config/brandy/mk_fs_image/fd230/fs/user/dial/sport.bin +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ce06332fcd4a61b22a41ae5c64b437b15edbf7dd855b2fab28d09897502186a -size 344285