增加下载状态上报与取消下载 2944/1 2944/head 2945/target/1 2946/target/1
authorxue <2144439972@qq.com>
Thu, 18 Dec 2025 10:08:24 +0000 (18:08 +0800)
committerxue <2144439972@qq.com>
Thu, 18 Dec 2025 10:08:24 +0000 (18:08 +0800)
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_web_ack.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c

index e1c87d7..5ddc9ee 100644 (file)
@@ -928,6 +928,24 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         }
         break;
     }
+    case WS_CMD_EMOJI_DOWNLOAD_STATUS_REPORT_ACK:
+    {
+        printf("[WS] EmojiDownloadStatusReportAck:表情包下载状态上报应答\n");
+        if (json_str)
+        {
+            ln_parse_emoji_download_status_report_ack(json_str, (int)strlen(json_str));
+        }
+        break;
+    }
+    case WS_CMD_CANCEL_DOWNLOAD_EMOJI:
+    {
+        printf("[WS] CancelDownloadEmoji:取消下载表情\n");
+        if (json_str)
+        {
+            ln_parse_cancel_download_emoji(json_str, (int)strlen(json_str));
+        }
+        break;
+    }
     case WS_CMD_DEVICE_UPGRADE:
     {
         printf("[WS] DeviceUpgrade:设备升级\n");
index 7d18a0b..89ed82a 100644 (file)
@@ -400,6 +400,16 @@ int ln_ws_send_schedule_reminder_ack(int schedule_id, bool success, const char *
 int ln_ws_send_schedule_reminder_config_ack(int schedule_id, bool success, const char *msg);
 int ln_ws_send_delete_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg);
 int ln_ws_send_download_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg);
+/* 发送表情包下载状态上报 */
+int ln_ws_send_emoji_download_status_report(const char *character_id, const char *eyesColor, const char *eyesShape, 
+                                             const char *status, int progress, const char *message);
+/* 解析表情包下载状态上报应答 */
+void ln_parse_emoji_download_status_report_ack(const char *json_str, int json_len);
+/* 解析取消下载表情命令 */
+void ln_parse_cancel_download_emoji(const char *json_str, int json_len);
+/* 发送取消下载表情应答 */
+int ln_ws_send_cancel_download_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, 
+                                           bool success, const char *message);
 int ln_ws_send_device_upgrade_ack(const char *update_id, const char *target_version, bool success, const char *msg);
 int ln_ws_send_bluetooth_connect_ack(bool success, const char *msg);
 int ln_ws_send_bluetooth_unbind_ack(const char *bluetooth_address, const char *bluetooth_name, bool success, const char *msg);
@@ -492,6 +502,10 @@ typedef enum {
     WS_CMD_BLUETOOTH_CONNECT,        /* 蓝牙连接(BluetoothConnect) */
     WS_CMD_BLUETOOTH_UNBIND,         /* 蓝牙解绑(BluetoothUnbind) */
     WS_CMD_BLUETOOTH_STATUS_REPORT_ACK, /* 蓝牙状态上报应答(BluetoothStatusReportAck) */
+    WS_CMD_EMOJI_DOWNLOAD_STATUS_REPORT, /* 表情包下载状态上报(EmojiDownloadStatusReport) - 发送 */
+    WS_CMD_EMOJI_DOWNLOAD_STATUS_REPORT_ACK, /* 表情包下载状态上报应答(EmojiDownloadStatusReportAck) - 接收 */
+    WS_CMD_CANCEL_DOWNLOAD_EMOJI, /* 取消下载表情(CancelDownloadEmoji) */
+    WS_CMD_CANCEL_DOWNLOAD_EMOJI_ACK, /* 取消下载表情应答(CancelDownloadEmojiAck) - 发送 */
     WS_CMD_MAX                       /* 最大命令 */
 } ws_command_t;
 
index 686efb9..2db8b57 100644 (file)
@@ -35,6 +35,7 @@ typedef struct
 
 /* 全局变量 */
 EmojiPackage g_emoji_package = {0};
+static volatile int g_emoji_download_cancelled = 0; /* 取消下载标志 */
 /* ========== ETA 粗略版辅助函数 ========== */
 /* 前置声明,便于在本节工具函数中调用 */
 static int ln_emoji_is_cached(const EmojiPackage *pkg, const EmotionEmoji *emoji);
