Enable Enterprise enrollment on desktop builds.
[chromium-blink-merge.git] / chrome / browser / extensions / api / bluetooth / bluetooth_api.cc
blob77128f855e5e43b5f74d27bbf51a9b7b09b4d910
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 "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
7 #include <string>
9 #include "base/lazy_instance.h"
10 #include "base/memory/ref_counted.h"
11 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h"
12 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/common/extensions/api/bluetooth.h"
15 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "device/bluetooth/bluetooth_adapter.h"
18 #include "device/bluetooth/bluetooth_device.h"
19 #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
20 #include "device/bluetooth/bluetooth_profile.h"
21 #include "device/bluetooth/bluetooth_service_record.h"
22 #include "device/bluetooth/bluetooth_socket.h"
23 #include "extensions/browser/event_router.h"
24 #include "extensions/common/permissions/permissions_data.h"
25 #include "net/base/io_buffer.h"
27 using content::BrowserContext;
28 using content::BrowserThread;
30 using device::BluetoothAdapter;
31 using device::BluetoothDevice;
32 using device::BluetoothProfile;
33 using device::BluetoothServiceRecord;
34 using device::BluetoothSocket;
36 using extensions::BluetoothApiSocket;
38 namespace AddProfile = extensions::api::bluetooth::AddProfile;
39 namespace bluetooth = extensions::api::bluetooth;
40 namespace Connect = extensions::api::bluetooth::Connect;
41 namespace Disconnect = extensions::api::bluetooth::Disconnect;
42 namespace GetDevice = extensions::api::bluetooth::GetDevice;
43 namespace GetDevices = extensions::api::bluetooth::GetDevices;
44 namespace RemoveProfile = extensions::api::bluetooth::RemoveProfile;
45 namespace SetOutOfBandPairingData =
46 extensions::api::bluetooth::SetOutOfBandPairingData;
47 namespace Send = extensions::api::bluetooth::Send;
49 namespace {
51 const char kCouldNotGetLocalOutOfBandPairingData[] =
52 "Could not get local Out Of Band Pairing Data";
53 const char kCouldNotSetOutOfBandPairingData[] =
54 "Could not set Out Of Band Pairing Data";
55 const char kInvalidDevice[] = "Invalid device";
56 const char kInvalidUuid[] = "Invalid UUID";
57 const char kPermissionDenied[] = "Permission to add profile denied.";
58 const char kProfileAlreadyRegistered[] =
59 "This profile has already been registered";
60 const char kProfileNotFound[] = "Profile not found: invalid uuid";
61 const char kProfileRegistrationFailed[] = "Profile registration failed";
62 const char kStartDiscoveryFailed[] = "Starting discovery failed";
63 const char kStopDiscoveryFailed[] = "Failed to stop discovery";
65 extensions::BluetoothEventRouter* GetEventRouter(BrowserContext* context) {
66 // Note: |context| is valid on UI thread only.
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
68 return extensions::BluetoothAPI::Get(context)->event_router();
71 static void DispatchConnectionEventWorker(
72 void* browser_context_id,
73 const std::string& extension_id,
74 const device::BluetoothUUID& profile_uuid,
75 const device::BluetoothDevice* device,
76 scoped_refptr<device::BluetoothSocket> socket) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79 content::BrowserContext* context =
80 reinterpret_cast<content::BrowserContext*>(browser_context_id);
81 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
82 return;
84 extensions::BluetoothAPI* bluetooth_api =
85 extensions::BluetoothAPI::Get(context);
86 if (!bluetooth_api)
87 return;
89 bluetooth_api->DispatchConnectionEvent(
90 extension_id, profile_uuid, device, socket);
93 } // namespace
95 namespace extensions {
97 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothAPI> >
98 g_factory = LAZY_INSTANCE_INITIALIZER;
100 // static
101 BrowserContextKeyedAPIFactory<BluetoothAPI>*
102 BluetoothAPI::GetFactoryInstance() {
103 return g_factory.Pointer();
106 // static
107 BluetoothAPI* BluetoothAPI::Get(BrowserContext* context) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109 return GetFactoryInstance()->Get(context);
112 BluetoothAPI::ConnectionParams::ConnectionParams() {}
114 BluetoothAPI::ConnectionParams::~ConnectionParams() {}
116 BluetoothAPI::BluetoothAPI(content::BrowserContext* context)
117 : browser_context_(context) {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 EventRouter* event_router = EventRouter::Get(browser_context_);
120 event_router->RegisterObserver(this,
121 bluetooth::OnAdapterStateChanged::kEventName);
122 event_router->RegisterObserver(this, bluetooth::OnDeviceAdded::kEventName);
123 event_router->RegisterObserver(this, bluetooth::OnDeviceChanged::kEventName);
124 event_router->RegisterObserver(this, bluetooth::OnDeviceRemoved::kEventName);
127 BluetoothAPI::~BluetoothAPI() {}
129 BluetoothEventRouter* BluetoothAPI::event_router() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
131 if (!event_router_) {
132 event_router_.reset(new BluetoothEventRouter(browser_context_));
134 return event_router_.get();
137 scoped_refptr<BluetoothAPI::SocketData> BluetoothAPI::socket_data() {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139 if (!socket_data_) {
140 ApiResourceManager<BluetoothApiSocket>* socket_manager =
141 ApiResourceManager<BluetoothApiSocket>::Get(browser_context_);
142 DCHECK(socket_manager)
143 << "There is no socket manager. "
144 "If this assertion is failing during a test, then it is likely that "
145 "TestExtensionSystem is failing to provide an instance of "
146 "ApiResourceManager<BluetoothApiSocket>.";
148 socket_data_ = socket_manager->data_;
150 return socket_data_;
153 void BluetoothAPI::Shutdown() {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155 EventRouter::Get(browser_context_)->UnregisterObserver(this);
158 void BluetoothAPI::OnListenerAdded(const EventListenerInfo& details) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 if (event_router()->IsBluetoothSupported())
161 event_router()->OnListenerAdded();
164 void BluetoothAPI::OnListenerRemoved(const EventListenerInfo& details) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166 if (event_router()->IsBluetoothSupported())
167 event_router()->OnListenerRemoved();
170 void BluetoothAPI::DispatchConnectionEvent(
171 const std::string& extension_id,
172 const device::BluetoothUUID& uuid,
173 const device::BluetoothDevice* device,
174 scoped_refptr<device::BluetoothSocket> socket) {
175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177 if (!event_router()->HasProfile(uuid))
178 return;
180 extensions::BluetoothAPI::ConnectionParams params;
181 params.browser_context_id = browser_context_;
182 params.thread_id = BluetoothApiSocket::kThreadId;
183 params.extension_id = extension_id;
184 params.uuid = uuid;
185 params.device_address = device->GetAddress();
186 params.socket = socket;
187 params.socket_data = socket_data();
188 BrowserThread::PostTask(
189 params.thread_id, FROM_HERE, base::Bind(&RegisterSocket, params));
192 // static
193 void BluetoothAPI::RegisterSocket(
194 const BluetoothAPI::ConnectionParams& params) {
195 DCHECK(BrowserThread::CurrentlyOn(params.thread_id));
197 BluetoothApiSocket* api_socket = new BluetoothApiSocket(
198 params.extension_id, params.socket, params.device_address, params.uuid);
199 int socket_id = params.socket_data->Add(api_socket);
201 BrowserThread::PostTask(BrowserThread::UI,
202 FROM_HERE,
203 base::Bind(&RegisterSocketUI, params, socket_id));
206 // static
207 void BluetoothAPI::RegisterSocketUI(const ConnectionParams& params,
208 int socket_id) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 content::BrowserContext* context =
212 reinterpret_cast<content::BrowserContext*>(params.browser_context_id);
213 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
214 return;
216 BluetoothAPI::Get(context)->event_router()->GetAdapter(
217 base::Bind(&RegisterSocketWithAdapterUI, params, socket_id));
220 void BluetoothAPI::RegisterSocketWithAdapterUI(
221 const ConnectionParams& params,
222 int socket_id,
223 scoped_refptr<device::BluetoothAdapter> adapter) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 content::BrowserContext* context =
227 reinterpret_cast<content::BrowserContext*>(params.browser_context_id);
228 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context))
229 return;
231 BluetoothDevice* device = adapter->GetDevice(params.device_address);
232 if (!device)
233 return;
235 api::bluetooth::Socket result_socket;
236 bluetooth::BluetoothDeviceToApiDevice(*device, &result_socket.device);
237 result_socket.uuid = params.uuid.canonical_value();
238 result_socket.id = socket_id;
240 scoped_ptr<base::ListValue> args =
241 bluetooth::OnConnection::Create(result_socket);
242 scoped_ptr<Event> event(
243 new Event(bluetooth::OnConnection::kEventName, args.Pass()));
245 EventRouter* router = EventRouter::Get(context);
246 if (router)
247 router->DispatchEventToExtension(params.extension_id, event.Pass());
250 namespace api {
252 BluetoothGetAdapterStateFunction::~BluetoothGetAdapterStateFunction() {}
254 bool BluetoothGetAdapterStateFunction::DoWork(
255 scoped_refptr<BluetoothAdapter> adapter) {
256 bluetooth::AdapterState state;
257 PopulateAdapterState(*adapter.get(), &state);
258 results_ = bluetooth::GetAdapterState::Results::Create(state);
259 SendResponse(true);
260 return true;
263 BluetoothGetDevicesFunction::~BluetoothGetDevicesFunction() {}
265 bool BluetoothGetDevicesFunction::DoWork(
266 scoped_refptr<BluetoothAdapter> adapter) {
267 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
269 base::ListValue* device_list = new base::ListValue;
270 SetResult(device_list);
272 BluetoothAdapter::DeviceList devices = adapter->GetDevices();
273 for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin();
274 iter != devices.end();
275 ++iter) {
276 const BluetoothDevice* device = *iter;
277 DCHECK(device);
279 bluetooth::Device extension_device;
280 bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
282 device_list->Append(extension_device.ToValue().release());
285 SendResponse(true);
287 return true;
290 BluetoothGetDeviceFunction::~BluetoothGetDeviceFunction() {}
292 bool BluetoothGetDeviceFunction::DoWork(
293 scoped_refptr<BluetoothAdapter> adapter) {
294 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
296 scoped_ptr<GetDevice::Params> params(GetDevice::Params::Create(*args_));
297 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
298 const std::string& device_address = params->device_address;
300 BluetoothDevice* device = adapter->GetDevice(device_address);
301 if (device) {
302 bluetooth::Device extension_device;
303 bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
304 SetResult(extension_device.ToValue().release());
305 SendResponse(true);
306 } else {
307 SetError(kInvalidDevice);
308 SendResponse(false);
311 return false;
314 BluetoothAddProfileFunction::BluetoothAddProfileFunction() {}
316 BluetoothAddProfileFunction::~BluetoothAddProfileFunction() {}
318 bool BluetoothAddProfileFunction::RunImpl() {
319 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
320 scoped_ptr<AddProfile::Params> params(AddProfile::Params::Create(*args_));
321 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
323 device::BluetoothUUID uuid(params->profile.uuid);
325 if (!uuid.IsValid()) {
326 SetError(kInvalidUuid);
327 return false;
330 BluetoothPermissionRequest param(params->profile.uuid);
331 if (!BluetoothManifestData::CheckRequest(GetExtension(), param)) {
332 error_ = kPermissionDenied;
333 return false;
336 uuid_ = uuid;
338 if (GetEventRouter(browser_context())->HasProfile(uuid_)) {
339 SetError(kProfileAlreadyRegistered);
340 return false;
343 BluetoothProfile::Options options;
344 if (params->profile.name.get())
345 options.name = *params->profile.name.get();
346 if (params->profile.channel.get())
347 options.channel = *params->profile.channel.get();
348 if (params->profile.psm.get())
349 options.psm = *params->profile.psm.get();
350 if (params->profile.require_authentication.get()) {
351 options.require_authentication =
352 *params->profile.require_authentication.get();
354 if (params->profile.require_authorization.get()) {
355 options.require_authorization =
356 *params->profile.require_authorization.get();
358 if (params->profile.auto_connect.get())
359 options.auto_connect = *params->profile.auto_connect.get();
360 if (params->profile.version.get())
361 options.version = *params->profile.version.get();
362 if (params->profile.features.get())
363 options.features = *params->profile.features.get();
365 RegisterProfile(
366 options,
367 base::Bind(&BluetoothAddProfileFunction::OnProfileRegistered, this));
369 return true;
372 void BluetoothAddProfileFunction::RegisterProfile(
373 const BluetoothProfile::Options& options,
374 const BluetoothProfile::ProfileCallback& callback) {
375 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
376 BluetoothProfile::Register(uuid_, options, callback);
379 void BluetoothAddProfileFunction::OnProfileRegistered(
380 BluetoothProfile* bluetooth_profile) {
381 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
382 if (!bluetooth_profile) {
383 SetError(kProfileRegistrationFailed);
384 SendResponse(false);
385 return;
388 if (GetEventRouter(browser_context())->HasProfile(uuid_)) {
389 bluetooth_profile->Unregister();
390 SetError(kProfileAlreadyRegistered);
391 SendResponse(false);
392 return;
395 bluetooth_profile->SetConnectionCallback(
396 base::Bind(&DispatchConnectionEventWorker,
397 browser_context(),
398 extension_id(),
399 uuid_));
400 GetEventRouter(browser_context())
401 ->AddProfile(uuid_, extension_id(), bluetooth_profile);
402 SendResponse(true);
405 BluetoothRemoveProfileFunction::~BluetoothRemoveProfileFunction() {}
407 bool BluetoothRemoveProfileFunction::RunSync() {
408 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
409 scoped_ptr<RemoveProfile::Params> params(
410 RemoveProfile::Params::Create(*args_));
412 device::BluetoothUUID uuid(params->profile.uuid);
414 if (!uuid.IsValid()) {
415 SetError(kInvalidUuid);
416 return false;
419 if (!GetEventRouter(browser_context())->HasProfile(uuid)) {
420 SetError(kProfileNotFound);
421 return false;
424 GetEventRouter(browser_context())->RemoveProfile(uuid);
425 return true;
428 BluetoothConnectFunction::~BluetoothConnectFunction() {}
430 bool BluetoothConnectFunction::DoWork(scoped_refptr<BluetoothAdapter> adapter) {
431 scoped_ptr<Connect::Params> params(Connect::Params::Create(*args_));
432 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
433 const bluetooth::ConnectOptions& options = params->options;
435 device::BluetoothUUID uuid(options.profile.uuid);
437 if (!uuid.IsValid()) {
438 SetError(kInvalidUuid);
439 SendResponse(false);
440 return false;
443 BluetoothDevice* device = adapter->GetDevice(options.device.address);
444 if (!device) {
445 SetError(kInvalidDevice);
446 SendResponse(false);
447 return false;
450 BluetoothProfile* bluetooth_profile =
451 GetEventRouter(browser_context())->GetProfile(uuid);
452 if (!bluetooth_profile) {
453 SetError(kProfileNotFound);
454 SendResponse(false);
455 return false;
458 device->ConnectToProfile(
459 bluetooth_profile,
460 base::Bind(&BluetoothConnectFunction::OnSuccessCallback, this),
461 base::Bind(&BluetoothConnectFunction::OnErrorCallback, this));
463 return true;
466 void BluetoothConnectFunction::OnSuccessCallback() {
467 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
468 SendResponse(true);
471 void BluetoothConnectFunction::OnErrorCallback(const std::string& error) {
472 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
473 SetError(error);
474 SendResponse(false);
477 bool BluetoothDisconnectFunction::RunImpl() {
478 // TODO(keybuk): Remove.
479 SetError("Removed. Use chrome.bluetoothSocket.disconnect() instead.");
480 return false;
483 bool BluetoothSendFunction::RunImpl() {
484 // TODO(keybuk): Remove.
485 SetError("Removed. Use chrome.bluetoothSocket.send() instead.");
486 return false;
489 bool BluetoothUpdateSocketFunction::RunImpl() {
490 // TODO(keybuk): Remove.
491 SetError("Removed. Use chrome.bluetoothSocket.update() instead.");
492 return false;
495 bool BluetoothSetSocketPausedFunction::RunImpl() {
496 // TODO(keybuk): Remove.
497 SetError("Removed. Use chrome.bluetoothSocket.setPaused() instead.");
498 return false;
501 bool BluetoothGetSocketFunction::RunImpl() {
502 // TODO(keybuk): Remove.
503 SetError("Removed. Use chrome.bluetoothSocket.getInfo() instead.");
504 return false;
507 bool BluetoothGetSocketsFunction::RunImpl() {
508 // TODO(keybuk): Remove.
509 SetError("Removed. Use chrome.bluetoothSocket.getSockets() instead.");
510 return false;
513 void BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback() {
514 SendResponse(true);
517 void BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback() {
518 SetError(kCouldNotSetOutOfBandPairingData);
519 SendResponse(false);
522 bool BluetoothSetOutOfBandPairingDataFunction::DoWork(
523 scoped_refptr<BluetoothAdapter> adapter) {
524 // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
525 // support is added
526 base::DictionaryValue* options;
527 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options));
528 std::string address;
529 EXTENSION_FUNCTION_VALIDATE(options->GetString("deviceAddress", &address));
531 BluetoothDevice* device = adapter->GetDevice(address);
532 if (!device) {
533 SetError(kInvalidDevice);
534 SendResponse(false);
535 return false;
538 if (options->HasKey("data")) {
539 base::DictionaryValue* data_in;
540 EXTENSION_FUNCTION_VALIDATE(options->GetDictionary("data", &data_in));
542 device::BluetoothOutOfBandPairingData data_out;
544 base::BinaryValue* tmp_data;
545 EXTENSION_FUNCTION_VALIDATE(data_in->GetBinary("hash", &tmp_data));
546 EXTENSION_FUNCTION_VALIDATE(
547 tmp_data->GetSize() == device::kBluetoothOutOfBandPairingDataSize);
548 memcpy(data_out.hash,
549 reinterpret_cast<uint8_t*>(tmp_data->GetBuffer()),
550 device::kBluetoothOutOfBandPairingDataSize);
552 EXTENSION_FUNCTION_VALIDATE(data_in->GetBinary("randomizer", &tmp_data));
553 EXTENSION_FUNCTION_VALIDATE(
554 tmp_data->GetSize() == device::kBluetoothOutOfBandPairingDataSize);
555 memcpy(data_out.randomizer,
556 reinterpret_cast<uint8_t*>(tmp_data->GetBuffer()),
557 device::kBluetoothOutOfBandPairingDataSize);
559 device->SetOutOfBandPairingData(
560 data_out,
561 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback,
562 this),
563 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback,
564 this));
565 } else {
566 device->ClearOutOfBandPairingData(
567 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback,
568 this),
569 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback,
570 this));
573 return true;
576 void BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback(
577 const device::BluetoothOutOfBandPairingData& data) {
578 base::BinaryValue* hash = base::BinaryValue::CreateWithCopiedBuffer(
579 reinterpret_cast<const char*>(data.hash),
580 device::kBluetoothOutOfBandPairingDataSize);
581 base::BinaryValue* randomizer = base::BinaryValue::CreateWithCopiedBuffer(
582 reinterpret_cast<const char*>(data.randomizer),
583 device::kBluetoothOutOfBandPairingDataSize);
585 // TODO(bryeung): convert to bluetooth::OutOfBandPairingData
586 // when ArrayBuffer support within objects is completed.
587 base::DictionaryValue* result = new base::DictionaryValue();
588 result->Set("hash", hash);
589 result->Set("randomizer", randomizer);
591 SetResult(result);
593 SendResponse(true);
596 void BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback() {
597 SetError(kCouldNotGetLocalOutOfBandPairingData);
598 SendResponse(false);
601 bool BluetoothGetLocalOutOfBandPairingDataFunction::DoWork(
602 scoped_refptr<BluetoothAdapter> adapter) {
603 adapter->ReadLocalOutOfBandPairingData(
604 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback,
605 this),
606 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback,
607 this));
609 return true;
612 void BluetoothStartDiscoveryFunction::OnSuccessCallback() {
613 SendResponse(true);
616 void BluetoothStartDiscoveryFunction::OnErrorCallback() {
617 SetError(kStartDiscoveryFailed);
618 SendResponse(false);
621 bool BluetoothStartDiscoveryFunction::DoWork(
622 scoped_refptr<BluetoothAdapter> adapter) {
623 GetEventRouter(browser_context())->StartDiscoverySession(
624 adapter,
625 extension_id(),
626 base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this),
627 base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this));
629 return true;
632 void BluetoothStopDiscoveryFunction::OnSuccessCallback() {
633 SendResponse(true);
636 void BluetoothStopDiscoveryFunction::OnErrorCallback() {
637 SetError(kStopDiscoveryFailed);
638 SendResponse(false);
641 bool BluetoothStopDiscoveryFunction::DoWork(
642 scoped_refptr<BluetoothAdapter> adapter) {
643 GetEventRouter(browser_context())->StopDiscoverySession(
644 adapter,
645 extension_id(),
646 base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback, this),
647 base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback, this));
649 return true;
652 } // namespace api
653 } // namespace extensions