Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /*
4 ** Copyright 2006, The Android Open Source Project
5 **
6 ** Licensed under the Apache License, Version 2.0 (the "License");
7 ** you may not use this file except in compliance with the License.
8 ** You may obtain a copy of the License at
9 **
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 **
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 */
19 #include "BluetoothServiceBluedroid.h"
21 #include <hardware/hardware.h>
23 #include "BluetoothA2dpManager.h"
24 #include "BluetoothHfpManager.h"
25 #include "BluetoothOppManager.h"
26 #include "BluetoothProfileController.h"
27 #include "BluetoothReplyRunnable.h"
28 #include "BluetoothUtils.h"
29 #include "BluetoothUuid.h"
30 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
31 #include "mozilla/ipc/UnixSocket.h"
32 #include "mozilla/StaticMutex.h"
33 #include "mozilla/StaticPtr.h"
34 #include "mozilla/unused.h"
36 using namespace mozilla;
37 using namespace mozilla::ipc;
38 USING_BLUETOOTH_NAMESPACE
40 /**
41 * Static variables
42 */
43 static bluetooth_device_t* sBtDevice;
44 static const bt_interface_t* sBtInterface;
45 static bool sAdapterDiscoverable = false;
46 static bool sIsBtEnabled = false;
47 static nsString sAdapterBdAddress;
48 static nsString sAdapterBdName;
49 static uint32_t sAdapterDiscoverableTimeout;
50 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
51 static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
52 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
53 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
54 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
55 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
56 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
57 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
58 static nsTArray<int> sRequestedDeviceCountArray;
60 /**
61 * Classes only used in this file
62 */
63 class DistributeBluetoothSignalTask : public nsRunnable {
64 public:
65 DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
66 mSignal(aSignal)
67 {
68 }
70 NS_IMETHOD
71 Run()
72 {
73 MOZ_ASSERT(NS_IsMainThread());
75 BluetoothService* bs = BluetoothService::Get();
76 NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
78 bs->DistributeSignal(mSignal);
80 return NS_OK;
81 }
83 private:
84 BluetoothSignal mSignal;
85 };
87 class SetupAfterEnabledTask : public nsRunnable
88 {
89 public:
90 SetupAfterEnabledTask()
91 { }
93 NS_IMETHOD
94 Run()
95 {
96 MOZ_ASSERT(NS_IsMainThread());
98 // Bluetooth scan mode is NONE by default
99 bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE;
100 bt_property_t prop;
101 prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
102 prop.val = (void*)&mode;
103 prop.len = sizeof(mode);
105 NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
107 int ret = sBtInterface->set_adapter_property(&prop);
108 if (ret != BT_STATUS_SUCCESS) {
109 BT_LOGR("Fail to set: BT_SCAN_MODE_CONNECTABLE");
110 }
112 // Try to fire event 'AdapterAdded' to fit the original behaviour when
113 // we used BlueZ as backend.
114 BluetoothService* bs = BluetoothService::Get();
115 NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
117 bs->AdapterAddedReceived();
118 bs->TryFiringAdapterAdded();
120 // Trigger BluetoothOppManager to listen
121 BluetoothOppManager* opp = BluetoothOppManager::Get();
122 if (!opp || !opp->Listen()) {
123 BT_LOGR("Fail to start BluetoothOppManager listening");
124 }
126 return NS_OK;
127 }
128 };
130 /**
131 * Static callback functions
132 */
133 static void
134 ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
135 {
136 switch ((aClass & 0x1f00) >> 8) {
137 case 0x01:
138 aRetIcon.AssignLiteral("computer");
139 break;
140 case 0x02:
141 switch ((aClass & 0xfc) >> 2) {
142 case 0x01:
143 case 0x02:
144 case 0x03:
145 case 0x05:
146 aRetIcon.AssignLiteral("phone");
147 break;
148 case 0x04:
149 aRetIcon.AssignLiteral("modem");
150 break;
151 }
152 break;
153 case 0x03:
154 aRetIcon.AssignLiteral("network-wireless");
155 break;
156 case 0x04:
157 switch ((aClass & 0xfc) >> 2) {
158 case 0x01:
159 case 0x02:
160 case 0x06:
161 aRetIcon.AssignLiteral("audio-card");
162 break;
163 case 0x0b:
164 case 0x0c:
165 case 0x0d:
166 aRetIcon.AssignLiteral("camera-video");
167 break;
168 default:
169 aRetIcon.AssignLiteral("audio-card");
170 break;
171 }
172 break;
173 case 0x05:
174 switch ((aClass & 0xc0) >> 6) {
175 case 0x00:
176 switch ((aClass && 0x1e) >> 2) {
177 case 0x01:
178 case 0x02:
179 aRetIcon.AssignLiteral("input-gaming");
180 break;
181 }
182 break;
183 case 0x01:
184 aRetIcon.AssignLiteral("input-keyboard");
185 break;
186 case 0x02:
187 switch ((aClass && 0x1e) >> 2) {
188 case 0x05:
189 aRetIcon.AssignLiteral("input-tablet");
190 break;
191 default:
192 aRetIcon.AssignLiteral("input-mouse");
193 break;
194 }
195 }
196 break;
197 case 0x06:
198 if (aClass & 0x80) {
199 aRetIcon.AssignLiteral("printer");
200 break;
201 }
202 if (aClass & 0x20) {
203 aRetIcon.AssignLiteral("camera-photo");
204 break;
205 }
206 break;
207 }
209 if (aRetIcon.IsEmpty()) {
210 if (HAS_AUDIO(aClass)) {
211 /**
212 * Property 'Icon' may be missed due to CoD of major class is TOY(0x08).
213 * But we need to assign Icon as audio-card if service class is 'Audio'.
214 * This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification
215 * defines that service class is 'Audio' can be considered as HFP HF.
216 */
217 aRetIcon.AssignLiteral("audio-card");
218 } else {
219 BT_LOGR("No icon to match class: %x", aClass);
220 }
221 }
222 }
224 static ControlPlayStatus
225 PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus)
226 {
227 ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
228 if (aPlayStatus.EqualsLiteral("STOPPED")) {
229 playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
230 } else if (aPlayStatus.EqualsLiteral("PLAYING")) {
231 playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING;
232 } else if (aPlayStatus.EqualsLiteral("PAUSED")) {
233 playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED;
234 } else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) {
235 playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK;
236 } else if (aPlayStatus.EqualsLiteral("REV_SEEK")) {
237 playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
238 } else if (aPlayStatus.EqualsLiteral("ERROR")) {
239 playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
240 }
242 return playStatus;
243 }
245 static bool
246 IsReady()
247 {
248 if (!sBtInterface || !sIsBtEnabled) {
249 BT_LOGR("Warning! Bluetooth Service is not ready");
250 return false;
251 }
252 return true;
253 }
255 static void
256 AdapterStateChangeCallback(bt_state_t aStatus)
257 {
258 MOZ_ASSERT(!NS_IsMainThread());
260 BT_LOGR("BT_STATE %d", aStatus);
262 sIsBtEnabled = (aStatus == BT_STATE_ON);
264 nsRefPtr<nsRunnable> runnable =
265 new BluetoothService::ToggleBtAck(sIsBtEnabled);
266 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
267 BT_WARNING("Failed to dispatch to main thread!");
268 return;
269 }
271 if (sIsBtEnabled &&
272 NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
273 BT_WARNING("Failed to dispatch to main thread!");
274 }
275 }
277 /**
278 * AdapterPropertiesCallback will be called after enable() but before
279 * AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both
280 * BluetoothManager/BluetoothAdapter does not register observer yet.
281 */
282 static void
283 AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
284 bt_property_t *aProperties)
285 {
286 MOZ_ASSERT(!NS_IsMainThread());
288 BluetoothValue propertyValue;
289 InfallibleTArray<BluetoothNamedValue> props;
291 for (int i = 0; i < aNumProperties; i++) {
292 bt_property_t p = aProperties[i];
294 if (p.type == BT_PROPERTY_BDADDR) {
295 BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress);
296 propertyValue = sAdapterBdAddress;
297 BT_APPEND_NAMED_VALUE(props, "Address", propertyValue);
298 } else if (p.type == BT_PROPERTY_BDNAME) {
299 // Construct nsCString here because Bd name returned from bluedroid
300 // is missing a null terminated character after SetProperty.
301 propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16(
302 nsCString((char*)p.val, p.len));
303 BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
304 } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
305 bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
307 if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
308 propertyValue = sAdapterDiscoverable = true;
309 } else {
310 propertyValue = sAdapterDiscoverable = false;
311 }
313 BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue);
314 } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
315 propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val;
316 BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue);
317 } else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
318 // We have to cache addresses of bonded devices. Unlike BlueZ,
319 // bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES
320 // event after bond completed
321 bt_bdaddr_t* deviceBdAddressTypes = (bt_bdaddr_t*)p.val;
322 int numOfAddresses = p.len / BLUETOOTH_ADDRESS_BYTES;
323 BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", numOfAddresses);
325 // Whenever reloading paired devices, force refresh
326 sAdapterBondedAddressArray.Clear();
328 for (int index = 0; index < numOfAddresses; index++) {
329 nsAutoString deviceBdAddress;
330 BdAddressTypeToString(deviceBdAddressTypes + index, deviceBdAddress);
331 sAdapterBondedAddressArray.AppendElement(deviceBdAddress);
332 }
334 propertyValue = sAdapterBondedAddressArray;
335 BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue);
336 } else if (p.type == BT_PROPERTY_UUIDS) {
337 //FIXME: This will be implemented in the later patchset
338 continue;
339 } else {
340 BT_LOGD("Unhandled adapter property type: %d", p.type);
341 continue;
342 }
343 }
345 NS_ENSURE_TRUE_VOID(props.Length() > 0);
347 BluetoothValue value(props);
348 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
349 NS_LITERAL_STRING(KEY_ADAPTER), value);
350 nsRefPtr<DistributeBluetoothSignalTask>
351 t = new DistributeBluetoothSignalTask(signal);
352 if (NS_FAILED(NS_DispatchToMainThread(t))) {
353 BT_WARNING("Failed to dispatch to main thread!");
354 }
356 // bluedroid BTU task was stored in the task queue, see GKI_send_msg
357 if (!sSetPropertyRunnableArray.IsEmpty()) {
358 DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true),
359 EmptyString());
360 sSetPropertyRunnableArray.RemoveElementAt(0);
361 }
362 }
364 /**
365 * RemoteDevicePropertiesCallback will be called, as the following conditions:
366 * 1. When BT is turning on, bluedroid automatically execute this callback
367 * 2. When get_remote_device_properties()
368 */
369 static void
370 RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
371 int aNumProperties, bt_property_t *aProperties)
372 {
373 MOZ_ASSERT(!NS_IsMainThread());
375 if (sRequestedDeviceCountArray.IsEmpty()) {
376 MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty());
377 return;
378 }
380 sRequestedDeviceCountArray[0]--;
382 InfallibleTArray<BluetoothNamedValue> props;
384 nsString remoteDeviceBdAddress;
385 BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
386 BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
388 for (int i = 0; i < aNumProperties; ++i) {
389 bt_property_t p = aProperties[i];
391 if (p.type == BT_PROPERTY_BDNAME) {
392 BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
393 BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
394 } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
395 uint32_t cod = *(uint32_t*)p.val;
396 BT_APPEND_NAMED_VALUE(props, "Class", cod);
398 nsString icon;
399 ClassToIcon(cod, icon);
400 BT_APPEND_NAMED_VALUE(props, "Icon", icon);
401 } else {
402 BT_LOGD("Other non-handled device properties. Type: %d", p.type);
403 }
404 }
406 // Update to registered BluetoothDevice objects
407 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
408 remoteDeviceBdAddress, props);
409 nsRefPtr<DistributeBluetoothSignalTask>
410 t = new DistributeBluetoothSignalTask(signal);
411 if (NS_FAILED(NS_DispatchToMainThread(t))) {
412 BT_WARNING("Failed to dispatch to main thread!");
413 }
415 // Use address as the index
416 sRemoteDevicesPack.AppendElement(
417 BluetoothNamedValue(remoteDeviceBdAddress, props));
419 if (sRequestedDeviceCountArray[0] == 0) {
420 MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty());
422 if (sGetDeviceRunnableArray.IsEmpty()) {
423 BT_LOGR("No runnable to return");
424 return;
425 }
427 DispatchBluetoothReply(sGetDeviceRunnableArray[0],
428 sRemoteDevicesPack, EmptyString());
430 // After firing it, clean up cache
431 sRemoteDevicesPack.Clear();
433 sRequestedDeviceCountArray.RemoveElementAt(0);
434 sGetDeviceRunnableArray.RemoveElementAt(0);
435 }
436 }
438 static void
439 DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
440 {
441 MOZ_ASSERT(!NS_IsMainThread());
443 BluetoothValue propertyValue;
444 InfallibleTArray<BluetoothNamedValue> propertiesArray;
446 for (int i = 0; i < aNumProperties; i++) {
447 bt_property_t p = aProperties[i];
449 if (p.type == BT_PROPERTY_BDADDR) {
450 nsString remoteDeviceBdAddress;
451 BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress);
452 propertyValue = remoteDeviceBdAddress;
454 BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue);
455 } else if (p.type == BT_PROPERTY_BDNAME) {
456 propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
457 BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue);
458 } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
459 uint32_t cod = *(uint32_t*)p.val;
460 propertyValue = cod;
461 BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue);
463 nsString icon;
464 ClassToIcon(cod, icon);
465 propertyValue = icon;
466 BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue);
467 } else {
468 BT_LOGD("Not handled remote device property: %d", p.type);
469 }
470 }
472 BluetoothValue value = propertiesArray;
473 BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"),
474 NS_LITERAL_STRING(KEY_ADAPTER), value);
475 nsRefPtr<DistributeBluetoothSignalTask>
476 t = new DistributeBluetoothSignalTask(signal);
477 if (NS_FAILED(NS_DispatchToMainThread(t))) {
478 BT_WARNING("Failed to dispatch to main thread!");
479 }
480 }
482 static void
483 DiscoveryStateChangedCallback(bt_discovery_state_t aState)
484 {
485 MOZ_ASSERT(!NS_IsMainThread());
487 if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
488 BluetoothValue values(true);
489 DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
490 values, EmptyString());
492 sChangeDiscoveryRunnableArray.RemoveElementAt(0);
493 }
494 }
496 static void
497 PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
498 bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass)
499 {
500 MOZ_ASSERT(!NS_IsMainThread());
502 InfallibleTArray<BluetoothNamedValue> propertiesArray;
503 nsAutoString remoteAddress;
504 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
506 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
507 BT_APPEND_NAMED_VALUE(propertiesArray, "method",
508 NS_LITERAL_STRING("pincode"));
509 BT_APPEND_NAMED_VALUE(propertiesArray, "name",
510 NS_ConvertUTF8toUTF16(
511 (const char*)aRemoteBdName->name));
513 BluetoothValue value = propertiesArray;
514 BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"),
515 NS_LITERAL_STRING(KEY_LOCAL_AGENT), value);
516 nsRefPtr<DistributeBluetoothSignalTask>
517 t = new DistributeBluetoothSignalTask(signal);
518 if (NS_FAILED(NS_DispatchToMainThread(t))) {
519 BT_WARNING("Failed to dispatch to main thread!");
520 }
521 }
523 static void
524 SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName,
525 uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant,
526 uint32_t aPasskey)
527 {
528 MOZ_ASSERT(!NS_IsMainThread());
530 InfallibleTArray<BluetoothNamedValue> propertiesArray;
531 nsAutoString remoteAddress;
532 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
534 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
535 BT_APPEND_NAMED_VALUE(propertiesArray, "method",
536 NS_LITERAL_STRING("confirmation"));
537 BT_APPEND_NAMED_VALUE(propertiesArray, "name",
538 NS_ConvertUTF8toUTF16(
539 (const char*)aRemoteBdName->name));
540 BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey);
542 BluetoothValue value = propertiesArray;
543 BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"),
544 NS_LITERAL_STRING(KEY_LOCAL_AGENT), value);
545 nsRefPtr<DistributeBluetoothSignalTask>
546 t = new DistributeBluetoothSignalTask(signal);
547 if (NS_FAILED(NS_DispatchToMainThread(t))) {
548 BT_WARNING("Failed to dispatch to main thread!");
549 }
550 }
552 static void
553 BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
554 bt_bond_state_t aState)
555 {
556 MOZ_ASSERT(!NS_IsMainThread());
558 nsAutoString remoteAddress;
559 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
561 // We don't need to handle bonding state
562 NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING);
563 NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED &&
564 sAdapterBondedAddressArray.Contains(remoteAddress));
565 bool bonded;
566 if (aState == BT_BOND_STATE_NONE) {
567 bonded = false;
568 sAdapterBondedAddressArray.RemoveElement(remoteAddress);
569 } else if (aState == BT_BOND_STATE_BONDED) {
570 bonded = true;
571 sAdapterBondedAddressArray.AppendElement(remoteAddress);
572 }
574 // Update bonded address list to BluetoothAdapter
575 InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
576 BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
577 sAdapterBondedAddressArray);
579 BluetoothValue value(propertiesChangeArray);
580 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
581 NS_LITERAL_STRING(KEY_ADAPTER),
582 BluetoothValue(propertiesChangeArray));
583 NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
585 // Update bonding status to gaia
586 InfallibleTArray<BluetoothNamedValue> propertiesArray;
587 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
588 BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
590 BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
591 NS_LITERAL_STRING(KEY_ADAPTER),
592 BluetoothValue(propertiesArray));
593 NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal));
595 if (bonded && !sBondingRunnableArray.IsEmpty()) {
596 DispatchBluetoothReply(sBondingRunnableArray[0],
597 BluetoothValue(true), EmptyString());
599 sBondingRunnableArray.RemoveElementAt(0);
600 } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
601 DispatchBluetoothReply(sUnbondingRunnableArray[0],
602 BluetoothValue(true), EmptyString());
604 sUnbondingRunnableArray.RemoveElementAt(0);
605 }
606 }
608 static void
609 AclStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
610 bt_acl_state_t aState)
611 {
612 //FIXME: This will be implemented in the later patchset
613 }
615 static void
616 CallbackThreadEvent(bt_cb_thread_evt evt)
617 {
618 //FIXME: This will be implemented in the later patchset
619 }
621 bt_callbacks_t sBluetoothCallbacks =
622 {
623 sizeof(sBluetoothCallbacks),
624 AdapterStateChangeCallback,
625 AdapterPropertiesCallback,
626 RemoteDevicePropertiesCallback,
627 DeviceFoundCallback,
628 DiscoveryStateChangedCallback,
629 PinRequestCallback,
630 SspRequestCallback,
631 BondStateChangedCallback,
632 AclStateChangedCallback,
633 CallbackThreadEvent
634 };
636 /**
637 * Static functions
638 */
639 static bool
640 EnsureBluetoothHalLoad()
641 {
642 hw_module_t* module;
643 hw_device_t* device;
644 int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
645 if (err != 0) {
646 BT_LOGR("Error: %s", strerror(err));
647 return false;
648 }
649 module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
650 sBtDevice = (bluetooth_device_t *)device;
651 sBtInterface = sBtDevice->get_bluetooth_interface();
653 int ret = sBtInterface->init(&sBluetoothCallbacks);
654 if (ret != BT_STATUS_SUCCESS) {
655 BT_LOGR("Error while setting the callbacks");
656 sBtInterface = nullptr;
657 }
659 return true;
660 }
662 static nsresult
663 StartStopGonkBluetooth(bool aShouldEnable)
664 {
665 MOZ_ASSERT(NS_IsMainThread());
666 NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
668 if (sIsBtEnabled == aShouldEnable) {
669 // Keep current enable status
670 nsRefPtr<nsRunnable> runnable =
671 new BluetoothService::ToggleBtAck(sIsBtEnabled);
672 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
673 BT_WARNING("Failed to dispatch to main thread!");
674 }
675 return NS_OK;
676 }
678 int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable();
679 NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE);
681 return NS_OK;
682 }
684 static void
685 ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
686 int aStatusCode, const nsAString& aCustomMsg)
687 {
688 MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
690 BT_LOGR("error code(%d)", aStatusCode);
692 nsAutoString replyError;
693 replyError.Assign(aCustomMsg);
695 if (aStatusCode == BT_STATUS_BUSY) {
696 replyError.AppendLiteral(":BT_STATUS_BUSY");
697 } else if (aStatusCode == BT_STATUS_NOT_READY) {
698 replyError.AppendLiteral(":BT_STATUS_NOT_READY");
699 } else if (aStatusCode == BT_STATUS_DONE) {
700 replyError.AppendLiteral(":BT_STATUS_DONE");
701 } else if (aStatusCode == BT_STATUS_AUTH_FAILURE) {
702 replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE");
703 } else if (aStatusCode == BT_STATUS_RMT_DEV_DOWN) {
704 replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN");
705 } else if (aStatusCode == BT_STATUS_FAIL) {
706 replyError.AppendLiteral(":BT_STATUS_FAIL");
707 }
709 DispatchBluetoothReply(aBluetoothReplyRunnable, BluetoothValue(true),
710 replyError);
711 }
713 /**
714 * Member functions
715 */
716 BluetoothServiceBluedroid::BluetoothServiceBluedroid()
717 {
718 if (!EnsureBluetoothHalLoad()) {
719 BT_LOGR("Error! Failed to load bluedroid library.");
720 return;
721 }
723 // Register all the bluedroid callbacks before enable() get called
724 // It is required to register a2dp callbacks before a2dp media task starts up.
725 BluetoothHfpManager::Get();
726 BluetoothA2dpManager::Get();
727 }
729 BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
730 {
731 }
733 nsresult
734 BluetoothServiceBluedroid::StartInternal()
735 {
736 MOZ_ASSERT(NS_IsMainThread());
738 nsresult ret = StartStopGonkBluetooth(true);
739 if (NS_FAILED(ret)) {
740 nsRefPtr<nsRunnable> runnable =
741 new BluetoothService::ToggleBtAck(false);
742 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
743 BT_WARNING("Failed to dispatch to main thread!");
744 }
745 BT_LOGR("Error");
746 }
748 return ret;
749 }
751 nsresult
752 BluetoothServiceBluedroid::StopInternal()
753 {
754 MOZ_ASSERT(NS_IsMainThread());
756 nsresult ret = StartStopGonkBluetooth(false);
757 if (NS_FAILED(ret)) {
758 nsRefPtr<nsRunnable> runnable =
759 new BluetoothService::ToggleBtAck(true);
760 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
761 BT_WARNING("Failed to dispatch to main thread!");
762 }
763 BT_LOGR("Error");
764 }
766 return ret;
767 }
769 nsresult
770 BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
771 BluetoothReplyRunnable* aRunnable)
772 {
773 MOZ_ASSERT(NS_IsMainThread());
775 nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
777 BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
779 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
780 "Address", sAdapterBdAddress);
782 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
783 "Name", sAdapterBdName);
785 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
786 "Discoverable", sAdapterDiscoverable);
788 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
789 "DiscoverableTimeout", sAdapterDiscoverableTimeout);
791 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
792 "Devices", sAdapterBondedAddressArray);
794 nsAutoString replyError;
795 DispatchBluetoothReply(runnable.get(), v, replyError);
797 unused << runnable.forget(); // picked up in DispatchBluetoothReply
799 return NS_OK;
800 }
802 nsresult
803 BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal(
804 uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable)
805 {
806 MOZ_ASSERT(NS_IsMainThread());
808 if (!IsReady()) {
809 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
810 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
811 return NS_OK;
812 }
814 BluetoothProfileManagerBase* profile =
815 BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
816 if (!profile) {
817 InfallibleTArray<BluetoothNamedValue> emptyArr;
818 DispatchBluetoothReply(aRunnable, emptyArr,
819 NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
820 return NS_OK;
821 }
823 nsTArray<nsString> deviceAddresses;
824 if (profile->IsConnected()) {
825 nsString address;
826 profile->GetAddress(address);
827 deviceAddresses.AppendElement(address);
828 }
830 int requestedDeviceCount = deviceAddresses.Length();
831 if (requestedDeviceCount == 0) {
832 InfallibleTArray<BluetoothNamedValue> emptyArr;
833 DispatchBluetoothReply(aRunnable, emptyArr, EmptyString());
834 return NS_OK;
835 }
837 for (int i = 0; i < requestedDeviceCount; i++) {
838 // Retrieve all properties of devices
839 bt_bdaddr_t addressType;
840 StringToBdAddressType(deviceAddresses[i], &addressType);
842 int ret = sBtInterface->get_remote_device_properties(&addressType);
843 if (ret != BT_STATUS_SUCCESS) {
844 DispatchBluetoothReply(aRunnable, BluetoothValue(true),
845 NS_LITERAL_STRING("GetConnectedDeviceFailed"));
846 return NS_OK;
847 }
848 }
850 sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
851 sGetDeviceRunnableArray.AppendElement(aRunnable);
853 return NS_OK;
854 }
856 nsresult
857 BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal(
858 const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
859 {
860 MOZ_ASSERT(NS_IsMainThread());
862 if (!IsReady()) {
863 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
864 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
865 return NS_OK;
866 }
868 int requestedDeviceCount = aDeviceAddress.Length();
869 if (requestedDeviceCount == 0) {
870 InfallibleTArray<BluetoothNamedValue> emptyArr;
871 DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString());
872 return NS_OK;
873 }
875 for (int i = 0; i < requestedDeviceCount; i++) {
876 // Retrieve all properties of devices
877 bt_bdaddr_t addressType;
878 StringToBdAddressType(aDeviceAddress[i], &addressType);
879 int ret = sBtInterface->get_remote_device_properties(&addressType);
880 if (ret != BT_STATUS_SUCCESS) {
881 DispatchBluetoothReply(aRunnable, BluetoothValue(true),
882 NS_LITERAL_STRING("GetPairedDeviceFailed"));
883 return NS_OK;
884 }
885 }
887 sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
888 sGetDeviceRunnableArray.AppendElement(aRunnable);
890 return NS_OK;
891 }
893 nsresult
894 BluetoothServiceBluedroid::StartDiscoveryInternal(
895 BluetoothReplyRunnable* aRunnable)
896 {
897 MOZ_ASSERT(NS_IsMainThread());
899 if (!IsReady()) {
900 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
901 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
903 return NS_OK;
904 }
905 int ret = sBtInterface->start_discovery();
906 if (ret != BT_STATUS_SUCCESS) {
907 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
909 return NS_OK;
910 }
912 sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
913 return NS_OK;
914 }
916 nsresult
917 BluetoothServiceBluedroid::StopDiscoveryInternal(
918 BluetoothReplyRunnable* aRunnable)
919 {
920 MOZ_ASSERT(NS_IsMainThread());
922 if (!IsReady()) {
923 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
924 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
925 return NS_OK;
926 }
928 int ret = sBtInterface->cancel_discovery();
929 if (ret != BT_STATUS_SUCCESS) {
930 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery"));
931 return NS_OK;
932 }
934 sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
936 return NS_OK;
937 }
939 nsresult
940 BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
941 const BluetoothNamedValue& aValue,
942 BluetoothReplyRunnable* aRunnable)
943 {
944 MOZ_ASSERT(NS_IsMainThread());
946 if (!IsReady()) {
947 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
948 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
950 return NS_OK;
951 }
953 const nsString propName = aValue.name();
954 bt_property_t prop;
955 bt_scan_mode_t scanMode;
956 nsCString str;
958 // For Bluedroid, it's necessary to check property name for SetProperty
959 if (propName.EqualsLiteral("Name")) {
960 prop.type = BT_PROPERTY_BDNAME;
961 } else if (propName.EqualsLiteral("Discoverable")) {
962 prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
963 } else if (propName.EqualsLiteral("DiscoverableTimeout")) {
964 prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
965 } else {
966 BT_LOGR("Warning: Property type is not supported yet, type: %d", prop.type);
967 }
969 if (aValue.value().type() == BluetoothValue::Tuint32_t) {
970 // Set discoverable timeout
971 prop.val = (void*)aValue.value().get_uint32_t();
972 } else if (aValue.value().type() == BluetoothValue::TnsString) {
973 // Set name
974 str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString());
975 const char* name = str.get();
976 prop.val = (void*)name;
977 prop.len = strlen(name);
978 } else if (aValue.value().type() == BluetoothValue::Tbool) {
979 scanMode = aValue.value().get_bool() ?
980 BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
981 BT_SCAN_MODE_CONNECTABLE;
983 prop.val = (void*)&scanMode;
984 prop.len = sizeof(scanMode);
985 } else {
986 BT_LOGR("SetProperty but the property cannot be recognized correctly.");
987 return NS_OK;
988 }
990 sSetPropertyRunnableArray.AppendElement(aRunnable);
992 int ret = sBtInterface->set_adapter_property(&prop);
993 if (ret != BT_STATUS_SUCCESS) {
994 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty"));
995 }
997 return NS_OK;
998 }
1000 nsresult
1001 BluetoothServiceBluedroid::GetServiceChannel(
1002 const nsAString& aDeviceAddress,
1003 const nsAString& aServiceUuid,
1004 BluetoothProfileManagerBase* aManager)
1005 {
1006 return NS_OK;
1007 }
1009 bool
1010 BluetoothServiceBluedroid::UpdateSdpRecords(
1011 const nsAString& aDeviceAddress,
1012 BluetoothProfileManagerBase* aManager)
1013 {
1014 return true;
1015 }
1017 nsresult
1018 BluetoothServiceBluedroid::CreatePairedDeviceInternal(
1019 const nsAString& aDeviceAddress, int aTimeout,
1020 BluetoothReplyRunnable* aRunnable)
1021 {
1022 MOZ_ASSERT(NS_IsMainThread());
1024 if (!IsReady()) {
1025 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
1026 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
1027 return NS_OK;
1028 }
1030 bt_bdaddr_t remoteAddress;
1031 StringToBdAddressType(aDeviceAddress, &remoteAddress);
1033 int ret = sBtInterface->create_bond(&remoteAddress);
1034 if (ret != BT_STATUS_SUCCESS) {
1035 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("CreatedPairedDevice"));
1036 } else {
1037 sBondingRunnableArray.AppendElement(aRunnable);
1038 }
1040 return NS_OK;
1041 }
1043 nsresult
1044 BluetoothServiceBluedroid::RemoveDeviceInternal(
1045 const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
1046 {
1047 MOZ_ASSERT(NS_IsMainThread());
1049 if (!IsReady()) {
1050 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
1051 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
1052 return NS_OK;
1053 }
1055 bt_bdaddr_t remoteAddress;
1056 StringToBdAddressType(aDeviceAddress, &remoteAddress);
1058 int ret = sBtInterface->remove_bond(&remoteAddress);
1059 if (ret != BT_STATUS_SUCCESS) {
1060 ReplyStatusError(aRunnable, ret,
1061 NS_LITERAL_STRING("RemoveDevice"));
1062 } else {
1063 sUnbondingRunnableArray.AppendElement(aRunnable);
1064 }
1066 return NS_OK;
1067 }
1069 bool
1070 BluetoothServiceBluedroid::SetPinCodeInternal(
1071 const nsAString& aDeviceAddress, const nsAString& aPinCode,
1072 BluetoothReplyRunnable* aRunnable)
1073 {
1074 MOZ_ASSERT(NS_IsMainThread());
1076 if (!IsReady()) {
1077 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
1078 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
1079 return false;
1080 }
1082 bt_bdaddr_t remoteAddress;
1083 StringToBdAddressType(aDeviceAddress, &remoteAddress);
1085 int ret = sBtInterface->pin_reply(
1086 &remoteAddress, true, aPinCode.Length(),
1087 (bt_pin_code_t*)NS_ConvertUTF16toUTF8(aPinCode).get());
1089 if (ret != BT_STATUS_SUCCESS) {
1090 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetPinCode"));
1091 } else {
1092 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1093 }
1095 return true;
1096 }
1098 bool
1099 BluetoothServiceBluedroid::SetPasskeyInternal(
1100 const nsAString& aDeviceAddress, uint32_t aPasskey,
1101 BluetoothReplyRunnable* aRunnable)
1102 {
1103 return true;
1104 }
1106 bool
1107 BluetoothServiceBluedroid::SetPairingConfirmationInternal(
1108 const nsAString& aDeviceAddress, bool aConfirm,
1109 BluetoothReplyRunnable* aRunnable)
1110 {
1111 MOZ_ASSERT(NS_IsMainThread());
1113 if (!IsReady()) {
1114 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
1115 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
1116 return false;
1117 }
1119 bt_bdaddr_t remoteAddress;
1120 StringToBdAddressType(aDeviceAddress, &remoteAddress);
1122 int ret = sBtInterface->ssp_reply(&remoteAddress, (bt_ssp_variant_t)0,
1123 aConfirm, 0);
1124 if (ret != BT_STATUS_SUCCESS) {
1125 ReplyStatusError(aRunnable, ret,
1126 NS_LITERAL_STRING("SetPairingConfirmation"));
1127 } else {
1128 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1129 }
1131 return true;
1132 }
1134 bool
1135 BluetoothServiceBluedroid::SetAuthorizationInternal(
1136 const nsAString& aDeviceAddress, bool aAllow,
1137 BluetoothReplyRunnable* aRunnable)
1138 {
1139 return true;
1140 }
1142 nsresult
1143 BluetoothServiceBluedroid::PrepareAdapterInternal()
1144 {
1145 return NS_OK;
1146 }
1148 static void
1149 NextBluetoothProfileController()
1150 {
1151 MOZ_ASSERT(NS_IsMainThread());
1153 // First, remove the task at the front which has been already done.
1154 NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
1155 sControllerArray.RemoveElementAt(0);
1156 // Re-check if the task array is empty, if it's not, the next task will begin.
1157 NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
1158 sControllerArray[0]->StartSession();
1159 }
1161 static void
1162 ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress,
1163 BluetoothReplyRunnable* aRunnable,
1164 uint16_t aServiceUuid, uint32_t aCod = 0)
1165 {
1166 MOZ_ASSERT(NS_IsMainThread());
1167 MOZ_ASSERT(aRunnable);
1169 BluetoothProfileController* controller =
1170 new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable,
1171 NextBluetoothProfileController,
1172 aServiceUuid, aCod);
1173 sControllerArray.AppendElement(controller);
1175 /**
1176 * If the request is the first element of the quene, start from here. Note
1177 * that other request is pushed into the quene and is popped out after the
1178 * first one is completed. See NextBluetoothProfileController() for details.
1179 */
1180 if (sControllerArray.Length() == 1) {
1181 sControllerArray[0]->StartSession();
1182 }
1183 }
1185 const bt_interface_t*
1186 BluetoothServiceBluedroid::GetBluetoothInterface()
1187 {
1188 return sBtInterface;
1189 }
1191 void
1192 BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress,
1193 uint32_t aCod,
1194 uint16_t aServiceUuid,
1195 BluetoothReplyRunnable* aRunnable)
1196 {
1197 ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod);
1198 }
1200 bool
1201 BluetoothServiceBluedroid::IsConnected(uint16_t aProfileId)
1202 {
1203 return true;
1204 }
1206 void
1207 BluetoothServiceBluedroid::Disconnect(
1208 const nsAString& aDeviceAddress, uint16_t aServiceUuid,
1209 BluetoothReplyRunnable* aRunnable)
1210 {
1211 ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid);
1212 }
1214 void
1215 BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
1216 BlobParent* aBlobParent,
1217 BlobChild* aBlobChild,
1218 BluetoothReplyRunnable* aRunnable)
1219 {
1220 MOZ_ASSERT(NS_IsMainThread());
1222 // Currently we only support one device sending one file at a time,
1223 // so we don't need aDeviceAddress here because the target device
1224 // has been determined when calling 'Connect()'. Nevertheless, keep
1225 // it for future use.
1226 BluetoothOppManager* opp = BluetoothOppManager::Get();
1227 nsAutoString errorStr;
1228 if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) {
1229 errorStr.AssignLiteral("Calling SendFile() failed");
1230 }
1232 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
1233 }
1235 void
1236 BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
1237 nsIDOMBlob* aBlob,
1238 BluetoothReplyRunnable* aRunnable)
1239 {
1240 MOZ_ASSERT(NS_IsMainThread());
1242 // Currently we only support one device sending one file at a time,
1243 // so we don't need aDeviceAddress here because the target device
1244 // has been determined when calling 'Connect()'. Nevertheless, keep
1245 // it for future use.
1246 BluetoothOppManager* opp = BluetoothOppManager::Get();
1247 nsAutoString errorStr;
1248 if (!opp || !opp->SendFile(aDeviceAddress, aBlob)) {
1249 errorStr.AssignLiteral("Calling SendFile() failed");
1250 }
1252 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
1253 }
1255 void
1256 BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress,
1257 BluetoothReplyRunnable* aRunnable)
1258 {
1259 MOZ_ASSERT(NS_IsMainThread());
1261 // Currently we only support one device sending one file at a time,
1262 // so we don't need aDeviceAddress here because the target device
1263 // has been determined when calling 'Connect()'. Nevertheless, keep
1264 // it for future use.
1265 BluetoothOppManager* opp = BluetoothOppManager::Get();
1266 nsAutoString errorStr;
1267 if (!opp || !opp->StopSendingFile()) {
1268 errorStr.AssignLiteral("Calling StopSendingFile() failed");
1269 }
1271 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
1272 }
1274 void
1275 BluetoothServiceBluedroid::ConfirmReceivingFile(
1276 const nsAString& aDeviceAddress, bool aConfirm,
1277 BluetoothReplyRunnable* aRunnable)
1278 {
1279 MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!");
1281 // Currently we only support one device sending one file at a time,
1282 // so we don't need aDeviceAddress here because the target device
1283 // has been determined when calling 'Connect()'. Nevertheless, keep
1284 // it for future use.
1285 BluetoothOppManager* opp = BluetoothOppManager::Get();
1286 nsAutoString errorStr;
1287 if (!opp || !opp->ConfirmReceivingFile(aConfirm)) {
1288 errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed");
1289 }
1291 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
1292 }
1294 void
1295 BluetoothServiceBluedroid::ConnectSco(BluetoothReplyRunnable* aRunnable)
1296 {
1297 MOZ_ASSERT(NS_IsMainThread());
1299 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
1300 if (!hfp || !hfp->ConnectSco()) {
1301 NS_NAMED_LITERAL_STRING(replyError, "Calling ConnectSco() failed");
1302 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
1303 return;
1304 }
1306 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1307 }
1309 void
1310 BluetoothServiceBluedroid::DisconnectSco(BluetoothReplyRunnable* aRunnable)
1311 {
1312 MOZ_ASSERT(NS_IsMainThread());
1314 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
1315 if (!hfp || !hfp->DisconnectSco()) {
1316 NS_NAMED_LITERAL_STRING(replyError, "Calling DisconnectSco() failed");
1317 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
1318 return;
1319 }
1321 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1322 }
1324 void
1325 BluetoothServiceBluedroid::IsScoConnected(BluetoothReplyRunnable* aRunnable)
1326 {
1327 MOZ_ASSERT(NS_IsMainThread());
1329 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
1330 if (!hfp) {
1331 NS_NAMED_LITERAL_STRING(replyError, "Fail to get BluetoothHfpManager");
1332 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
1333 return;
1334 }
1336 DispatchBluetoothReply(aRunnable, hfp->IsScoConnected(), EmptyString());
1337 }
1339 void
1340 BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle,
1341 const nsAString& aArtist,
1342 const nsAString& aAlbum,
1343 int64_t aMediaNumber,
1344 int64_t aTotalMediaCount,
1345 int64_t aDuration,
1346 BluetoothReplyRunnable* aRunnable)
1347 {
1348 BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
1349 if (a2dp) {
1350 a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
1351 aTotalMediaCount, aDuration);
1352 }
1353 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1354 }
1356 void
1357 BluetoothServiceBluedroid::SendPlayStatus(
1358 int64_t aDuration, int64_t aPosition,
1359 const nsAString& aPlayStatus,
1360 BluetoothReplyRunnable* aRunnable)
1361 {
1362 BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
1363 if (a2dp) {
1364 ControlPlayStatus playStatus =
1365 PlayStatusStringToControlPlayStatus(aPlayStatus);
1366 a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
1367 }
1368 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
1369 }
1371 void
1372 BluetoothServiceBluedroid::UpdatePlayStatus(
1373 uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus)
1374 {
1375 // We don't need this function for bluedroid.
1376 // In bluez, it only calls dbus api
1377 // But it does not update BluetoothA2dpManager member fields
1378 MOZ_ASSERT(false);
1379 }
1381 nsresult
1382 BluetoothServiceBluedroid::SendSinkMessage(const nsAString& aDeviceAddresses,
1383 const nsAString& aMessage)
1384 {
1385 return NS_OK;
1386 }
1388 nsresult
1389 BluetoothServiceBluedroid::SendInputMessage(const nsAString& aDeviceAddresses,
1390 const nsAString& aMessage)
1391 {
1392 return NS_OK;
1393 }
1395 void
1396 BluetoothServiceBluedroid::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable)
1397 {
1398 }
1400 void
1401 BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable)
1402 {
1403 }
1405 void
1406 BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable)
1407 {
1408 }