@@ -432,6 +433,13 @@ static void ln_emoji_download(void *arg)
         return;
     }
 
+    // 重置取消标志
+    g_emoji_download_cancelled = 0;
+
+    // 上报下载开始状态
+    ln_ws_send_emoji_download_status_report(pkg->characterId, pkg->eyesColor, pkg->eyesShape, 
+                                             "downloading", 0, "开始下载表情包");
+
     int all_success = 1;
     int downloaded_count = 0; /* 包含已缓存与成功下载的 */
     int failed_count = 0;
@@ -460,6 +468,9 @@ static void ln_emoji_download(void *arg)
             ln_safe_strcpy(mail.status, sizeof(mail.status), "download_fail");
             ln_safe_strcpy(mail.description, sizeof(mail.description), "没有足够的空间,跳过下载");
             do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_EMOJI_REPORT, (char *)&mail, (uint32_t)sizeof(mail));
+            // 上报下载失败状态
+            ln_ws_send_emoji_download_status_report(g_emoji_package.characterId, g_emoji_package.eyesColor, g_emoji_package.eyesShape, 
+                                                     "download_fail", -1, "没有足够的空间,跳过下载");
             push_download_fail_notification(DOWNLOAD_FILE_TYPE_EMOJI);
             ln_free_emoji_list();
             return;
@@ -496,6 +507,14 @@ static void ln_emoji_download(void *arg)
     // 遍历下载所有表情
     for (int i = 0; i < pkg->emojiCount; i++)
     {
+        // 检查是否取消下载
+        if (g_emoji_download_cancelled)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 检测到取消下载标志,停止下载");
+            all_success = 0;
+            break;
+        }
+
         // 跳过已缓存的文件
         if (ln_emoji_is_cached(pkg, &pkg->emojis[i]))
         {
@@ -522,11 +541,32 @@ static void ln_emoji_download(void *arg)
                 uapi_create_folder(dir_buf);
             }
         }
+        // 再次检查是否取消下载(在下载前)
+        if (g_emoji_download_cancelled)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 检测到取消下载标志,停止下载");
+            all_success = 0;
+            break;
+        }
+
         if (uapi_ln_download_file_resume_with_retry(pkg->emojis[i].emojiUrl, save_path, 10) != ERRCODE_SUCC)
         {
+            // 检查是否因为取消而失败
+            if (g_emoji_download_cancelled)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 下载被取消");
+                all_success = 0;
+                break;
+            }
+
             all_success = 0;
             failed_count++;
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 下载失败", pkg->emojis[i].emotion);
+            // 上报下载失败状态
+            char fail_msg[128];
+            snprintf(fail_msg, sizeof(fail_msg), "表情 %s 下载失败", pkg->emojis[i].emotion);
+            ln_ws_send_emoji_download_status_report(pkg->characterId, pkg->eyesColor, pkg->eyesShape, 
+                                                     "download_fail", -1, fail_msg);
             /* 单个文件三次重试仍失败,终止后续下载并尽快上报失败 */
             break;
         }
@@ -537,6 +577,12 @@ static void ln_emoji_download(void *arg)
             int progress = (int)(((double)downloaded_count / pkg->emojiCount) * 100);
             push_download_progress_notification(progress);
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s 下载完成", pkg->emojis[i].emotion);
+            
+            // 每次进度更新都同步发送协议给服务器更新进度
+            char progress_msg[64];
+            snprintf(progress_msg, sizeof(progress_msg), "下载进度%d%%", progress);
+            ln_ws_send_emoji_download_status_report(pkg->characterId, pkg->eyesColor, pkg->eyesShape, 
+                                                     "downloading", progress, progress_msg);
 
             /* 粗略版 ETA(平滑版):在单个文件完成后估算一次 */
             if (total_bytes_all > 0)
@@ -643,17 +689,35 @@ static void ln_emoji_download(void *arg)
     /* 下载完释放本次表情包占用的内存 */
     ln_free_emoji_list();
 
+    /* 检查是否因为取消而结束 */
+    if (g_emoji_download_cancelled)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 下载已取消");
+        /* 通知ui下载失败 */
+        push_download_fail_notification(DOWNLOAD_FILE_TYPE_EMOJI);
+        // 上报取消状态
+        ln_ws_send_emoji_download_status_report(mail.characterId, mail.eyesColor, mail.eyesShape, 
+                                                 "cancelled", -1, "表情包下载已取消");
+        // 清理已下载的部分文件(可选)
+        // 这里可以选择清理部分下载的文件,或者保留以便断点续传
+    }
     /* 持久化:仅在整个表情组下载成功时记录该表情组 */
