1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "devices.h"
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <map>
24
25 #include "bta_gatt_api_mock.h"
26 #include "bta_gatt_queue_mock.h"
27 #include "btm_api_mock.h"
28 #include "gatt/database_builder.h"
29 #include "stack/include/bt_uuid16.h"
30 #include "types/bluetooth/uuid.h"
31 #include "types/raw_address.h"
32
33 namespace bluetooth {
34 namespace vc {
35 namespace internal {
36
37 using ::testing::_;
38 using ::testing::DoAll;
39 using ::testing::Invoke;
40 using ::testing::Mock;
41 using ::testing::Return;
42 using ::testing::SetArgPointee;
43 using ::testing::Test;
44
GetTestAddress(int index)45 RawAddress GetTestAddress(int index) {
46 EXPECT_LT(index, UINT8_MAX);
47 RawAddress result = {
48 {0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}};
49 return result;
50 }
51
52 class VolumeControlDevicesTest : public ::testing::Test {
53 protected:
SetUp()54 void SetUp() override {
55 devices_ = new VolumeControlDevices();
56 gatt::SetMockBtaGattInterface(&gatt_interface);
57 gatt::SetMockBtaGattQueue(&gatt_queue);
58 }
59
TearDown()60 void TearDown() override {
61 gatt::SetMockBtaGattQueue(nullptr);
62 gatt::SetMockBtaGattInterface(nullptr);
63 delete devices_;
64 }
65
66 VolumeControlDevices* devices_ = nullptr;
67 gatt::MockBtaGattInterface gatt_interface;
68 gatt::MockBtaGattQueue gatt_queue;
69 };
70
TEST_F(VolumeControlDevicesTest,test_add)71 TEST_F(VolumeControlDevicesTest, test_add) {
72 RawAddress test_address_0 = GetTestAddress(0);
73 ASSERT_EQ((size_t)0, devices_->Size());
74 devices_->Add(test_address_0, true);
75 ASSERT_EQ((size_t)1, devices_->Size());
76 }
77
TEST_F(VolumeControlDevicesTest,test_add_twice)78 TEST_F(VolumeControlDevicesTest, test_add_twice) {
79 RawAddress test_address_0 = GetTestAddress(0);
80 ASSERT_EQ((size_t)0, devices_->Size());
81 devices_->Add(test_address_0, true);
82 devices_->Add(test_address_0, true);
83 ASSERT_EQ((size_t)1, devices_->Size());
84 }
85
TEST_F(VolumeControlDevicesTest,test_remove)86 TEST_F(VolumeControlDevicesTest, test_remove) {
87 RawAddress test_address_0 = GetTestAddress(0);
88 RawAddress test_address_1 = GetTestAddress(1);
89 devices_->Add(test_address_0, true);
90 devices_->Add(test_address_1, true);
91 ASSERT_EQ((size_t)2, devices_->Size());
92 devices_->Remove(test_address_0);
93 ASSERT_EQ((size_t)1, devices_->Size());
94 }
95
TEST_F(VolumeControlDevicesTest,test_clear)96 TEST_F(VolumeControlDevicesTest, test_clear) {
97 RawAddress test_address_0 = GetTestAddress(0);
98 ASSERT_EQ((size_t)0, devices_->Size());
99 devices_->Add(test_address_0, true);
100 ASSERT_EQ((size_t)1, devices_->Size());
101 devices_->Clear();
102 ASSERT_EQ((size_t)0, devices_->Size());
103 }
104
TEST_F(VolumeControlDevicesTest,test_find_by_address)105 TEST_F(VolumeControlDevicesTest, test_find_by_address) {
106 RawAddress test_address_0 = GetTestAddress(0);
107 RawAddress test_address_1 = GetTestAddress(1);
108 RawAddress test_address_2 = GetTestAddress(2);
109 devices_->Add(test_address_0, true);
110 devices_->Add(test_address_1, false);
111 devices_->Add(test_address_2, true);
112 VolumeControlDevice* device = devices_->FindByAddress(test_address_1);
113 ASSERT_NE(nullptr, device);
114 ASSERT_EQ(test_address_1, device->address);
115 }
116
TEST_F(VolumeControlDevicesTest,test_find_by_conn_id)117 TEST_F(VolumeControlDevicesTest, test_find_by_conn_id) {
118 RawAddress test_address_0 = GetTestAddress(0);
119 devices_->Add(test_address_0, true);
120 VolumeControlDevice* test_device = devices_->FindByAddress(test_address_0);
121 test_device->connection_id = 0x0005;
122 ASSERT_NE(nullptr, devices_->FindByConnId(test_device->connection_id));
123 }
124
TEST_F(VolumeControlDevicesTest,test_disconnect)125 TEST_F(VolumeControlDevicesTest, test_disconnect) {
126 RawAddress test_address_0 = GetTestAddress(0);
127 RawAddress test_address_1 = GetTestAddress(1);
128 devices_->Add(test_address_0, true);
129 devices_->Add(test_address_1, true);
130 VolumeControlDevice* test_device_0 = devices_->FindByAddress(test_address_0);
131 test_device_0->connection_id = 0x0005;
132 tGATT_IF gatt_if = 8;
133 EXPECT_CALL(gatt_interface, Close(test_device_0->connection_id));
134 devices_->Disconnect(gatt_if);
135 }
136
TEST_F(VolumeControlDevicesTest,test_control_point_operation)137 TEST_F(VolumeControlDevicesTest, test_control_point_operation) {
138 uint8_t opcode = 50;
139 std::vector<RawAddress> devices;
140
141 for (int i = 5; i > 0; i--) {
142 RawAddress test_address = GetTestAddress(i);
143 devices.push_back(test_address);
144 uint8_t change_counter = 10 * i;
145 uint16_t control_point_handle = 0x0020 + i;
146 uint16_t connection_id = i;
147 devices_->Add(test_address, true);
148 VolumeControlDevice* device = devices_->FindByAddress(test_address);
149 device->connection_id = connection_id;
150 device->change_counter = change_counter;
151 device->volume_control_point_handle = control_point_handle;
152 std::vector<uint8_t> data_expected({opcode, change_counter});
153
154 EXPECT_CALL(gatt_queue,
155 WriteCharacteristic(connection_id, control_point_handle,
156 data_expected, GATT_WRITE, _, _));
157 }
158
159 const std::vector<uint8_t>* arg = nullptr;
160 GATT_WRITE_OP_CB cb = nullptr;
161 void* cb_data = nullptr;
162 devices_->ControlPointOperation(devices, opcode, arg, cb, cb_data);
163 }
164
TEST_F(VolumeControlDevicesTest,test_control_point_operation_args)165 TEST_F(VolumeControlDevicesTest, test_control_point_operation_args) {
166 uint8_t opcode = 60;
167 uint8_t arg_1 = 0x02;
168 uint8_t arg_2 = 0x05;
169 std::vector<RawAddress> devices;
170
171 for (int i = 5; i > 0; i--) {
172 RawAddress test_address = GetTestAddress(i);
173 devices.push_back(test_address);
174 uint8_t change_counter = 10 * i;
175 uint16_t control_point_handle = 0x0020 + i;
176 uint16_t connection_id = i;
177 devices_->Add(test_address, true);
178 VolumeControlDevice* device = devices_->FindByAddress(test_address);
179 device->connection_id = connection_id;
180 device->change_counter = change_counter;
181 device->volume_control_point_handle = control_point_handle;
182 std::vector<uint8_t> data_expected({opcode, change_counter, arg_1, arg_2});
183
184 EXPECT_CALL(gatt_queue,
185 WriteCharacteristic(connection_id, control_point_handle,
186 data_expected, GATT_WRITE, _, _));
187 }
188
189 std::vector<uint8_t> arg({arg_1, arg_2});
190 GATT_WRITE_OP_CB cb = nullptr;
191 void* cb_data = nullptr;
192 devices_->ControlPointOperation(devices, opcode, &arg, cb, cb_data);
193 }
194
TEST_F(VolumeControlDevicesTest,test_control_point_skip_not_connected)195 TEST_F(VolumeControlDevicesTest, test_control_point_skip_not_connected) {
196 RawAddress test_address = GetTestAddress(1);
197 devices_->Add(test_address, true);
198 VolumeControlDevice* device = devices_->FindByAddress(test_address);
199 device->connection_id = GATT_INVALID_CONN_ID;
200 uint16_t control_point_handle = 0x0020;
201 device->volume_control_point_handle = control_point_handle;
202
203 EXPECT_CALL(gatt_queue,
204 WriteCharacteristic(_, control_point_handle, _, _, _, _))
205 .Times(0);
206
207 uint8_t opcode = 5;
208 std::vector<RawAddress> devices = {test_address};
209 const std::vector<uint8_t>* arg = nullptr;
210 GATT_WRITE_OP_CB cb = nullptr;
211 void* cb_data = nullptr;
212 devices_->ControlPointOperation(devices, opcode, arg, cb, cb_data);
213 }
214
215 class VolumeControlDeviceTest : public ::testing::Test {
216 protected:
SetUp()217 void SetUp() override {
218 device = new VolumeControlDevice(GetTestAddress(1), true);
219 gatt::SetMockBtaGattInterface(&gatt_interface);
220 gatt::SetMockBtaGattQueue(&gatt_queue);
221 bluetooth::manager::SetMockBtmInterface(&btm_interface);
222
223 ON_CALL(gatt_interface, GetCharacteristic(_, _))
224 .WillByDefault(
225 Invoke([&](uint16_t conn_id,
226 uint16_t handle) -> const gatt::Characteristic* {
227 for (auto const& service : services) {
228 for (auto const& characteristic : service.characteristics) {
229 if (characteristic.value_handle == handle) {
230 return &characteristic;
231 }
232 }
233 }
234
235 return nullptr;
236 }));
237
238 ON_CALL(gatt_interface, GetOwningService(_, _))
239 .WillByDefault(Invoke(
240 [&](uint16_t conn_id, uint16_t handle) -> const gatt::Service* {
241 for (auto const& service : services) {
242 if (service.handle <= handle && service.end_handle >= handle) {
243 return &service;
244 }
245 }
246
247 return nullptr;
248 }));
249
250 ON_CALL(gatt_interface, GetServices(_)).WillByDefault(Return(&services));
251 }
252
TearDown()253 void TearDown() override {
254 bluetooth::manager::SetMockBtmInterface(nullptr);
255 gatt::SetMockBtaGattQueue(nullptr);
256 gatt::SetMockBtaGattInterface(nullptr);
257 delete device;
258 }
259
260 /* sample database 1xVCS, 2xAICS, 2xVOCS */
SetSampleDatabase1(void)261 void SetSampleDatabase1(void) {
262 gatt::DatabaseBuilder builder;
263 builder.AddService(0x0001, 0x0016, kVolumeControlUuid, true);
264 builder.AddIncludedService(0x0004, kVolumeOffsetUuid, 0x0060, 0x0069);
265 builder.AddIncludedService(0x0005, kVolumeOffsetUuid, 0x0080, 0x008b);
266 builder.AddCharacteristic(
267 0x0010, 0x0011, kVolumeControlStateUuid,
268 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
269 builder.AddDescriptor(0x0012,
270 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
271 builder.AddCharacteristic(0x0013, 0x0014, kVolumeControlPointUuid,
272 GATT_CHAR_PROP_BIT_WRITE);
273 builder.AddCharacteristic(0x0015, 0x0016, kVolumeFlagsUuid,
274 GATT_CHAR_PROP_BIT_READ);
275 builder.AddService(0x0060, 0x0069, kVolumeOffsetUuid, false);
276 builder.AddCharacteristic(
277 0x0061, 0x0062, kVolumeOffsetStateUuid,
278 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
279 builder.AddDescriptor(0x0063,
280 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
281 builder.AddCharacteristic(0x0064, 0x0065, kVolumeOffsetLocationUuid,
282 GATT_CHAR_PROP_BIT_READ);
283 builder.AddCharacteristic(0x0066, 0x0067, kVolumeOffsetControlPointUuid,
284 GATT_CHAR_PROP_BIT_WRITE);
285 builder.AddCharacteristic(0x0068, 0x0069,
286 kVolumeOffsetOutputDescriptionUuid,
287 GATT_CHAR_PROP_BIT_READ);
288 builder.AddService(0x0080, 0x008b, kVolumeOffsetUuid, false);
289 builder.AddCharacteristic(
290 0x0081, 0x0082, kVolumeOffsetStateUuid,
291 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
292 builder.AddDescriptor(0x0083,
293 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
294 builder.AddCharacteristic(0x0084, 0x0085, kVolumeOffsetLocationUuid,
295 GATT_CHAR_PROP_BIT_READ |
296 GATT_CHAR_PROP_BIT_WRITE_NR |
297 GATT_CHAR_PROP_BIT_NOTIFY);
298 builder.AddDescriptor(0x0086,
299 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
300 builder.AddCharacteristic(0x0087, 0x0088, kVolumeOffsetControlPointUuid,
301 GATT_CHAR_PROP_BIT_WRITE);
302 builder.AddCharacteristic(
303 0x0089, 0x008a, kVolumeOffsetOutputDescriptionUuid,
304 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE_NR |
305 GATT_CHAR_PROP_BIT_NOTIFY);
306 builder.AddDescriptor(0x008b,
307 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
308 builder.AddService(0x00a0, 0x00a3,
309 Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER), true);
310 builder.AddCharacteristic(0x00a1, 0x00a2,
311 Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD),
312 GATT_CHAR_PROP_BIT_NOTIFY);
313 builder.AddDescriptor(0x00a3,
314 Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
315 services = builder.Build().Services();
316 ASSERT_EQ(true, device->UpdateHandles());
317 }
318
319 /* sample database no VCS */
SetSampleDatabase2(void)320 void SetSampleDatabase2(void) {
321 gatt::DatabaseBuilder builder;
322 builder.AddService(0x0001, 0x0003, Uuid::From16Bit(0x1800), true);
323 builder.AddCharacteristic(0x0002, 0x0003, Uuid::From16Bit(0x2a00),
324 GATT_CHAR_PROP_BIT_READ);
325 services = builder.Build().Services();
326 ASSERT_EQ(false, device->UpdateHandles());
327 }
328
329 VolumeControlDevice* device = nullptr;
330 gatt::MockBtaGattInterface gatt_interface;
331 gatt::MockBtaGattQueue gatt_queue;
332 bluetooth::manager::MockBtmInterface btm_interface;
333 std::list<gatt::Service> services;
334 };
335
TEST_F(VolumeControlDeviceTest,test_service_volume_control_not_found)336 TEST_F(VolumeControlDeviceTest, test_service_volume_control_not_found) {
337 SetSampleDatabase2();
338 ASSERT_EQ(false, device->HasHandles());
339 }
340
TEST_F(VolumeControlDeviceTest,test_service_volume_control_incomplete)341 TEST_F(VolumeControlDeviceTest, test_service_volume_control_incomplete) {
342 gatt::DatabaseBuilder builder;
343 builder.AddService(0x0001, 0x0006, kVolumeControlUuid, true);
344 builder.AddCharacteristic(
345 0x0002, 0x0003, kVolumeControlStateUuid,
346 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
347 builder.AddDescriptor(0x0004, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
348 builder.AddCharacteristic(0x0005, 0x0006, kVolumeControlPointUuid,
349 GATT_CHAR_PROP_BIT_WRITE);
350 /* no Volume Control Flags characteristic */
351 services = builder.Build().Services();
352 ASSERT_EQ(false, device->UpdateHandles());
353 ASSERT_EQ(0x0000, device->volume_state_handle);
354 ASSERT_EQ(0x0000, device->volume_state_ccc_handle);
355 ASSERT_EQ(0x0000, device->volume_control_point_handle);
356 ASSERT_EQ(0x0000, device->volume_flags_handle);
357 ASSERT_EQ(0x0000, device->volume_flags_ccc_handle);
358 ASSERT_EQ(false, device->HasHandles());
359 }
360
TEST_F(VolumeControlDeviceTest,test_service_vocs_incomplete)361 TEST_F(VolumeControlDeviceTest, test_service_vocs_incomplete) {
362 gatt::DatabaseBuilder builder;
363 builder.AddService(0x0001, 0x000a, kVolumeControlUuid, true);
364 builder.AddIncludedService(0x0002, kVolumeOffsetUuid, 0x000b, 0x0013);
365 builder.AddCharacteristic(
366 0x0003, 0x0004, kVolumeControlStateUuid,
367 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
368 builder.AddDescriptor(0x0005, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
369 builder.AddCharacteristic(0x0006, 0x0007, kVolumeControlPointUuid,
370 GATT_CHAR_PROP_BIT_WRITE);
371 builder.AddCharacteristic(
372 0x0008, 0x0009, kVolumeFlagsUuid,
373 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
374 builder.AddDescriptor(0x000a, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
375 builder.AddService(0x000b, 0x0013, kVolumeOffsetUuid, false);
376 builder.AddCharacteristic(
377 0x000c, 0x000d, kVolumeOffsetStateUuid,
378 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
379 builder.AddDescriptor(0x000e, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
380 builder.AddCharacteristic(
381 0x000f, 0x0010, kVolumeOffsetLocationUuid,
382 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
383 builder.AddDescriptor(0x0011, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
384 builder.AddCharacteristic(0x0012, 0x0013, kVolumeOffsetControlPointUuid,
385 GATT_CHAR_PROP_BIT_WRITE);
386 /* no Audio Output Description characteristic */
387 services = builder.Build().Services();
388 ASSERT_EQ(true, device->UpdateHandles());
389 ASSERT_EQ((size_t)0, device->audio_offsets.Size());
390 ASSERT_EQ(0x0004, device->volume_state_handle);
391 ASSERT_EQ(0x0005, device->volume_state_ccc_handle);
392 ASSERT_EQ(0x0007, device->volume_control_point_handle);
393 ASSERT_EQ(0x0009, device->volume_flags_handle);
394 ASSERT_EQ(0x000a, device->volume_flags_ccc_handle);
395 ASSERT_EQ(true, device->HasHandles());
396 }
397
TEST_F(VolumeControlDeviceTest,test_service_vocs_found)398 TEST_F(VolumeControlDeviceTest, test_service_vocs_found) {
399 gatt::DatabaseBuilder builder;
400 builder.AddService(0x0001, 0x000a, kVolumeControlUuid, true);
401 builder.AddIncludedService(0x0002, kVolumeOffsetUuid, 0x000b, 0x0015);
402 builder.AddCharacteristic(
403 0x0003, 0x0004, kVolumeControlStateUuid,
404 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
405 builder.AddDescriptor(0x0005, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
406 builder.AddCharacteristic(0x0006, 0x0007, kVolumeControlPointUuid,
407 GATT_CHAR_PROP_BIT_WRITE);
408 builder.AddCharacteristic(
409 0x0008, 0x0009, kVolumeFlagsUuid,
410 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
411 builder.AddDescriptor(0x000a, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
412 builder.AddService(0x000b, 0x0015, kVolumeOffsetUuid, false);
413 builder.AddCharacteristic(
414 0x000c, 0x000d, kVolumeOffsetStateUuid,
415 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
416 builder.AddDescriptor(0x000e, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
417 builder.AddCharacteristic(
418 0x000f, 0x0010, kVolumeOffsetLocationUuid,
419 GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
420 builder.AddDescriptor(0x0011, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
421 builder.AddCharacteristic(0x0012, 0x0013, kVolumeOffsetControlPointUuid,
422 GATT_CHAR_PROP_BIT_WRITE);
423 builder.AddCharacteristic(0x0014, 0x0015, kVolumeOffsetOutputDescriptionUuid,
424 GATT_CHAR_PROP_BIT_READ);
425 services = builder.Build().Services();
426 ASSERT_EQ(true, device->UpdateHandles());
427 ASSERT_EQ((size_t)1, device->audio_offsets.Size());
428 VolumeOffset* offset = device->audio_offsets.FindByServiceHandle(0x000b);
429 ASSERT_NE(nullptr, offset);
430 ASSERT_EQ(0x000d, offset->state_handle);
431 ASSERT_EQ(0x000e, offset->state_ccc_handle);
432 ASSERT_EQ(0x0010, offset->audio_location_handle);
433 ASSERT_EQ(0x0011, offset->audio_location_ccc_handle);
434 ASSERT_EQ(0x0013, offset->control_point_handle);
435 ASSERT_EQ(0x0015, offset->audio_descr_handle);
436 ASSERT_EQ(0x0000, offset->audio_descr_ccc_handle);
437 ASSERT_EQ(true, device->HasHandles());
438 }
439
TEST_F(VolumeControlDeviceTest,test_multiple_services_found)440 TEST_F(VolumeControlDeviceTest, test_multiple_services_found) {
441 SetSampleDatabase1();
442 ASSERT_EQ((size_t)2, device->audio_offsets.Size());
443 VolumeOffset* offset_1 = device->audio_offsets.FindById(1);
444 VolumeOffset* offset_2 = device->audio_offsets.FindById(2);
445 ASSERT_NE(nullptr, offset_1);
446 ASSERT_NE(nullptr, offset_2);
447 ASSERT_NE(offset_1->service_handle, offset_2->service_handle);
448 }
449
TEST_F(VolumeControlDeviceTest,test_services_changed)450 TEST_F(VolumeControlDeviceTest, test_services_changed) {
451 SetSampleDatabase1();
452 ASSERT_NE((size_t)0, device->audio_offsets.Size());
453 ASSERT_NE(0, device->volume_state_handle);
454 ASSERT_NE(0, device->volume_control_point_handle);
455 ASSERT_NE(0, device->volume_flags_handle);
456 ASSERT_EQ(true, device->HasHandles());
457 SetSampleDatabase2();
458 ASSERT_EQ((size_t)0, device->audio_offsets.Size());
459 ASSERT_EQ(0, device->volume_state_handle);
460 ASSERT_EQ(0, device->volume_control_point_handle);
461 ASSERT_EQ(0, device->volume_flags_handle);
462 ASSERT_EQ(false, device->HasHandles());
463 }
464
TEST_F(VolumeControlDeviceTest,test_enqueue_initial_requests)465 TEST_F(VolumeControlDeviceTest, test_enqueue_initial_requests) {
466 SetSampleDatabase1();
467
468 tGATT_IF gatt_if = 0x0001;
469 std::vector<uint8_t> register_for_notification_data({0x01, 0x00});
470
471 std::map<uint16_t, uint16_t> expected_to_read_write{
472 {0x0011, 0x0012} /* volume control state */,
473 {0x0062, 0x0063} /* volume offset state 1 */,
474 {0x0082, 0x0083} /* volume offset state 2 */};
475
476 for (auto const& handle_pair : expected_to_read_write) {
477 EXPECT_CALL(gatt_queue, ReadCharacteristic(_, handle_pair.first, _, _));
478 EXPECT_CALL(gatt_queue, WriteDescriptor(_, handle_pair.second,
479 register_for_notification_data,
480 GATT_WRITE, _, _));
481 EXPECT_CALL(gatt_interface,
482 RegisterForNotifications(gatt_if, _, handle_pair.first));
483 }
484
485 auto chrc_read_cb = [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
486 uint16_t len, uint8_t* value, void* data) {};
487 auto cccd_write_cb = [](uint16_t conn_id, tGATT_STATUS status,
488 uint16_t handle, uint16_t len, const uint8_t* value,
489 void* data) {};
490 ASSERT_EQ(true, device->EnqueueInitialRequests(gatt_if, chrc_read_cb,
491 cccd_write_cb));
492 };
493
TEST_F(VolumeControlDeviceTest,test_device_ready)494 TEST_F(VolumeControlDeviceTest, test_device_ready) {
495 SetSampleDatabase1();
496
497 // grab all the handles requested
498 std::vector<uint16_t> requested_handles;
499 ON_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _))
500 .WillByDefault(Invoke(
501 [&requested_handles](
502 uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value,
503 tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb,
504 void* cb_data) -> void { requested_handles.push_back(handle); }));
505 ON_CALL(gatt_queue, ReadCharacteristic(_, _, _, _))
506 .WillByDefault(Invoke(
507 [&requested_handles](uint16_t conn_id, uint16_t handle,
508 GATT_READ_OP_CB cb, void* cb_data) -> void {
509 requested_handles.push_back(handle);
510 }));
511
512 auto chrc_read_cb = [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
513 uint16_t len, uint8_t* value, void* data) {};
514 auto cccd_write_cb = [](uint16_t conn_id, tGATT_STATUS status,
515 uint16_t handle, uint16_t len, const uint8_t* value,
516 void* data) {};
517 ASSERT_EQ(true, device->EnqueueInitialRequests(0x0001, chrc_read_cb,
518 cccd_write_cb));
519 ASSERT_NE((size_t)0, requested_handles.size());
520
521 // indicate non-pending requests
522 ASSERT_EQ(false, device->device_ready);
523 device->VerifyReady(0xffff);
524
525 for (uint16_t handle : requested_handles) {
526 ASSERT_EQ(false, device->device_ready);
527 device->VerifyReady(handle);
528 }
529
530 ASSERT_EQ(true, device->device_ready);
531 }
532
TEST_F(VolumeControlDeviceTest,test_enqueue_remaining_requests)533 TEST_F(VolumeControlDeviceTest, test_enqueue_remaining_requests) {
534 SetSampleDatabase1();
535
536 tGATT_IF gatt_if = 0x0001;
537 std::vector<uint8_t> register_for_notification_data({0x01, 0x00});
538
539 std::vector<uint16_t> expected_to_read{
540 0x0016 /* volume flags */, 0x0065 /* audio location 1 */,
541 0x0069 /* audio output description 1 */, 0x0085 /* audio location 1 */,
542 0x008a /* audio output description 1 */};
543
544 std::map<uint16_t, uint16_t> expected_to_write_value_ccc_handle_map{
545 {0x0085, 0x0086} /* audio location ccc 2 */,
546 {0x008a, 0x008b} /* audio output description ccc */
547 };
548
549 for (uint16_t handle : expected_to_read) {
550 EXPECT_CALL(gatt_queue, ReadCharacteristic(_, handle, _, _));
551 }
552
553 for (auto const& handle_pair : expected_to_write_value_ccc_handle_map) {
554 EXPECT_CALL(gatt_queue, WriteDescriptor(_, handle_pair.second,
555 register_for_notification_data,
556 GATT_WRITE, _, _));
557 EXPECT_CALL(gatt_interface,
558 RegisterForNotifications(gatt_if, _, handle_pair.first));
559 }
560
561 auto chrc_read_cb = [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
562 uint16_t len, uint8_t* value, void* data) {};
563 auto cccd_write_cb = [](uint16_t conn_id, tGATT_STATUS status,
564 uint16_t handle, uint16_t len, const uint8_t* value,
565 void* data) {};
566 device->EnqueueRemainingRequests(gatt_if, chrc_read_cb, cccd_write_cb);
567 }
568
TEST_F(VolumeControlDeviceTest,test_check_link_encrypted)569 TEST_F(VolumeControlDeviceTest, test_check_link_encrypted) {
570 ON_CALL(btm_interface, BTM_IsEncrypted(_, _))
571 .WillByDefault(DoAll(Return(true)));
572 ASSERT_EQ(true, device->IsEncryptionEnabled());
573
574 ON_CALL(btm_interface, BTM_IsEncrypted(_, _))
575 .WillByDefault(DoAll(Return(false)));
576 ASSERT_NE(true, device->IsEncryptionEnabled());
577 }
578
TEST_F(VolumeControlDeviceTest,test_control_point_operation)579 TEST_F(VolumeControlDeviceTest, test_control_point_operation) {
580 GATT_WRITE_OP_CB write_cb = [](uint16_t conn_id, tGATT_STATUS status,
581 uint16_t handle, uint16_t len,
582 const uint8_t* value, void* data) {};
583 SetSampleDatabase1();
584 device->change_counter = 0x01;
585 std::vector<uint8_t> expected_data({0x03, 0x01});
586 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, 0x0014, expected_data,
587 GATT_WRITE, write_cb, nullptr));
588 device->ControlPointOperation(0x03, nullptr, write_cb, nullptr);
589 }
590
TEST_F(VolumeControlDeviceTest,test_control_point_operation_arg)591 TEST_F(VolumeControlDeviceTest, test_control_point_operation_arg) {
592 GATT_WRITE_OP_CB write_cb = [](uint16_t conn_id, tGATT_STATUS status,
593 uint16_t handle, uint16_t len,
594 const uint8_t* value, void* data) {};
595 SetSampleDatabase1();
596 device->change_counter = 0x55;
597 std::vector<uint8_t> expected_data({0x01, 0x55, 0x02, 0x03});
598 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, 0x0014, expected_data,
599 GATT_WRITE, write_cb, nullptr));
600 std::vector<uint8_t> arg({0x02, 0x03});
601 device->ControlPointOperation(0x01, &arg, write_cb, nullptr);
602 }
603
TEST_F(VolumeControlDeviceTest,test_get_ext_audio_out_volume_offset)604 TEST_F(VolumeControlDeviceTest, test_get_ext_audio_out_volume_offset) {
605 GATT_READ_OP_CB read_cb = [](uint16_t conn_id, tGATT_STATUS status,
606 uint16_t handle, uint16_t len, uint8_t* value,
607 void* data) {};
608 SetSampleDatabase1();
609 EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0062, read_cb, nullptr));
610 device->GetExtAudioOutVolumeOffset(1, read_cb, nullptr);
611 }
612
TEST_F(VolumeControlDeviceTest,test_get_ext_audio_out_location)613 TEST_F(VolumeControlDeviceTest, test_get_ext_audio_out_location) {
614 GATT_READ_OP_CB read_cb = [](uint16_t conn_id, tGATT_STATUS status,
615 uint16_t handle, uint16_t len, uint8_t* value,
616 void* data) {};
617 SetSampleDatabase1();
618 EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0085, read_cb, nullptr));
619 device->GetExtAudioOutLocation(2, read_cb, nullptr);
620 }
621
TEST_F(VolumeControlDeviceTest,test_set_ext_audio_out_location)622 TEST_F(VolumeControlDeviceTest, test_set_ext_audio_out_location) {
623 SetSampleDatabase1();
624 std::vector<uint8_t> expected_data({0x44, 0x33, 0x22, 0x11});
625 EXPECT_CALL(gatt_queue,
626 WriteCharacteristic(_, 0x0085, expected_data, GATT_WRITE_NO_RSP,
627 nullptr, nullptr));
628 device->SetExtAudioOutLocation(2, 0x11223344);
629 }
630
TEST_F(VolumeControlDeviceTest,test_set_ext_audio_out_location_non_writable)631 TEST_F(VolumeControlDeviceTest, test_set_ext_audio_out_location_non_writable) {
632 SetSampleDatabase1();
633 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
634 device->SetExtAudioOutLocation(1, 0x11223344);
635 }
636
TEST_F(VolumeControlDeviceTest,test_get_ext_audio_out_description)637 TEST_F(VolumeControlDeviceTest, test_get_ext_audio_out_description) {
638 GATT_READ_OP_CB read_cb = [](uint16_t conn_id, tGATT_STATUS status,
639 uint16_t handle, uint16_t len, uint8_t* value,
640 void* data) {};
641 SetSampleDatabase1();
642 EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x008a, read_cb, nullptr));
643 device->GetExtAudioOutDescription(2, read_cb, nullptr);
644 }
645
TEST_F(VolumeControlDeviceTest,test_set_ext_audio_out_description)646 TEST_F(VolumeControlDeviceTest, test_set_ext_audio_out_description) {
647 SetSampleDatabase1();
648 std::string descr = "right front";
649 std::vector<uint8_t> expected_data(descr.begin(), descr.end());
650 EXPECT_CALL(gatt_queue,
651 WriteCharacteristic(_, 0x008a, expected_data, GATT_WRITE_NO_RSP,
652 nullptr, nullptr));
653 device->SetExtAudioOutDescription(2, descr);
654 }
655
TEST_F(VolumeControlDeviceTest,test_set_ext_audio_out_description_non_writable)656 TEST_F(VolumeControlDeviceTest,
657 test_set_ext_audio_out_description_non_writable) {
658 SetSampleDatabase1();
659 std::string descr = "left front";
660 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
661 device->SetExtAudioOutDescription(1, descr);
662 }
663
TEST_F(VolumeControlDeviceTest,test_ext_audio_out_control_point_operation)664 TEST_F(VolumeControlDeviceTest, test_ext_audio_out_control_point_operation) {
665 GATT_WRITE_OP_CB write_cb = [](uint16_t conn_id, tGATT_STATUS status,
666 uint16_t handle, uint16_t len,
667 const uint8_t* value, void* data) {};
668 SetSampleDatabase1();
669 VolumeOffset* offset = device->audio_offsets.FindById(1);
670 ASSERT_NE(nullptr, offset);
671 offset->change_counter = 0x09;
672 std::vector<uint8_t> expected_data({0x0b, 0x09});
673 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, 0x0067, expected_data,
674 GATT_WRITE, write_cb, nullptr));
675 device->ExtAudioOutControlPointOperation(1, 0x0b, nullptr, write_cb, nullptr);
676 }
677
TEST_F(VolumeControlDeviceTest,test_ext_audio_out_control_point_operation_arg)678 TEST_F(VolumeControlDeviceTest,
679 test_ext_audio_out_control_point_operation_arg) {
680 GATT_WRITE_OP_CB write_cb = [](uint16_t conn_id, tGATT_STATUS status,
681 uint16_t handle, uint16_t len,
682 const uint8_t* value, void* data) {};
683 SetSampleDatabase1();
684 VolumeOffset* offset = device->audio_offsets.FindById(1);
685 ASSERT_NE(nullptr, offset);
686 offset->change_counter = 0x09;
687 std::vector<uint8_t> expected_data({0x0b, 0x09, 0x01, 0x02, 0x03, 0x04});
688 std::vector<uint8_t> arg({0x01, 0x02, 0x03, 0x04});
689 EXPECT_CALL(gatt_queue, WriteCharacteristic(_, 0x0067, expected_data,
690 GATT_WRITE, write_cb, nullptr));
691 device->ExtAudioOutControlPointOperation(1, 0x0b, &arg, write_cb, nullptr);
692 }
693
694 } // namespace internal
695 } // namespace vc
696 } // namespace bluetooth
697