OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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. | |
4 | |
5 #include "components/proximity_auth/bluetooth_connection.h" | |
6 | |
7 #include "base/message_loop/message_loop.h" | |
8 #include "base/numerics/safe_conversions.h" | |
9 #include "base/run_loop.h" | |
10 #include "components/proximity_auth/remote_device.h" | |
11 #include "components/proximity_auth/wire_message.h" | |
12 #include "device/bluetooth/bluetooth_adapter_factory.h" | |
13 #include "device/bluetooth/bluetooth_uuid.h" | |
14 #include "device/bluetooth/test/mock_bluetooth_adapter.h" | |
15 #include "device/bluetooth/test/mock_bluetooth_device.h" | |
16 #include "device/bluetooth/test/mock_bluetooth_socket.h" | |
17 #include "net/base/io_buffer.h" | |
18 #include "testing/gmock/include/gmock/gmock.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 using testing::_; | |
22 using testing::AnyNumber; | |
23 using testing::NiceMock; | |
24 using testing::Ref; | |
25 using testing::Return; | |
26 using testing::SaveArg; | |
27 using testing::StrictMock; | |
28 | |
29 namespace proximity_auth { | |
30 namespace { | |
31 | |
32 const char kDeviceName[] = "Device name"; | |
33 const char kOtherDeviceName[] = "Other device name"; | |
34 | |
35 const char kBluetoothAddress[] = "11:22:33:44:55:66"; | |
36 const char kOtherBluetoothAddress[] = "AA:BB:CC:DD:EE:FF"; | |
37 | |
38 const char kSerializedMessage[] = "Yarrr, this be a serialized message. Yarr!"; | |
39 const int kSerializedMessageLength = strlen(kSerializedMessage); | |
40 | |
41 const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF"; | |
42 | |
43 const RemoteDevice kRemoteDevice = {kDeviceName, kBluetoothAddress}; | |
44 | |
45 const int kReceiveBufferSize = 6; | |
46 const char kReceiveBufferContents[] = "bytes"; | |
47 | |
48 // Create a buffer for testing received data. | |
49 scoped_refptr<net::IOBuffer> CreateReceiveBuffer() { | |
50 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kReceiveBufferSize); | |
51 memcpy(buffer->data(), kReceiveBufferContents, kReceiveBufferSize); | |
52 return buffer; | |
53 } | |
54 | |
55 class MockBluetoothConnection : public BluetoothConnection { | |
56 public: | |
57 MockBluetoothConnection() | |
58 : BluetoothConnection(kRemoteDevice, device::BluetoothUUID(kUuid)) {} | |
59 | |
60 // Bluetooth dependencies. | |
61 typedef device::BluetoothDevice::ConnectToServiceCallback | |
62 ConnectToServiceCallback; | |
63 typedef device::BluetoothDevice::ConnectToServiceErrorCallback | |
64 ConnectToServiceErrorCallback; | |
65 MOCK_METHOD4(ConnectToService, | |
66 void(device::BluetoothDevice* device, | |
67 const device::BluetoothUUID& uuid, | |
68 const ConnectToServiceCallback& callback, | |
69 const ConnectToServiceErrorCallback& error_callback)); | |
70 | |
71 // Calls back into the parent Connection class. | |
72 MOCK_METHOD1(SetStatusProxy, void(Status status)); | |
73 MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes)); | |
74 MOCK_METHOD2(OnDidSendMessage, | |
75 void(const WireMessage& message, bool success)); | |
76 | |
77 virtual void SetStatus(Status status) OVERRIDE { | |
78 SetStatusProxy(status); | |
79 BluetoothConnection::SetStatus(status); | |
80 } | |
81 | |
82 using BluetoothConnection::status; | |
83 using BluetoothConnection::Connect; | |
84 using BluetoothConnection::DeviceRemoved; | |
85 using BluetoothConnection::Disconnect; | |
86 | |
87 private: | |
88 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection); | |
89 }; | |
90 | |
91 class TestWireMessage : public WireMessage { | |
92 public: | |
93 TestWireMessage() : WireMessage("permit id", "payload") {} | |
94 virtual ~TestWireMessage() {} | |
95 | |
96 virtual std::string Serialize() const OVERRIDE { return kSerializedMessage; } | |
97 | |
98 private: | |
99 DISALLOW_COPY_AND_ASSIGN(TestWireMessage); | |
100 }; | |
101 | |
102 } // namespace | |
103 | |
104 class ProximityAuthBluetoothConnectionTest : public testing::Test { | |
105 public: | |
106 ProximityAuthBluetoothConnectionTest() | |
107 : adapter_(new device::MockBluetoothAdapter), | |
108 device_(adapter_.get(), 0, kDeviceName, kBluetoothAddress, true, true), | |
109 socket_(new StrictMock<device::MockBluetoothSocket>), | |
110 uuid_(kUuid) { | |
111 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); | |
112 | |
113 // Suppress uninteresting Gmock call warnings. | |
114 EXPECT_CALL(*adapter_, GetDevice(_)).Times(AnyNumber()); | |
115 } | |
116 | |
117 // Transition the connection into an in-progress state. | |
118 void BeginConnecting(MockBluetoothConnection* connection) { | |
119 EXPECT_EQ(Connection::DISCONNECTED, connection->status()); | |
120 | |
121 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); | |
122 EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS)); | |
123 EXPECT_CALL(*adapter_, AddObserver(connection)); | |
124 EXPECT_CALL(*connection, ConnectToService(&device_, uuid_, _, _)); | |
125 connection->Connect(); | |
126 | |
127 EXPECT_EQ(Connection::IN_PROGRESS, connection->status()); | |
128 } | |
129 | |
130 // Transition the connection into a connected state. | |
131 // If |receive_callback| or |receive_error_callback| is non-NULL, it is filled | |
132 // with the appropriate callback from the socket's |Receive()| call. | |
133 void ConnectAndCaptureReceiveCallbacks( | |
Tim Song
2014/09/24 01:15:40
It might be more readable to just save these callb
Ilya Sherman
2014/09/26 02:22:47
Done.
| |
134 MockBluetoothConnection* connection, | |
135 device::BluetoothSocket::ReceiveCompletionCallback* receive_callback, | |
136 device::BluetoothSocket::ReceiveErrorCompletionCallback* | |
137 receive_error_callback) { | |
138 EXPECT_EQ(Connection::DISCONNECTED, connection->status()); | |
139 | |
140 device::BluetoothDevice::ConnectToServiceCallback callback; | |
141 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); | |
142 EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS)); | |
143 EXPECT_CALL(*adapter_, AddObserver(connection)); | |
144 EXPECT_CALL(*connection, ConnectToService(_, _, _, _)) | |
145 .WillOnce(SaveArg<2>(&callback)); | |
146 connection->Connect(); | |
147 ASSERT_FALSE(callback.is_null()); | |
148 | |
149 device::BluetoothSocket::ReceiveCompletionCallback local_receive_callback; | |
150 device::BluetoothSocket::ReceiveErrorCompletionCallback | |
151 local_receive_error_callback; | |
152 EXPECT_CALL(*connection, SetStatusProxy(Connection::CONNECTED)); | |
153 EXPECT_CALL(*socket_, Receive(_, _, _)) | |
154 .WillOnce(DoAll(SaveArg<1>(&local_receive_callback), | |
155 SaveArg<2>(&local_receive_error_callback))); | |
156 callback.Run(socket_); | |
157 | |
158 EXPECT_EQ(Connection::CONNECTED, connection->status()); | |
159 | |
160 if (receive_callback) | |
161 *receive_callback = local_receive_callback; | |
162 if (receive_error_callback) | |
163 *receive_error_callback = local_receive_error_callback; | |
164 } | |
165 | |
166 // Transition the connection into a connected state. | |
167 void Connect(MockBluetoothConnection* connection) { | |
168 ConnectAndCaptureReceiveCallbacks(connection, NULL, NULL); | |
169 } | |
170 | |
171 protected: | |
172 // Mocks used for verifying interactions with the Bluetooth subsystem. | |
173 scoped_refptr<device::MockBluetoothAdapter> adapter_; | |
174 NiceMock<device::MockBluetoothDevice> device_; | |
175 scoped_refptr<StrictMock<device::MockBluetoothSocket> > socket_; | |
176 | |
177 device::BluetoothUUID uuid_; | |
178 | |
179 private: | |
180 base::MessageLoop message_loop_; | |
181 }; | |
182 | |
183 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasInProgress) { | |
184 // Create an in-progress connection. | |
185 StrictMock<MockBluetoothConnection> connection; | |
186 BeginConnecting(&connection); | |
187 | |
188 // A second call to Connect() should be ignored. | |
189 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
190 connection.Connect(); | |
191 | |
192 // The connection cleans up after itself upon destruction. | |
193 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
194 } | |
195 | |
196 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasConnected) { | |
197 // Create a connected connection. | |
198 StrictMock<MockBluetoothConnection> connection; | |
199 Connect(&connection); | |
200 | |
201 // A second call to Connect() should be ignored. | |
202 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
203 connection.Connect(); | |
204 | |
205 // The connection disconnects and unregisters as an observer upon destruction. | |
206 EXPECT_CALL(*socket_, Disconnect(_)); | |
207 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
208 } | |
209 | |
210 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_NoBluetoothAdapter) { | |
211 // Some platforms do not support Bluetooth. This test is only meaningful on | |
212 // those platforms. | |
213 adapter_ = NULL; | |
214 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) | |
215 return; | |
216 | |
217 StrictMock<MockBluetoothConnection> connection; | |
218 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
219 connection.Connect(); | |
220 } | |
221 | |
222 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_DeviceMissing) { | |
223 StrictMock<MockBluetoothConnection> connection; | |
224 | |
225 ON_CALL(*adapter_, GetDevice(_)) | |
226 .WillByDefault(Return(static_cast<device::BluetoothDevice*>(NULL))); | |
227 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); | |
228 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
229 connection.Connect(); | |
230 } | |
231 | |
232 TEST_F(ProximityAuthBluetoothConnectionTest, | |
233 Connect_DeviceRemovedWhileConnecting) { | |
234 // Create an in-progress connection. | |
235 StrictMock<MockBluetoothConnection> connection; | |
236 BeginConnecting(&connection); | |
237 | |
238 // Remove the device while the connection is in-progress. This should cause | |
239 // the connection to disconnect. | |
240 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
241 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
242 connection.DeviceRemoved(adapter_.get(), &device_); | |
243 } | |
244 | |
245 TEST_F(ProximityAuthBluetoothConnectionTest, | |
246 Connect_OtherDeviceRemovedWhileConnecting) { | |
247 // Create an in-progress connection. | |
248 StrictMock<MockBluetoothConnection> connection; | |
249 BeginConnecting(&connection); | |
250 | |
251 // Remove a device other than the one that is being connected to. This should | |
252 // not have any effect on the connection. | |
253 NiceMock<device::MockBluetoothDevice> other_device( | |
254 adapter_.get(), 0, kOtherDeviceName, kOtherBluetoothAddress, true, true); | |
255 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
256 connection.DeviceRemoved(adapter_.get(), &other_device); | |
257 | |
258 // The connection removes itself as an observer when it is destroyed. | |
259 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
260 } | |
261 | |
262 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionFails) { | |
263 StrictMock<MockBluetoothConnection> connection; | |
264 | |
265 device::BluetoothDevice::ConnectToServiceErrorCallback error_callback; | |
266 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); | |
267 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); | |
268 EXPECT_CALL(*adapter_, AddObserver(&connection)); | |
269 EXPECT_CALL(connection, ConnectToService(&device_, uuid_, _, _)) | |
270 .WillOnce(SaveArg<3>(&error_callback)); | |
271 connection.Connect(); | |
272 ASSERT_FALSE(error_callback.is_null()); | |
273 | |
274 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
275 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
276 error_callback.Run("super descriptive error message"); | |
277 } | |
278 | |
279 TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionSucceeds) { | |
280 StrictMock<MockBluetoothConnection> connection; | |
281 Connect(&connection); | |
282 | |
283 // The connection disconnects and unregisters as an observer upon destruction. | |
284 EXPECT_CALL(*socket_, Disconnect(_)); | |
285 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
286 } | |
287 | |
288 TEST_F(ProximityAuthBluetoothConnectionTest, | |
289 Connect_ConnectionSucceeds_ThenDeviceRemoved) { | |
290 StrictMock<MockBluetoothConnection> connection; | |
291 Connect(&connection); | |
292 | |
293 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
294 EXPECT_CALL(*socket_, Disconnect(_)); | |
295 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
296 connection.DeviceRemoved(adapter_.get(), &device_); | |
297 } | |
298 | |
299 TEST_F(ProximityAuthBluetoothConnectionTest, | |
300 Connect_ConnectionSucceeds_ReceiveData) { | |
301 StrictMock<MockBluetoothConnection> connection; | |
302 device::BluetoothSocket::ReceiveCompletionCallback receive_callback; | |
303 ConnectAndCaptureReceiveCallbacks(&connection, &receive_callback, NULL); | |
304 ASSERT_FALSE(receive_callback.is_null()); | |
305 | |
306 // Receive some data. Once complete, the connection should re-register to be | |
307 // ready receive more data. | |
308 scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer(); | |
309 EXPECT_CALL( | |
310 connection, | |
311 OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize))); | |
312 EXPECT_CALL(*socket_, Receive(_, _, _)); | |
313 receive_callback.Run(kReceiveBufferSize, buffer); | |
314 base::RunLoop run_loop; | |
315 run_loop.RunUntilIdle(); | |
316 | |
317 // The connection disconnects and unregisters as an observer upon destruction. | |
318 EXPECT_CALL(*socket_, Disconnect(_)); | |
319 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
320 } | |
321 | |
322 TEST_F(ProximityAuthBluetoothConnectionTest, | |
323 Connect_ConnectionSucceeds_ReceiveDataAfterReceiveError) { | |
324 StrictMock<MockBluetoothConnection> connection; | |
325 device::BluetoothSocket::ReceiveErrorCompletionCallback | |
326 receive_error_callback; | |
327 ConnectAndCaptureReceiveCallbacks(&connection, NULL, &receive_error_callback); | |
328 ASSERT_FALSE(receive_error_callback.is_null()); | |
329 | |
330 // Simulate an error while receiving data. The connection should re-register | |
331 // to be ready receive more data despite the error. | |
332 device::BluetoothSocket::ReceiveCompletionCallback receive_callback; | |
333 EXPECT_CALL(*socket_, Receive(_, _, _)) | |
334 .WillOnce(SaveArg<1>(&receive_callback)); | |
335 receive_error_callback.Run(device::BluetoothSocket::kSystemError, | |
336 "The system is down. They're taking over!"); | |
337 base::RunLoop run_loop; | |
338 run_loop.RunUntilIdle(); | |
339 | |
340 // Receive some data. | |
341 scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer(); | |
342 EXPECT_CALL( | |
343 connection, | |
344 OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize))); | |
345 EXPECT_CALL(*socket_, Receive(_, _, _)); | |
346 receive_callback.Run(kReceiveBufferSize, buffer); | |
347 base::RunLoop run_loop2; | |
348 run_loop2.RunUntilIdle(); | |
349 | |
350 // The connection disconnects and unregisters as an observer upon destruction. | |
351 EXPECT_CALL(*socket_, Disconnect(_)); | |
352 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
353 } | |
354 | |
355 TEST_F(ProximityAuthBluetoothConnectionTest, | |
356 Disconnect_ConnectionWasAlreadyDisconnected) { | |
357 StrictMock<MockBluetoothConnection> connection; | |
358 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
359 connection.Disconnect(); | |
360 } | |
361 | |
362 TEST_F(ProximityAuthBluetoothConnectionTest, | |
363 Disconnect_ConnectionWasInProgress) { | |
364 // Create an in-progress connection. | |
365 StrictMock<MockBluetoothConnection> connection; | |
366 BeginConnecting(&connection); | |
367 | |
368 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
369 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
370 connection.Disconnect(); | |
371 } | |
372 | |
373 TEST_F(ProximityAuthBluetoothConnectionTest, | |
374 Disconnect_ConnectionWasConnected) { | |
375 // Create a connected connection. | |
376 StrictMock<MockBluetoothConnection> connection; | |
377 Connect(&connection); | |
378 | |
379 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
380 EXPECT_CALL(*socket_, Disconnect(_)); | |
381 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
382 connection.Disconnect(); | |
383 } | |
384 | |
385 TEST_F(ProximityAuthBluetoothConnectionTest, | |
386 Connect_ThenDisconnectWhileInProgress_ThenBackingConnectionSucceeds) { | |
387 StrictMock<MockBluetoothConnection> connection; | |
388 device::BluetoothDevice::ConnectToServiceCallback callback; | |
389 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); | |
390 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); | |
391 EXPECT_CALL(*adapter_, AddObserver(&connection)); | |
392 EXPECT_CALL(connection, ConnectToService(&device_, uuid_, _, _)) | |
393 .WillOnce(SaveArg<2>(&callback)); | |
394 connection.Connect(); | |
395 ASSERT_FALSE(callback.is_null()); | |
396 | |
397 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
398 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
399 connection.Disconnect(); | |
400 | |
401 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); | |
402 EXPECT_CALL(*socket_, Receive(_, _, _)).Times(0); | |
403 callback.Run(socket_); | |
404 } | |
405 | |
406 TEST_F(ProximityAuthBluetoothConnectionTest, | |
407 SendMessage_SendsExpectedDataOverTheWire) { | |
408 // Create a connected connection. | |
409 StrictMock<MockBluetoothConnection> connection; | |
410 Connect(&connection); | |
411 | |
412 scoped_refptr<net::IOBuffer> buffer; | |
413 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); | |
414 EXPECT_CALL(*socket_, Send(_, kSerializedMessageLength, _, _)) | |
415 .WillOnce(SaveArg<0>(&buffer)); | |
416 connection.SendMessage(wire_message.PassAs<WireMessage>()); | |
417 ASSERT_TRUE(buffer.get()); | |
418 EXPECT_EQ(kSerializedMessage, | |
419 std::string(buffer->data(), kSerializedMessageLength)); | |
420 | |
421 // The connection disconnects and unregisters as an observer upon destruction. | |
422 EXPECT_CALL(*socket_, Disconnect(_)); | |
423 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
424 } | |
425 | |
426 TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Success) { | |
427 // Create a connected connection. | |
428 StrictMock<MockBluetoothConnection> connection; | |
429 Connect(&connection); | |
430 | |
431 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); | |
432 // Ownership will be transfered below, so grab a reference here. | |
433 TestWireMessage* expected_wire_message = wire_message.get(); | |
434 | |
435 device::BluetoothSocket::SendCompletionCallback callback; | |
436 EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<2>(&callback)); | |
437 connection.SendMessage(wire_message.PassAs<WireMessage>()); | |
438 ASSERT_FALSE(callback.is_null()); | |
439 | |
440 EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), true)); | |
441 callback.Run(kSerializedMessageLength); | |
442 | |
443 // The connection disconnects and unregisters as an observer upon destruction. | |
444 EXPECT_CALL(*socket_, Disconnect(_)); | |
445 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
446 } | |
447 | |
448 TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Failure) { | |
449 // Create a connected connection. | |
450 StrictMock<MockBluetoothConnection> connection; | |
451 Connect(&connection); | |
452 | |
453 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); | |
454 // Ownership will be transfered below, so grab a reference here. | |
455 TestWireMessage* expected_wire_message = wire_message.get(); | |
456 | |
457 device::BluetoothSocket::ErrorCompletionCallback error_callback; | |
458 EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<3>(&error_callback)); | |
459 connection.SendMessage(wire_message.PassAs<WireMessage>()); | |
460 | |
461 ASSERT_FALSE(error_callback.is_null()); | |
462 EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), false)); | |
463 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); | |
464 EXPECT_CALL(*socket_, Disconnect(_)); | |
465 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); | |
466 error_callback.Run("The most helpful of error messages"); | |
467 } | |
468 | |
469 } // namespace proximity_auth | |
OLD | NEW |