Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: chrome/browser/extensions/api/bluetooth/bluetooth_api.h

Issue 180163009: chrome.bluetooth API improvements. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address code review feedback, simplify threading model. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_ 5 #ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_ 6 #define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_
7 7
8 #include <string> 8 #include <string>
9 9
10 #include "base/memory/ref_counted.h" 10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_socket.h"
12 #include "chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h " 13 #include "chrome/browser/extensions/api/bluetooth/bluetooth_extension_function.h "
14 #include "chrome/common/extensions/api/bluetooth.h"
13 #include "device/bluetooth/bluetooth_device.h" 15 #include "device/bluetooth/bluetooth_device.h"
14 #include "device/bluetooth/bluetooth_profile.h" 16 #include "device/bluetooth/bluetooth_profile.h"
17 #include "device/bluetooth/bluetooth_socket.h"
18 #include "extensions/browser/api/api_resource_manager.h"
15 #include "extensions/browser/api/async_api_function.h" 19 #include "extensions/browser/api/async_api_function.h"
16 #include "extensions/browser/browser_context_keyed_api_factory.h" 20 #include "extensions/browser/browser_context_keyed_api_factory.h"
17 #include "extensions/browser/event_router.h" 21 #include "extensions/browser/event_router.h"
18 #include "extensions/browser/extension_function.h" 22 #include "extensions/browser/extension_function.h"
19 23
20 namespace content { 24 namespace content {
21 class BrowserContext; 25 class BrowserContext;
22 } 26 }
23 27
24 namespace device { 28 namespace device {
29 class BluetoothAdapter;
30 struct BluetoothOutOfBandPairingData;
31 }
25 32
26 class BluetoothAdapter; 33 namespace net {
27 class BluetoothDevice; 34 class IOBuffer;
28 class BluetoothSocket; 35 }
29 struct BluetoothOutOfBandPairingData;
30
31 } // namespace device
32 36
33 namespace extensions { 37 namespace extensions {
34 38
35 class ExtensionBluetoothEventRouter; 39 class ExtensionBluetoothEventRouter;
36 40
37 // The profile-keyed service that manages the bluetooth extension API. 41 // The profile-keyed service that manages the bluetooth extension API.
42 // All methods of this class must be called on the UI thread.
43 // TODO(rpaquay): Rename this and move to separate file.
38 class BluetoothAPI : public BrowserContextKeyedAPI, 44 class BluetoothAPI : public BrowserContextKeyedAPI,
39 public EventRouter::Observer { 45 public EventRouter::Observer {
40 public: 46 public:
41 // Convenience method to get the BluetoothAPI for a profile. 47 typedef ApiResourceManager<BluetoothApiSocket>::ApiResourceData SocketData;
48
49 struct ConnectionParams {
50 ConnectionParams();
51 ~ConnectionParams();
52
53 content::BrowserThread::ID thread_id;
54 void* browser_context_id;
55 std::string extension_id;
56 std::string device_address;
57 std::string uuid;
58 scoped_refptr<device::BluetoothSocket> socket;
59 scoped_refptr<SocketData> socket_data;
60 };
61
62 // Convenience method to get the BluetoothAPI for a browser context.
42 static BluetoothAPI* Get(content::BrowserContext* context); 63 static BluetoothAPI* Get(content::BrowserContext* context);
43 64
44 static BrowserContextKeyedAPIFactory<BluetoothAPI>* GetFactoryInstance(); 65 static BrowserContextKeyedAPIFactory<BluetoothAPI>* GetFactoryInstance();
45 66
46 explicit BluetoothAPI(content::BrowserContext* context); 67 explicit BluetoothAPI(content::BrowserContext* context);
47 virtual ~BluetoothAPI(); 68 virtual ~BluetoothAPI();
48 69
49 ExtensionBluetoothEventRouter* bluetooth_event_router(); 70 ExtensionBluetoothEventRouter* event_router();
71 scoped_refptr<SocketData> socket_data();
72 scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher();
50 73
51 // KeyedService implementation. 74 // KeyedService implementation.
52 virtual void Shutdown() OVERRIDE; 75 virtual void Shutdown() OVERRIDE;
53 76
54 // EventRouter::Observer implementation. 77 // EventRouter::Observer implementation.
55 virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE; 78 virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
56 virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE; 79 virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE;
57 80
81 // Dispatch an event that takes a connection socket as a parameter to the
82 // extension that registered the profile that the socket has connected to.
83 void DispatchConnectionEvent(const std::string& extension_id,
84 const std::string& profile_uuid,
85 const device::BluetoothDevice* device,
86 scoped_refptr<device::BluetoothSocket> socket);
87
58 private: 88 private:
59 friend class BrowserContextKeyedAPIFactory<BluetoothAPI>; 89 static void RegisterSocket(const ConnectionParams& params);
90 static void RegisterSocketUI(const ConnectionParams& params, int socket_id);
91 static void RegisterSocketWithAdapterUI(
92 const ConnectionParams& params,
93 int socket_id,
94 scoped_refptr<device::BluetoothAdapter> adapter);
60 95
61 // BrowserContextKeyedAPI implementation. 96 // BrowserContextKeyedAPI implementation.
97 friend class BrowserContextKeyedAPIFactory<BluetoothAPI>;
62 static const char* service_name() { return "BluetoothAPI"; } 98 static const char* service_name() { return "BluetoothAPI"; }
63 static const bool kServiceRedirectedInIncognito = true; 99 static const bool kServiceRedirectedInIncognito = true;
64 static const bool kServiceIsNULLWhileTesting = true; 100 static const bool kServiceIsNULLWhileTesting = true;
65 101
66 content::BrowserContext* browser_context_; 102 content::BrowserContext* browser_context_;
67 103
68 // Created lazily on first access. 104 // Created lazily on first access.
69 scoped_ptr<ExtensionBluetoothEventRouter> bluetooth_event_router_; 105 scoped_ptr<ExtensionBluetoothEventRouter> event_router_;
106 scoped_refptr<SocketData> socket_data_;
107 scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher_;
70 }; 108 };
71 109
72 namespace api { 110 namespace api {
73 111
112 class BluetoothSocketEventDispatcher;
113
114 // Base class for methods dealing with BluetoothSocketApi and
115 // ApiResourceManager<BluetoothSocketApi>.
116 class BluetoothSocketApiFunction : public UIThreadExtensionFunction {
117 public:
118 BluetoothSocketApiFunction();
119
120 protected:
121 virtual ~BluetoothSocketApiFunction();
122
123 // ExtensionFunction::RunImpl()
124 virtual bool RunImpl() OVERRIDE;
125
126 bool PrePrepare();
127 bool Respond();
128 void AsyncWorkCompleted();
129
130 virtual bool Prepare() = 0;
131 virtual void Work();
132 virtual void AsyncWorkStart();
133
134 content::BrowserThread::ID work_thread_id() const {
135 return BluetoothApiSocket::kThreadId;
136 }
137
138 scoped_refptr<BluetoothAPI::SocketData> socket_data_;
139 scoped_refptr<api::BluetoothSocketEventDispatcher> socket_event_dispatcher_;
140 };
141
142 class BluetoothGetAdapterStateFunction : public BluetoothExtensionFunction {
143 public:
144 DECLARE_EXTENSION_FUNCTION("bluetooth.getAdapterState",
145 BLUETOOTH_GETADAPTERSTATE)
146
147 protected:
148 virtual ~BluetoothGetAdapterStateFunction();
149
150 // BluetoothExtensionFunction:
151 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
152 };
153
154 class BluetoothGetDevicesFunction : public BluetoothExtensionFunction {
155 public:
156 DECLARE_EXTENSION_FUNCTION("bluetooth.getDevices", BLUETOOTH_GETDEVICES)
157
158 protected:
159 virtual ~BluetoothGetDevicesFunction();
160
161 // BluetoothExtensionFunction:
162 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
163 };
164
74 class BluetoothAddProfileFunction : public UIThreadExtensionFunction { 165 class BluetoothAddProfileFunction : public UIThreadExtensionFunction {
75 public: 166 public:
76 DECLARE_EXTENSION_FUNCTION("bluetooth.addProfile", BLUETOOTH_ADDPROFILE) 167 DECLARE_EXTENSION_FUNCTION("bluetooth.addProfile", BLUETOOTH_ADDPROFILE)
77 168
78 BluetoothAddProfileFunction(); 169 BluetoothAddProfileFunction();
79 170
80 protected: 171 protected:
81 virtual ~BluetoothAddProfileFunction() {} 172 virtual ~BluetoothAddProfileFunction();
82 virtual bool RunImpl() OVERRIDE; 173 virtual bool RunImpl() OVERRIDE;
83 174
84 virtual void RegisterProfile( 175 virtual void RegisterProfile(
85 const device::BluetoothProfile::Options& options, 176 const device::BluetoothProfile::Options& options,
86 const device::BluetoothProfile::ProfileCallback& callback); 177 const device::BluetoothProfile::ProfileCallback& callback);
87 178
88 private: 179 private:
89 void OnProfileRegistered(device::BluetoothProfile* bluetooth_profile); 180 void OnProfileRegistered(device::BluetoothProfile* bluetooth_profile);
90 181
91 std::string uuid_; 182 std::string uuid_;
92 }; 183 };
93 184
94 class BluetoothRemoveProfileFunction : public SyncExtensionFunction { 185 class BluetoothRemoveProfileFunction : public SyncExtensionFunction {
95 public: 186 public:
96 DECLARE_EXTENSION_FUNCTION("bluetooth.removeProfile", 187 DECLARE_EXTENSION_FUNCTION("bluetooth.removeProfile",
97 BLUETOOTH_REMOVEPROFILE) 188 BLUETOOTH_REMOVEPROFILE)
98 189
99 protected: 190 protected:
100 virtual ~BluetoothRemoveProfileFunction() {} 191 virtual ~BluetoothRemoveProfileFunction();
101 virtual bool RunImpl() OVERRIDE; 192 virtual bool RunImpl() OVERRIDE;
102 }; 193 };
103 194
104 class BluetoothGetProfilesFunction : public BluetoothExtensionFunction { 195 class BluetoothGetProfilesFunction : public BluetoothExtensionFunction {
105 public: 196 public:
106 DECLARE_EXTENSION_FUNCTION("bluetooth.getProfiles", BLUETOOTH_GETPROFILES) 197 DECLARE_EXTENSION_FUNCTION("bluetooth.getProfiles", BLUETOOTH_GETPROFILES)
107 198
108 protected: 199 protected:
109 virtual ~BluetoothGetProfilesFunction() {} 200 virtual ~BluetoothGetProfilesFunction();
110 201
111 // BluetoothExtensionFunction: 202 // BluetoothExtensionFunction:
112 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE; 203 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
113 }; 204 };
114 205
115 class BluetoothGetAdapterStateFunction : public BluetoothExtensionFunction {
116 public:
117 DECLARE_EXTENSION_FUNCTION("bluetooth.getAdapterState",
118 BLUETOOTH_GETADAPTERSTATE)
119
120 protected:
121 virtual ~BluetoothGetAdapterStateFunction() {}
122
123 // BluetoothExtensionFunction:
124 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
125 };
126
127 class BluetoothGetDevicesFunction : public BluetoothExtensionFunction {
128 public:
129 DECLARE_EXTENSION_FUNCTION("bluetooth.getDevices", BLUETOOTH_GETDEVICES)
130
131 protected:
132 virtual ~BluetoothGetDevicesFunction() {}
133
134 // BluetoothExtensionFunction:
135 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
136 };
137
138 class BluetoothGetServicesFunction : public BluetoothExtensionFunction {
139 public:
140 DECLARE_EXTENSION_FUNCTION("bluetooth.getServices", BLUETOOTH_GETSERVICES)
141
142 protected:
143 virtual ~BluetoothGetServicesFunction() {}
144
145 // BluetoothExtensionFunction:
146 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
147
148 private:
149 void GetServiceRecordsCallback(
150 base::ListValue* services,
151 const device::BluetoothDevice::ServiceRecordList& records);
152 void OnErrorCallback();
153 };
154
155 class BluetoothConnectFunction : public BluetoothExtensionFunction { 206 class BluetoothConnectFunction : public BluetoothExtensionFunction {
156 public: 207 public:
157 DECLARE_EXTENSION_FUNCTION("bluetooth.connect", BLUETOOTH_CONNECT) 208 DECLARE_EXTENSION_FUNCTION("bluetooth.connect", BLUETOOTH_CONNECT)
158 209
159 protected: 210 protected:
160 virtual ~BluetoothConnectFunction() {} 211 virtual ~BluetoothConnectFunction();
161 212
162 // BluetoothExtensionFunction: 213 // BluetoothExtensionFunction:
163 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE; 214 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
164 215
165 private: 216 private:
166 void OnSuccessCallback(); 217 void OnSuccessCallback();
167 void OnErrorCallback(); 218 void OnErrorCallback(const std::string& error);
168 }; 219 };
169 220
170 class BluetoothDisconnectFunction : public SyncExtensionFunction { 221 class BluetoothDisconnectFunction : public BluetoothSocketApiFunction {
171 public: 222 public:
172 DECLARE_EXTENSION_FUNCTION("bluetooth.disconnect", BLUETOOTH_DISCONNECT) 223 DECLARE_EXTENSION_FUNCTION("bluetooth.disconnect", BLUETOOTH_DISCONNECT)
224 BluetoothDisconnectFunction();
173 225
174 protected: 226 protected:
175 virtual ~BluetoothDisconnectFunction() {} 227 virtual ~BluetoothDisconnectFunction();
176
177 // ExtensionFunction:
178 virtual bool RunImpl() OVERRIDE;
179 };
180
181 class BluetoothReadFunction : public AsyncApiFunction {
182 public:
183 DECLARE_EXTENSION_FUNCTION("bluetooth.read", BLUETOOTH_READ)
184 BluetoothReadFunction();
185
186 protected:
187 virtual ~BluetoothReadFunction();
188 228
189 // AsyncApiFunction: 229 // AsyncApiFunction:
190 virtual bool Prepare() OVERRIDE; 230 virtual bool Prepare() OVERRIDE;
191 virtual bool Respond() OVERRIDE; 231 virtual void AsyncWorkStart() OVERRIDE;
232
233 private:
234 void OnSuccess();
235
236 scoped_ptr<bluetooth::Disconnect::Params> params_;
237 };
238
239 class BluetoothSendFunction : public BluetoothSocketApiFunction {
240 public:
241 DECLARE_EXTENSION_FUNCTION("bluetooth.send", BLUETOOTH_SEND)
242 BluetoothSendFunction();
243
244 protected:
245 virtual ~BluetoothSendFunction();
246
247 // AsyncApiFunction:
248 virtual bool Prepare() OVERRIDE;
249 virtual void AsyncWorkStart() OVERRIDE;
250
251 private:
252 void OnSendSuccess(int bytes_sent);
253 void OnSendError(const std::string& message);
254
255 scoped_ptr<bluetooth::Send::Params> params_;
256 scoped_refptr<net::IOBuffer> io_buffer_;
257 size_t io_buffer_size_;
258 };
259
260 class BluetoothUpdateSocketFunction : public BluetoothSocketApiFunction {
261 public:
262 DECLARE_EXTENSION_FUNCTION("bluetooth.updateSocket", BLUETOOTH_UPDATE_SOCKET)
263 BluetoothUpdateSocketFunction();
264
265 protected:
266 virtual ~BluetoothUpdateSocketFunction();
267
268 // AsyncApiFunction:
269 virtual bool Prepare() OVERRIDE;
192 virtual void Work() OVERRIDE; 270 virtual void Work() OVERRIDE;
193 271
194 private: 272 private:
195 bool success_; 273 scoped_ptr<bluetooth::UpdateSocket::Params> params_;
196 scoped_refptr<device::BluetoothSocket> socket_;
197 }; 274 };
198 275
199 class BluetoothWriteFunction : public AsyncApiFunction { 276 class BluetoothSetSocketPausedFunction : public BluetoothSocketApiFunction {
200 public: 277 public:
201 DECLARE_EXTENSION_FUNCTION("bluetooth.write", BLUETOOTH_WRITE) 278 DECLARE_EXTENSION_FUNCTION("bluetooth.setSocketPaused",
202 BluetoothWriteFunction(); 279 BLUETOOTH_SET_SOCKET_PAUSED)
280 BluetoothSetSocketPausedFunction();
203 281
204 protected: 282 protected:
205 virtual ~BluetoothWriteFunction(); 283 virtual ~BluetoothSetSocketPausedFunction();
206 284
207 // AsyncApiFunction: 285 // AsyncApiFunction:
208 virtual bool Prepare() OVERRIDE; 286 virtual bool Prepare() OVERRIDE;
209 virtual bool Respond() OVERRIDE;
210 virtual void Work() OVERRIDE; 287 virtual void Work() OVERRIDE;
211 288
212 private: 289 private:
213 bool success_; 290 scoped_ptr<bluetooth::SetSocketPaused::Params> params_;
214 const base::BinaryValue* data_to_write_; // memory is owned by args_ 291 };
215 scoped_refptr<device::BluetoothSocket> socket_; 292
293 class BluetoothGetSocketFunction : public BluetoothSocketApiFunction {
294 public:
295 DECLARE_EXTENSION_FUNCTION("bluetooth.getSocket", BLUETOOTH_GET_SOCKET)
296
297 BluetoothGetSocketFunction();
298
299 protected:
300 virtual ~BluetoothGetSocketFunction();
301
302 // AsyncApiFunction:
303 virtual bool Prepare() OVERRIDE;
304 virtual void Work() OVERRIDE;
305
306 private:
307 scoped_ptr<bluetooth::GetSocket::Params> params_;
308 };
309
310 class BluetoothGetSocketsFunction : public BluetoothSocketApiFunction {
311 public:
312 DECLARE_EXTENSION_FUNCTION("bluetooth.getSockets", BLUETOOTH_GET_SOCKETS)
313
314 BluetoothGetSocketsFunction();
315
316 protected:
317 virtual ~BluetoothGetSocketsFunction();
318
319 // AsyncApiFunction:
320 virtual bool Prepare() OVERRIDE;
321 virtual void Work() OVERRIDE;
322 };
323
324 class BluetoothGetLocalOutOfBandPairingDataFunction
325 : public BluetoothExtensionFunction {
326 public:
327 DECLARE_EXTENSION_FUNCTION("bluetooth.getLocalOutOfBandPairingData",
328 BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA)
329
330 protected:
331 virtual ~BluetoothGetLocalOutOfBandPairingDataFunction() {}
332
333 void ReadCallback(const device::BluetoothOutOfBandPairingData& data);
334 void ErrorCallback();
335
336 // BluetoothExtensionFunction:
337 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
216 }; 338 };
217 339
218 class BluetoothSetOutOfBandPairingDataFunction 340 class BluetoothSetOutOfBandPairingDataFunction
219 : public BluetoothExtensionFunction { 341 : public BluetoothExtensionFunction {
220 public: 342 public:
221 DECLARE_EXTENSION_FUNCTION("bluetooth.setOutOfBandPairingData", 343 DECLARE_EXTENSION_FUNCTION("bluetooth.setOutOfBandPairingData",
222 BLUETOOTH_SETOUTOFBANDPAIRINGDATA) 344 BLUETOOTH_SETOUTOFBANDPAIRINGDATA)
223 345
224 protected: 346 protected:
225 virtual ~BluetoothSetOutOfBandPairingDataFunction() {} 347 virtual ~BluetoothSetOutOfBandPairingDataFunction() {}
226 348
227 void OnSuccessCallback(); 349 void OnSuccessCallback();
228 void OnErrorCallback(); 350 void OnErrorCallback();
229 351
230 // BluetoothExtensionFunction: 352 // BluetoothExtensionFunction:
231 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE; 353 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
232 };
233
234 class BluetoothGetLocalOutOfBandPairingDataFunction
235 : public BluetoothExtensionFunction {
236 public:
237 DECLARE_EXTENSION_FUNCTION("bluetooth.getLocalOutOfBandPairingData",
238 BLUETOOTH_GETLOCALOUTOFBANDPAIRINGDATA)
239
240 protected:
241 virtual ~BluetoothGetLocalOutOfBandPairingDataFunction() {}
242
243 void ReadCallback(
244 const device::BluetoothOutOfBandPairingData& data);
245 void ErrorCallback();
246
247 // BluetoothExtensionFunction:
248 virtual bool DoWork(scoped_refptr<device::BluetoothAdapter> adapter) OVERRIDE;
249 }; 354 };
250 355
251 class BluetoothStartDiscoveryFunction : public BluetoothExtensionFunction { 356 class BluetoothStartDiscoveryFunction : public BluetoothExtensionFunction {
252 public: 357 public:
253 DECLARE_EXTENSION_FUNCTION("bluetooth.startDiscovery", 358 DECLARE_EXTENSION_FUNCTION("bluetooth.startDiscovery",
254 BLUETOOTH_STARTDISCOVERY) 359 BLUETOOTH_STARTDISCOVERY)
255 360
256 protected: 361 protected:
257 virtual ~BluetoothStartDiscoveryFunction() {} 362 virtual ~BluetoothStartDiscoveryFunction() {}
258 363
(...skipping 17 matching lines...) Expand all
276 381
277 private: 382 private:
278 void OnSuccessCallback(); 383 void OnSuccessCallback();
279 void OnErrorCallback(); 384 void OnErrorCallback();
280 }; 385 };
281 386
282 } // namespace api 387 } // namespace api
283 } // namespace extensions 388 } // namespace extensions
284 389
285 #endif // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_ 390 #endif // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_BLUETOOTH_API_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698