-    if (all_success)
+    else if (all_success)
     {
         /* 通知ui下载成功 */
         push_download_success_notification(DOWNLOAD_FILE_TYPE_EMOJI);
         ln_persist_add_emoji_group(mail.characterId, mail.eyesColor, mail.eyesShape);
+        // 上报下载成功状态
+        ln_ws_send_emoji_download_status_report(mail.characterId, mail.eyesColor, mail.eyesShape, 
+                                                 "download_success", 100, "表情包下载成功");
     }
     else
     {
         /* 通知ui下载失败 */
         push_download_fail_notification(DOWNLOAD_FILE_TYPE_EMOJI);
+        // 上报下载失败状态(如果之前没有上报过)
+        ln_ws_send_emoji_download_status_report(mail.characterId, mail.eyesColor, mail.eyesShape, 
+                                                 "download_fail", -1, "表情包下载失败");
     }
 }
 
@@ -661,6 +725,8 @@ static void ln_emoji_download(void *arg)
 void ln_start_emoji_download(void)
 {
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 启动表情下载任务");
+    // 重置取消标志
+    g_emoji_download_cancelled = 0;
     uapi_ln_set_file_download_type(LN_FILE_DOWNLOAD_TYPE_EMOJI);
     if (g_emoji_package.emojiCount <= 0 || !g_emoji_package.emojis)
     {
@@ -842,7 +908,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len)
     if(uapi_ln_get_file_download_type() == LN_FILE_DOWNLOAD_TYPE_NONE && uapi_ln_is_file_downloading() == 0)
     {
         push_download_file_notification(DOWNLOAD_FILE_TYPE_EMOJI);
-        ln_ws_send_download_emoji_ack(g_emoji_package.characterId, g_emoji_package.eyesColor, g_emoji_package.eyesShape, true, "ä¸\8b载表æ\83\85");
+        ln_ws_send_download_emoji_ack(g_emoji_package.characterId, g_emoji_package.eyesColor, g_emoji_package.eyesShape, true, "å¼\80å§\8bä¸\8b载表æ\83\85å\8c\85");
     }
     else
     {
@@ -988,10 +1054,16 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len)
     if (ret == 0)
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] cached files in %s deleted", del_dir);
+        // 删除成功,发送 delete_success 状态上报
+        ln_ws_send_emoji_download_status_report(del_characterId, del_eyesColor, del_eyesShape, 
+                                                 "delete_success", -1, "表情包删除成功");
     }
     else
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] failed to delete cached files in %s", del_dir);
+        // 删除失败,发送 delete_fail 状态上报
+        ln_ws_send_emoji_download_status_report(del_characterId, del_eyesColor, del_eyesShape, 
+                                                 "delete_fail", -1, "表情包删除失败");
     }
 
     // [WEARABLE E/] [DELETE_EMOJI] parsed successfully:
@@ -1404,4 +1476,164 @@ void ln_emoji_report_all(void)
     if (groups)
         free(groups);
     cJSON_Delete(root);
