// 连接远程设备\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
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
} 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
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
// 检查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;
}
// 检查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;
}
#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 {
DeviceItemType type;
BluetoothCaseInfo deviceInfo;
bool isSelected;
+ bool isConnecting; // 是否是“连接中”状态(用于显示右侧 loading 动画)
};
// 蓝牙设备列表项视图
void SetSectionHeader(const char* title);
// 设置选中状态
void SetSelected(bool selected);
+ // 设置是否处于“连接中”状态(显示/隐藏右侧 loading 动画)
+ void SetConnecting(bool connecting);
// 获取设备信息
BluetoothCaseInfo* GetDeviceInfo(void);
// 检查是否是分组标题
UILabel nameLabel_; // 设备名称标签
UIImageView connectedIcon_; // 已连接图标(小圆点)
UIImageView borderImage_; // 选中边框
+ UIImageAnimatorView *connectingAnimator_; // 连接中 loading 动画
BluetoothCaseInfo deviceInfo_{};
bool isSelected_{false};
bool isSectionHeader_{false};
bool isConnected_{false};
+ bool isConnecting_{false};
};
// 蓝牙设备列表适配器
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,
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;
// 动画组件
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};
#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;
// 颜色定义
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; // 已连接指示点颜色(绿色)
//========================================
Remove(&borderImage_);
Remove(&nameLabel_);
Remove(&connectedIcon_);
+ Remove(connectingAnimator_);
+ if(connectingAnimator_)
+ {
+ connectingAnimator_->Stop();
+ delete connectingAnimator_;
+ connectingAnimator_ = nullptr;
+ }
}
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);
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;
// 显示/隐藏已连接指示
connectedIcon_.SetVisible(isConnected);
+
+ // “连接中”动画状态由 SetConnecting 控制,这里不做处理
Invalidate();
}
isSectionHeader_ = true;
isConnected_ = false;
+ isConnecting_ = false;
// 设置标题文字
nameLabel_.SetText(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_);
node = node->next_;
}
- // 第二步:优先添加已连接的设备
+ // 获取当前正在尝试连接的设备(用于判断“连接中”状态)
+ bool hasClick = btModel->IsTagScanDeviceClicked();
+ BluetoothCaseInfo* connectingInfo = hasClick ? btModel->GetTempMacValue() : nullptr;
+
+ // 第二步:优先添加已连接的设备(已连接的不显示 loading)
for (auto& device : connectedDevicesList) {
if (connectedCount >= MAX_CONNECTED_DEVICES) {
break;
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;
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);
}
}
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",
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:
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()
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");
{
return nullptr;
}
- if(!EnsureSelectAnimator())
- {
- return nullptr;
- }
group->Add(searchAnimator);
- group->Add(selectAnimator);
// 初始化设备列表适配器
InitDeviceListAdapter();
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)
{
searchAnimator->Stop();
}
- // 显示选择动画
- if (selectAnimator)
- {
- // selectAnimator->SetVisible(true);
- // selectAnimator->Start();
- }
-
// 不显示标题(列表中已有分组标题)
if (TextLabel)
{
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);
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;
}
// 处理连接失败操作:重新发送连接操作
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();
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;
}
// 获取当前选中的设备索引
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();
+ }
}
}
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();// 音量+键:选择上一个设备
case ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_CONNECT_FAILED:
//重新发送连接操作
ThunderBirdBlueView::GetInstance()->OnConnectFailed();
+ ThunderBirdMainView::GetInstance()->ChangeView(currentView, THUNDERBIRD_BLUEVIEW, ThunderBirdBlueView::THUNDERBIRD_BULEVIEW_DEVICE_LIST);
break;
}
}