雷鸟:蓝牙列表添加连接中动画,优化显示 2842/1 2842/head
authorluozheng <1732036298@qq.com>
Tue, 2 Dec 2025 08:21:32 +0000 (16:21 +0800)
committerluozheng <1732036298@qq.com>
Tue, 2 Dec 2025 08:21:32 +0000 (16:21 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/BluetoothModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/bluetooth/src/Ln_Bluetooth_apiC.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdBlueListAdapter.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/include/ThunderBirdBlueView.h
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdBlueListAdapter.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdBlueView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp

index eab84ba..514c98b 100644 (file)
@@ -544,6 +544,9 @@ void BluetoothModel::SetAdvStartState(bool state)
 // 连接远程设备\r
 int BluetoothModel::ConnectRemoteDevice(const bd_addr_t *addr)\r
 {\r
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ConnectRemoteDevice: 准备连接设备 addr=%02x%02x%02x%02x%02x%02x",\r
+                  addr->addr[5], addr->addr[4], addr->addr[3],\r
+                  addr->addr[2], addr->addr[1], addr->addr[0]);\r
     /* 恢厂后耳机连接要开启BT广播否则会导致AVRCP无法音量控制 */\r
     bool ret = gap_br_set_bt_scan_mode(GAP_SCAN_MODE_CONNECTABLE, 60);\r
     if (!ret) {\r
@@ -552,6 +555,9 @@ int BluetoothModel::ConnectRemoteDevice(const bd_addr_t *addr)
     errcode_t retVal = gap_connect_remote_device(addr);\r
     WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "连接远程设备 ret = 0x%x", retVal);\r
     (void)memcpy_s(&remoteConnectAddr, sizeof(bd_addr_t), addr, sizeof(bd_addr_t));\r
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ConnectRemoteDevice: remoteConnectAddr已设置为 %02x%02x%02x%02x%02x%02x",\r
+                  remoteConnectAddr.addr[5], remoteConnectAddr.addr[4], remoteConnectAddr.addr[3],\r
+                  remoteConnectAddr.addr[2], remoteConnectAddr.addr[1], remoteConnectAddr.addr[0]);\r
     return retVal;\r
 }\r
 \r
@@ -974,6 +980,37 @@ void BluetoothModel::BtGapAclStateChangedHandle(gap_acl_state_t state, unsigned
     } else if ((reason == 0xb) || (reason > 0x45)) { // 0xb:重复点击连接按钮 0x45:acl状态最大参数\r
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "reason is false.");\r
         SetTagDisconnectView(false);\r
+    } \r
+    else if(reason == 0x2){\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "连接失败,链路连接被对端主动拒绝/未响应 reason is 0x2.");\r
+        // 检查是否是期望连接的设备\r
+        BluetoothCaseInfo *expectedDevice = GetTempMacValue();\r
+        bool isExpectedDevice = false;\r
+        if (expectedDevice != nullptr) {\r
+            isExpectedDevice = (memcmp(expectedDevice->addr, bdAddr.addr, BD_ADDR_LEN) == 0);\r
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "连接失败: 期望设备=%02x%02x%02x%02x%02x%02x, 回调地址=%02x%02x%02x%02x%02x%02x, 匹配=%d",\r
+                          expectedDevice->addr[5], expectedDevice->addr[4], expectedDevice->addr[3],\r
+                          expectedDevice->addr[2], expectedDevice->addr[1], expectedDevice->addr[0],\r
+                          bdAddr.addr[5], bdAddr.addr[4], bdAddr.addr[3],\r
+                          bdAddr.addr[2], bdAddr.addr[1], bdAddr.addr[0],\r
+                          isExpectedDevice);\r
+        }\r
+        // 清除连接状态标记(无论地址是否匹配,都清除,因为连接已失败)\r
+        SetTagScanDeviceClicked(false);\r
+        // 清空正在连接的设备地址\r
+        (void)memset_s(&remoteConnectAddr, sizeof(bd_addr_t), 0, sizeof(bd_addr_t));\r
+        // 刷新设备列表以停止"连接中"动画\r
+        ThunderBirdBlueView *thunderBirdBlueView = ThunderBirdBlueView::GetInstance();\r
+        if (thunderBirdBlueView != nullptr) {\r
+            thunderBirdBlueView->RefreshDeviceList();\r
+        }\r
+        if(ThunderBirdMainView::GetInstance()) {\r
+                int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView();\r
+                ThunderBirdMainView::GetInstance()->ChangeView(currentView, \r
+                    THUNDERBIRD_BLUEVIEW, \r
+                    ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_CONNECT_FAILED);\r
+        }\r
+        return;\r
     }\r
 \r
     if ((state == GAP_ACL_STATE_CONNECTED) || (state == GAP_ACL_STATE_LE_CONNECTED)) {\r
@@ -1037,9 +1074,25 @@ void GapAclStateChangedCallback(const bd_addr_t *bdAddr, gap_acl_state_t state,
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "addr: %02x%02x%02x%02x%02x%02x",\r
         bdAddr->addr[5], bdAddr->addr[4], bdAddr->addr[3], /* mac下标 0 1 2 3 4 5 */\r
         bdAddr->addr[2], bdAddr->addr[1], bdAddr->addr[0]); /* mac下标 0 1 2 3 4 5 */\r
+    \r
+    // 检查设备类型\r
+    uint32_t deviceClass = gap_get_device_class(bdAddr);\r
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GapAclStateChangedCallback: deviceClass=0x%x, (class&0x200)=0x%x", \r
+                  deviceClass, deviceClass & 0x200);\r
+    \r
+    // 获取当前期望连接的设备地址\r
+    BluetoothModel* btModel = BluetoothModel::GetInstance();\r
+    BluetoothCaseInfo* expectedDevice = btModel->GetTempMacValue();\r
+    if (expectedDevice != nullptr) {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GapAclStateChangedCallback: 期望连接的设备 addr=%02x%02x%02x%02x%02x%02x",\r
+                      expectedDevice->addr[5], expectedDevice->addr[4], expectedDevice->addr[3],\r
+                      expectedDevice->addr[2], expectedDevice->addr[1], expectedDevice->addr[0]);\r
+    }\r
+    \r
     static bd_addr_t gapAclConnectAddr{0}; /* 连接后保存手机地址,手表清除手机配对后查询不到class比较手机地址 */\r