+}
+
+/* 解析表情包下载状态上报应答 EmojiDownloadStatusReportAck */
+void ln_parse_emoji_download_status_report_ack(const char *json_str, int json_len)
+{
+    if (!json_str || json_len <= 0)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_STATUS_ACK] Invalid JSON string or length\n");
+        return;
+    }
+
+    cJSON *root = cJSON_Parse(json_str);
+    if (!root)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_STATUS_ACK] Failed to parse JSON\n");
+        return;
+    }
+
+    cJSON *data_obj = cJSON_GetObjectItem(root, "data");
+    if (!data_obj || !cJSON_IsObject(data_obj))
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_STATUS_ACK] Missing or invalid data object\n");
+        cJSON_Delete(root);
+        return;
+    }
+
+    // 解析data字段
+    cJSON *characterId = cJSON_GetObjectItem(data_obj, "characterId");
+    cJSON *eyesColor = cJSON_GetObjectItem(data_obj, "eyesColor");
+    cJSON *eyesShape = cJSON_GetObjectItem(data_obj, "eyesShape");
+    cJSON *success = cJSON_GetObjectItem(data_obj, "success");
+    cJSON *message = cJSON_GetObjectItem(data_obj, "message");
+
+    const char *char_id = characterId && cJSON_IsString(characterId) ? characterId->valuestring : "";
+    const char *ec = eyesColor && cJSON_IsString(eyesColor) ? eyesColor->valuestring : "";
+    const char *es = eyesShape && cJSON_IsString(eyesShape) ? eyesShape->valuestring : "";
+    bool success_flag = success && cJSON_IsBool(success) ? cJSON_IsTrue(success) : false;
+    const char *msg = message && cJSON_IsString(message) ? message->valuestring : "";
+
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_STATUS_ACK] Received EmojiDownloadStatusReportAck: characterId=%s, eyesColor=%s, eyesShape=%s, success=%d, message=%s\n",
+                  char_id, ec, es, success_flag, msg);
+
+    // 如果处理失败,可以在这里添加重试逻辑
+    if (!success_flag)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_STATUS_ACK] Server failed to process status report: %s\n", msg);
+    }
+
+    cJSON_Delete(root);
+}
+
+/* 解析取消下载表情命令 CancelDownloadEmoji */
+void ln_parse_cancel_download_emoji(const char *json_str, int json_len)
+{
+    if (!json_str || json_len <= 0)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] Invalid JSON string or length\n");
+        return;
+    }
+
+    // 复制并终止字符串
+    char *text = (char *)malloc((size_t)json_len + 1);
+    if (!text)
+        return;
+    memcpy(text, json_str, (size_t)json_len);
+    text[json_len] = '\0';
+
+    // 解析JSON根对象
+    cJSON *root = cJSON_Parse(text);
+    if (!root)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] json parse failed");
+        free(text);
+        return;
+    }
+
+    // 检查错误码
+    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+    if (errorCode && !cJSON_IsNull(errorCode))
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] server error: %s",
+                      cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 获取data对象
+    cJSON *data = cJSON_GetObjectItem(root, "data");
+    if (!data || !cJSON_IsObject(data))
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] no data object");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+
+    // 解析字段
+    cJSON *characterId = cJSON_GetObjectItem(data, "characterId");
+    cJSON *eyesColor = cJSON_GetObjectItem(data, "eyesColor");
+    cJSON *eyesShape = cJSON_GetObjectItem(data, "eyesShape");
+
+    char cancel_characterId[64] = {0};
+    char cancel_eyesColor[32] = {0};
+    char cancel_eyesShape[32] = {0};
+
+    ln_safe_strcpy(cancel_characterId, sizeof(cancel_characterId),
+                   (characterId && cJSON_IsString(characterId)) ? characterId->valuestring : "");
+
+    ln_safe_strcpy(cancel_eyesColor, sizeof(cancel_eyesColor),
+                   (eyesColor && cJSON_IsString(eyesColor)) ? eyesColor->valuestring : "");
+
+    ln_safe_strcpy(cancel_eyesShape, sizeof(cancel_eyesShape),
+                   (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : "");
+
+    // 打印解析结果
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] parsed successfully:");
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  characterId: %s", cancel_characterId);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  eyesColor: %s", cancel_eyesColor);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  eyesShape: %s", cancel_eyesShape);
+
+    // 检查是否正在下载表情
+    if (uapi_ln_get_file_download_type() == LN_FILE_DOWNLOAD_TYPE_EMOJI && uapi_ln_is_file_downloading() == 1)
+    {
+        // 检查是否匹配当前下载的表情包
+        if (g_emoji_package.characterId && g_emoji_package.eyesColor && g_emoji_package.eyesShape &&
+            strcmp(cancel_characterId, g_emoji_package.characterId) == 0 &&
+            strcmp(cancel_eyesColor, g_emoji_package.eyesColor) == 0 &&
+            strcmp(cancel_eyesShape, g_emoji_package.eyesShape) == 0)
+        {
+            // 设置取消标志
+            g_emoji_download_cancelled = 1;
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] 设置取消下载标志,停止下载");
+            
+            // 发送取消下载应答
+            ln_ws_send_cancel_download_emoji_ack(cancel_characterId, cancel_eyesColor, cancel_eyesShape, 
+                                                  true, "取消下载成功");
+            
+            // 发送取消状态上报
+            ln_ws_send_emoji_download_status_report(cancel_characterId, cancel_eyesColor, cancel_eyesShape, 
+                                                     "cancelled", -1, "表情包下载已取消");
+        }
+        else
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] 当前下载的表情包不匹配,无法取消");
+            // 发送取消下载应答(失败)
+            ln_ws_send_cancel_download_emoji_ack(cancel_characterId, cancel_eyesColor, cancel_eyesShape, 
+                                                  false, "当前下载的表情包不匹配");
+        }
+    }
+    else
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[CANCEL_DOWNLOAD_EMOJI] 当前没有正在下载的表情包");
+        // 发送取消下载应答(失败)
+        ln_ws_send_cancel_download_emoji_ack(cancel_characterId, cancel_eyesColor, cancel_eyesShape, 
+                                              false, "当前没有正在下载的表情包");
+    }
+
+    cJSON_Delete(root);
+    free(text);
 }
