优化语音结束操作
authorxue <2144439972@qq.com>
Fri, 10 Oct 2025 02:21:35 +0000 (10:21 +0800)
committerxue <2144439972@qq.com>
Fri, 10 Oct 2025 02:21:35 +0000 (10:21 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdDialogueView.h
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/include/ThunderBirdReminderView.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdDialogueView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdLullabyView.cpp
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

index de7dd42..332d167 100644 (file)
@@ -133,6 +133,7 @@ namespace OHOS
         void ClearAll(void);
         void Show(int16_t showView);
         void UpdateDialogueText(const char *text);
+        void AudioPlaybackEnd();
 
         enum : int16_t {
             THUNDERBIRD_DIALOGUEVIEW_SPEAKING = 0,     // 说话中
index 69133c4..f12354b 100644 (file)
@@ -97,6 +97,7 @@ namespace OHOS
         MediaVideoPlay *videoPlay_ = nullptr;
         UIImageView *batteryimage{nullptr};          // 电池图片
         UILabel *batteryLabel{nullptr};              // 电池电量
+        UILabel *batteryLabelBlack{nullptr};         // 黑色电量组件
         UIBoxProgress *progress{nullptr};            // 电池进度条
         UIImageView *chargeBatteryicon{nullptr};     // 充电图标
         bool isChargeBatteryIconVisible{false};      // 充电图标是否可见
@@ -128,6 +129,7 @@ namespace OHOS
 
         UIViewGroup *group1{nullptr};
         UILabelExt *timeLabel{nullptr};
+        UILabelExt *timeLabelBlack{nullptr};         // 黑色时间组件
         UIImageView *showSignalStrength[4]{nullptr}; // 信号强度
         UIImageView *NoSignal{nullptr};              // 无信号
         
index ad007c0..74a208e 100644 (file)
@@ -119,7 +119,7 @@ namespace OHOS
         
         // 对话文本管理函数
         std::string GetTextStr();
-        void SetTextStr(const char *textId);
+        void SetTextStr(char *textId);
         void ClearTextStr();
         size_t GetTextLength() const;
         bool IsTextEmpty() const;
@@ -219,6 +219,9 @@ namespace OHOS
         // 恢复视频帧率
         void HighFrequence();
 
+        // 音频播放结束处理函数
+        void HandleAudioPlaybackEnd();
+
         void at_set_fps(uint32_t freq);
         uint32_t at_get_fps(void);
 
index c7c29a7..7523c38 100644 (file)
@@ -27,7 +27,8 @@ namespace OHOS
         // 任务提醒文本更新接口(用于 THUNDERBIRD_REMINDERVIEW_TASK_REMINDER)
         void UpdateTaskReminderText(const char* title, const char* content);
         void UpdateTaskReminderText(const char* text);
-
+        void UpdateTaskReminderIcon(const char* icon);
+        
         enum : int16_t {
             THUNDERBIRD_REMINDERVIEW_VOLUME = 0,      // 音量调节
             THUNDERBIRD_REMINDERVIEW_TASK_REMINDER,   // 事项提醒
index cdc7c24..52a43b9 100644 (file)
@@ -237,6 +237,14 @@ namespace OHOS
         TextLabel->SetText(text); 
         TextLabel_Y->SetText(text); 
     }
+
+    void ThunderBirdDialogueView::AudioPlaybackEnd()
+    {
+        if(!TextLabel || !TextLabel_Y) return;
+        TextLabel->SetText("");
+        TextLabel_Y->SetText("");
+        if(speakAnimator) {speakAnimator->Stop();}
+    }
 }
 
 
index fe4d93b..e6e52c9 100644 (file)
@@ -359,11 +359,9 @@ namespace OHOS
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdLullabyView::Show: THUNDERBIRD_LULLABYVIEW_4");
             //长亮屏
             ScreenAlwaysOnCtr(OPEN_SCREEN_ALWAYS_ON);
-            //ThunderBirdModel::GetInstance()->StartCountUpTimer(15 * 60);
             if (TextLabel)
             {
                 TextLabel->SetPosition(0, 64, 360, 42);
-                //TextLabel->SetText("从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?");
                 TextLabel->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE); 
                 TextLabel->SetRollSpeed(35); 
                 TextLabel->SetVisible(true);
@@ -371,8 +369,8 @@ namespace OHOS
             if (TextLabel_Y)
             {
                 TextLabel_Y->SetPosition(2, 66, 360, 42);
-                //TextLabel_Y->SetText("从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲什么呢?");
                 TextLabel_Y->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE); 
+                TextLabel_Y->SetStyle(STYLE_TEXT_COLOR, 0xff000000);
                 TextLabel_Y->SetRollSpeed(35); 
                 TextLabel_Y->SetVisible(true);
             }
