From bd9bcf9fa84d1c78136d361db794c7f13501005b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Sat, 17 Jan 2026 10:55:34 +0800 Subject: [PATCH] =?utf8?q?=E6=81=A2=E5=A4=8D=E9=83=A8=E5=88=86=E6=97=A5?= =?utf8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../thunderbird/src/ThunderBirdModel.cpp | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp index 708d447fe..85fa7596d 100644 --- a/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp +++ b/code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp @@ -86,9 +86,6 @@ extern "C" { #define LOW_FREQUENCE 18 //最高视频帧率 #define HIGH_FREQUENCE 30 - -// uapi_get_py_ver() 函数声明已在 cat1_pub_api.h 中 - namespace OHOS { enum OTA_STATUS @@ -2779,38 +2776,60 @@ extern "C" { return true; // 异步调用,返回 true 表示调用已提交 } + // 切换表情 bool ThunderBirdModel::SwitchExpressionVideo(const char* videoPath) { + // 参数验证 if (videoPath == nullptr) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: videoPath is null"); return false; } + // 检查文件是否存在(宽松检查) if (access(videoPath, F_OK) != 0) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file does not exist: %s", videoPath); return false; } + // 尝试检查文件大小(非强制) struct stat fileStat; if (stat(videoPath, &fileStat) == 0) { if (fileStat.st_size == 0) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file is empty: %s", videoPath); return false; } + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: file size: %ld bytes", fileStat.st_size); + } else { + WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: cannot get file stat for %s, proceeding anyway", videoPath); } + // 预处理文件路径,确保realpath能够成功 std::string normalizedPath = videoPath; + + // 尝试使用realpath规范化路径 char resolvedPath[PATH_MAX]; if (realpath(videoPath, resolvedPath) != nullptr) { normalizedPath = std::string(resolvedPath); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: normalized path: %s", normalizedPath.c_str()); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: realpath failed for %s, using original path", videoPath); + // 如果realpath失败,使用原始路径 + normalizedPath = std::string(videoPath); } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: switching to video: %s", normalizedPath.c_str()); + + // 检查 ThunderBirdMainView 是否已初始化 + // 如果未初始化,直接返回,避免在启动时出现问题 if (ThunderBirdMainView::GetInstance() == nullptr) { WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView not initialized yet, skipping switch"); return false; } + // 如果正在切换视频,等待完成(最多等待2秒) + // 这样可以避免快速进入/退出对话模式时导致的表情切换冲突 if (ThunderBirdMainView::IsSwitchingVideo()) { WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch in progress, waiting for completion..."); @@ -2819,27 +2838,42 @@ extern "C" { auto pathPtr = std::make_shared(normalizedPath); GraphicService::GetInstance()->PostGraphicEvent( [pathPtr]() { + // 等待之前的切换完成 ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance(); if (mainView != nullptr) { ThunderBirdMainView::WaitForVideoSwitchComplete(2000); + // 再次检查是否还在切换(防止超时后仍在切换) if (!ThunderBirdMainView::IsSwitchingVideo()) { + // 再次检查对象有效性,防止在执行过程中被销毁 ThunderBirdMainView* view = ThunderBirdMainView::GetInstance(); if (view != nullptr && pathPtr != nullptr) { view->SwitchVideo(pathPtr->c_str()); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Object invalidated during execution"); } + } else { + WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch still in progress after wait, skipping this switch"); } + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null"); } }); } else { + // 通过图形服务调用 ThunderBirdMainView 的 SwitchVideo 函数 + // 注意:PostGraphicEvent 是异步的,这里直接返回 true 表示调用已提交 + // 使用 shared_ptr 确保字符串生命周期,避免 lambda 执行时对象已销毁 auto pathPtr = std::make_shared(normalizedPath); GraphicService::GetInstance()->PostGraphicEvent( [pathPtr]() { ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance(); if (mainView != nullptr && pathPtr != nullptr) { mainView->SwitchVideo(pathPtr->c_str()); + } else { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null or path invalid"); } }); } + return true; // 异步调用,返回 true 表示调用已提交 } @@ -2985,8 +3019,8 @@ extern "C" { { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd"); // 清除哄睡模式激活标志位(防止后续SleepModeStart被拒绝) - uapi_set_sleep_mode_active(false); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd: sleep mode flag cleared"); + // uapi_set_sleep_mode_active(false); + // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd: sleep mode flag cleared"); // 停止故事模式超时定时器 StopStoryModeTimeoutTimer(); // 停止故事模式音频播放超时定时器 @@ -3038,8 +3072,8 @@ extern "C" { { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd"); // 清除哄睡模式激活标志位(防止后续SleepModeStart被拒绝) - uapi_set_sleep_mode_active(false); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd_BlueView: sleep mode flag cleared"); + // uapi_set_sleep_mode_active(false); + // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleSleepModeEnd_BlueView: sleep mode flag cleared"); // 停止故事模式超时定时器 StopStoryModeTimeoutTimer(); // 重置故事模式finished标志 -- 2.17.1