blob: 9fc11f54a749d9ef1173d14dc96aba209c6e1d30 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <base/logging.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <cstdint>
#include "bta/include/bta_av_api.h"
#include "btif/include/btif_common.h"
#include "common/message_loop_thread.h"
#include "device/include/interop.h"
#include "include/hardware/bt_rc.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/btm_api_types.h"
#include "test/common/mock_functions.h"
#include "test/mock/mock_osi_alarm.h"
#include "test/mock/mock_osi_allocator.h"
#include "test/mock/mock_osi_list.h"
#include "types/raw_address.h"
#undef LOG_TAG
#include "avrcp_service.h"
#include "btif/src/btif_rc.cc"
namespace bluetooth {
namespace avrcp {
int VolChanged = 0;
AvrcpService* AvrcpService::instance_ = nullptr;
void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state,
bool queue){};
void AvrcpService::SendFolderUpdate(bool available_players,
bool addressed_players, bool uids){};
void AvrcpService::SendActiveDeviceChanged(const RawAddress& address){};
void AvrcpService::SendPlayerSettingsChanged(
std::vector<PlayerAttribute> attributes, std::vector<uint8_t> values){};
void AvrcpService::ServiceInterfaceImpl::Init(
MediaInterface* media_interface, VolumeInterface* volume_interface,
PlayerSettingsInterface* player_settings_interface){};
void AvrcpService::ServiceInterfaceImpl::RegisterBipServer(int psm){};
void AvrcpService::ServiceInterfaceImpl::UnregisterBipServer(){};
bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
const RawAddress& bdaddr) {
return true;
};
bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(
const RawAddress& bdaddr) {
return true;
};
void AvrcpService::ServiceInterfaceImpl::SetBipClientStatus(
const RawAddress& bdaddr, bool connected){};
bool AvrcpService::ServiceInterfaceImpl::Cleanup() { return true; };
AvrcpService* AvrcpService::Get() {
CHECK(instance_ == nullptr);
instance_ = new AvrcpService();
return instance_;
}
void AvrcpService::RegisterVolChanged(const RawAddress& bdaddr) {
VolChanged++;
}
} // namespace avrcp
} // namespace bluetooth
namespace {
int AVRC_BldResponse_ = 0;
int AVRC_BldCmd_ = 0;
} // namespace
uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING;
uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING;
const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
bool avrcp_absolute_volume_is_enabled() { return true; }
tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) {
AVRC_BldCmd_++;
return 0;
}
tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp,
BT_HDR** pp_pkt) {
AVRC_BldResponse_++;
return 0;
}
tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
return 0;
}
tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
uint8_t* p_buf, uint16_t* buf_len) {
return 0;
}
tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
uint8_t* p_buf, uint16_t buf_len) {
return 0;
}
tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
UNUSED_ATTR uint8_t* p_buf,
UNUSED_ATTR uint16_t buf_len) {
return 0;
}
void BTA_AvCloseRc(uint8_t rc_handle) {}
void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
BT_HDR* p_pkt) {}
void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
BT_HDR* p_pkt) {}
void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
tBTA_AV_STATE key_state) {}
void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
tBTA_AV_STATE key_state, uint8_t* p_msg,
uint8_t buf_len) {}
void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
uint8_t* p_data, uint16_t len) {}
void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
uint8_t* p_data, uint16_t len, uint32_t company_id) {}
void btif_av_clear_remote_suspend_flag(void) {}
bool btif_av_is_connected(void) { return true; }
bool btif_av_is_sink_enabled(void) { return true; }
RawAddress btif_av_sink_active_peer(void) { return RawAddress(); }
RawAddress btif_av_source_active_peer(void) { return RawAddress(); }
bool btif_av_stream_started_ready(void) { return false; }
bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
char* p_params, int param_len,
tBTIF_COPY_CBACK* p_copy_cback) {
return BT_STATUS_SUCCESS;
}
bool btif_av_src_sink_coexist_enabled() { return true; }
bool btif_av_is_connected_addr(const RawAddress& peer_address) { return true; }
bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) {
return false;
}
bool btif_av_peer_is_connected_source(const RawAddress& peer_address) {
return true;
}
bool btif_av_peer_is_sink(const RawAddress& peer_address) { return false; }
bool btif_av_peer_is_source(const RawAddress& peer_address) { return true; }
bool btif_av_both_enable(void) { return true; }
const char* dump_rc_event(uint8_t event) { return nullptr; }
const char* dump_rc_notification_event_id(uint8_t event_id) { return nullptr; }
const char* dump_rc_pdu(uint8_t pdu) { return nullptr; }
const char* dump_rc_opcode(uint8_t pdu) { return nullptr; }
static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread");
bt_status_t do_in_jni_thread(const base::Location& from_here,
base::OnceClosure task) {
if (!jni_thread.DoInThread(from_here, std::move(task))) {
LOG(ERROR) << __func__ << ": Post task to task runner failed!";
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
bool interop_match_addr(const interop_feature_t feature,
const RawAddress* addr) {
return false;
}
/**
* Test class to test selected functionality in hci/src/hci_layer.cc
*/
class BtifRcTest : public ::testing::Test {};
TEST_F(BtifRcTest, get_element_attr_rsp) {
RawAddress bd_addr;
btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr;
btif_rc_cb.rc_multi_cb[0].rc_connected = true;
btif_rc_cb.rc_multi_cb[0]
.rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP]
.is_rsp_pending = true;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
btrc_element_attr_val_t p_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
uint8_t num_attr = BTRC_MAX_ELEM_ATTR_SIZE + 1;
CHECK(get_element_attr_rsp(bd_addr, num_attr, p_attrs) == BT_STATUS_SUCCESS);
CHECK(AVRC_BldResponse_ == 1);
}
TEST_F(BtifRcTest, btif_rc_get_addr_by_handle) {
RawAddress get_bd_addr;
btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
btif_rc_get_addr_by_handle(0, get_bd_addr);
CHECK(kDeviceAddress == get_bd_addr);
}
static btrc_ctrl_callbacks_t btrc_ctrl_callbacks = {
.size = sizeof(btrc_ctrl_callbacks_t),
.passthrough_rsp_cb = NULL,
.groupnavigation_rsp_cb = NULL,
.connection_state_cb = NULL,
.getrcfeatures_cb = NULL,
.setplayerappsetting_rsp_cb = NULL,
.playerapplicationsetting_cb = NULL,
.playerapplicationsetting_changed_cb = NULL,
.setabsvol_cmd_cb = NULL,
.registernotification_absvol_cb = NULL,
.track_changed_cb = NULL,
.play_position_changed_cb = NULL,
.play_status_changed_cb = NULL,
.get_folder_items_cb = NULL,
.change_folder_path_cb = NULL,
.set_browsed_player_cb = NULL,
.set_addressed_player_cb = NULL,
.addressed_player_changed_cb = NULL,
.now_playing_contents_changed_cb = NULL,
.available_player_changed_cb = NULL,
.get_cover_art_psm_cb = NULL,
};
struct rc_connection_state_cb_t {
bool rc_state;
bool bt_state;
RawAddress raw_address;
};
struct rc_feature_cb_t {
int feature;
RawAddress raw_address;
};
static std::promise<rc_connection_state_cb_t> g_btrc_connection_state_promise;
static std::promise<rc_connection_state_cb_t>
g_btrc_browse_connection_state_promise;
static std::promise<rc_feature_cb_t> g_btrc_feature;
class BtifRcFeatureTest : public BtifRcTest {
protected:
void SetUp() override {
BtifRcTest::SetUp();
init_ctrl(&btrc_ctrl_callbacks);
jni_thread.StartUp();
btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& bd_addr,
int features) {
rc_feature_cb_t rc_feature = {
.feature = features,
.raw_address = bd_addr,
};
g_btrc_feature.set_value(rc_feature);
};
}
void TearDown() override {
bt_rc_ctrl_callbacks->getrcfeatures_cb = [](const RawAddress& bd_addr,
int features) {};
BtifRcTest::TearDown();
}
};
TEST_F(BtifRcFeatureTest, handle_rc_ctrl_features) {
AVRC_BldCmd_ = 0;
g_btrc_feature = std::promise<rc_feature_cb_t>();
std::future<rc_feature_cb_t> future = g_btrc_feature.get_future();
btif_rc_device_cb_t p_dev;
p_dev.peer_tg_features =
(BTA_AV_FEAT_RCTG | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT |
BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_BROWSE |
BTA_AV_FEAT_COVER_ARTWORK);
p_dev.rc_connected = true;
handle_rc_ctrl_features(&p_dev);
CHECK(AVRC_BldCmd_ == 1);
CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2)));
auto res = future.get();
LOG_INFO("FEATURES:%d", res.feature);
CHECK(res.feature == (BTRC_FEAT_ABSOLUTE_VOLUME | BTRC_FEAT_METADATA |
BTRC_FEAT_BROWSE | BTRC_FEAT_COVER_ARTWORK));
}
class BtifRcBrowseConnectionTest : public BtifRcTest {
protected:
void SetUp() override {
BtifRcTest::SetUp();
init_ctrl(&btrc_ctrl_callbacks);
jni_thread.StartUp();
btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state,
const RawAddress& bd_addr) {
rc_connection_state_cb_t rc_connection_state = {
.rc_state = rc_state,
.bt_state = bt_state,
.raw_address = bd_addr,
};
g_btrc_browse_connection_state_promise.set_value(rc_connection_state);
};
}
void TearDown() override {
bt_rc_ctrl_callbacks->connection_state_cb =
[](bool rc_state, bool bt_state, const RawAddress& bd_addr) {};
BtifRcTest::TearDown();
}
};
TEST_F(BtifRcBrowseConnectionTest, handle_rc_browse_connect) {
g_btrc_browse_connection_state_promise =
std::promise<rc_connection_state_cb_t>();
std::future<rc_connection_state_cb_t> future =
g_btrc_browse_connection_state_promise.get_future();
tBTA_AV_RC_BROWSE_OPEN browse_data = {
.status = BTA_AV_SUCCESS,
.rc_handle = 0,
};
btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
btif_rc_cb.rc_multi_cb[0].rc_connected = false;
/* process unit test handle_rc_browse_connect */
handle_rc_browse_connect(&browse_data);
CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2)));
auto res = future.get();
CHECK(res.bt_state == true);
}
class BtifRcConnectionTest : public BtifRcTest {
protected:
void SetUp() override {
BtifRcTest::SetUp();
init_ctrl(&btrc_ctrl_callbacks);
jni_thread.StartUp();
btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state,
const RawAddress& bd_addr) {
rc_connection_state_cb_t rc_connection_state = {
.rc_state = rc_state,
.bt_state = bt_state,
.raw_address = bd_addr,
};
g_btrc_connection_state_promise.set_value(rc_connection_state);
};
}
void TearDown() override {
bt_rc_ctrl_callbacks->connection_state_cb =
[](bool rc_state, bool bt_state, const RawAddress& bd_addr) {};
BtifRcTest::TearDown();
}
};
TEST_F(BtifRcConnectionTest, btif_rc_check_pending_cmd) {
AVRC_BldCmd_ = 0;
g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>();
std::future<rc_connection_state_cb_t> future =
g_btrc_connection_state_promise.get_future();
btif_rc_cb.rc_multi_cb[0].rc_handle = 0xff;
btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
btif_rc_cb.rc_multi_cb[0].rc_connected = true;
btif_rc_cb.rc_multi_cb[0].launch_cmd_pending |=
(RC_PENDING_ACT_REG_VOL | RC_PENDING_ACT_GET_CAP |
RC_PENDING_ACT_REPORT_CONN);
btif_rc_check_pending_cmd(kDeviceAddress);
CHECK(AVRC_BldCmd_ == 1);
CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(3)));
auto res = future.get();
CHECK(res.rc_state == true);
}
TEST_F(BtifRcConnectionTest, BTA_AV_RC_OPEN_EVT) {
g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>();
std::future<rc_connection_state_cb_t> future =
g_btrc_connection_state_promise.get_future();
/* handle_rc_connect */
tBTA_AV data = {
.rc_open =
{
.rc_handle = 0,
.cover_art_psm = 0,
.peer_features = 0,
.peer_ct_features = 0,
.peer_tg_features = (BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT),
.peer_addr = kDeviceAddress,
.status = BTA_AV_SUCCESS,
},
};
btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
btif_rc_cb.rc_multi_cb[0].rc_connected = false;
btif_rc_handler(BTA_AV_RC_OPEN_EVT, &data);
CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_connected == true);
CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_state ==
BTRC_CONNECTION_STATE_CONNECTED);
CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2)));
auto res = future.get();
CHECK(res.rc_state == true);
}
class BtifTrackChangeCBTest : public BtifRcTest {
protected:
void SetUp() override {
BtifRcTest::SetUp();
init_ctrl(&btrc_ctrl_callbacks);
jni_thread.StartUp();
btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& bd_addr,
uint8_t num_attr, btrc_element_attr_val_t* p_attrs) {
btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr;
};
}
void TearDown() override {
btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& bd_addr,
uint8_t num_attr, btrc_element_attr_val_t* p_attrs) {};
BtifRcTest::TearDown();
}
};
TEST_F(BtifTrackChangeCBTest, handle_get_metadata_attr_response) {
tBTA_AV_META_MSG meta_msg = {
.rc_handle = 0,
};
tAVRC_GET_ATTRS_RSP rsp = {
.status = AVRC_STS_NO_ERROR,
.num_attrs = 0,
};
btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
btif_rc_cb.rc_multi_cb[0].rc_connected = true;
handle_get_metadata_attr_response(&meta_msg, &rsp);
ASSERT_EQ(1, get_func_call_count("osi_free_and_reset"));
}