修复屏保bug
authorxue <2144439972@qq.com>
Fri, 26 Dec 2025 09:24:26 +0000 (17:24 +0800)
committerxue <2144439972@qq.com>
Fri, 26 Dec 2025 09:24:26 +0000 (17:24 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdMainView.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdModel.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdMainView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdReminderView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/uiservice/src/ui_service.cpp
code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c
code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.cpp
code/sdk/zhihui/leiniao/ln_api_cpp/ln_api_interface.h

index 8dd6f00..ba90700 100644 (file)
@@ -102,6 +102,8 @@ namespace OHOS
         bool CloseScreenImageModel(void);
         // 关机前关闭视频与相关资源
         void CloseVideo();
+        // 复杂操作函数(在新线程中执行)
+        static void ComplexOperationThread(bool isNewDialogue);
         // 打开遮罩(部分视图需要)
         void OpenBackGround(void);
         // 刷新黄色背景
index bcc0033..e0cba1a 100644 (file)
@@ -169,7 +169,7 @@ namespace OHOS
         //存储表情和发型信息函数
         std::string ReadlocalExpression();
         std::string ReadlocalHair();
-        bool ReadlocalScreenImage();
+        int ReadlocalScreenImage();
 
         // 对话状态相关函数
         int GetConversationStatus();
@@ -190,10 +190,11 @@ namespace OHOS
         void HandleTaskReminder(const char* scheduleName);
         
         // 角色配置更改处理函数
-        void HandleCharacterConfigChange(const char* characterId, const char* characterName, 
-                                        const char* eyesShape, const char* hairColor, 
-                                        const char* eyesColor, const char* hairStyle, 
-                                        int screenImageAsEmoji);
+        void HandleCharacterConfigChange(const char* characterId, const char* characterName,
+                                         const char* eyesShape, const char* hairColor,
+                                         const char* eyesColor, const char* hairStyle,
+                                         int hasScreenImage, 
+                                         int screenImageAsEmoji);
         
         // 聊天体力更改处理函数
         void HandleChatStaminaChange(int chatLeft, const char* chatDesc, int flowLeft, 
@@ -400,6 +401,7 @@ namespace OHOS
         std::string eyesColor_;
         std::string hairStyle_;
         std::string screenImage_;
+        int hasScreenImage_{0};
         bool screenImageAsEmoji_{false};
 
         // 上次角色配置
@@ -408,6 +410,7 @@ namespace OHOS
         std::string last_eyesColor_;
         std::string last_hairStyle_;
         std::string last_screenImage_;
+        int last_hasScreenImage_{0};
         bool last_screenImageAsEmoji_{false};
 
         // 对话状态显示相关变量
@@ -426,6 +429,10 @@ namespace OHOS
         
         // 对话模式相关标志
         bool m_dialogueModeFinished = false; // 对话模式是否已finished(收到finished=true)
+        
+        // 屏保关闭标志(用于记录在进入对话/哄睡时是否关闭了屏保)
+        bool m_screenImageClosedForDialogue = false; // 进入对话模式时是否关闭了屏保
+        bool m_screenImageClosedForLullaby = false; // 进入哄睡模式时是否关闭了屏保
 
     };
 }
index d4b2869..3775b5c 100644 (file)
@@ -28,6 +28,9 @@
 #include "battery_hal.h"
 #include "battery_service.h"
 #include "custom_runtime.h"
+#include "cmsis_os2.h"
+#include "thread_init.h"
+#include "soc_osal.h"
 #include <service/graphic_service.h>
 #include "ln_api.h"
 #include "common/screen.h"