-    if ((gap_get_device_class(bdAddr) & 0x200) != 0 || memcmp(gapAclConnectAddr.addr, bdAddr->addr, BD_ADDR_LEN) == 0) {\r
-        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GapAclStateChangedCallback: Mobile Phone Device");\r
+    if ((deviceClass & 0x200) != 0 || memcmp(gapAclConnectAddr.addr, bdAddr->addr, BD_ADDR_LEN) == 0) {\r
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GapAclStateChangedCallback: Mobile Phone Device (class&0x200=%d, matched=%d)", \r
+                      (deviceClass & 0x200) != 0, memcmp(gapAclConnectAddr.addr, bdAddr->addr, BD_ADDR_LEN) == 0);\r
         if (state == GAP_ACL_STATE_DISCONNECTED) {\r
             /* 通知msg_center,ble状态仍用bt状态,此处不区分 */\r
             // MsgCenterSendMsg(BT_DISCONNECTED_TO_MSGCENTER, 0, nullptr, 0);\r
index 466acbe..71b104c 100644 (file)
@@ -379,9 +379,6 @@ extern "C"
         // 检查AVRCP连接状态
         if (avrcpInf.avrcp_srv_conn_stat != PROFILE_STATE_CONNECTED) {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_bt_earphone_set_volume: AVRCP not connected");
-            //尝试连接一次AVRCP服务
-            uint32_t ret = avrcp_ct_connect(&avrcpInf.bd_addr);
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_bt_earphone_get_volume: connect AVRCP, ret=%d", ret);
             return -1;
         }
         
@@ -413,9 +410,6 @@ extern "C"
         // 检查AVRCP连接状态
         if (avrcpInf.avrcp_srv_conn_stat != PROFILE_STATE_CONNECTED) {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_bt_earphone_get_volume: AVRCP not connected");
-            //尝试连接一次AVRCP服务
-            uint32_t ret = avrcp_ct_connect(&avrcpInf.bd_addr);
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_bt_earphone_get_volume: connect AVRCP, ret=%d", ret);
             return -1;
         }
         
index 121f36e..a7d9ce3 100644 (file)
@@ -12,6 +12,7 @@
 #include "components/ui_view_group.h"
 #include "components/ui_label.h"
 #include "components/ui_image_view.h"
+#include "components/ui_image_animator.h"
 #include "bluetooth/BluetoothModel.h"
 
 namespace OHOS {
@@ -29,6 +30,7 @@ struct DeviceListItem {
     DeviceItemType type;
     BluetoothCaseInfo deviceInfo;
     bool isSelected;
+    bool isConnecting;   // 是否是“连接中”状态(用于显示右侧 loading 动画)
 };
 
 // 蓝牙设备列表项视图
@@ -43,6 +45,8 @@ public:
     void SetSectionHeader(const char* title);
     // 设置选中状态
     void SetSelected(bool selected);
+    // 设置是否处于“连接中”状态(显示/隐藏右侧 loading 动画)
+    void SetConnecting(bool connecting);
     // 获取设备信息
     BluetoothCaseInfo* GetDeviceInfo(void);
     // 检查是否是分组标题
@@ -54,10 +58,12 @@ private:
     UILabel nameLabel_;           // 设备名称标签
     UIImageView connectedIcon_;   // 已连接图标(小圆点)
     UIImageView borderImage_;     // 选中边框
+    UIImageAnimatorView *connectingAnimator_; // 连接中 loading 动画
     BluetoothCaseInfo deviceInfo_{};
     bool isSelected_{false};
     bool isSectionHeader_{false};
     bool isConnected_{false};
+    bool isConnecting_{false};
 };
 
 // 蓝牙设备列表适配器
index f9c5d23..40c18ce 100644 (file)
@@ -20,14 +20,6 @@ namespace OHOS
     static constexpr int16_t TB_BLUE_SEARCH_ANIM_FRAMES = 24;
     static constexpr int16_t TB_BLUE_SEARCH_ANIM_INTERVAL = 33;
     
-    // 选择动画配置
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_X = 148;
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_Y = 102;
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_W = 24;
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_H = 24;
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_FRAMES = 49;
-    static constexpr int16_t TB_BLUE_SELECT_ANIM_INTERVAL = 41;
-    
     // 搜索动画图片路径数组
     static const char *TB_BLUE_SEARCH_PATHS[TB_BLUE_SEARCH_ANIM_FRAMES] = {
         TB_SEARCH_IMAGE_1,
@@ -56,58 +48,6 @@ namespace OHOS
         TB_SEARCH_IMAGE_24,
     };
     
-    // 选择动画图片路径数组(复用搜索动画图片)
-    static const char *TB_BLUE_SELECT_PATHS[TB_BLUE_SELECT_ANIM_FRAMES] = {
-        TB_LIST_IMAGE_1,
-        TB_LIST_IMAGE_2,
-        TB_LIST_IMAGE_3,
-        TB_LIST_IMAGE_4,
-        TB_LIST_IMAGE_5,
-        TB_LIST_IMAGE_6,
-        TB_LIST_IMAGE_7,
-        TB_LIST_IMAGE_8,
-        TB_LIST_IMAGE_9,
-        TB_LIST_IMAGE_10,
-        TB_LIST_IMAGE_11,
-        TB_LIST_IMAGE_12,
-        TB_LIST_IMAGE_13,
-        TB_LIST_IMAGE_14,
-        TB_LIST_IMAGE_15,
-        TB_LIST_IMAGE_16,
-        TB_LIST_IMAGE_17,
-        TB_LIST_IMAGE_18,
-        TB_LIST_IMAGE_19,
-        TB_LIST_IMAGE_20,
-        TB_LIST_IMAGE_21,
-        TB_LIST_IMAGE_22,
-        TB_LIST_IMAGE_23,
-        TB_LIST_IMAGE_24,
-        TB_LIST_IMAGE_25,
-        TB_LIST_IMAGE_26,
-        TB_LIST_IMAGE_27,
-        TB_LIST_IMAGE_28,
-        TB_LIST_IMAGE_29,
-        TB_LIST_IMAGE_30,
-        TB_LIST_IMAGE_31,
-        TB_LIST_IMAGE_32,
-        TB_LIST_IMAGE_33,
-        TB_LIST_IMAGE_34,
-        TB_LIST_IMAGE_35,
-        TB_LIST_IMAGE_36,
-        TB_LIST_IMAGE_37,
-        TB_LIST_IMAGE_38,
-        TB_LIST_IMAGE_39,
-        TB_LIST_IMAGE_40,
-        TB_LIST_IMAGE_41,
-        TB_LIST_IMAGE_42,
-        TB_LIST_IMAGE_43,
-        TB_LIST_IMAGE_44,
-        TB_LIST_IMAGE_45,
-        TB_LIST_IMAGE_46,
-        TB_LIST_IMAGE_47,
-        TB_LIST_IMAGE_48,
-        TB_LIST_IMAGE_49,
-    };
     // 前向声明
     class ThunderBirdBlueListAdapter;
 
@@ -170,11 +110,8 @@ namespace OHOS
         
         // 动画组件
         UIImageAnimatorView *searchAnimator{nullptr};
-        UIImageAnimatorView *selectAnimator{nullptr};
         ImageAnimatorInfo searchImageInfo[TB_BLUE_SEARCH_ANIM_FRAMES];
-        ImageAnimatorInfo selectImageInfo[TB_BLUE_SELECT_ANIM_FRAMES];
         const char **searchPathsArray{nullptr};
-        const char **selectPathsArray{nullptr};
         
         // 设备列表适配器
         ThunderBirdBlueListAdapter *deviceListAdapter_{nullptr};
index 67a863c..b6ce3c3 100644 (file)
@@ -7,9 +7,54 @@
 #include "thunderbird/include/ThunderBirdBlueListAdapter.h"
 #include "wearable_log.h"
 #include "bts_br_gap.h"
+#include "UiConfig.h"
 
 namespace OHOS {
 
+//========================================
+// 连接中动画资源配置(复用列表动画帧)
+//========================================
+namespace {
+// 使用前 16 帧列表动画作为“连接中” loading 动画
+constexpr uint8_t TB_BLUE_CONNECT_ANIM_FRAMES = 49;
+constexpr uint16_t TB_BLUE_CONNECT_ANIM_INTERVAL = 50; // 每帧 50ms,约 20fps
+
+static const char *TB_BLUE_CONNECT_PATHS[TB_BLUE_CONNECT_ANIM_FRAMES] = {
+    TB_LIST_IMAGE_1,  TB_LIST_IMAGE_2,  TB_LIST_IMAGE_3,  TB_LIST_IMAGE_4,
+    TB_LIST_IMAGE_5,  TB_LIST_IMAGE_6,  TB_LIST_IMAGE_7,  TB_LIST_IMAGE_8,
+    TB_LIST_IMAGE_9,  TB_LIST_IMAGE_10, TB_LIST_IMAGE_11, TB_LIST_IMAGE_12,
+    TB_LIST_IMAGE_13, TB_LIST_IMAGE_14, TB_LIST_IMAGE_15, TB_LIST_IMAGE_16,
+    TB_LIST_IMAGE_17, TB_LIST_IMAGE_18, TB_LIST_IMAGE_19, TB_LIST_IMAGE_20,
+    TB_LIST_IMAGE_21, TB_LIST_IMAGE_22, TB_LIST_IMAGE_23, TB_LIST_IMAGE_24,
+    TB_LIST_IMAGE_25, TB_LIST_IMAGE_26, TB_LIST_IMAGE_27, TB_LIST_IMAGE_28,
+    TB_LIST_IMAGE_29, TB_LIST_IMAGE_30, TB_LIST_IMAGE_31, TB_LIST_IMAGE_32,
+    TB_LIST_IMAGE_33, TB_LIST_IMAGE_34, TB_LIST_IMAGE_35, TB_LIST_IMAGE_36,
+    TB_LIST_IMAGE_37, TB_LIST_IMAGE_38, TB_LIST_IMAGE_39, TB_LIST_IMAGE_40,
+    TB_LIST_IMAGE_41, TB_LIST_IMAGE_42, TB_LIST_IMAGE_43, TB_LIST_IMAGE_44,
+    TB_LIST_IMAGE_45, TB_LIST_IMAGE_46, TB_LIST_IMAGE_47, TB_LIST_IMAGE_48,
+    TB_LIST_IMAGE_49,
+};
+
+static ImageAnimatorInfo g_connectAnimInfo[TB_BLUE_CONNECT_ANIM_FRAMES];
+static bool g_connectAnimInited = false;
+
+static void InitConnectAnimInfo()
+{
+    if (g_connectAnimInited) {
+        return;
+    }
+    for (uint8_t i = 0; i < TB_BLUE_CONNECT_ANIM_FRAMES; i++) {
+        g_connectAnimInfo[i].imagePath = TB_BLUE_CONNECT_PATHS[i];
+        g_connectAnimInfo[i].imageType = IMG_SRC_FILE_PATH;
+        g_connectAnimInfo[i].pos.x = 0;
+        g_connectAnimInfo[i].pos.y = 0;
+        g_connectAnimInfo[i].width = 24;
+        g_connectAnimInfo[i].height = 24;
+    }
+    g_connectAnimInited = true;
+}
+} // namespace
+
 // 列表项尺寸常量
 constexpr uint16_t ITEM_WIDTH = 240;
 constexpr uint16_t ITEM_HEIGHT = 40;
@@ -21,9 +66,8 @@ constexpr uint16_t SECTION_FONT_SIZE = 14;
 
 // 颜色定义
 constexpr int64_t COLOR_ITEM_BG = 0xFFAD590B;          // 设备项背景色(深灰)
-constexpr int64_t COLOR_BORDER_SELECTED = 0xFFED6C00;  // 选中边框颜色(橙色)
+constexpr int64_t COLOR_BORDER_SELECTED = 0xFFAD590B;  // 选中边框颜色(橙色)
 constexpr int64_t COLOR_TEXT_WHITE = 0xFFFFFFFF;       // 白色文字
-constexpr int64_t COLOR_TEXT_GRAY = 0xFFCCCCCC;        // 灰色文字(分组标题)
 constexpr int64_t COLOR_CONNECTED_DOT = 0xFF4FC34C;    // 已连接指示点颜色(绿色)
 
 //========================================
@@ -44,6 +88,13 @@ ThunderBirdBlueDeviceItemView::~ThunderBirdBlueDeviceItemView()
     Remove(&borderImage_);
     Remove(&nameLabel_);
     Remove(&connectedIcon_);
+    Remove(connectingAnimator_);
+    if(connectingAnimator_) 
+    {
+        connectingAnimator_->Stop();
+        delete connectingAnimator_;
+        connectingAnimator_ = nullptr;
+    }
 }
 
 void ThunderBirdBlueDeviceItemView::SetupChildViews()
@@ -51,7 +102,7 @@ void ThunderBirdBlueDeviceItemView::SetupChildViews()
     WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetupChildViews");
 
     borderImage_.SetPosition(0, 0, ITEM_WIDTH, ITEM_HEIGHT);
-    borderImage_.SetStyle(STYLE_BACKGROUND_COLOR, COLOR_TEXT_GRAY);
+    borderImage_.SetStyle(STYLE_BACKGROUND_COLOR, COLOR_BORDER_SELECTED);
     borderImage_.SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
     borderImage_.SetStyle(STYLE_BORDER_RADIUS, 10);
     borderImage_.SetVisible(false);
@@ -70,12 +121,40 @@ void ThunderBirdBlueDeviceItemView::SetupChildViews()
     connectedIcon_.SetStyle(STYLE_BORDER_RADIUS, CONNECTED_ICON_SIZE / 2);
     connectedIcon_.SetVisible(false);
     Add(&connectedIcon_);
+
+    // “连接中” loading 动画(在已连接小圆点左侧)
+    InitConnectAnimInfo();
+    int16_t animX = ITEM_WIDTH - 40;
+    int16_t animY = (ITEM_HEIGHT - 24) / 2;
+    printf("animX=%d animY=%d\n", animX, animY);
+    connectingAnimator_ = new UIImageAnimatorView();
+    if(!connectingAnimator_)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "connectingAnimator_ create failed");
+        return;
+    }
+    connectingAnimator_->SetPosition(animX, animY, 24, 24);
+    connectingAnimator_->SetStyle(STYLE_BACKGROUND_COLOR, 0xffffffff);
+    connectingAnimator_->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
+    // 更新帧位置
+    for (uint8_t i = 0; i < TB_BLUE_CONNECT_ANIM_FRAMES; i++) {
+        g_connectAnimInfo[i].pos.x = animX;
+        g_connectAnimInfo[i].pos.y = animY;
+        g_connectAnimInfo[i].width = 24;
+        g_connectAnimInfo[i].height = 24;
+    }
+    connectingAnimator_->SetImageAnimatorSrc(g_connectAnimInfo, TB_BLUE_CONNECT_ANIM_FRAMES, TB_BLUE_CONNECT_ANIM_INTERVAL);
+    connectingAnimator_->SetRepeat(true);
+    connectingAnimator_->SetAutoEnable(false);
+    connectingAnimator_->SetResizeMode(UIImageView::FILL);
+    connectingAnimator_->SetVisible(false);
+    Add(connectingAnimator_);
 }
 
 // 设置设备信息(包括分组标题)
 void ThunderBirdBlueDeviceItemView::SetDeviceInfo(const BluetoothCaseInfo& info, bool isConnected)
 {
-    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetDeviceInfo name=%s isConnected=%d", 
+    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetDeviceInfo name=%s isConnected=%d", 
                   info.deviceName, isConnected);
     
     isSectionHeader_ = false;