index 9c2cc7a..81dd0ef 100644 (file)
@@ -203,6 +203,11 @@ namespace OHOS
                 delete timeLabel;
                 timeLabel = nullptr;
             }
+            if (timeLabelBlack != nullptr)
+            {
+                delete timeLabelBlack;
+                timeLabelBlack = nullptr;
+            }
             for (int i = 0; i < 4; i++)
             {
                 if (showSignalStrength[i] != nullptr)
@@ -226,6 +231,11 @@ namespace OHOS
                 delete batteryLabel;
                 batteryLabel = nullptr;
             }
+            if (batteryLabelBlack != nullptr)
+            {
+                delete batteryLabelBlack;
+                batteryLabelBlack = nullptr;
+            }
             if (progress != nullptr)
             {
                 delete progress;
@@ -841,6 +851,24 @@ namespace OHOS
         timeLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 24);
         timeLabel->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
         timeLabel->SetVisible(true);
+        // 先创建黑色时间组件(作为背景)
+        timeLabelBlack = new UILabelExt();
+        if (timeLabelBlack == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "timeLabelBlack new fail");
+            return nullptr;
+        }
+        timeLabelBlack->SetPosition(2, 6, 60, 33); // 位置偏移+2
+        timeLabelBlack->SetViewId("timeLabelBlack");
+        timeLabelBlack->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 24);
+        timeLabelBlack->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        timeLabelBlack->SetStyle(STYLE_TEXT_COLOR, Color::Black().full); // 黑色
+        timeLabelBlack->SetVisible(true);
+        timeLabelBlack->SetText(ThunderBirdModel::GetInstance()->GetCurrentTimeStr().c_str()); // 每秒变化
+        group1->Add(timeLabelBlack);
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "timeLabelBlack add success - Position: (2,6) Size: (60,33) Color: Black");
+
+        // 再创建白色时间组件(作为前景)
         timeLabel->SetText(ThunderBirdModel::GetInstance()->GetCurrentTimeStr().c_str()); // 每秒变化
         group1->Add(timeLabel);
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "timeLabel add success");
@@ -938,8 +966,23 @@ namespace OHOS
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "batteryLabel new fail");
             return nullptr;
         }
-        batteryLabel->SetPosition(batteryimage->GetX() + 35, (group1->GetHeight() - 14) / 2, 30, 30);
+        batteryLabel->SetPosition(batteryimage->GetX() + 35, (group1->GetHeight() - 14) / 2-2, 32, 30);
         batteryLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 15);
+        // 先创建黑色电量组件(作为背景)
+        batteryLabelBlack = new UILabel();
+        if (batteryLabelBlack == nullptr)
+        {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "batteryLabelBlack new fail");
+            return nullptr;
+        }
+        batteryLabelBlack->SetPosition(batteryimage->GetX() + 37, (group1->GetHeight() - 14) / 2 , 32, 30); // 位置偏移+2
+        batteryLabelBlack->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 15);
+        batteryLabelBlack->SetText("100");
+        batteryLabelBlack->SetStyle(STYLE_TEXT_COLOR, Color::Black().full); // 黑色
+        batteryLabelBlack->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_LEFT);
+        group1->Add(batteryLabelBlack);
+
+        // 再创建白色电量组件(作为前景)
         batteryLabel->SetText("100");
         batteryLabel->SetStyle(STYLE_TEXT_COLOR, Color::White().full);
         batteryLabel->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_LEFT);