\ No newline at end of file
index 4b88ff4..2a8e0da 100644 (file)
@@ -666,4 +666,118 @@ int ln_ws_send_bluetooth_unbind_ack(const char *bluetooth_address, const char *b
     cJSON_free(json_string);
     cJSON_Delete(json);
     return ret;
+}
+
+/* 发送表情包下载状态上报 EmojiDownloadStatusReport */
+int ln_ws_send_emoji_download_status_report(const char *character_id, const char *eyesColor, const char *eyesShape, 
+                                             const char *status, int progress, const char *message)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send EmojiDownloadStatusReport, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[128];
+    // 使用时间戳和计数器生成唯一消息ID
+    static uint32_t emoji_status_counter = 0;
+    emoji_status_counter++;
+    snprintf(message_id, sizeof(message_id), "emoji_status_%u_%u", timestamp, emoji_status_counter);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "EmojiDownloadStatusReport");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", character_id ? character_id : "");
+    cJSON_AddStringToObject(data, "eyesColor", eyesColor ? eyesColor : "");
+    cJSON_AddStringToObject(data, "eyesShape", eyesShape ? eyesShape : "");
+    cJSON_AddStringToObject(data, "status", status ? status : "");
+    if (progress >= 0 && progress <= 100)
+    {
+        cJSON_AddNumberToObject(data, "progress", progress);
+    }
+    cJSON_AddStringToObject(data, "message", message ? message : "");
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent EmojiDownloadStatusReport: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送取消下载表情应答 CancelDownloadEmojiAck */
+int ln_ws_send_cancel_download_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, 
+                                          bool success, const char *message)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send CancelDownloadEmojiAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[128];
+    // 使用时间戳和计数器生成唯一消息ID
+    static uint32_t cancel_emoji_ack_counter = 0;
+    cancel_emoji_ack_counter++;
+    snprintf(message_id, sizeof(message_id), "ack_cancel_download_emoji_%u_%u", timestamp, cancel_emoji_ack_counter);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "CancelDownloadEmojiAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", character_id ? character_id : "");
+    cJSON_AddStringToObject(data, "eyesColor", eyesColor ? eyesColor : "");
+    cJSON_AddStringToObject(data, "eyesShape", eyesShape ? eyesShape : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", message ? message : (success ? "取消下载成功" : "取消下载失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent CancelDownloadEmojiAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
 }
\ No newline at end of file
index c727b94..10cbb75 100644 (file)
@@ -1909,6 +1909,14 @@ static ws_command_t ln_ws_parse_command_string(const char *command_str)
         return WS_CMD_BLUETOOTH_UNBIND;
     } else if (strcmp(command_str, "BluetoothStatusReportAck") == 0) {
         return WS_CMD_BLUETOOTH_STATUS_REPORT_ACK;
+    } else if (strcmp(command_str, "EmojiDownloadStatusReport") == 0) {
+        return WS_CMD_EMOJI_DOWNLOAD_STATUS_REPORT;
+    } else if (strcmp(command_str, "EmojiDownloadStatusReportAck") == 0) {
+        return WS_CMD_EMOJI_DOWNLOAD_STATUS_REPORT_ACK;
+    } else if (strcmp(command_str, "CancelDownloadEmoji") == 0) {
+        return WS_CMD_CANCEL_DOWNLOAD_EMOJI;
+    } else if (strcmp(command_str, "CancelDownloadEmojiAck") == 0) {
+        return WS_CMD_CANCEL_DOWNLOAD_EMOJI_ACK;
     } else {
         return WS_CMD_UNKNOWN;
     }