@@ -91,6 +170,8 @@ void ThunderBirdBlueDeviceItemView::SetDeviceInfo(const BluetoothCaseInfo& info,
     
     // 显示/隐藏已连接指示
     connectedIcon_.SetVisible(isConnected);
+
+    // “连接中”动画状态由 SetConnecting 控制,这里不做处理
     
     Invalidate();
 }
@@ -102,6 +183,7 @@ void ThunderBirdBlueDeviceItemView::SetSectionHeader(const char* title)
     
     isSectionHeader_ = true;
     isConnected_ = false;
+    isConnecting_ = false;
     
     // 设置标题文字
     nameLabel_.SetText(title);
@@ -109,14 +191,39 @@ void ThunderBirdBlueDeviceItemView::SetSectionHeader(const char* title)
     nameLabel_.SetPosition(20, 0, 200, ITEM_HEIGHT);
     nameLabel_.SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_BOTTOM,UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
    
-    // 隐藏已连接指示
+    // 隐藏已连接指示与加载动画
     connectedIcon_.SetVisible(false);
+    connectingAnimator_->SetVisible(false);
+    connectingAnimator_->Stop();
 
     borderImage_.SetVisible(false);
     
     Invalidate();
 }
 
+// 设置是否处于“连接中”状态(显示/隐藏右侧 loading 动画)
+void ThunderBirdBlueDeviceItemView::SetConnecting(bool connecting)
+{
+    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetConnecting=%d isSectionHeader=%d", connecting, isSectionHeader_);
+    isConnecting_ = connecting;
+
+    if (isSectionHeader_) {
+        connectingAnimator_->SetVisible(false);
+        connectingAnimator_->Stop();
+        return;
+    }
+
+    if (connecting) {
+        connectingAnimator_->SetVisible(true);
+        connectingAnimator_->Start();
+    } else {
+        connectingAnimator_->SetVisible(false);
+        connectingAnimator_->Stop();
+    }
+
+    Invalidate();
+}
+
 void ThunderBirdBlueDeviceItemView::SetSelected(bool selected)
 {
     WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetSelected=%d isSectionHeader=%d", selected, isSectionHeader_);
@@ -218,7 +325,11 @@ void ThunderBirdBlueListAdapter::BuildDisplayList()
             node = node->next_;
         }
         