@@ -970,6 +1013,12 @@ namespace OHOS
     void ThunderBirdMainView::UpdateTimeText(const char *time)
     {
         timeLabel->SetText(time); // 每秒变化
+        if (timeLabelBlack != nullptr) {
+            timeLabelBlack->SetText(time); // 同时更新黑色时间组件
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "UpdateTimeText: Updated black time component with: %s", time);
+        } else {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateTimeText: timeLabelBlack is null!");
+        }
     }
 
     void ThunderBirdMainView::updateSignalDisplay() // 信号接收
@@ -1117,6 +1166,10 @@ namespace OHOS
         {
             batteryLabel->SetText((std::to_string(static_cast<int>(Batteryvalue))).c_str()); // 电量
         }
+        if (batteryLabelBlack)
+        {
+            batteryLabelBlack->SetText((std::to_string(static_cast<int>(Batteryvalue))).c_str()); // 同时更新黑色电量组件
+        }
         if (progress)
         {
             progress->SetValue(Batteryvalue);
index 3c75801..448071c 100644 (file)
@@ -34,6 +34,7 @@
 #include "NativeRegisterManager.h"
 #include "graphic_service_wrapper.h"
 #include "cJSON.h"
+#include "font/ui_font.h"
  #define JUHEPINGTAI 0
  #if JUHEPINGTAI
  #include "websocket_server_manager.h"
      // ==================== 对话文本管理函数 ====================
      std::string ThunderBirdModel::GetTextStr()
      { 
-        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "获取对话文本: %s", m_currentTimeStr.c_str());
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "获取对话文本: %s", m_currentTimeStr.c_str());
          return m_currentTimeStr;
      }
