From: luozheng <1732036298@qq.com> Date: Mon, 29 Sep 2025 09:24:53 +0000 (+0800) Subject: 优化表情下载功能,添加通知ui切换slice消息id X-Git-Tag: V1.0.9_20251128_194606_LN~250^2~28^2~1 X-Git-Url: http://git.snicker.com.cn/css/static/gitweb.css?a=commitdiff_plain;h=62ba060536a32971723aee2da4bca18bdc22527f;p=mirrors%2FFD230.git 优化表情下载功能,添加通知ui切换slice消息id --- diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/include/uiservice/ui_service.h b/code/sdk/application/wearable/ln/nativeapp/nativeui/include/uiservice/ui_service.h index 1c8fbc33f..4c421496b 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/include/uiservice/ui_service.h +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/include/uiservice/ui_service.h @@ -60,8 +60,9 @@ typedef enum { HAND_CHAT_STAMINA_NOTIFY, // 对话体力与流量通知 HAND_API_ERROR_NOTIFY, // 协议错误通知 HAND_BIND_AND_UNBIND_NOTIFY, // 绑定和解绑通知 - HAND_SCREEN_IMAGE_DOWNLOAD_SUCCESS_NOTIFY, // 屏保下载成功通知 HAND_TEXT_UPDATE_NOTIFY, // 更新文本内容通知 + HAND_DOWNLOAD_FILE_NOTIFY, // 下载文件通知 + HAND_DOWNLOAD_SUCCESS_NOTIFY, // 下载成功通知 MAX_NUM_HANDLER, } UiServiceMsgId; diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/uiservice/src/ui_service.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/uiservice/src/ui_service.cpp index 4d542c874..c858f15d8 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/uiservice/src/ui_service.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/uiservice/src/ui_service.cpp @@ -96,8 +96,9 @@ static void HandChatStaminaNotify(Request *request); static void HandDownloadEmojiNotify(Request *request); static void HandApiErrorNotify(Request *request); static void HandBindAndUnbindNotify(Request *request); -static void HandScreenImageDownloadSuccessNotify(Request *request); static void HandTextUpdateNotify(Request *request); +static void HandDownloadFileNotify(Request *request); +static void HandDownloadSuccessNotify(Request *request); // 消息处理程序项数组(每个消息类型对应一个处理函数,函数名以 Handle 开头) MsgHandlerEntry msgHandlers[] = { {HANDLE_JUMP_OTA_VIEW, HandleJumpOtaView}, @@ -110,8 +111,9 @@ MsgHandlerEntry msgHandlers[] = { {HAND_DOWNLOAD_EMOJI_NOTIFY,HandDownloadEmojiNotify}, {HAND_API_ERROR_NOTIFY,HandApiErrorNotify}, {HAND_BIND_AND_UNBIND_NOTIFY,HandBindAndUnbindNotify}, - {HAND_SCREEN_IMAGE_DOWNLOAD_SUCCESS_NOTIFY,HandScreenImageDownloadSuccessNotify}, {HAND_TEXT_UPDATE_NOTIFY,HandTextUpdateNotify}, + {HAND_DOWNLOAD_FILE_NOTIFY,HandDownloadFileNotify}, + {HAND_DOWNLOAD_SUCCESS_NOTIFY,HandDownloadSuccessNotify}, }; /* -------------------------------------------------------------------------- */ void ScreenTurnOn(int32_t timeout) @@ -534,14 +536,6 @@ void HandBindAndUnbindNotify(Request *request) std::bind(&OHOS::ThunderBirdModel::HandleBindAndUnbind,OHOS::ThunderBirdModel::GetInstance(), is_bind)); } -// 屏保下载成功通知 -void HandScreenImageDownloadSuccessNotify(Request *request) -{ - WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandScreenImageDownloadSuccessNotify msg_id = %d", request->msgId); - // GraphicService::GetInstance()->PostGraphicEvent( - // std::bind(&OHOS::ThunderBirdModel::HandleScreenImageDownloadSuccess,OHOS::ThunderBirdModel::GetInstance())); -} - // 更新文本内容通知 void HandTextUpdateNotify(Request *request) { @@ -550,6 +544,24 @@ void HandTextUpdateNotify(Request *request) std::bind(&OHOS::ThunderBirdModel::SetTextStr,OHOS::ThunderBirdModel::GetInstance(),value.c_str())); } +// 下载文件通知 +void HandDownloadFileNotify(Request *request) +{ + WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandDownloadFileNotify msg_id = %d", request->msgId); + int type = *(int *)request->data; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandDownloadFileNotify type = %d", type); + // GraphicService::GetInstance()->PostGraphicEvent( + // std::bind(&OHOS::ThunderBirdModel::HandleDownloadFile,OHOS::ThunderBirdModel::GetInstance(), type)); +} +// 下载成功通知 +void HandDownloadSuccessNotify(Request *request) +{ + WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandDownloadSuccessNotify msg_id = %d", request->msgId); + int type = *(int *)request->data; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandDownloadSuccessNotify type = %d", type); + // GraphicService::GetInstance()->PostGraphicEvent( + // std::bind(&OHOS::ThunderBirdModel::HandleDownloadSuccess,OHOS::ThunderBirdModel::GetInstance(), type)); +} /* -------------------------------------------------------------------------- */ #ifdef __cplusplus } diff --git a/code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c b/code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c index 3cbb8da4c..5fb801ccc 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c @@ -1770,14 +1770,31 @@ static uint32_t ln_api_error_at(uint8_t *para, uint32_t paraLen, char *strCommon return ERRCODE_SUCC; } -static uint32_t ln_notify_screen_image_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +//AT^LN_NOTIFY_DOWNLOAD_SUCCESS=0/1 +static uint32_t ln_download_success_notification_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd) { - VAD_UNUSED(para); - VAD_UNUSED(paraLen); VAD_UNUSED(strCommonCmd); - push_screen_image_download_success_notification(); - printf("+LN_NOTIFY_SCREEN_IMAGE: OK\n"); - printf("[LN][NOTIFY_SCREEN_IMAGE] ok\n"); + int type = 0; + uint8_t argv[LN_MAX_ARGC][LN_MAX_ARGV_LEN] = {0}; + uint32_t argc = 0; + + if (para != NULL && paraLen > 0) { + if (ConvertCmdToParam(para, paraLen, argv, &argc) != VAD_SUCCESS) { + printf("ERROR: Failed to parse parameters\n"); + return ERRCODE_FAIL; + } + if (argc >= 1) { + type = atoi((char*)argv[0]); + } + } + + if (type != 0 && type != 1) { + printf("ERROR: Type too long (max 1 characters)\n"); + return ERRCODE_FAIL; + } + push_download_success_notification(type); + printf("+LN_NOTIFY_DOWNLOAD_SUCCESS: OK\n"); + printf("[LN][NOTIFY_DOWNLOAD_SUCCESS] ok\n"); return ERRCODE_SUCC; } @@ -1844,7 +1861,7 @@ static const at_cmd_table_t g_ln_api_cmd[] = { {(char *)"AT^LN_SWITCH_EXPRESSION", ln_switch_expression_at, (char *)"切换表情视频: AT^LN_SWITCH_EXPRESSION="}, {(char *)"AT^LN_API_ERROR", ln_api_error_at, (char *)"推送协议错误: AT^LN_API_ERROR[=message]"}, {(char *)"AT^LN_NOTIFY_BIND_AND_UNBIND", ln_notify_bind_and_unbind_at, (char *)"通知用户绑定或解绑: AT^LN_NOTIFY_BIND_AND_UNBIND=1/0"}, - {(char *)"AT^LN_NOTIFY_SCREEN_IMAGE", ln_notify_screen_image_at, (char *)"通知切换屏保: AT^LN_NOTIFY_SCREEN_IMAGE"}, + {(char *)"AT^LN_NOTIFY_DOWNLOAD_SUCCESS", ln_download_success_notification_at, (char *)"通知切换屏保: AT^LN_NOTIFY_DOWNLOAD_SUCCESS=0/1"}, /* 内存查看相关AT命令 */ diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c index f6df7e583..332782c5c 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c @@ -330,6 +330,13 @@ const char *uapi_ln_get_user_id(void) return g_ln_device_user_id; } +/* 获取当前是否正在下载文件 */ +int uapi_ln_is_file_downloading(void) +{ + return g_ln_is_file_downloading; +} + + /* 下载文件 @param url 文件URL @param save_path 保存路径 @@ -421,51 +428,62 @@ int uapi_ln_download_file(const char *url, const char *save_path) } else { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] recv_res = %d, break", recv_res); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 接收响应失败, break, recv_res = %d", recv_res); break; } } while (client_data.isMore); if (client_data.responseContentLen == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] receive length = 0"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 接收长度为0"); } WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] responsecode = %d", client.responseCode); if (total_written == client_data.responseContentLen && client.responseCode == 200 && total_written > 0) { ret = ERRCODE_SUCC; - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] The file is downloaded successfully and the data is complete!"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 文件下载成功"); } else { ret = ERRCODE_FAIL; - unlink(save_path); // 删除不完整文件 - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] The file data is incomplete!"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 文件下载失败删除不完整文件,save_path = %s", save_path); + if (unlink(save_path) < 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "删除不完整文件失败\r\n"); + } + else + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "删除不完整文件成功\r\n"); + } } HttpClientUnprepare(&client_data); HttpClientClse(&client); fclose(fd); g_ln_is_file_downloading = 0; - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] download process finished,ret=%d", ret); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 下载过程结束,ret=%d", ret); return ret; } /* 下载函数封装:带重试,不做UI通知与资源释放 */ int uapi_ln_download_with_retry(const char *url, const char *save_path, int max_retries) { - if (url == NULL || save_path == NULL) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] invalid params"); + if (url == NULL || save_path == NULL) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 参数无效"); return ERRCODE_FAIL; } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] start: %s -> %s", url, save_path); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 开始下载: %s -> %s", url, save_path); int ret = uapi_ln_download_file(url, save_path); - if (ERRCODE_SUCC != ret) { - for (int i = 1; i <= max_retries; i++) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] retry %d/%d", i, max_retries); + if (ERRCODE_SUCC != ret) + { + for (int i = 1; i <= max_retries; i++) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 重试 %d/%d", i, max_retries); ret = uapi_ln_download_file(url, save_path); - if (ERRCODE_SUCC == ret) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] success on retry %d", i); + if (ERRCODE_SUCC == ret) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 重试成功 %d", i); break; } } @@ -594,7 +612,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type) printf("[WS] DownloadEmoji:下载表情\n"); if (json_str) { - // ln_parse_download_emoji(json_str, (int)strlen(json_str)); + ln_parse_download_emoji(json_str, (int)strlen(json_str)); } break; } @@ -1187,6 +1205,19 @@ static void ln_http_server_send_task(void const *arg) printf("LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD:下载OTA升级包\n"); ln_ota_download_flow_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version()); } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_DOWNLOAD_EMOJI) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LN_HTTP_SERVICE_CMD_DOWNLOAD_EMOJI:下载表情\n"); + ln_start_emoji_download(); + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_DELETE_EMOJI) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LN_HTTP_SERVICE_CMD_DELETE_EMOJI:删除表情\n"); + if (mail.data) + { + // ln_delete_emoji_http(mail.data, mail.len); + } + } else if (mail.cmd == LN_HTTP_SERVICE_CMD_EMOJI_REPORT) { printf("LN_HTTP_SERVICE_CMD_EMOJI_REPORT:上报角色表情组下载状态\n"); @@ -1212,7 +1243,7 @@ static void ln_http_server_send_task(void const *arg) if (ret == ERRCODE_SUCC) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保下载成功,通知去切换屏保"); - push_screen_image_download_success_notification(); + push_download_success_notification(DOWNLOAD_FILE_TYPE_SCREEN_IMAGE); } else { @@ -1233,7 +1264,7 @@ static void ln_http_server_send_task(void const *arg) } else if (mail.cmd == LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER) { - printf("LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER:日程提醒\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER] 日程提醒"); ln_parse_schedule_reminder(mail.data, mail.len); } if (mail.data != NULL) diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h index 51aed1d89..3f4515c8e 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h @@ -114,6 +114,10 @@ typedef struct #define LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE 0x1009 /* 下载屏保文件 */ #define LN_HTTP_SERVICE_CMD_SCHEDULE_REMINDER 0x1010 /* 日程提醒 */ +// 表情下载相关命令 +#define LN_HTTP_SERVICE_CMD_DOWNLOAD_EMOJI 0x1011 /* 下载表情 */ +#define LN_HTTP_SERVICE_CMD_DELETE_EMOJI 0x1012 /* 删除表情 */ + /* 下载文件相关结构体 */ typedef struct { @@ -135,6 +139,16 @@ typedef struct const char *status; /* 状态: download_success/download_fail/delete_success/delete_fail */ } LnEmojiGroup; +/* Emoji 上报(队列透传)邮件结构体 - 固定大小,避免二次内存管理 */ +typedef struct +{ + char characterId[64]; + char eyesColor[32]; + char eyesShape[32]; + char status[32]; /* download_success/download_fail/delete_success/delete_fail */ + char description[64]; /* 描述,如 “下载成功” */ +} ln_emoji_report_mail_t; + /* 设备绑定状态 */ typedef enum { @@ -198,6 +212,8 @@ const char *uapi_ln_ota_get_saved_path(void); const char *uapi_ln_get_audio_path(void); /* 获取设备绑定用户ID */ const char *uapi_ln_get_user_id(void); +//获取当前是否正在下载文件 +int uapi_ln_is_file_downloading(void); /*文件下载函数:从URL下载到指定路径*/ int uapi_ln_download_file(const char *url, const char *save_path); int uapi_ln_download_with_retry(const char *url, const char *save_path, int max_retries); @@ -228,6 +244,7 @@ uint32_t ln_token_load_json(char **token_out, uint64_t *expire_timestamp_out); uint32_t ln_token_is_expired(int *expired_out); /* 主动刷新设备Token(调用HTTP接口),并落盘保存 */ uint32_t uapi_ln_refresh_device_token(void); +void ln_start_emoji_download(void); /* 从本地读取角色配置 */ void ln_read_character_config(void); @@ -247,6 +264,8 @@ void ln_parse_schedule_reminder_config(const char *json_str, int json_len); void ln_parse_download_emoji(const char *json_str, int json_len); /* 解析删除表情 */ void ln_parse_delete_emoji(const char *json_str, int json_len); +/* 上报角色表情组下载状态(从队列数据解析)*/ +void ln_emoji_report_status(char *data); /* ============================== 各接口函数声明 ============================== */ uint32_t ln_get_device_token_http(const char *device_id, diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c index 38e13609a..ef687da41 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c @@ -409,7 +409,7 @@ void ln_parse_character_config_local(const char *json_buf, int json_len) if (access(LN_DEVICE_SCREEN_IMAGE_FILE, F_OK) != -1) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片存在,直接发送切换屏保通知"); - push_screen_image_download_success_notification(); + push_download_success_notification(DOWNLOAD_FILE_TYPE_SCREEN_IMAGE); } else { @@ -439,6 +439,10 @@ void ln_parse_character_config_local(const char *json_buf, int json_len) memcpy(req.save_path, save, slen + 1); } } + + //通知ui切换slice下载屏保 + push_download_file_notification(DOWNLOAD_FILE_TYPE_SCREEN_IMAGE); + do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_DOWNLOAD_SCREEN_IMAGE, (char *)&req, sizeof(req)); } diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c index 20224903a..96c91e66c 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c @@ -15,23 +15,23 @@ /* 表情信息结构体定义 */ typedef struct { - char emotion[32]; // 心情类型 - char emojiUrl[512]; // 表情文件URL + char *emotion; // 心情类型(动态分配) + char *emojiUrl; // 表情文件URL(动态分配) } EmotionEmoji; /* 表情包配置结构体 */ typedef struct { - char characterId[64]; // 角色ID - char eyesColor[32]; // 瞳色 - char eyesShape[32]; // 眼型 + char *characterId; // 角色ID(动态分配) + char *eyesColor; // 瞳色(动态分配) + char *eyesShape; // 眼型(动态分配) EmotionEmoji *emojis; // 表情列表 int emojiCount; // 表情数量 + long long totalSize; // 服务端汇报的表情包总大小(字节) } EmojiPackage; /* 全局变量 */ EmojiPackage g_emoji_package = {0}; -static volatile int g_emoji_downloading = 0; // 下载状态标志 /* 安全字符串复制函数 */ static inline void ln_safe_strcpy(char *dst, size_t dst_size, const char *src) @@ -47,15 +47,58 @@ static inline void ln_safe_strcpy(char *dst, size_t dst_size, const char *src) dst[dst_size - 1] = '\0'; } -/* 释放表情列表资源 */ +/* 动态分配字符串(返回非NULL,至少为空串)*/ +static inline char *ln_safe_strdup(const char *src) +{ + const char *s = src ? src : ""; + size_t n = strlen(s) + 1; + char *p = (char *)malloc(n); + if (!p) + { + return NULL; + } + memcpy(p, s, n); + return p; +} + +/* 释放表情包所有动态资源 */ static void ln_free_emoji_list() { + if (g_emoji_package.characterId) + { + free(g_emoji_package.characterId); + g_emoji_package.characterId = NULL; + } + if (g_emoji_package.eyesColor) + { + free(g_emoji_package.eyesColor); + g_emoji_package.eyesColor = NULL; + } + if (g_emoji_package.eyesShape) + { + free(g_emoji_package.eyesShape); + g_emoji_package.eyesShape = NULL; + } if (g_emoji_package.emojis) { + for (int i = 0; i < g_emoji_package.emojiCount; i++) + { + if (g_emoji_package.emojis[i].emotion) + { + free(g_emoji_package.emojis[i].emotion); + g_emoji_package.emojis[i].emotion = NULL; + } + if (g_emoji_package.emojis[i].emojiUrl) + { + free(g_emoji_package.emojis[i].emojiUrl); + g_emoji_package.emojis[i].emojiUrl = NULL; + } + } free(g_emoji_package.emojis); g_emoji_package.emojis = NULL; } g_emoji_package.emojiCount = 0; + g_emoji_package.totalSize = 0; } /* 工具函数:生成表情缓存路径 */ @@ -67,9 +110,15 @@ static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji return; } - // 路径格式:BASE/characterId/eyesColor_eyesShape/emotion.ext + const char *characterId = pkg->characterId ? pkg->characterId : ""; + const char *eyesColor = pkg->eyesColor ? pkg->eyesColor : ""; + const char *eyesShape = pkg->eyesShape ? pkg->eyesShape : ""; + const char *emotion = emoji->emotion ? emoji->emotion : ""; + const char *emojiUrl = emoji->emojiUrl ? emoji->emojiUrl : ""; + + // 路径格式:EMOJI_CACHE_BASE_PATH/eyesShape/eyesColor/emotion.mp4 char ext[32] = {0}; - const char *dot = strrchr(emoji->emojiUrl, '.'); + const char *dot = emojiUrl[0] ? strrchr(emojiUrl, '.') : NULL; if (dot && strlen(dot) < sizeof(ext)) { strncpy(ext, dot, sizeof(ext) - 1); @@ -80,16 +129,15 @@ static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji return; } - // emojiUrl=https://ambybox-emoji.test.leiniao.com/v1/emoji/getEmoji?characterId=1&eyesColor=1&eyesShape=1&emotion=1 - // path=/user/userdata/leiniao/emoji/1/1_1/1.png + //表情存放路径 + // 生成表情缓存路径成功,path=/user/userdata/leiniao/emoji/round-eyes/blue/angry.mp4 snprintf(path, path_len, - "%s%s/%s_%s/%s%s", + "%s%s/%s/%s%s", EMOJI_CACHE_BASE_PATH, - pkg->characterId, - pkg->eyesColor, - pkg->eyesShape, - emoji->emotion, + eyesShape, + eyesColor, + emotion, ext); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 生成表情缓存路径成功,path=%s", path); } @@ -110,11 +158,26 @@ static void ln_emoji_download(void *arg) if (!pkg || pkg->emojiCount <= 0 || !pkg->emojis) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 没有表情需要下载"); - g_emoji_downloading = 0; + ln_free_emoji_list(); return; } int all_success = 1; + int downloaded_count = 0; /* 包含已缓存与成功下载的 */ + int failed_count = 0; + + /* 若有总大小信息,则进行磁盘空间预检查(考虑已缓存文件大小) */ + if (pkg->totalSize > 0) + { + if (can_download_file(EMOJI_CACHE_BASE_PATH, pkg->totalSize) == 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 没有足够的空间,跳过下载"); + //通知ui + push_api_error_notification("没有足够的空间,跳过下载"); + ln_free_emoji_list(); + return; + } + } // 遍历下载所有表情 for (int i = 0; i < pkg->emojiCount; i++) @@ -122,7 +185,8 @@ static void ln_emoji_download(void *arg) // 跳过已缓存的文件 if (ln_emoji_is_cached(pkg, &pkg->emojis[i])) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s already cached", pkg->emojis[i].emotion); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 已缓存", pkg->emojis[i].emotion); + downloaded_count++; continue; } @@ -143,43 +207,57 @@ static void ln_emoji_download(void *arg) uapi_create_folder(dir_buf); } } - if (uapi_ln_download_file(pkg->emojis[i].emojiUrl, save_path) != ERRCODE_SUCC) + if (uapi_ln_download_with_retry(pkg->emojis[i].emojiUrl, save_path, 3) != ERRCODE_SUCC) { all_success = 0; - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s download failed", pkg->emojis[i].emotion); + failed_count++; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 下载失败", pkg->emojis[i].emotion); + } + else + { + downloaded_count++; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 下载完成", pkg->emojis[i].emotion); } } + /* 汇总统计打印 */ + { + int remaining_count = pkg->emojiCount - downloaded_count; + if (remaining_count < 0) + remaining_count = 0; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, + "[DOWNLOAD] 统计: 总数=%d, 已完成=%d, 失败=%d, 剩余未下载=%d", + pkg->emojiCount, downloaded_count, failed_count, remaining_count); + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "上报表情下载状态"); // 下载完成后上报状态 - const char *status = all_success ? "success" : "failed"; - /* 传递包含'\0'的长度,确保下游按字符串安全处理 */ - do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_EMOJI_REPORT, (char *)status, (uint32_t)(strlen(status) + 1)); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] report status %s, all_success: %d", status, all_success); - - g_emoji_downloading = 0; + /* 构建上报邮件(包含状态与描述),遵循新协议 */ + ln_emoji_report_mail_t mail = {0}; + ln_safe_strcpy(mail.characterId, sizeof(mail.characterId), g_emoji_package.characterId); + ln_safe_strcpy(mail.eyesColor, sizeof(mail.eyesColor), g_emoji_package.eyesColor); + ln_safe_strcpy(mail.eyesShape, sizeof(mail.eyesShape), g_emoji_package.eyesShape); + ln_safe_strcpy(mail.status, sizeof(mail.status), all_success ? "download_success" : "download_fail"); + ln_safe_strcpy(mail.description, sizeof(mail.description), all_success ? "下载成功" : "下载失败"); + do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_EMOJI_REPORT, (char *)&mail, (uint32_t)sizeof(mail)); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] report status %s, all_success: %d", mail.status, all_success); + + /* 下载完释放本次表情包占用的内存 */ + ln_free_emoji_list(); } -/* 启动下载任务 */ -static void ln_start_emoji_download() +/* 启动表情下载任务 */ +void ln_start_emoji_download(void) { - if (g_emoji_downloading) - { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] already downloading, skip"); - return; - } - + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 启动表情下载任务"); if (g_emoji_package.emojiCount <= 0 || !g_emoji_package.emojis) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] no emojis to download"); return; } - // 下载表情 ln_emoji_download(&g_emoji_package); - - g_emoji_downloading = 1; } /* 解析下载表情命令JSON */ @@ -190,6 +268,12 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] invalid json input"); return; } + if(uapi_ln_is_file_downloading() == 1) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] 已有文件正在下载中,跳过下载"); + // push_api_error_notification("已有文件正在下载中,跳过下载"); + return; + } // 释放原有表情资源 ln_free_emoji_list(); @@ -236,17 +320,29 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) cJSON *eyesColor = cJSON_GetObjectItem(data, "eyesColor"); cJSON *eyesShape = cJSON_GetObjectItem(data, "eyesShape"); - ln_safe_strcpy(g_emoji_package.characterId, - sizeof(g_emoji_package.characterId), - (characterId && cJSON_IsString(characterId)) ? characterId->valuestring : ""); - - ln_safe_strcpy(g_emoji_package.eyesColor, - sizeof(g_emoji_package.eyesColor), - (eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : ""); + g_emoji_package.characterId = ln_safe_strdup((characterId && cJSON_IsString(characterId)) ? characterId->valuestring : ""); + g_emoji_package.eyesColor = ln_safe_strdup((eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : ""); + g_emoji_package.eyesShape = ln_safe_strdup((eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : ""); - ln_safe_strcpy(g_emoji_package.eyesShape, - sizeof(g_emoji_package.eyesShape), - (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : ""); + /* 解析总大小(字节) */ + cJSON *size_node = cJSON_GetObjectItem(data, "size"); + if (size_node && (cJSON_IsNumber(size_node) || cJSON_IsString(size_node))) + { + long long parsed_size = 0; + if (cJSON_IsNumber(size_node)) + { + parsed_size = (long long)size_node->valuedouble; + } + else if (cJSON_IsString(size_node) && size_node->valuestring) + { + parsed_size = atoll(size_node->valuestring); + } + g_emoji_package.totalSize = parsed_size > 0 ? parsed_size : 0; + } + else + { + g_emoji_package.totalSize = 0; + } // 解析表情列表 cJSON *emotionEmojis = cJSON_GetObjectItem(data, "emotionEmojis"); @@ -256,7 +352,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) if (count > 0) { g_emoji_package.emojiCount = count; - g_emoji_package.emojis = (EmotionEmoji *)malloc(sizeof(EmotionEmoji) * count); + g_emoji_package.emojis = (EmotionEmoji *)calloc((size_t)count, sizeof(EmotionEmoji)); if (!g_emoji_package.emojis) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] malloc failed for emojis"); @@ -273,13 +369,8 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) cJSON *emotion = cJSON_GetObjectItem(item, "emotion"); cJSON *emojiUrl = cJSON_GetObjectItem(item, "emojiUrl"); - ln_safe_strcpy(g_emoji_package.emojis[i].emotion, - sizeof(g_emoji_package.emojis[i].emotion), - (emotion && cJSON_IsString(emotion)) ? emotion->valuestring : ""); - - ln_safe_strcpy(g_emoji_package.emojis[i].emojiUrl, - sizeof(g_emoji_package.emojis[i].emojiUrl), - (emojiUrl && cJSON_IsString(emojiUrl)) ? emojiUrl->valuestring : ""); + g_emoji_package.emojis[i].emotion = ln_safe_strdup((emotion && cJSON_IsString(emotion)) ? emotion->valuestring : ""); + g_emoji_package.emojis[i].emojiUrl = ln_safe_strdup((emojiUrl && cJSON_IsString(emojiUrl)) ? emojiUrl->valuestring : ""); } } } @@ -292,9 +383,8 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesColor: %s", g_emoji_package.eyesColor); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesShape: %s", g_emoji_package.eyesShape); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " emojiCount: %d", g_emoji_package.emojiCount); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " totalSize: %lld", g_emoji_package.totalSize); - // 通知UI切换表情 - // push_download_emoji_notification(g_emoji_package.characterId, g_emoji_package.eyesColor, g_emoji_package.eyesShape); for (int i = 0; i < g_emoji_package.emojiCount; i++) { @@ -304,9 +394,11 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) g_emoji_package.emojis[i].emojiUrl); } - // 解析完成后启动下载任务 - ln_start_emoji_download(); - + // 解析完成后启动下载任务(通过发送队列触发下载逻辑) + // 说明:下载所需信息已填充到全局 g_emoji_package,触发命令无需携带负载 + //通知ui切换slice下载表情 + push_download_file_notification(DOWNLOAD_FILE_TYPE_EMOJI); + do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_DOWNLOAD_EMOJI, NULL, 0); // 清理资源 cJSON_Delete(root); free(text); @@ -427,11 +519,10 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) // 删除本地表情缓存 char del_dir[MAX_PATH_LEN] = {0}; snprintf(del_dir, sizeof(del_dir), - "%s%s/%s_%s", + "%s%s/%s", EMOJI_CACHE_BASE_PATH, - del_characterId, - del_eyesColor, - del_eyesShape); + del_eyesShape, + del_eyesColor); if (ln_rmdir_recursive(del_dir) == 0) { @@ -447,13 +538,14 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) free(text); } -/* 7.1 上报角色表情组下载状态 */ +/* 7.1 上报角色表情组下载状态(支持 description) */ uint32_t ln_emoji_report_status_http(const char *device_id, const char *device_token, const char *character_id, const char *eyes_color, const char *eyes_shape, - const char *status) + const char *status, + const char *description) { if (!device_id || !device_token || !character_id || !eyes_color || !eyes_shape || !status) { @@ -505,6 +597,7 @@ uint32_t ln_emoji_report_status_http(const char *device_id, cJSON_AddStringToObject(root, "eyesColor", eyes_color); cJSON_AddStringToObject(root, "eyesShape", eyes_shape); cJSON_AddStringToObject(root, "status", status); + cJSON_AddStringToObject(root, "description", description ? description : ""); char *body = cJSON_PrintUnformatted(root); cJSON_Delete(root); if (!body) @@ -544,6 +637,14 @@ uint32_t ln_emoji_report_status_http(const char *device_id, } int code = HttpClientGetResponseCode(&client); + if (code != 200) + { + free(body); + HttpClientUnprepare(&clientData); + free(header_buf); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response code not 200"); + return ERRCODE_FAIL; + } if (clientData.responseBuf && clientData.responseBufLen > 0) { // { @@ -564,14 +665,7 @@ uint32_t ln_emoji_report_status_http(const char *device_id, WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response body: %s", response_buf); free(response_buf); } - if (code != 200) - { - free(body); - HttpClientUnprepare(&clientData); - free(header_buf); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response code not 200"); - return ERRCODE_FAIL; - } + free(body); HttpClientUnprepare(&clientData); @@ -695,14 +789,30 @@ uint32_t ln_emoji_report_all_http(const char *device_id, } /* 上报角色表情组下载状态 */ -void ln_emoji_report_status(char* status) +void ln_emoji_report_status(char* data) { - ln_emoji_report_status_http(uapi_ln_get_device_id(), - uapi_ln_get_device_token(), - g_emoji_package.characterId, - g_emoji_package.eyesColor, - g_emoji_package.eyesShape, - status); + if (!data) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] empty mail data"); + return; + } + ln_emoji_report_mail_t mail; + memcpy(&mail, data, sizeof(mail)); + + const char *device_id = uapi_ln_get_device_id(); + const char *device_token = uapi_ln_get_device_token(); + + if (!device_id || !device_token) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] missing device id/token"); + return; + } + + ln_emoji_report_status_http(device_id, + device_token, + mail.characterId, + mail.eyesColor, + mail.eyesShape, + mail.status, + mail.description); } /* 上报所有角色表情组状态 */ diff --git a/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp b/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp index 946c4345b..5a24c2edc 100644 --- a/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp +++ b/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp @@ -118,6 +118,16 @@ uint64_t get_folder_size(const char *folder_path) return memoryManager->GetFolderSize(folder_path); } + +int can_download_file(const char *path, uint64_t downloadSize) +{ + OHOS::MemoryManager* memoryManager = OHOS::MemoryManager::GetInstance(); + if (memoryManager == NULL) { + return 0; + } + int ret = memoryManager->CheckPathMemory(path, downloadSize); + return ret ? 1 : 0; +} // 推送角色配置更改通知(简洁载荷) void push_character_config_change_notification(const char* characterId, const char *characterName, @@ -215,11 +225,18 @@ void push_bind_and_unbind_notification(int is_bind) SendMsgToUIService(HAND_BIND_AND_UNBIND_NOTIFY, 0, &is_bind, sizeof(is_bind)); } -// 推送屏保下载成功通知到UI -void push_screen_image_download_success_notification(void) +// 通知ui需要下载文件了需要切换slice +void push_download_file_notification(int type) +{ + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_FILE] type=%d", type); + SendMsgToUIService(HAND_DOWNLOAD_FILE_NOTIFY, 0, &type, sizeof(type)); +} + +// 推送文件下载成功通知到UI +void push_download_success_notification(int type) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[SCREEN_IMAGE_DOWNLOAD_SUCCESS]"); - SendMsgToUIService(HAND_SCREEN_IMAGE_DOWNLOAD_SUCCESS_NOTIFY, 0, NULL, 0); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_SUCCESS] type=%d", type); + SendMsgToUIService(HAND_DOWNLOAD_SUCCESS_NOTIFY, 0, &type, sizeof(type)); } #ifdef __cplusplus diff --git a/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h b/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h index 8bfe15e5d..2e422e01b 100644 --- a/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h +++ b/code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h @@ -57,6 +57,8 @@ void push_task_reminder_notification(const char *scheduleName); // 内存管理相关C接口 const char* get_system_memory_info(void); uint64_t get_folder_size(const char *folder_path); +//获取能否下载文件 +int can_download_file(const char *path, uint64_t downloadSize); //推送角色(配置更改)/切换通知 void push_character_config_change_notification( @@ -84,9 +86,14 @@ bool switch_expression_video(const char *video_path); void push_api_error_notification(const char *message); //通知ui绑定和解绑 void push_bind_and_unbind_notification(int is_bind); -// 推送屏保下载成功通知到UI -void push_screen_image_download_success_notification(void); - +enum { + DOWNLOAD_FILE_TYPE_SCREEN_IMAGE = 0,//屏保下载 + DOWNLOAD_FILE_TYPE_EMOJI = 1, //表情下载 +}; +// 通知ui需要下载文件了需要切换slice +void push_download_file_notification(int type); +// 推送文件下载成功通知到UI +void push_download_success_notification(int type); #ifdef __cplusplus } #endif