-        // 第二步:优先添加已连接的设备
+        // 获取当前正在尝试连接的设备(用于判断“连接中”状态)
+        bool hasClick = btModel->IsTagScanDeviceClicked();
+        BluetoothCaseInfo* connectingInfo = hasClick ? btModel->GetTempMacValue() : nullptr;
+        
+        // 第二步:优先添加已连接的设备(已连接的不显示 loading)
         for (auto& device : connectedDevicesList) {
             if (connectedCount >= MAX_CONNECTED_DEVICES) {
                 break;
@@ -227,12 +338,13 @@ void ThunderBirdBlueListAdapter::BuildDisplayList()
             item.type = DeviceItemType::DEVICE_CONNECTED;
             item.deviceInfo = device;
             item.isSelected = false;
+            item.isConnecting = false;
             displayList_.push_back(item);
             connectedCount++;
             WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Added my device (connected): %s", device.deviceName);
         }
         
-        // 第三步:再添加未连接的设备(如果还有空间)
+        // 第三步:再添加未连接的设备(如果还有空间),若为当前点击目标且未连接,则标记为“连接中”
         for (auto& device : unconnectedDevicesList) {
             if (connectedCount >= MAX_CONNECTED_DEVICES) {
                 break;
@@ -241,9 +353,17 @@ void ThunderBirdBlueListAdapter::BuildDisplayList()
             item.type = DeviceItemType::DEVICE_CONNECTED;
             item.deviceInfo = device;
             item.isSelected = false;
+            bool isConnecting = false;
+            if (hasClick && connectingInfo != nullptr &&
+                (memcmp(connectingInfo->addr, device.addr, BD_ADDR_LEN) == 0) &&
+                !bt_is_acl_connected(reinterpret_cast<const bd_addr_t*>(device.addr))) {
+                isConnecting = true;
+            }
+            item.isConnecting = isConnecting;
             displayList_.push_back(item);
             connectedCount++;
-            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Added my device (unconnected): %s", device.deviceName);
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Added my device (unconnected, connecting=%d): %s",
+                          isConnecting, device.deviceName);
         }
     }
     