+     static int32_t chat_filter_unsupported_chars(const char *input_str, char *output_str, uint32_t max_len)
+     {
+         if (input_str == NULL || output_str == NULL || max_len == 0)
+         {
+             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid parameters for asr_filter_unsupported_chars\n");
+             return -1;
+         }
+ 
+         // 初始化输出缓冲区
+         memset(output_str, 0, max_len);
+ 
+         uint32_t input_len = strlen(input_str);
+         uint32_t output_pos = 0;
+         uint32_t input_pos = 0;
+ 
+         while (input_pos < input_len && output_pos < max_len - 1)
+         {
+             uint32_t char_start = input_pos;
+             uint32_t char_end = input_pos;
+ 
+             // 获取下一个UTF-8字符
+             uint32_t unicode_char = 0;
+             bool valid_utf8 = false;
+ 
+             // 简单的UTF-8解码
+             if ((unsigned char)input_str[input_pos] < 0x80)
+             {
+                 // ASCII字符
+                 unicode_char = (unsigned char)input_str[input_pos];
+                 char_end = input_pos + 1;
+                 valid_utf8 = true;
+             }
+             else if ((unsigned char)input_str[input_pos] >= 0xC0 && (unsigned char)input_str[input_pos] < 0xE0)
+             {
+                 // 2字节UTF-8字符
+                 if (input_pos + 1 < input_len)
+                 {
+                     unicode_char = ((unsigned char)input_str[input_pos] & 0x1F) << 6 |
+                                    ((unsigned char)input_str[input_pos + 1] & 0x3F);
+                     char_end = input_pos + 2;
+                     valid_utf8 = true;
+                 }
+             }
+             else if ((unsigned char)input_str[input_pos] >= 0xE0 && (unsigned char)input_str[input_pos] < 0xF0)
+             {
+                 // 3字节UTF-8字符
+                 if (input_pos + 2 < input_len)
+                 {
+                     unicode_char = ((unsigned char)input_str[input_pos] & 0x0F) << 12 |
+                                    ((unsigned char)input_str[input_pos + 1] & 0x3F) << 6 |
+                                    ((unsigned char)input_str[input_pos + 2] & 0x3F);
+                     char_end = input_pos + 3;
+                     valid_utf8 = true;
+                 }
+             }
+             else if ((unsigned char)input_str[input_pos] >= 0xF0 && (unsigned char)input_str[input_pos] < 0xF8)
+             {
+                 // 4字节UTF-8字符
+                 if (input_pos + 3 < input_len)
+                 {
+                     unicode_char = ((unsigned char)input_str[input_pos] & 0x07) << 18 |
+                                    ((unsigned char)input_str[input_pos + 1] & 0x3F) << 12 |
+                                    ((unsigned char)input_str[input_pos + 2] & 0x3F) << 6 |
+                                    ((unsigned char)input_str[input_pos + 3] & 0x3F);
+                     char_end = input_pos + 4;
+                     valid_utf8 = true;
+                 }
+             }
+ 
+             if (!valid_utf8)
+             {
+                 // 无效的UTF-8字符,跳过
+                 input_pos++;
+                 continue;
+             }
+ 
+             // 使用GetGlyphPathData接口检查字符是否可以在字体中显示
+             bool char_supported = true;
+ 
+             // 对于ASCII字符,直接支持
+             if (unicode_char < 0x80)
+             {
+                 char_supported = true;
+             }
+             else
+             {
+                 // 使用字体引擎检查字符是否支持
+                 OHOS::UIFont *fontEngine = OHOS::UIFont::GetInstance();
+                 if (fontEngine != NULL)
+                 {
+                     // 使用GetGlyphPathData检查字符是否支持
+                     OHOS::GlyphPathData path;
+                     if (!fontEngine->GetGlyphPathData(unicode_char, 0, path))
+                     {
+                         // 字符不支持,标记为不支持
+                         char_supported = false;
+                         WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Character 0x%X not supported by font engine\n", unicode_char);
+                     }
+                     else
+                     {
+                         // 字符支持
+                         char_supported = true;
+                     }
+                 }
+                 else
+                 {
+                     // 字体引擎不可用,使用简化的字符范围检查
+                     if (unicode_char >= 0x4E00 && unicode_char <= 0x9FFF)
+                     {
+                         // 中文字符范围
+                         char_supported = true;
+                     }
+                     else if (unicode_char >= 0xAC00 && unicode_char <= 0xD7AF)
+                     {
+                         // 韩文字符范围
+                         char_supported = true;
+                     }
+                     else if (unicode_char >= 0x3040 && unicode_char <= 0x309F)
+                     {
+                         // 平假名
+                         char_supported = true;
+                     }
+                     else if (unicode_char >= 0x30A0 && unicode_char <= 0x30FF)
+                     {
+                         // 片假名
+                         char_supported = true;
+                     }
+                     else if (unicode_char >= 0x2000 && unicode_char <= 0x206F)
+                     {
+                         // 标点符号
+                         char_supported = true;
+                     }
+                     else
+                     {
+                         // 其他字符,标记为不支持
+                         char_supported = false;
+                     }
+                 }
+             }
+ 
+             if (char_supported)
+             {
+                 // 字符支持,复制到输出缓冲区
+                 uint32_t char_len = char_end - char_start;
+                 if (output_pos + char_len < max_len)
+                 {
+                     memcpy(&output_str[output_pos], &input_str[char_start], char_len);
+                     output_pos += char_len;
+                 }
+                 else
+                 {
+                     break; // 输出缓冲区已满
+                 }
+             }
+             else
+             {
+                 // 字符不支持,跳过不支持的字符
+                 WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Unsupported character: 0x%X, skipping\n", unicode_char);
+             }
+ 
+             input_pos = char_end;
+         }
+ 
+         // 确保输出字符串以null结尾
+         output_str[output_pos] = '\0';
+ 
+         WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Filtered string: '%s' -> '%s' (length: %d)\n",
+                       input_str, output_str, output_pos);
+ 
+         return output_pos;
+     }
+ 
+     /**
+      * @brief 过滤chat结果中的无法显示字符
+      * @param result chat识别结果字符串
+      * @return 过滤后的字符串长度,-1表示失败
+      */
+     static int32_t chat_filter_result_chars(char *result)
+     {
+         if (result == NULL)
+         {
+             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " result string is NULL\n");
+             return -1;
+         }
+ 
+         uint32_t max_len = strlen(result) + 1;
+         char *temp_buffer = (char *)malloc(max_len);
+         if (temp_buffer == NULL)
+         {
+             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to allocate memory for temp buffer\n");
+             return -1;
+         }
+ 
+         int32_t filtered_len = chat_filter_unsupported_chars(result, temp_buffer, max_len);
+         if (filtered_len >= 0)
+         {
+             strcpy(result, temp_buffer);
+         }
+ 
+         free(temp_buffer);
+         return filtered_len;
+     }
      
