1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #undef LOG_TAG // Undefine the LOG_TAG by this compilation unit
18 #include "btif/src/btif_rc.cc"
19
20 #include <bluetooth/log.h>
21 #include <gtest/gtest.h>
22
23 #include <cstdint>
24 #include <future>
25
26 #include "bta/include/bta_av_api.h"
27 #include "btif/avrcp/avrcp_service.h"
28 #include "btif/include/btif_common.h"
29 #include "common/message_loop_thread.h"
30 #include "device/include/interop.h"
31 #include "include/hardware/bt_rc.h"
32 #include "stack/include/main_thread.h"
33 #include "test/common/mock_functions.h"
34 #include "test/mock/mock_osi_alarm.h"
35 #include "test/mock/mock_osi_allocator.h"
36 #include "test/mock/mock_osi_list.h"
37 #include "types/raw_address.h"
38
39 namespace bluetooth {
40 namespace avrcp {
41 int VolChanged = 0;
42 AvrcpService* AvrcpService::instance_ = nullptr;
43
SendMediaUpdate(bool,bool,bool)44 void AvrcpService::SendMediaUpdate(bool /*track_changed*/, bool /*play_state*/, bool /*queue*/) {}
SendFolderUpdate(bool,bool,bool)45 void AvrcpService::SendFolderUpdate(bool /*available_players*/, bool /*addressed_players*/,
46 bool /*uids*/) {}
SendPlayerSettingsChanged(std::vector<PlayerAttribute>,std::vector<uint8_t>)47 void AvrcpService::SendPlayerSettingsChanged(std::vector<PlayerAttribute> /*attributes*/,
48 std::vector<uint8_t> /*values*/) {}
Init(MediaInterface *,VolumeInterface *,PlayerSettingsInterface *)49 void AvrcpService::ServiceInterfaceImpl::Init(
50 MediaInterface* /*media_interface*/, VolumeInterface* /*volume_interface*/,
51 PlayerSettingsInterface* /*player_settings_interface*/) {}
RegisterBipServer(int)52 void AvrcpService::ServiceInterfaceImpl::RegisterBipServer(int /*psm*/) {}
UnregisterBipServer()53 void AvrcpService::ServiceInterfaceImpl::UnregisterBipServer() {}
ConnectDevice(const RawAddress &)54 bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(const RawAddress& /*bdaddr*/) {
55 return true;
56 }
DisconnectDevice(const RawAddress &)57 bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(const RawAddress& /*bdaddr*/) {
58 return true;
59 }
SetBipClientStatus(const RawAddress &,bool)60 void AvrcpService::ServiceInterfaceImpl::SetBipClientStatus(const RawAddress& /*bdaddr*/,
61 bool /*connected*/) {}
Cleanup()62 bool AvrcpService::ServiceInterfaceImpl::Cleanup() { return true; }
63
Get()64 AvrcpService* AvrcpService::Get() {
65 EXPECT_EQ(instance_, nullptr);
66 instance_ = new AvrcpService();
67 return instance_;
68 }
69
RegisterVolChanged(const RawAddress &)70 void AvrcpService::RegisterVolChanged(const RawAddress& /*bdaddr*/) { VolChanged++; }
71 } // namespace avrcp
72 } // namespace bluetooth
73
74 namespace {
75 const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
76 const uint8_t kRcHandle = 123;
77 } // namespace
78
btif_av_clear_remote_suspend_flag(const A2dpType)79 void btif_av_clear_remote_suspend_flag(const A2dpType /*local_a2dp_type*/) {}
btif_av_is_connected(const A2dpType)80 bool btif_av_is_connected(const A2dpType /*local_a2dp_type*/) { return true; }
btif_av_is_sink_enabled(void)81 bool btif_av_is_sink_enabled(void) { return true; }
btif_av_sink_active_peer(void)82 RawAddress btif_av_sink_active_peer(void) { return RawAddress(); }
btif_av_source_active_peer(void)83 RawAddress btif_av_source_active_peer(void) { return RawAddress(); }
btif_av_stream_started_ready(const A2dpType)84 bool btif_av_stream_started_ready(const A2dpType /*local_a2dp_type*/) { return false; }
btif_transfer_context(tBTIF_CBACK *,uint16_t,char *,int,tBTIF_COPY_CBACK *)85 bt_status_t btif_transfer_context(tBTIF_CBACK* /*p_cback*/, uint16_t /*event*/, char* /*p_params*/,
86 int /*param_len*/, tBTIF_COPY_CBACK* /*p_copy_cback*/) {
87 return BT_STATUS_SUCCESS;
88 }
btif_av_src_sink_coexist_enabled()89 bool btif_av_src_sink_coexist_enabled() { return true; }
btif_av_is_connected_addr(const RawAddress &,const A2dpType)90 bool btif_av_is_connected_addr(const RawAddress& /*peer_address*/,
91 const A2dpType /*local_a2dp_type*/) {
92 return true;
93 }
btif_av_peer_is_connected_sink(const RawAddress &)94 bool btif_av_peer_is_connected_sink(const RawAddress& /*peer_address*/) { return false; }
btif_av_peer_is_connected_source(const RawAddress &)95 bool btif_av_peer_is_connected_source(const RawAddress& /*peer_address*/) { return true; }
btif_av_peer_is_sink(const RawAddress &)96 bool btif_av_peer_is_sink(const RawAddress& /*peer_address*/) { return false; }
btif_av_peer_is_source(const RawAddress &)97 bool btif_av_peer_is_source(const RawAddress& /*peer_address*/) { return true; }
btif_av_both_enable(void)98 bool btif_av_both_enable(void) { return true; }
99
100 static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread");
do_in_jni_thread(base::OnceClosure task)101 bt_status_t do_in_jni_thread(base::OnceClosure task) {
102 if (!jni_thread.DoInThread(FROM_HERE, std::move(task))) {
103 log::error("Post task to task runner failed!");
104 return BT_STATUS_JNI_THREAD_ATTACH_ERROR;
105 }
106 return BT_STATUS_SUCCESS;
107 }
get_main_thread()108 bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; }
interop_match_addr(const interop_feature_t,const RawAddress *)109 bool interop_match_addr(const interop_feature_t /*feature*/, const RawAddress* /*addr*/) {
110 return false;
111 }
112
113 /**
114 * Test class to test selected functionality in hci/src/hci_layer.cc
115 */
116 class BtifRcTest : public ::testing::Test {
117 protected:
SetUp()118 void SetUp() override { reset_mock_function_count_map(); }
TearDown()119 void TearDown() override {}
120 };
121
TEST_F(BtifRcTest,get_element_attr_rsp)122 TEST_F(BtifRcTest, get_element_attr_rsp) {
123 btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
124 btif_rc_cb.rc_multi_cb[0].rc_connected = true;
125 btif_rc_cb.rc_multi_cb[0].rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].is_rsp_pending = true;
126 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
127
128 btrc_element_attr_val_t p_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
129 uint8_t num_attr = BTRC_MAX_ELEM_ATTR_SIZE + 1;
130
131 ASSERT_EQ(get_element_attr_rsp(kDeviceAddress, num_attr, p_attrs), BT_STATUS_SUCCESS);
132 ASSERT_EQ(1, get_func_call_count("AVRC_BldResponse"));
133 }
134
TEST_F(BtifRcTest,btif_rc_get_addr_by_handle)135 TEST_F(BtifRcTest, btif_rc_get_addr_by_handle) {
136 RawAddress bd_addr;
137
138 btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
139 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
140 btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
141
142 btif_rc_get_addr_by_handle(0, bd_addr);
143 ASSERT_EQ(kDeviceAddress, bd_addr);
144 }
145
146 static btrc_ctrl_callbacks_t default_btrc_ctrl_callbacks = {
147 .size = sizeof(btrc_ctrl_callbacks_t),
148 .passthrough_rsp_cb = [](const RawAddress& /* bd_addr */, int /* id */,
__anon3fbae4330202() 149 int /* key_state */) { FAIL(); },
__anon3fbae4330302() 150 .groupnavigation_rsp_cb = [](int /* id */, int /* key_state */) { FAIL(); },
151 .connection_state_cb = [](bool /* rc_connect */, bool /* bt_connect */,
__anon3fbae4330402() 152 const RawAddress& /* bd_addr */) { FAIL(); },
__anon3fbae4330502() 153 .getrcfeatures_cb = [](const RawAddress& /* bd_addr */, int /* features */) { FAIL(); },
154 .setplayerappsetting_rsp_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4330602() 155 uint8_t /* accepted */) { FAIL(); },
156 .playerapplicationsetting_cb = [](const RawAddress& /* bd_addr */, uint8_t /* num_attr */,
157 btrc_player_app_attr_t* /* app_attrs */,
158 uint8_t /* num_ext_attr */,
__anon3fbae4330702() 159 btrc_player_app_ext_attr_t* /* ext_attrs */) { FAIL(); },
160 .playerapplicationsetting_changed_cb =
__anon3fbae4330802() 161 [](const RawAddress& /* bd_addr */, const btrc_player_settings_t& /* vals */) {
162 FAIL();
163 },
164 .setabsvol_cmd_cb = [](const RawAddress& /* bd_addr */, uint8_t /* abs_vol */,
__anon3fbae4330902() 165 uint8_t /* label */) { FAIL(); },
166 .registernotification_absvol_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4330a02() 167 uint8_t /* label */) { FAIL(); },
168 .track_changed_cb = [](const RawAddress& /* bd_addr */, uint8_t /* num_attr */,
__anon3fbae4330b02() 169 btrc_element_attr_val_t* /* p_attrs */) { FAIL(); },
170 .play_position_changed_cb = [](const RawAddress& /* bd_addr */, uint32_t /* song_len */,
__anon3fbae4330c02() 171 uint32_t /* song_pos */) { FAIL(); },
172 .play_status_changed_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4330d02() 173 btrc_play_status_t /* play_status */) { FAIL(); },
174 .get_folder_items_cb = [](const RawAddress& /* bd_addr */, btrc_status_t /* status */,
175 const btrc_folder_items_t* /* folder_items */,
__anon3fbae4330e02() 176 uint8_t /* count */) { FAIL(); },
177 .change_folder_path_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4330f02() 178 uint32_t /* count */) { FAIL(); },
179 .set_browsed_player_cb = [](const RawAddress& /* bd_addr */, uint8_t /* num_items */,
__anon3fbae4331002() 180 uint8_t /* depth */) { FAIL(); },
181 .set_addressed_player_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4331102() 182 uint8_t /* status */) { FAIL(); },
183 .addressed_player_changed_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4331202() 184 uint16_t /* id */) { FAIL(); },
__anon3fbae4331302() 185 .now_playing_contents_changed_cb = [](const RawAddress& /* bd_addr */) { FAIL(); },
__anon3fbae4331402() 186 .available_player_changed_cb = [](const RawAddress& /* bd_addr */) { FAIL(); },
187 .get_cover_art_psm_cb = [](const RawAddress& /* bd_addr */,
__anon3fbae4331502() 188 const uint16_t /* psm */) { FAIL(); },
189 };
190 static btrc_ctrl_callbacks_t btrc_ctrl_callbacks = default_btrc_ctrl_callbacks;
191
192 struct rc_connection_state_cb_t {
193 bool rc_state;
194 bool bt_state;
195 RawAddress raw_address;
196 };
197
198 struct rc_feature_cb_t {
199 int feature;
200 RawAddress raw_address;
201 };
202
203 static std::promise<rc_connection_state_cb_t> g_btrc_connection_state_promise;
204 static std::promise<rc_feature_cb_t> g_btrc_feature;
205
206 class BtifRcWithCallbacksTest : public BtifRcTest {
207 protected:
SetUp()208 void SetUp() override {
209 BtifRcTest::SetUp();
210 btrc_ctrl_callbacks = default_btrc_ctrl_callbacks;
211 init_ctrl(&btrc_ctrl_callbacks);
212 jni_thread.StartUp();
213 btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& bd_addr, int features) {
214 rc_feature_cb_t rc_feature = {
215 .feature = features,
216 .raw_address = bd_addr,
217 };
218 g_btrc_feature.set_value(rc_feature);
219 };
220 }
221
TearDown()222 void TearDown() override {
223 jni_thread.ShutDown();
224 bt_rc_ctrl_callbacks->getrcfeatures_cb = [](const RawAddress& /*bd_addr*/, int /*features*/) {};
225 btrc_ctrl_callbacks = default_btrc_ctrl_callbacks;
226 BtifRcTest::TearDown();
227 }
228 };
229
TEST_F(BtifRcWithCallbacksTest,handle_rc_ctrl_features)230 TEST_F(BtifRcWithCallbacksTest, handle_rc_ctrl_features) {
231 g_btrc_feature = std::promise<rc_feature_cb_t>();
232 std::future<rc_feature_cb_t> future = g_btrc_feature.get_future();
233 btif_rc_device_cb_t p_dev;
234
235 p_dev.peer_tg_features =
236 (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_METADATA |
237 BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_BROWSE | BTA_AV_FEAT_COVER_ARTWORK);
238 p_dev.rc_connected = true;
239
240 handle_rc_ctrl_features(&p_dev);
241 ASSERT_EQ(1, get_func_call_count("AVRC_BldCommand"));
242
243 ASSERT_EQ(std::future_status::ready, future.wait_for(std::chrono::seconds(2)));
244 auto res = future.get();
245 log::info("FEATURES:{}", res.feature);
246 ASSERT_EQ(res.feature, (BTRC_FEAT_ABSOLUTE_VOLUME | BTRC_FEAT_METADATA | BTRC_FEAT_BROWSE |
247 BTRC_FEAT_COVER_ARTWORK));
248 }
249
250 class BtifRcBrowseConnectionTest : public BtifRcTest {
251 protected:
SetUp()252 void SetUp() override {
253 BtifRcTest::SetUp();
254 init_ctrl(&btrc_ctrl_callbacks);
255 jni_thread.StartUp();
256 btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state,
257 const RawAddress& bd_addr) {
258 rc_connection_state_cb_t rc_connection_state = {
259 .rc_state = rc_state,
260 .bt_state = bt_state,
261 .raw_address = bd_addr,
262 };
263 g_btrc_connection_state_promise.set_value(rc_connection_state);
264 };
265 }
266
TearDown()267 void TearDown() override {
268 jni_thread.ShutDown();
269 bt_rc_ctrl_callbacks->connection_state_cb = [](bool /*rc_state*/, bool /*bt_state*/,
270 const RawAddress& /*bd_addr*/) {};
271 BtifRcTest::TearDown();
272 }
273 };
274
TEST_F(BtifRcBrowseConnectionTest,handle_rc_browse_connect)275 TEST_F(BtifRcBrowseConnectionTest, handle_rc_browse_connect) {
276 g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>();
277 std::future<rc_connection_state_cb_t> future = g_btrc_connection_state_promise.get_future();
278
279 tBTA_AV_RC_BROWSE_OPEN browse_data = {
280 .rc_handle = 0,
281 .peer_addr = {},
282 .status = BTA_AV_SUCCESS,
283 };
284
285 btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
286 btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
287 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
288 btif_rc_cb.rc_multi_cb[0].rc_connected = false;
289
290 /* process unit test handle_rc_browse_connect */
291 handle_rc_browse_connect(&browse_data);
292 ASSERT_EQ(std::future_status::ready, future.wait_for(std::chrono::seconds(2)));
293 auto res = future.get();
294 ASSERT_TRUE(res.bt_state);
295 }
296
297 class BtifRcConnectionTest : public BtifRcTest {
298 protected:
SetUp()299 void SetUp() override {
300 BtifRcTest::SetUp();
301 init_ctrl(&btrc_ctrl_callbacks);
302 jni_thread.StartUp();
303 g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>();
304 g_btrc_connection_state_future = g_btrc_connection_state_promise.get_future();
305 btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state,
306 const RawAddress& bd_addr) {
307 rc_connection_state_cb_t rc_connection_state = {
308 .rc_state = rc_state,
309 .bt_state = bt_state,
310 .raw_address = bd_addr,
311 };
312 g_btrc_connection_state_promise.set_value(rc_connection_state);
313 };
314 }
315
TearDown()316 void TearDown() override {
317 jni_thread.ShutDown();
318 bt_rc_ctrl_callbacks->connection_state_cb = [](bool /*rc_state*/, bool /*bt_state*/,
319 const RawAddress& /*bd_addr*/) {};
320 BtifRcTest::TearDown();
321 }
322 std::future<rc_connection_state_cb_t> g_btrc_connection_state_future;
323 };
324
TEST_F(BtifRcConnectionTest,btif_rc_connection_test)325 TEST_F(BtifRcConnectionTest, btif_rc_connection_test) {}
326
TEST_F(BtifRcConnectionTest,handle_rc_browse_connect)327 TEST_F(BtifRcConnectionTest, handle_rc_browse_connect) {
328 tBTA_AV_RC_BROWSE_OPEN browse_data = {
329 .rc_handle = 0,
330 .peer_addr = {},
331 .status = BTA_AV_SUCCESS,
332 };
333
334 btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
335 btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
336 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
337 btif_rc_cb.rc_multi_cb[0].rc_connected = false;
338
339 /* process unit test handle_rc_browse_connect */
340 handle_rc_browse_connect(&browse_data);
341 ASSERT_EQ(std::future_status::ready,
342 g_btrc_connection_state_future.wait_for(std::chrono::seconds(2)));
343 auto res = g_btrc_connection_state_future.get();
344 ASSERT_TRUE(res.bt_state);
345 }
346
TEST_F(BtifRcConnectionTest,btif_rc_check_pending_cmd)347 TEST_F(BtifRcConnectionTest, btif_rc_check_pending_cmd) {
348 btif_rc_cb.rc_multi_cb[0].rc_handle = 0xff;
349 btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
350 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
351 btif_rc_cb.rc_multi_cb[0].rc_connected = true;
352 btif_rc_cb.rc_multi_cb[0].launch_cmd_pending |=
353 (RC_PENDING_ACT_REG_VOL | RC_PENDING_ACT_GET_CAP | RC_PENDING_ACT_REPORT_CONN);
354
355 btif_rc_check_pending_cmd(kDeviceAddress);
356 ASSERT_EQ(1, get_func_call_count("AVRC_BldCommand"));
357
358 ASSERT_EQ(std::future_status::ready,
359 g_btrc_connection_state_future.wait_for(std::chrono::seconds(3)));
360 auto res = g_btrc_connection_state_future.get();
361 ASSERT_TRUE(res.rc_state);
362 }
363
TEST_F(BtifRcConnectionTest,bt_av_rc_open_evt)364 TEST_F(BtifRcConnectionTest, bt_av_rc_open_evt) {
365 btrc_ctrl_callbacks.get_cover_art_psm_cb = [](const RawAddress& /* bd_addr */,
366 const uint16_t /* psm */) {};
367 btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& /* bd_addr */, int /* features */) {};
368
369 /* handle_rc_connect */
370 tBTA_AV data = {
371 .rc_open =
372 {
373 .rc_handle = 0,
374 .cover_art_psm = 0,
375 .peer_features = 0,
376 .peer_ct_features = 0,
377 .peer_tg_features = (BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
378 BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT),
379 .peer_addr = kDeviceAddress,
380 .status = BTA_AV_SUCCESS,
381 },
382 };
383 btif_rc_cb.rc_multi_cb[0].rc_handle = 0;
384 btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty;
385 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
386 btif_rc_cb.rc_multi_cb[0].rc_connected = false;
387
388 btif_rc_handler(BTA_AV_RC_OPEN_EVT, &data);
389
390 ASSERT_TRUE(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_connected);
391 ASSERT_EQ(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_state,
392 BTRC_CONNECTION_STATE_CONNECTED);
393
394 ASSERT_EQ(std::future_status::ready,
395 g_btrc_connection_state_future.wait_for(std::chrono::seconds(2)));
396 auto res = g_btrc_connection_state_future.get();
397 ASSERT_TRUE(res.rc_state);
398 }
399
400 class BtifTrackChangeCBTest : public BtifRcTest {
401 protected:
SetUp()402 void SetUp() override {
403 BtifRcTest::SetUp();
404 init_ctrl(&btrc_ctrl_callbacks);
405 jni_thread.StartUp();
406 btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& bd_addr, uint8_t /*num_attr*/,
407 btrc_element_attr_val_t* /*p_attrs*/) {
408 btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr;
409 };
410 }
411
TearDown()412 void TearDown() override {
413 jni_thread.ShutDown();
414 btrc_ctrl_callbacks.track_changed_cb = [](const RawAddress& /*bd_addr*/, uint8_t /*num_attr*/,
415 btrc_element_attr_val_t* /*p_attrs*/) {};
416 BtifRcTest::TearDown();
417 }
418 };
419
TEST_F(BtifTrackChangeCBTest,handle_get_metadata_attr_response)420 TEST_F(BtifTrackChangeCBTest, handle_get_metadata_attr_response) {
421 // Setup an already connected device
422 btif_rc_cb.rc_multi_cb[0].rc_connected = true;
423 btif_rc_cb.rc_multi_cb[0].br_connected = false;
424 btif_rc_cb.rc_multi_cb[0].rc_handle = kRcHandle;
425 btif_rc_cb.rc_multi_cb[0].rc_features = {};
426 btif_rc_cb.rc_multi_cb[0].rc_cover_art_psm = 0;
427 btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
428 btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress;
429 btif_rc_cb.rc_multi_cb[0].rc_pending_play = 0;
430 btif_rc_cb.rc_multi_cb[0].rc_volume = 0;
431 btif_rc_cb.rc_multi_cb[0].rc_vol_label = 0;
432 btif_rc_cb.rc_multi_cb[0].rc_supported_event_list = nullptr;
433 btif_rc_cb.rc_multi_cb[0].rc_app_settings = {};
434 btif_rc_cb.rc_multi_cb[0].rc_play_status_timer = nullptr;
435 btif_rc_cb.rc_multi_cb[0].rc_features_processed = false;
436 btif_rc_cb.rc_multi_cb[0].rc_playing_uid = 0;
437 btif_rc_cb.rc_multi_cb[0].rc_procedure_complete = false;
438 btif_rc_cb.rc_multi_cb[0].peer_ct_features = {};
439 btif_rc_cb.rc_multi_cb[0].peer_tg_features = {};
440 btif_rc_cb.rc_multi_cb[0].launch_cmd_pending = 0;
441 ASSERT_TRUE(btif_rc_get_device_by_handle(kRcHandle));
442
443 tBTA_AV_META_MSG meta_msg = {
444 .rc_handle = kRcHandle,
445 .len = 0,
446 .label = 0,
447 .code{},
448 .company_id = 0,
449 .p_data = {},
450 .p_msg = nullptr,
451 };
452
453 tAVRC_GET_ATTRS_RSP rsp = {
454 .pdu = 0,
455 .status = AVRC_STS_NO_ERROR,
456 .opcode = 0,
457 .num_attrs = 0,
458 .p_attrs = nullptr,
459 };
460
461 handle_get_metadata_attr_response(&meta_msg, &rsp);
462
463 ASSERT_EQ(1, get_func_call_count("osi_free_and_reset"));
464 }
465