@@ -274,9 +394,19 @@ void ThunderBirdBlueListAdapter::BuildDisplayList()
         item.type = DeviceItemType::DEVICE_NEARBY;
         item.deviceInfo = device;
         item.isSelected = false;
+        // 判断是否为当前正在发起连接的设备(用于显示“连接中”动画)
+        bool hasClick = btModel->IsTagScanDeviceClicked();
+        BluetoothCaseInfo* connectingInfo = hasClick ? btModel->GetTempMacValue() : nullptr;
+        bool isConnecting = false;
+        if (hasClick && connectingInfo != nullptr &&
+            (memcmp(connectingInfo->addr, device.addr, BD_ADDR_LEN) == 0)) {
+            isConnecting = true;
+        }
+        item.isConnecting = isConnecting;
         displayList_.push_back(item);
         nearbyCount++;
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Added nearby device: %s", device.deviceName);
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Added nearby device: %s, connecting=%d",
+                      device.deviceName, isConnecting);
     }
     
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "BuildDisplayList done: connected=%d, nearby=%d, total=%d",
@@ -323,22 +453,28 @@ UIView* ThunderBirdBlueListAdapter::GetView(UIView* inView, int16_t index)
         case DeviceItemType::SECTION_HEADER_CONNECTED:
             WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Setting SECTION_HEADER_CONNECTED");
             item->SetSectionHeader("我的设备");