-     void ThunderBirdModel::SetTextStr(const char *textId)
+     void ThunderBirdModel::SetTextStr(char *textId)
      {
+        //chat_filter_result_chars(textId);
         if (textId == nullptr) {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "设置对话文本: textId is null");
             return;
         ThunderBirdMainView *view = ThunderBirdMainView::GetInstance();
         if (view) {
             std::string currentTime = GetCurrentTimeStr();
+            // 检查夜间更新状态(每天凌晨2点检查)
+            if(currentTime == "2:00")
+            {
+                // 从KV存储中读取夜间更新状态
+                char temp[10] = { 0 };
+                (void)UtilsGetValue("night_update_enabled", temp, 10);
+                if(strcmp(temp, "1") == 0)
+                {
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "检测到夜间更新已启用,切换到OTA slice");
+                    // 切换到OTA slice
+                    NativeAbility::GetInstance().SwitchSlice(VIEW_OTA);
+                }
+            }
             view->UpdateTimeText(currentTime.c_str());
             WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "TimeDisplayCallback: %s", currentTime.c_str());
         }
         // 这里可以添加聊天体力更改的具体处理逻辑
        if (ThunderBirdMainView::GetInstance()) {
            int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView();
+           //更新充值二维码
+           if(ThunderBirdReminderView::GetInstance())
+           {
+                ThunderBirdReminderView::GetInstance()->UpdateTaskReminderIcon(qrcodeUrl);
+           }        
            if((chatLeft < 20 && chatLeft > 0))//对话不足
            {
              ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_REMINDERVIEW, ThunderBirdReminderView::THUNDERBIRD_REMINDERVIEW_DIALOGUE_NOT_ENOUGH);
         NativeAbility::GetInstance().ChangeSlice(VIEW_OTA);
     }
 
+    void ThunderBirdModel::HandleAudioPlaybackEnd()
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioPlaybackEnd");
+        if(ThunderBirdDialogueView::GetInstance())
+        {
+            ThunderBirdDialogueView::GetInstance()->AudioPlaybackEnd();
+        }
+    }
+
     int ThunderBirdModel::GetDownloadFile()
     {
         return downloadFileType;
index da66b71..e296159 100644 (file)
@@ -190,6 +190,24 @@ namespace OHOS
                         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateDialogueText:%s\n",dialogueText.c_str());
                         ThunderBirdDialogueView::GetInstance()->UpdateDialogueText(dialogueText.c_str());
                     }
+                    else{
+                        //如果不是对话需要判断是否服务准备好
+                        if(ThunderBirdModel::GetInstance()->Get_is_all_services_ready() == false)
+                        ThunderBirdDialogueView::GetInstance()->UpdateDialogueText("等待网络连接");
+                        else
+                        ThunderBirdDialogueView::GetInstance()->UpdateDialogueText("网络连接成功");
+                    }
+                    
+                }
+            }
+            //如果是哄睡界面 需要更新哄睡文本
+            if(currentView == THUNDERBIRD_LULLABYVIEW && currentSubView == ThunderBirdLullabyView::THUNDERBIRD_LULLABYVIEW_4)
+            {
+                if(ThunderBirdLullabyView::GetInstance() != nullptr)
+                {
+                    std::string lullabyText = ThunderBirdModel::GetInstance()->GetTextStr();
+                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "UpdateLullabyText:%s\n",lullabyText.c_str());
+                    ThunderBirdLullabyView::GetInstance()->UpdateLullabyText(lullabyText.c_str());
                 }
             }
         }