@@ -37,6 +40,95 @@ namespace OHOS
 {
     static constexpr int16_t VIDEO_WIDTH = 360;
     static constexpr int16_t VIDEO_HEIGHT = 360;
+    
+    // 复杂操作线程配置和消息队列
+    static app_task_definition_t g_complex_operation_taskcfg = {0};
+    static unsigned long g_complex_operation_queue = 0xFFFFFFFF;
+    
+    // 消息结构体
+    typedef struct {
+        bool isNewDialogue;
+    } ComplexOperationMsg_t;
+    
+    // 创建消息队列
+    static void create_complex_operation_queue(void)
+    {
+        if (osal_msg_queue_create("complex_operation_queue", 32, &g_complex_operation_queue,
+                                  0, sizeof(ComplexOperationMsg_t)) != ERRCODE_SUCC)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "create_complex_operation_queue: Failed to create queue");
+        }
+        else
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "create_complex_operation_queue: Queue created successfully");
+        }
+    }
+    
+    // 复杂操作线程函数(在线程中循环等待消息并执行)
+    static void complex_operation_task(void *arg)
+    {
+        (void)arg;
+        errcode_t ret;
+        ComplexOperationMsg_t msg = {0};
+        uint32_t msgsize = sizeof(ComplexOperationMsg_t);
+        
+        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "complex_operation_task: Thread started, waiting for messages");
+        
+        while (1)
+        {
+            // 每轮重置 msgsize,兼容底层可能改写该值的实现
+            msgsize = sizeof(ComplexOperationMsg_t);
+            ret = osal_msg_queue_read_copy(g_complex_operation_queue, (void *)&msg, &msgsize,
+                                          OSAL_MSGQ_WAIT_FOREVER);
+            if (ret != OSAL_SUCCESS)
+            {
+                WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "complex_operation_task: Failed to read queue, ret=%d", ret);
+                LOS_Msleep(100);
+                continue;
+            }
+            
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "complex_operation_task: Received message, isNewDialogue=%d", msg.isNewDialogue);
+            
+            // 在线程中执行复杂操作
+            if(msg.isNewDialogue)
+            {
+                AI_ForceInterrupt();
+                ln_ws_end_audio_chat();
+                ln_ws_send_voice_chat_interrupt("新对话开始");
+            }
+            else
+            {
+                AI_ForceInterrupt();
+                ln_ws_end_audio_chat();
+                ln_ws_send_voice_chat_interrupt("退出对话");
+            }
+        }
+    }
+    
+    // 复杂操作函数(向消息队列发送消息,在线程中执行)
+    void ThunderBirdMainView::ComplexOperationThread(bool isNewDialogue)
+    {
+        if (g_complex_operation_queue == 0xFFFFFFFF)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ComplexOperationThread: Message queue not initialized");
+            return;
+        }
+        
+        ComplexOperationMsg_t send_data = {0};
+        send_data.isNewDialogue = isNewDialogue;
+        
+        // 向消息队列发送消息
+        errcode_t ret = osal_msg_queue_write_copy(g_complex_operation_queue, (void *)&send_data,
+                                                  sizeof(ComplexOperationMsg_t), 0);
+        if (ret != ERRCODE_SUCC)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ComplexOperationThread: Failed to send message to queue, ret=%d", ret);
+        }
+        else
+        {
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ComplexOperationThread: Message sent to queue, isNewDialogue=%d", isNewDialogue);
+        }
+    }
     static constexpr int16_t STRIDE_ALIGNMENT_VALUE = 128;
     static constexpr int16_t JPEG_WIDTH_BYTE_ALIGNMENT = 128;
     static constexpr int16_t JPEG_HEIGHT_BYTE_ALIGNMENT = 16;