+            item->SetConnecting(false);
             break;
         case DeviceItemType::SECTION_HEADER_NEARBY:
             WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Setting SECTION_HEADER_NEARBY");
             item->SetSectionHeader("附近的设备");
+            item->SetConnecting(false);
             break;
         case DeviceItemType::DEVICE_CONNECTED: {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Setting DEVICE_CONNECTED: %s", it->deviceInfo.deviceName);
             // 仅对当前实际已连接的设备显示橙色小圆点
             bool isConnectedNow = bt_is_acl_connected(reinterpret_cast<const bd_addr_t*>(it->deviceInfo.addr));
             item->SetDeviceInfo(it->deviceInfo, isConnectedNow);
+            // “连接中”动画:仅对未连接但标记为 isConnecting 的设备显示
+            bool showConnecting = (!isConnectedNow) && it->isConnecting;
+            item->SetConnecting(showConnecting);
             item->SetSelected(index == selectedIndex_);
             break;
         }
         case DeviceItemType::DEVICE_NEARBY:
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Setting DEVICE_NEARBY: %s", it->deviceInfo.deviceName);
             item->SetDeviceInfo(it->deviceInfo, false);
+            item->SetConnecting(it->isConnecting);
             item->SetSelected(index == selectedIndex_);
             break;
         default:
index 7663c61..9350f48 100644 (file)
@@ -51,7 +51,6 @@ namespace OHOS
         if (DeviceList != nullptr) { delete DeviceList; DeviceList = nullptr; }
         if (deviceListAdapter_ != nullptr) { delete deviceListAdapter_; deviceListAdapter_ = nullptr; }
         if (searchAnimator != nullptr) { delete searchAnimator; searchAnimator = nullptr; }
-        if (selectAnimator != nullptr) { delete selectAnimator; selectAnimator = nullptr; }
     }
 
     bool ThunderBirdBlueView::EnsureNetAnimator()
