Move notification sending out of AutocompleteController
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_win_unittest.cc
blobb8522820c26032db88f035288cec54ed433d6668
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <string>
7 #include "base/bind.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/test_simple_task_runner.h"
11 #include "device/bluetooth/bluetooth_adapter.h"
12 #include "device/bluetooth/bluetooth_adapter_win.h"
13 #include "device/bluetooth/bluetooth_device.h"
14 #include "device/bluetooth/bluetooth_task_manager_win.h"
15 #include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 namespace {
20 const char kAdapterAddress[] = "A1:B2:C3:D4:E5:F6";
21 const char kAdapterName[] = "Bluetooth Adapter Name";
23 const char kTestAudioSdpName[] = "Audio";
24 const char kTestAudioSdpName2[] = "Audio2";
25 const char kTestAudioSdpBytes[] =
26 "35510900000a00010001090001350319110a09000435103506190100090019350619001909"
27 "010209000535031910020900093508350619110d090102090100250c417564696f20536f75"
28 "726365090311090001";
29 const device::BluetoothUUID kTestAudioSdpUuid("110a");
31 void MakeDeviceState(const std::string& name,
32 const std::string& address,
33 device::BluetoothTaskManagerWin::DeviceState* state) {
34 state->name = name;
35 state->address = address;
36 state->bluetooth_class = 0;
37 state->authenticated = false;
38 state->connected = false;
41 } // namespace
43 namespace device {
45 class BluetoothAdapterWinTest : public testing::Test {
46 public:
47 BluetoothAdapterWinTest()
48 : ui_task_runner_(new base::TestSimpleTaskRunner()),
49 bluetooth_task_runner_(new base::TestSimpleTaskRunner()),
50 adapter_(new BluetoothAdapterWin(
51 base::Bind(&BluetoothAdapterWinTest::RunInitCallback,
52 base::Unretained(this)))),
53 adapter_win_(static_cast<BluetoothAdapterWin*>(adapter_.get())),
54 observer_(adapter_),
55 init_callback_called_(false) {
56 adapter_win_->InitForTest(ui_task_runner_, bluetooth_task_runner_);
59 void SetUp() override {
60 num_start_discovery_callbacks_ = 0;
61 num_start_discovery_error_callbacks_ = 0;
62 num_stop_discovery_callbacks_ = 0;
63 num_stop_discovery_error_callbacks_ = 0;
66 void RunInitCallback() {
67 init_callback_called_ = true;
70 void IncrementNumStartDiscoveryCallbacks() {
71 num_start_discovery_callbacks_++;
74 void IncrementNumStartDiscoveryErrorCallbacks() {
75 num_start_discovery_error_callbacks_++;
78 void IncrementNumStopDiscoveryCallbacks() {
79 num_stop_discovery_callbacks_++;
82 void IncrementNumStopDiscoveryErrorCallbacks() {
83 num_stop_discovery_error_callbacks_++;
86 void CallAddDiscoverySession(
87 const base::Closure& callback,
88 const BluetoothAdapter::ErrorCallback& error_callback) {
89 adapter_win_->AddDiscoverySession(nullptr, callback, error_callback);
92 void CallRemoveDiscoverySession(
93 const base::Closure& callback,
94 const BluetoothAdapter::ErrorCallback& error_callback) {
95 adapter_win_->RemoveDiscoverySession(nullptr, callback, error_callback);
98 protected:
99 scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
100 scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_;
101 scoped_refptr<BluetoothAdapter> adapter_;
102 BluetoothAdapterWin* adapter_win_;
103 TestBluetoothAdapterObserver observer_;
104 bool init_callback_called_;
105 int num_start_discovery_callbacks_;
106 int num_start_discovery_error_callbacks_;
107 int num_stop_discovery_callbacks_;
108 int num_stop_discovery_error_callbacks_;
111 TEST_F(BluetoothAdapterWinTest, AdapterNotPresent) {
112 BluetoothTaskManagerWin::AdapterState state;
113 adapter_win_->AdapterStateChanged(state);
114 EXPECT_FALSE(adapter_win_->IsPresent());
117 TEST_F(BluetoothAdapterWinTest, AdapterPresent) {
118 BluetoothTaskManagerWin::AdapterState state;
119 state.address = kAdapterAddress;
120 state.name = kAdapterName;
121 adapter_win_->AdapterStateChanged(state);
122 EXPECT_TRUE(adapter_win_->IsPresent());
125 TEST_F(BluetoothAdapterWinTest, AdapterPresentChanged) {
126 BluetoothTaskManagerWin::AdapterState state;
127 state.address = kAdapterAddress;
128 state.name = kAdapterName;
129 adapter_win_->AdapterStateChanged(state);
130 EXPECT_EQ(1, observer_.present_changed_count());
131 adapter_win_->AdapterStateChanged(state);
132 EXPECT_EQ(1, observer_.present_changed_count());
133 BluetoothTaskManagerWin::AdapterState empty_state;
134 adapter_win_->AdapterStateChanged(empty_state);
135 EXPECT_EQ(2, observer_.present_changed_count());
138 TEST_F(BluetoothAdapterWinTest, AdapterPoweredChanged) {
139 BluetoothTaskManagerWin::AdapterState state;
140 state.powered = true;
141 adapter_win_->AdapterStateChanged(state);
142 EXPECT_EQ(1, observer_.powered_changed_count());
143 adapter_win_->AdapterStateChanged(state);
144 EXPECT_EQ(1, observer_.powered_changed_count());
145 state.powered = false;
146 adapter_win_->AdapterStateChanged(state);
147 EXPECT_EQ(2, observer_.powered_changed_count());
150 TEST_F(BluetoothAdapterWinTest, AdapterInitialized) {
151 EXPECT_FALSE(adapter_win_->IsInitialized());
152 EXPECT_FALSE(init_callback_called_);
153 BluetoothTaskManagerWin::AdapterState state;
154 adapter_win_->AdapterStateChanged(state);
155 EXPECT_TRUE(adapter_win_->IsInitialized());
156 EXPECT_TRUE(init_callback_called_);
159 TEST_F(BluetoothAdapterWinTest, SingleStartDiscovery) {
160 bluetooth_task_runner_->ClearPendingTasks();
161 CallAddDiscoverySession(
162 base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
163 base::Unretained(this)),
164 BluetoothAdapter::ErrorCallback());
165 EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
166 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
167 EXPECT_FALSE(adapter_->IsDiscovering());
168 EXPECT_EQ(0, num_start_discovery_callbacks_);
169 adapter_win_->DiscoveryStarted(true);
170 ui_task_runner_->RunPendingTasks();
171 EXPECT_TRUE(adapter_->IsDiscovering());
172 EXPECT_EQ(1, num_start_discovery_callbacks_);
173 EXPECT_EQ(1, observer_.discovering_changed_count());
176 TEST_F(BluetoothAdapterWinTest, SingleStartDiscoveryFailure) {
177 CallAddDiscoverySession(
178 base::Closure(),
179 base::Bind(
180 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
181 base::Unretained(this)));
182 adapter_win_->DiscoveryStarted(false);
183 ui_task_runner_->RunPendingTasks();
184 EXPECT_FALSE(adapter_->IsDiscovering());
185 EXPECT_EQ(1, num_start_discovery_error_callbacks_);
186 EXPECT_EQ(0, observer_.discovering_changed_count());
189 TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveries) {
190 bluetooth_task_runner_->ClearPendingTasks();
191 int num_discoveries = 5;
192 for (int i = 0; i < num_discoveries; i++) {
193 CallAddDiscoverySession(
194 base::Bind(
195 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
196 base::Unretained(this)),
197 BluetoothAdapter::ErrorCallback());
198 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
200 EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
201 EXPECT_FALSE(adapter_->IsDiscovering());
202 EXPECT_EQ(0, num_start_discovery_callbacks_);
203 adapter_win_->DiscoveryStarted(true);
204 ui_task_runner_->RunPendingTasks();
205 EXPECT_TRUE(adapter_->IsDiscovering());
206 EXPECT_EQ(num_discoveries, num_start_discovery_callbacks_);
207 EXPECT_EQ(1, observer_.discovering_changed_count());
210 TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesFailure) {
211 int num_discoveries = 5;
212 for (int i = 0; i < num_discoveries; i++) {
213 CallAddDiscoverySession(
214 base::Closure(),
215 base::Bind(
216 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
217 base::Unretained(this)));
219 adapter_win_->DiscoveryStarted(false);
220 ui_task_runner_->RunPendingTasks();
221 EXPECT_FALSE(adapter_->IsDiscovering());
222 EXPECT_EQ(num_discoveries, num_start_discovery_error_callbacks_);
223 EXPECT_EQ(0, observer_.discovering_changed_count());
226 TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesAfterDiscovering) {
227 CallAddDiscoverySession(
228 base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
229 base::Unretained(this)),
230 BluetoothAdapter::ErrorCallback());
231 adapter_win_->DiscoveryStarted(true);
232 ui_task_runner_->RunPendingTasks();
233 EXPECT_TRUE(adapter_->IsDiscovering());
234 EXPECT_EQ(1, num_start_discovery_callbacks_);
236 bluetooth_task_runner_->ClearPendingTasks();
237 for (int i = 0; i < 5; i++) {
238 int num_start_discovery_callbacks = num_start_discovery_callbacks_;
239 CallAddDiscoverySession(
240 base::Bind(
241 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
242 base::Unretained(this)),
243 BluetoothAdapter::ErrorCallback());
244 EXPECT_TRUE(adapter_->IsDiscovering());
245 EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
246 EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty());
247 EXPECT_EQ(num_start_discovery_callbacks + 1,
248 num_start_discovery_callbacks_);
250 EXPECT_EQ(1, observer_.discovering_changed_count());
253 TEST_F(BluetoothAdapterWinTest, StartDiscoveryAfterDiscoveringFailure) {
254 CallAddDiscoverySession(
255 base::Closure(),
256 base::Bind(
257 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
258 base::Unretained(this)));
259 adapter_win_->DiscoveryStarted(false);
260 ui_task_runner_->RunPendingTasks();
261 EXPECT_FALSE(adapter_->IsDiscovering());
262 EXPECT_EQ(1, num_start_discovery_error_callbacks_);
264 CallAddDiscoverySession(
265 base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
266 base::Unretained(this)),
267 BluetoothAdapter::ErrorCallback());
268 adapter_win_->DiscoveryStarted(true);
269 ui_task_runner_->RunPendingTasks();
270 EXPECT_TRUE(adapter_->IsDiscovering());
271 EXPECT_EQ(1, num_start_discovery_callbacks_);
274 TEST_F(BluetoothAdapterWinTest, SingleStopDiscovery) {
275 CallAddDiscoverySession(
276 base::Closure(), BluetoothAdapter::ErrorCallback());
277 adapter_win_->DiscoveryStarted(true);
278 ui_task_runner_->ClearPendingTasks();
279 CallRemoveDiscoverySession(
280 base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
281 base::Unretained(this)),
282 BluetoothAdapter::ErrorCallback());
283 EXPECT_TRUE(adapter_->IsDiscovering());
284 EXPECT_EQ(0, num_stop_discovery_callbacks_);
285 bluetooth_task_runner_->ClearPendingTasks();
286 adapter_win_->DiscoveryStopped();
287 ui_task_runner_->RunPendingTasks();
288 EXPECT_FALSE(adapter_->IsDiscovering());
289 EXPECT_EQ(1, num_stop_discovery_callbacks_);
290 EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
291 EXPECT_EQ(2, observer_.discovering_changed_count());
294 TEST_F(BluetoothAdapterWinTest, MultipleStopDiscoveries) {
295 int num_discoveries = 5;
296 for (int i = 0; i < num_discoveries; i++) {
297 CallAddDiscoverySession(
298 base::Closure(), BluetoothAdapter::ErrorCallback());
300 adapter_win_->DiscoveryStarted(true);
301 ui_task_runner_->ClearPendingTasks();
302 bluetooth_task_runner_->ClearPendingTasks();
303 for (int i = 0; i < num_discoveries - 1; i++) {
304 CallRemoveDiscoverySession(
305 base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
306 base::Unretained(this)),
307 BluetoothAdapter::ErrorCallback());
308 EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
309 ui_task_runner_->RunPendingTasks();
310 EXPECT_EQ(i + 1, num_stop_discovery_callbacks_);
312 CallRemoveDiscoverySession(
313 base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
314 base::Unretained(this)),
315 BluetoothAdapter::ErrorCallback());
316 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
317 EXPECT_TRUE(adapter_->IsDiscovering());
318 adapter_win_->DiscoveryStopped();
319 ui_task_runner_->RunPendingTasks();
320 EXPECT_FALSE(adapter_->IsDiscovering());
321 EXPECT_EQ(num_discoveries, num_stop_discovery_callbacks_);
322 EXPECT_EQ(2, observer_.discovering_changed_count());
325 TEST_F(BluetoothAdapterWinTest,
326 StartDiscoveryAndStartDiscoveryAndStopDiscoveries) {
327 CallAddDiscoverySession(
328 base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
329 base::Unretained(this)),
330 BluetoothAdapter::ErrorCallback());
331 adapter_win_->DiscoveryStarted(true);
332 CallAddDiscoverySession(
333 base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
334 base::Unretained(this)),
335 BluetoothAdapter::ErrorCallback());
336 ui_task_runner_->ClearPendingTasks();
337 bluetooth_task_runner_->ClearPendingTasks();
338 CallRemoveDiscoverySession(
339 base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
340 base::Unretained(this)),
341 BluetoothAdapter::ErrorCallback());
342 EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
343 CallRemoveDiscoverySession(
344 base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
345 base::Unretained(this)),
346 BluetoothAdapter::ErrorCallback());
347 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
350 TEST_F(BluetoothAdapterWinTest,
351 StartDiscoveryAndStopDiscoveryAndStartDiscovery) {
352 CallAddDiscoverySession(
353 base::Closure(), BluetoothAdapter::ErrorCallback());
354 adapter_win_->DiscoveryStarted(true);
355 EXPECT_TRUE(adapter_->IsDiscovering());
356 CallRemoveDiscoverySession(
357 base::Closure(), BluetoothAdapter::ErrorCallback());
358 adapter_win_->DiscoveryStopped();
359 EXPECT_FALSE(adapter_->IsDiscovering());
360 CallAddDiscoverySession(
361 base::Closure(), BluetoothAdapter::ErrorCallback());
362 adapter_win_->DiscoveryStarted(true);
363 EXPECT_TRUE(adapter_->IsDiscovering());
366 TEST_F(BluetoothAdapterWinTest, StartDiscoveryBeforeDiscoveryStopped) {
367 CallAddDiscoverySession(
368 base::Closure(), BluetoothAdapter::ErrorCallback());
369 adapter_win_->DiscoveryStarted(true);
370 CallRemoveDiscoverySession(
371 base::Closure(), BluetoothAdapter::ErrorCallback());
372 CallAddDiscoverySession(
373 base::Closure(), BluetoothAdapter::ErrorCallback());
374 bluetooth_task_runner_->ClearPendingTasks();
375 adapter_win_->DiscoveryStopped();
376 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
379 TEST_F(BluetoothAdapterWinTest, StopDiscoveryWithoutStartDiscovery) {
380 CallRemoveDiscoverySession(
381 base::Closure(),
382 base::Bind(
383 &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks,
384 base::Unretained(this)));
385 EXPECT_EQ(1, num_stop_discovery_error_callbacks_);
388 TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStarted) {
389 CallAddDiscoverySession(
390 base::Closure(), BluetoothAdapter::ErrorCallback());
391 CallRemoveDiscoverySession(
392 base::Closure(), BluetoothAdapter::ErrorCallback());
393 bluetooth_task_runner_->ClearPendingTasks();
394 adapter_win_->DiscoveryStarted(true);
395 EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
398 TEST_F(BluetoothAdapterWinTest, StartAndStopBeforeDiscoveryStarted) {
399 int num_expected_start_discoveries = 3;
400 int num_expected_stop_discoveries = 2;
401 for (int i = 0; i < num_expected_start_discoveries; i++) {
402 CallAddDiscoverySession(
403 base::Bind(
404 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks,
405 base::Unretained(this)),
406 BluetoothAdapter::ErrorCallback());
408 for (int i = 0; i < num_expected_stop_discoveries; i++) {
409 CallRemoveDiscoverySession(
410 base::Bind(
411 &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
412 base::Unretained(this)),
413 BluetoothAdapter::ErrorCallback());
415 bluetooth_task_runner_->ClearPendingTasks();
416 adapter_win_->DiscoveryStarted(true);
417 EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty());
418 ui_task_runner_->RunPendingTasks();
419 EXPECT_EQ(num_expected_start_discoveries, num_start_discovery_callbacks_);
420 EXPECT_EQ(num_expected_stop_discoveries, num_stop_discovery_callbacks_);
423 TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStartedAndFailed) {
424 CallAddDiscoverySession(
425 base::Closure(),
426 base::Bind(
427 &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks,
428 base::Unretained(this)));
429 CallRemoveDiscoverySession(
430 base::Bind(
431 &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks,
432 base::Unretained(this)),
433 BluetoothAdapter::ErrorCallback());
434 ui_task_runner_->ClearPendingTasks();
435 adapter_win_->DiscoveryStarted(false);
436 ui_task_runner_->RunPendingTasks();
437 EXPECT_EQ(1, num_start_discovery_error_callbacks_);
438 EXPECT_EQ(1, num_stop_discovery_callbacks_);
439 EXPECT_EQ(0, observer_.discovering_changed_count());
442 TEST_F(BluetoothAdapterWinTest, DevicesPolled) {
443 BluetoothTaskManagerWin::DeviceState* android_phone_state =
444 new BluetoothTaskManagerWin::DeviceState();
445 MakeDeviceState("phone", "A1:B2:C3:D4:E5:E0", android_phone_state);
446 BluetoothTaskManagerWin::DeviceState* laptop_state =
447 new BluetoothTaskManagerWin::DeviceState();
448 MakeDeviceState("laptop", "A1:B2:C3:D4:E5:E1", laptop_state);
449 BluetoothTaskManagerWin::DeviceState* iphone_state =
450 new BluetoothTaskManagerWin::DeviceState();
451 MakeDeviceState("phone", "A1:B2:C3:D4:E5:E2", iphone_state);
452 ScopedVector<BluetoothTaskManagerWin::DeviceState> devices;
453 devices.push_back(android_phone_state);
454 devices.push_back(laptop_state);
455 devices.push_back(iphone_state);
457 // Add 3 devices
458 observer_.Reset();
459 adapter_win_->DevicesPolled(devices);
460 EXPECT_EQ(3, observer_.device_added_count());
461 EXPECT_EQ(0, observer_.device_removed_count());
462 EXPECT_EQ(0, observer_.device_changed_count());
464 // Change a device name
465 android_phone_state->name = "phone2";
466 observer_.Reset();
467 adapter_win_->DevicesPolled(devices);
468 EXPECT_EQ(0, observer_.device_added_count());
469 EXPECT_EQ(0, observer_.device_removed_count());
470 EXPECT_EQ(1, observer_.device_changed_count());
472 // Change a device address
473 android_phone_state->address = "A1:B2:C3:D4:E5:E6";
474 observer_.Reset();
475 adapter_win_->DevicesPolled(devices);
476 EXPECT_EQ(1, observer_.device_added_count());
477 EXPECT_EQ(1, observer_.device_removed_count());
478 EXPECT_EQ(0, observer_.device_changed_count());
480 // Remove a device
481 devices.erase(devices.begin());
482 observer_.Reset();
483 adapter_win_->DevicesPolled(devices);
484 EXPECT_EQ(0, observer_.device_added_count());
485 EXPECT_EQ(1, observer_.device_removed_count());
486 EXPECT_EQ(0, observer_.device_changed_count());
488 // Add a service
489 BluetoothTaskManagerWin::ServiceRecordState* audio_state =
490 new BluetoothTaskManagerWin::ServiceRecordState();
491 audio_state->name = kTestAudioSdpName;
492 base::HexStringToBytes(kTestAudioSdpBytes, &audio_state->sdp_bytes);
493 laptop_state->service_record_states.push_back(audio_state);
494 observer_.Reset();
495 adapter_win_->DevicesPolled(devices);
496 EXPECT_EQ(0, observer_.device_added_count());
497 EXPECT_EQ(0, observer_.device_removed_count());
498 EXPECT_EQ(1, observer_.device_changed_count());
500 // Change a service
501 audio_state->name = kTestAudioSdpName2;
502 observer_.Reset();
503 adapter_win_->DevicesPolled(devices);
504 EXPECT_EQ(0, observer_.device_added_count());
505 EXPECT_EQ(0, observer_.device_removed_count());
506 EXPECT_EQ(1, observer_.device_changed_count());
508 // Remove a service
509 laptop_state->service_record_states.clear();
510 observer_.Reset();
511 adapter_win_->DevicesPolled(devices);
512 EXPECT_EQ(0, observer_.device_added_count());
513 EXPECT_EQ(0, observer_.device_removed_count());
514 EXPECT_EQ(1, observer_.device_changed_count());
517 } // namespace device