@@ -364,6 +456,26 @@ namespace OHOS
     }
     void ThunderBirdMainView::OnStart()//开机操作
     {
+        // 创建复杂操作线程(栈大小0x1000 = 4096字节)
+        if (g_complex_operation_taskcfg.task_handle == nullptr)
+        {
+            g_complex_operation_taskcfg.create_queue_handle = create_complex_operation_queue;
+            g_complex_operation_taskcfg.attr.name = "complex_operation_task";
+            g_complex_operation_taskcfg.attr.priority = osPriorityNormal;
+            g_complex_operation_taskcfg.attr.stack_size = 0x1000;  // 4096字节
+            g_complex_operation_taskcfg.func = complex_operation_task;
+            g_complex_operation_taskcfg.use_mem = USE_EXTEND_MEM;
+            
+            errcode_t ret = uapi_create_osThread_custom(&g_complex_operation_taskcfg);
+            if (ret != ERRCODE_SUCC)
+            {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::OnStart: Failed to create complex operation thread, ret=%d", ret);
+            }
+            else
+            {
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::OnStart: Complex operation thread created successfully");
+            }
+        }
 
         //下载文件被打断的恢复操作
         if(ThunderBirdModel::GetInstance()->GetDownloadFile() != -1)
@@ -423,7 +535,8 @@ namespace OHOS
             //backGroundView->SetVisible(false);
             ScrollView_->Add(backGroundView);
 
-            if(ThunderBirdModel::GetInstance()->ReadlocalScreenImage() == true)//开启屏保模式
+            int screenImageMode = ThunderBirdModel::GetInstance()->ReadlocalScreenImage();
+            if(screenImageMode == 1 || screenImageMode == 2)//开启屏保模式(1:屏保模式,2:屏保模式作为对话表情)
             {
                 printf("开启屏保模式\n");
                 OpenScreenImageModel();
index 08187ab..140a93a 100644 (file)
@@ -150,12 +150,14 @@ extern "C" {
          last_hairColor_ = hairColor_;
          last_eyesColor_ = eyesColor_;
          last_hairStyle_ = hairStyle_;
+         last_hasScreenImage_ = hasScreenImage_;
          last_screenImageAsEmoji_ = screenImageAsEmoji_;
 
          printf("  eyesShape_ = %s", eyesShape_.c_str());
          printf("  hairColor_ = %s", hairColor_.c_str());
          printf("  eyesColor_ = %s", eyesColor_.c_str());
          printf("  hairStyle_ = %s", hairStyle_.c_str());
+         printf("  hasScreenImage_ = %d", hasScreenImage_);
          printf("  screenImageAsEmoji_ = %d", screenImageAsEmoji_);
          
          // 初始化对话状态显示变量
@@ -1718,10 +1720,8 @@ extern "C" {
             {
                 if (init_falg == false) 
                 {
-                    //发送获取绑定用户ID,异步执行,避免阻塞UI线程
-                    GraphicService::GetInstance()->PostGraphicEvent([]() {
+                    //发送获取绑定用户ID
                     do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_USER_ID, NULL, 0);
-                    });
                     cat1_gettime();
                     if( ThunderBirdGuideView::GetInstance() != nullptr)
                     {
@@ -1903,10 +1903,9 @@ extern "C" {
                     else if (currentView == THUNDERBIRD_REMINDERVIEW && 
                              currentSubView == ThunderBirdReminderView::THUNDERBIRD_REMINDERVIEW_TASK_REMINDER) {
                         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "任务提醒界面超时,返回原任务");
-                        //设置提醒音量为0
-                        GraphicService::GetInstance()->PostGraphicEvent([]() {
+
                             ln_schedule_reminder_set_volume_zero();
-                        });
+                      
                         ThunderBirdModel::GetInstance()->HighFrequence();
                         ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_STATUS_SHOW);
                         //关闭语音初始化
@@ -2400,6 +2399,7 @@ extern "C" {
     void ThunderBirdModel::HandleCharacterConfigChange(const char* characterId, const char* characterName, 
                                                       const char* eyesShape, const char* hairColor, 
                                                       const char* eyesColor, const char* hairStyle, 
+                                                      int hasScreenImage,
                                                       int screenImageAsEmoji)
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange");
@@ -2409,6 +2409,7 @@ extern "C" {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  hairColor: %s", hairColor ? hairColor : "null");
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  eyesColor: %s", eyesColor ? eyesColor : "null");
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  hairStyle: %s", hairStyle ? hairStyle : "null");
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  hasScreenImage: %d", hasScreenImage);
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  screenImageAsEmoji: %d", screenImageAsEmoji);
         
         // 将传入的参数转换为std::string(处理nullptr和字符串比较)
@@ -2427,7 +2428,7 @@ extern "C" {
         // 比较传入的新值和上次保存的值(last_xxx_)
         if(newEyesShape == last_eyesShape_ && newHairColor == last_hairColor_ && 
            newEyesColor == last_eyesColor_ && newHairStyle == last_hairStyle_ && 
-           screenImageAsEmoji == last_screenImageAsEmoji_)
+           hasScreenImage == last_hasScreenImage_ && screenImageAsEmoji == last_screenImageAsEmoji_)
         {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange: 角色配置没有变化,不进行处理");
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  上次配置: eyesShape=%s, hairColor=%s, eyesColor=%s, hairStyle=%s, screenImageAsEmoji=%d",
@@ -2442,7 +2443,7 @@ extern "C" {
         // 检查是否是默认/空配置(calm-eyes, amber, warm-orange, curly-hair)
         if(newEyesShape == "calm-eyes" && newEyesColor == "amber" && 
            newHairColor == "orange" && newHairStyle == "curly-hair" && screenImageAsEmoji == false &&
-            last_eyesShape_.empty() && last_hairColor_.empty() && last_eyesColor_.empty() && last_hairStyle_.empty() && last_screenImageAsEmoji_ == false)
+            last_eyesShape_.empty() && last_hairColor_.empty() && last_eyesColor_.empty() && last_hairStyle_.empty() && last_hasScreenImage_ == false && last_screenImageAsEmoji_ == false)
         {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange: 角色配置为默认配置,不进行处理");
             // 更新last_xxx_为当前值,避免下次误判
@@ -2503,14 +2504,14 @@ extern "C" {
         eyesColor_ = newEyesColor;
         hairStyle_ = newHairStyle;
         screenImageAsEmoji_ = screenImageAsEmoji;
-        
+        hasScreenImage_ = hasScreenImage;
         //更新上次角色配置信息(在处理完成后更新,用于下次比较)
         last_eyesShape_ = newEyesShape;
         last_hairColor_ = newHairColor;
         last_eyesColor_ = newEyesColor;
         last_hairStyle_ = newHairStyle;
         last_screenImageAsEmoji_ = screenImageAsEmoji;
-        
+        last_hasScreenImage_ = hasScreenImage;
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleCharacterConfigChange: 角色配置已更新");
 
         // SaveCharacterConfig(characterId, characterName, eyesShape, hairColor, eyesColor, hairStyle, screenImageAsEmoji);
@@ -2536,9 +2537,18 @@ extern "C" {
         return "/user/res/hair/" + hairStyle_ + "/" + hairColor_ + ".bin";
     }
     //是否开启屏保模式
-    bool ThunderBirdModel::ReadlocalScreenImage()
+    int ThunderBirdModel::ReadlocalScreenImage()
     {
-        return screenImageAsEmoji_;
+        //0:关闭屏保模式 1:开启屏保模式 2:屏保模式作为对话表情
+        if(hasScreenImage_ == 0)
+        {
+            return 0;
+        }
+        else if(screenImageAsEmoji_ == true)
+        {
+            return 2;
+        }
+        return 1;
     }
     
     void ThunderBirdModel::HandleChatStaminaChange(int chatLeft, const char* chatDesc, int flowLeft, 
@@ -3434,6 +3444,20 @@ extern "C" {
         // 设置标志位,表示在对话模式中
         m_needGetTimelineExpression = true;
         
+        // 如果ReadlocalScreenImage() == 1(有屏保但不是作为对话表情),先关闭屏保
+        int screenImageMode = ReadlocalScreenImage();
+        if (screenImageMode == 1) {
+            // 有屏保但不是作为对话表情,需要先关闭屏保
+            ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+            if (mainView != nullptr && mainView->GetIsOpenScreenImageModel()) {
+                mainView->CloseScreenImageModel();
+                m_screenImageClosedForDialogue = true;
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 关闭屏保模式(ReadlocalScreenImage==1)");
+            }
+        } else {
+            m_screenImageClosedForDialogue = false;
+        }
+        
         // 等待视频切换完成,避免在视频切换过程中切换表情导致冲突
         if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::IsSwitchingVideo()) {
             WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 等待视频切换完成");
@@ -3458,16 +3482,39 @@ extern "C" {
             ln_bt_earphone_set_volume(m_volume);
         }
         
-        // 切换到眨眼表情(winking)
-        std::string winkingExpressionPath = "/user/res/video/CloseEyes/" + eyesShape_ + "/" + eyesColor_ + ".mp4";
-        
-        // 检查文件是否存在
-        if (access(winkingExpressionPath.c_str(), F_OK) == 0) {
-            // 切换到眨眼表情(但不更新m_currentExpression,因为退出时要恢复时间线表情)
-            SwitchExpressionVideo(winkingExpressionPath.c_str());
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 切换到眨眼表情: %s", winkingExpressionPath.c_str());
+        // 如果ReadlocalScreenImage() == 2(屏保作为对话表情),播放屏保图片
+        if (screenImageMode == 2) {
+            // 屏保作为对话表情,播放屏保图片
+            ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+            if (mainView != nullptr && access(LN_DEVICE_SCREEN_IMAGE_FILE, F_OK) == 0) {
+                // 暂停视频播放(如果正在播放)
+                if (mainView->videoPlay_ != nullptr && 
+                    mainView->videoPlay_->isEntered_ && mainView->videoPlay_->isPlayed_) {
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 暂停视频播放以显示屏保图片");
+                    mainView->videoPlay_->PauseVideoPlay();
+                }
+                // 屏保图片存在,切换到屏保图片
+                mainView->SwitchIconImage(LN_DEVICE_SCREEN_IMAGE_FILE);
+                // 设置iconView为可见状态
+                if (mainView->iconView != nullptr) {
+                    mainView->iconView->SetVisible(true);
+                }
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: screenImageMode==2,切换到屏保图片: %s", LN_DEVICE_SCREEN_IMAGE_FILE);
+            } else {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: screenImageMode==2,但屏保图片文件不存在: %s", LN_DEVICE_SCREEN_IMAGE_FILE);
+            }
         } else {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 眨眼表情文件不存在: %s", winkingExpressionPath.c_str());
+            // 正常情况,切换到眨眼表情(winking)
+            std::string winkingExpressionPath = "/user/res/video/CloseEyes/" + eyesShape_ + "/" + eyesColor_ + ".mp4";
+            
+            // 检查文件是否存在
+            if (access(winkingExpressionPath.c_str(), F_OK) == 0) {
+                // 切换到眨眼表情(但不更新m_currentExpression,因为退出时要恢复时间线表情)
+                SwitchExpressionVideo(winkingExpressionPath.c_str());
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 切换到眨眼表情: %s", winkingExpressionPath.c_str());
+            } else {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 眨眼表情文件不存在: %s", winkingExpressionPath.c_str());
+            }
         }
     }
     
@@ -3484,6 +3531,19 @@ extern "C" {
         // 重置对话模式finished标志
         m_dialogueModeFinished = false;
         
+        // 如果之前在进入对话时关闭了屏保,现在需要恢复屏保
+        if (m_screenImageClosedForDialogue) {
+            int screenImageMode = ReadlocalScreenImage();
+            if (screenImageMode == 1) {
+                // 有屏保但不是作为对话表情,恢复屏保
+                if (mainView != nullptr && !mainView->GetIsOpenScreenImageModel()) {
+                    mainView->OpenScreenImageModel();
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 恢复屏保模式(ReadlocalScreenImage==1)");
+                }
+            }
+            m_screenImageClosedForDialogue = false;
+        }
+        
         // 不在这里切换表情,标志位保持为1,在发呆中界面时获取时间线表情
         // m_needGetTimelineExpression 保持为 true,表示需要获取时间线表情
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 退出对话模式,标志位保持为true,将在发呆中界面获取时间线表情");
@@ -3497,6 +3557,21 @@ extern "C" {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterLullabyMode: 记录时间线表情: %s", m_currentExpression.c_str());
         // 设置标志位,表示在哄睡模式中
         m_needGetTimelineExpression = true;
+        
+        // 如果ReadlocalScreenImage() == 1(有屏保但不是作为对话表情),先关闭屏保
+        int screenImageMode = ReadlocalScreenImage();
+        if (screenImageMode == 1) {
+            // 有屏保但不是作为对话表情,需要先关闭屏保
+            ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+            if (mainView != nullptr && mainView->GetIsOpenScreenImageModel()) {
+                mainView->CloseScreenImageModel();
+                m_screenImageClosedForLullaby = true;
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterLullabyMode: 关闭屏保模式(ReadlocalScreenImage==1)");
+            }
+        } else {
+            m_screenImageClosedForLullaby = false;
+        }
+        
         //如果本来就是眨眼的表情直接返回
         if (m_currentExpression == "winking" || m_currentExpression.empty() == true) {
             return;
@@ -3529,8 +3604,22 @@ extern "C" {
     void ThunderBirdModel::OnExitLullabyMode()
     {   
         // 隐藏小绿点
-        if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::GetInstance()->listenIcon) {
-            ThunderBirdMainView::GetInstance()->listenIcon->SetVisible(false);
+        ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+        if (mainView != nullptr && mainView->listenIcon) {
+            mainView->listenIcon->SetVisible(false);
+        }
+        
+        // 如果之前在进入哄睡时关闭了屏保,现在需要恢复屏保
+        if (m_screenImageClosedForLullaby) {
+            int screenImageMode = ReadlocalScreenImage();
+            if (screenImageMode == 1) {
+                // 有屏保但不是作为对话表情,恢复屏保
+                if (mainView != nullptr && !mainView->GetIsOpenScreenImageModel()) {
+                    mainView->OpenScreenImageModel();
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 恢复屏保模式(ReadlocalScreenImage==1)");
+                }
+            }
+            m_screenImageClosedForLullaby = false;
         }
         
         // 不在这里切换表情,标志位保持为1,在发呆中界面时获取时间线表情
@@ -3565,9 +3654,17 @@ extern "C" {
             ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(m_currentStatusText.c_str());
         
         //切换表情
-        //不为屏保模式
+        //不为屏保模式(ReadlocalScreenImage() == 1 时,在发呆中界面也应该显示屏保,不切换表情)
         std::string expressionPath;
         std::string targetExpression = expression;
+        int screenImageMode = ReadlocalScreenImage();
+        // 如果ReadlocalScreenImage() == 1(有屏保但不是作为对话表情),在发呆中界面不切换表情,保持屏保显示
+        if(screenImageMode == 1 && currentView == THUNDERBIRD_DIALOGUEVIEW && currentSubView == ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_STATUS_SHOW)
+        {
+            // 有屏保但不是作为对话表情,在发呆中界面保持屏保显示,不切换表情
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SetCurrentExpressionAndStatus: ReadlocalScreenImage()==1,在发呆中界面保持屏保显示,不切换表情");
+            return;
+        }
         if(screenImageAsEmoji_ == false)
         {
             //获取当前角色配置
index 0838dca..0dbe31f 100644 (file)
@@ -6,6 +6,7 @@
  * @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/ThunderBird/src/ThunderBirdPresenter.cpp
  */
 #include "thunderbird/include/ThunderBirdPresenter.h"
+#include "thunderbird/include/ThunderBirdMainView.h"
 #include "thunderbird/include/ThunderBirdGuideView.h"
 #include "thunderbird/include/ThunderBirdLullabyView.h"
 #include "thunderbird/include/ThunderBirdDialogueView.h"
@@ -453,9 +454,7 @@ namespace OHOS
                 // WebSocket 未连接,不执行操作,避免状态混乱
                 return;
             }
-                AI_ForceInterrupt();
-                ln_ws_end_audio_chat();
-                ln_ws_send_voice_chat_interrupt("新对话开始");
+            ThunderBirdMainView::ComplexOperationThread(true);
             ThunderBirdDialogueView::GetInstance()->IsReconnect = true;
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始录音,跳转到聆听状态");
             // 开始录音
@@ -871,10 +870,9 @@ namespace OHOS
             {
                 //回原界面
                 ThunderBirdModel::GetInstance()->StopCountUpTimer(); // 手动跳转时关闭定时器
-                //设置提醒音量为0(异步执行,避免阻塞按键处理,特别是在连网状态下)
-                GraphicService::GetInstance()->PostGraphicEvent([]() {
+
                     ln_schedule_reminder_set_volume_zero();
-                });
+ 
                 ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_DIALOGUEVIEW, ThunderBirdDialogueView::THUNDERBIRD_DIALOGUEVIEW_STATUS_SHOW);
                 //关闭语音初始化
                 // AI_ForceInterrupt();
index a82e443..805faed 100644 (file)
@@ -448,12 +448,11 @@ namespace OHOS
         
         if (async) {
             // 异步执行,避免阻塞按键处理
-            GraphicService::GetInstance()->PostGraphicEvent([volumeToApply]() {
+
                 AudioManager::GetInstance().SetVolume(AUDIO_STREAM_VOICE_ASSISTANT, volumeToApply);
                 ln_bt_earphone_set_volume(volumeToApply);
                 // 更新Model中的音量值
                 ThunderBirdModel::GetInstance()->m_volume = volumeToApply;
-            });
         } else {
             // 同步执行
             AudioManager::GetInstance().SetVolume(AUDIO_STREAM_VOICE_ASSISTANT, volumeToApply);
index 9f22c2a..99210d4 100644 (file)
@@ -439,8 +439,8 @@ void HandTaskCharacterConfigNotify(Request *request)
         fields.push_back(field);
     }
     
-    if (fields.size() < 7) {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify: invalid payload format, expected 7 fields, got %zu", fields.size());
+    if (fields.size() < 8) {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify: invalid payload format, expected 8 fields, got %zu", fields.size());
         return;
     }
     
@@ -450,7 +450,8 @@ void HandTaskCharacterConfigNotify(Request *request)
     std::string hairColor = fields[3];
     std::string eyesColor = fields[4];
     std::string hairStyle = fields[5];
-    int screenImageAsEmoji = std::stoi(fields[6]);
+    int hasScreenImage = std::stoi(fields[6]);
+    int screenImageAsEmoji = std::stoi(fields[7]);
     
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify characterId = %s", characterId.c_str());
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify characterName = %s", characterName.c_str());
@@ -458,15 +459,16 @@ void HandTaskCharacterConfigNotify(Request *request)
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify hairColor = %s", hairColor.c_str());
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify eyesColor = %s", eyesColor.c_str());
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify hairStyle = %s", hairStyle.c_str());
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify hasScreenImage = %d", hasScreenImage);
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_UI_SERVICE, "HandTaskCharacterConfigNotify screenImageAsEmoji = %d", screenImageAsEmoji);
     
     // 通过图形服务调用 ThunderBirdModel 的处理函数
     GraphicService::GetInstance()->PostGraphicEvent(
-        [characterId, characterName, eyesShape, hairColor, eyesColor, hairStyle, screenImageAsEmoji]() {
+        [characterId, characterName, eyesShape, hairColor, eyesColor, hairStyle, hasScreenImage, screenImageAsEmoji]() {
             if (OHOS::ThunderBirdModel::GetInstance()) {
                 OHOS::ThunderBirdModel::GetInstance()->HandleCharacterConfigChange(
                     characterId.c_str(), characterName.c_str(), eyesShape.c_str(), 
-                    hairColor.c_str(), eyesColor.c_str(), hairStyle.c_str(), screenImageAsEmoji);
+                    hairColor.c_str(), eyesColor.c_str(), hairStyle.c_str(), hasScreenImage, screenImageAsEmoji);
             }
         });
 }
index c06bbea..9dceb04 100644 (file)
@@ -281,9 +281,27 @@ void ln_parse_character_config_startUp(const char *json_buf, int json_len)
     WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "  avatar_screen_image_as_emoji: %d\n", g_ln_character_config.avatar_screen_image_as_emoji);
 
     // 如果屏保图片不为空,则保存到本地
-    if (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0 && g_ln_character_config.avatar_screen_image_as_emoji == 1)
+    // 条件1:screenImageAsEmoji为真时,下载屏保(作为对话表情)
+    // 条件2:deviceScreen不为空时,下载屏保(屏保模式)
+    int need_download_screen_image = 0;
+    if (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0)
+    {
+        if (g_ln_character_config.avatar_screen_image_as_emoji == 1)
+        {
+            // screenImageAsEmoji为真,屏保作为对话表情
+            need_download_screen_image = 1;
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片不为空且screenImageAsEmoji为真,下载屏保图片(作为对话表情)");
+        }
+        else
+        {
+            // deviceScreen不为空,屏保模式
+            need_download_screen_image = 1;
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片不为空,下载屏保图片(屏保模式)");
+        }
+    }
+    
+    if (need_download_screen_image)
     {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片不为空,下载屏保图片");
         /* 解析阶段先拷贝URL,避免稍后清理结构体后URL丢失 */
         ln_set_pending_screen_image(g_ln_character_config.avatar_screen_image);
         if(uapi_ln_get_file_download_type() == LN_FILE_DOWNLOAD_TYPE_NONE && uapi_ln_is_file_downloading() == 0)
@@ -310,6 +328,7 @@ void ln_parse_character_config_startUp(const char *json_buf, int json_len)
                                               g_ln_character_config.avatar_hair_color,
                                               g_ln_character_config.avatar_eyes_color,
                                               g_ln_character_config.avatar_hair_style,
+                                              need_download_screen_image,
                                               g_ln_character_config.avatar_screen_image_as_emoji);
 
     cJSON_Delete(root);
@@ -442,7 +461,7 @@ void ln_parse_character_config(const char *json_buf, int json_len)
     printf("  avatar_screen_image_as_emoji: %d\n", g_ln_character_config.avatar_screen_image_as_emoji);
 
     // 如果屏保图片不为空,则保存到本地
-    if (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0 && g_ln_character_config.avatar_screen_image_as_emoji == 1)
+    if (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0)
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DEVICE_CHARACTER] 屏保图片不为空,下载屏保图片");
         /* 解析阶段先拷贝URL,避免稍后清理结构体后URL丢失 */
@@ -461,12 +480,15 @@ void ln_parse_character_config(const char *json_buf, int json_len)
     }
 
     /* 推送角色配置更改通知 */
+    // 判断是否有屏保:avatar_screen_image不为空
+    int has_screen_image = (g_ln_character_config.avatar_screen_image && strlen(g_ln_character_config.avatar_screen_image) > 0) ? 1 : 0;
     push_character_config_change_notification(g_ln_character_config.character_id,
                                               g_ln_character_config.character_name,
                                               g_ln_character_config.avatar_eyes_shape,
                                               g_ln_character_config.avatar_hair_color,
                                               g_ln_character_config.avatar_eyes_color,
                                               g_ln_character_config.avatar_hair_style,
+                                              has_screen_image,
                                               g_ln_character_config.avatar_screen_image_as_emoji);
 
     cJSON_Delete(root);
index 5ff00c0..1e9845c 100644 (file)
@@ -135,6 +135,7 @@ void push_character_config_change_notification(const char* characterId,
     const char *hairColor,
     const char *eyesColor,
     const char *hairStyle,
+    int hasScreenImage,
     int screenImageAsEmoji)
 {
     // 组装紧凑 payload: 使用分隔符拼装,UI 侧再拆分(或改用结构体)
@@ -145,8 +146,8 @@ void push_character_config_change_notification(const char* characterId,
     const char *hc = hairColor ? hairColor : "";
     const char *ec = eyesColor ? eyesColor : "";
     const char *hs = hairStyle ? hairStyle : "";
-    (void)snprintf(payload, sizeof(payload) - 1, "%s|%s|%s|%s|%s|%s|%d", id,n, es, hc, ec, hs, screenImageAsEmoji ? 1 : 0);
-    printf("push_character_config_change_notification: characterId=%s, characterName=%s, eyesShape=%s, hairColor=%s, eyesColor=%s, hairStyle=%s, screenImageAsEmoji=%d\r\n", id, n, es, hc, ec, hs, screenImageAsEmoji ? 1 : 0);
+    (void)snprintf(payload, sizeof(payload) - 1, "%s|%s|%s|%s|%s|%s|%d|%d", id,n, es, hc, ec, hs, hasScreenImage ? 1 : 0, screenImageAsEmoji ? 1 : 0);
+    printf("push_character_config_change_notification: characterId=%s, characterName=%s, eyesShape=%s, hairColor=%s, eyesColor=%s, hairStyle=%s, hasScreenImage=%d, screenImageAsEmoji=%d\r\n", id, n, es, hc, ec, hs, hasScreenImage ? 1 : 0, screenImageAsEmoji ? 1 : 0);
 
     SendMsgToUIService(HAND_CHARACTER_CONFIG_CHANGE_NOTIFY, 0, (void *)payload, (int32_t)strlen(payload));
 }
index 09163a8..2d58254 100644 (file)
@@ -69,6 +69,7 @@ void push_character_config_change_notification(
                                               const char *hairColor,
                                               const char *eyesColor,
                                               const char *hairStyle,
+                                              int hasScreenImage,
                                               int screenImageAsEmoji);
 //通知ui跳转哄睡界面,是否是意图识别结果
 void push_sleep_mode_start_notification(const char *storyTheme, int is_intention_result);