@@ -95,41 +94,6 @@ namespace OHOS
         return true;
     }
 
-    bool ThunderBirdBlueView::EnsureSelectAnimator()
-    {
-        if (selectAnimator == nullptr)
-        {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdBlueView::EnsureSelectAnimator: 创建选择动画");
-            selectPathsArray = TB_BLUE_SELECT_PATHS;
-            selectAnimator = new UIImageAnimatorView();
-            if (selectAnimator == nullptr)
-            {
-                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdBlueView new UIImageAnimatorView fail");
-                return false;
-            }
-            selectAnimator->SetAutoEnable(false);
-            for (uint8_t i = 0; i < TB_BLUE_SELECT_ANIM_FRAMES; i++)
-            {
-                selectImageInfo[i].imagePath = (selectPathsArray[i]);
-                selectImageInfo[i].imageType = IMG_SRC_FILE_PATH;
-                selectImageInfo[i].pos.x = TB_BLUE_SELECT_ANIM_X;
-                selectImageInfo[i].pos.y = TB_BLUE_SELECT_ANIM_Y;
-                selectImageInfo[i].width = TB_BLUE_SELECT_ANIM_W;
-                selectImageInfo[i].height = TB_BLUE_SELECT_ANIM_H;
-            }
-            selectAnimator->SetPosition(TB_BLUE_SELECT_ANIM_X, TB_BLUE_SELECT_ANIM_Y, TB_BLUE_SELECT_ANIM_W, TB_BLUE_SELECT_ANIM_H);
-            selectAnimator->SetStyle(STYLE_BACKGROUND_COLOR, 0xffffffff);
-            selectAnimator->SetStyle(STYLE_BACKGROUND_OPA, 0x00);
-            selectAnimator->SetImageAnimatorSrc(selectImageInfo, TB_BLUE_SELECT_ANIM_FRAMES, TB_BLUE_SELECT_ANIM_INTERVAL);
-            selectAnimator->SetRepeat(true);
-            selectAnimator->SetRepeatTimes(1);
-            selectAnimator->SetResizeMode(UIImageView::COVER);
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdBlueView::EnsureSelectAnimator: 动画配置完成,位置=(%d,%d), 大小=(%d,%d), 帧数=%d", 
-                         TB_BLUE_SELECT_ANIM_X, TB_BLUE_SELECT_ANIM_Y, TB_BLUE_SELECT_ANIM_W, TB_BLUE_SELECT_ANIM_H, TB_BLUE_SELECT_ANIM_FRAMES);
-        }
-        return true;
-    }
-
     void ThunderBirdBlueView::InitDeviceListAdapter(void)
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdBlueView::InitDeviceListAdapter");
@@ -261,12 +225,7 @@ namespace OHOS
         {
             return nullptr;
         }
-        if(!EnsureSelectAnimator())
-        {
-            return nullptr;
-        }
         group->Add(searchAnimator);
-        group->Add(selectAnimator);
         
         // 初始化设备列表适配器
         InitDeviceListAdapter();
@@ -291,7 +250,6 @@ namespace OHOS
         if (RemindIcon4) { RemindIcon4->SetVisible(false); }
         if (DeviceList) { DeviceList->SetVisible(false); }
         if (searchAnimator) { searchAnimator->SetVisible(false); searchAnimator->Stop(); }
-        if (selectAnimator) { selectAnimator->SetVisible(false); selectAnimator->Stop(); }
         
         switch (showView)
         {
@@ -461,13 +419,6 @@ namespace OHOS
                 searchAnimator->Stop();
             }
             
-            // 显示选择动画
-            if (selectAnimator)
-            {
-                // selectAnimator->SetVisible(true);
-                // selectAnimator->Start();
-            }
-            
             // 不显示标题(列表中已有分组标题)
             if (TextLabel)
             {
@@ -845,8 +796,14 @@ namespace OHOS
             return;
         }
         
-        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "OnKeyConfirm: connecting to %s", 
-                      selectedDevice->deviceName);
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "OnKeyConfirm: connecting to %s,addr:%02x%02x%02x%02x%02x%02x",
+            selectedDevice->deviceName,
+            selectedDevice->addr[5], 
+            selectedDevice->addr[4], 
+            selectedDevice->addr[3], 
+            selectedDevice->addr[2], 
+            selectedDevice->addr[1], 
+            selectedDevice->addr[0]);
         
         // 设置临时MAC值并发起连接
         BluetoothModel::GetInstance()->SetTempMacValue(selectedDevice);
@@ -873,20 +830,12 @@ namespace OHOS
             BluetoothModel::GetInstance()->DisconnectRemoteDevice();
             BluetoothModel::GetInstance()->SetTagConnectNew(true);
         }
+
+        RefreshDeviceList();
+
         // 发起连接
-        int ret = BluetoothModel::GetInstance()->ConnectRemoteDevice(
-            (const bd_addr_t*)&selectedDevice->addr);
-        
-        if (ret != true) {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ConnectRemoteDevice failed: %d", ret);
-            // 可以在这里显示连接失败提示
-            if(ThunderBirdMainView::GetInstance()) {
-                int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView();
-                ThunderBirdMainView::GetInstance()->ChangeView(currentView, 
-                    THUNDERBIRD_BLUEVIEW, 
-                    ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_CONNECT_FAILED);
-            }
-        }
+        BluetoothModel::GetInstance()->ConnectRemoteDevice((const bd_addr_t*)&selectedDevice->addr);
+        return;
     }
 
     // 处理连接失败操作:重新发送连接操作
@@ -908,9 +857,16 @@ namespace OHOS
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GetTempMacValue failed");
             return;
         }
+        BluetoothModel::GetInstance()->SetTagScanDeviceClicked(true);
 
-        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "OnKeyConfirm: connecting to %s", 
-                      caseInfo->deviceName);
+        WEARABLE_LOGI(WEARABLE_LOG_MODULE_APP, "OnKeyConfirm: connecting to %s,addr:%02x%02x%02x%02x%02x%02x",
+            caseInfo->deviceName,
+            caseInfo->addr[5], 
+            caseInfo->addr[4], 
+            caseInfo->addr[3], 
+            caseInfo->addr[2], 
+            caseInfo->addr[1], 
+            caseInfo->addr[0]);
         
         // 判断是否已有连接
         bd_addr_t *lastAddr = BluetoothModel::GetInstance()->GetLastConnedAddr();
@@ -923,20 +879,11 @@ namespace OHOS
             BluetoothModel::GetInstance()->SetTagConnectNew(true);
         }
 
+        RefreshDeviceList();
+
         // 发起连接
-        int ret = BluetoothModel::GetInstance()->ConnectRemoteDevice(
-            (const bd_addr_t*)&caseInfo->addr);
-        
-        if (ret != true) {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ConnectRemoteDevice failed: %d", ret);
-            // 可以在这里显示连接失败提示
-            if(ThunderBirdMainView::GetInstance()) {
-                int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView();
-                ThunderBirdMainView::GetInstance()->ChangeView(currentView, 
-                    THUNDERBIRD_BLUEVIEW, 
-                    ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_CONNECT_FAILED);
-            }
-        }
+        BluetoothModel::GetInstance()->ConnectRemoteDevice((const bd_addr_t*)&caseInfo->addr);
+        return;
     }
     
     // 获取当前选中的设备索引
index 7c1013f..bdce460 100644 (file)
@@ -2874,10 +2874,30 @@ extern "C" {
     void ThunderBirdModel::HandleBluetoothEarphoneConnectStatus(int connectStatus)
     {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleBluetoothEarphoneConnectStatus: 收到蓝牙耳机连接状态通知,connectStatus=%d", connectStatus);
-        if(ThunderBirdMainView::GetInstance()){
-            int currentView = ThunderBirdMainView::GetInstance()->GetCurrentView(); //获取当前视图
-            ThunderBirdMainView::GetInstance()->earphoneIcon->SetVisible(connectStatus);
-            // ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_BLUEVIEW, ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_EXIT);
+        ThunderBirdMainView *mainView = ThunderBirdMainView::GetInstance();
+        if (mainView == nullptr) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "HandleBluetoothEarphoneConnectStatus: mainView nullptr");
+            return;
+        }
+
+        int currentView = mainView->GetCurrentView(); // 获取当前视图
+        // 更新耳机图标
+        if (mainView->earphoneIcon != nullptr) {
+            mainView->earphoneIcon->SetVisible(connectStatus != 0);
+        }
+
+        // 连接完成/失败后,停止列表中的“连接中”动画
+        // 逻辑:无论成功(1)还是失败(0),都认为一次连接流程结束,清除“正在连接”标志并刷新列表
+        BluetoothModel::GetInstance()->SetTagScanDeviceClicked(false);
+
+        if (currentView == THUNDERBIRD_BLUEVIEW) {
+            ThunderBirdBlueView *blueView = ThunderBirdBlueView::GetInstance();
+            if (blueView != nullptr) {
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+                              "HandleBluetoothEarphoneConnectStatus: refresh blue list, connectStatus=%d",
+                              connectStatus);
+                blueView->RefreshDeviceList();
+            }
         }
     }
 
index 4076756..028a445 100644 (file)
@@ -890,6 +890,7 @@ namespace OHOS
                 case ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_DISCONNECT_SUCCESS: 
                     //重新发送连接操作
                     ThunderBirdBlueView::GetInstance()->OnConnectFailed();
+                    ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_BLUEVIEW, ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_DEVICE_LIST);
                     break;
                 case ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_DEVICE_LIST:
                     // ThunderBirdBlueView::GetInstance()->OnKeyUp();// 音量+键:选择上一个设备
@@ -899,6 +900,7 @@ namespace OHOS
                 case ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_CONNECT_FAILED:
                     //重新发送连接操作
                     ThunderBirdBlueView::GetInstance()->OnConnectFailed();
+                    ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_BLUEVIEW, ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_DEVICE_LIST);
                     break;
             }
         }