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 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
8 #include "nsCxPusher.h"
9 #include "nsDOMClassInfo.h"
10 #include "nsTArrayHelpers.h"
11 #include "DOMRequest.h"
12 #include "nsThreadUtils.h"
14 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
15 #include "mozilla/dom/BluetoothAdapterBinding.h"
16 #include "mozilla/dom/BluetoothDeviceEvent.h"
17 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
18 #include "mozilla/dom/ContentChild.h"
19 #include "mozilla/LazyIdleThread.h"
21 #include "BluetoothAdapter.h"
22 #include "BluetoothDevice.h"
23 #include "BluetoothReplyRunnable.h"
24 #include "BluetoothService.h"
25 #include "BluetoothUtils.h"
27 using namespace mozilla;
28 using namespace mozilla::dom;
30 USING_BLUETOOTH_NAMESPACE
32 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
34 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter,
35 DOMEventTargetHelper)
36 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
37 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsDeviceAddresses)
38 NS_IMPL_CYCLE_COLLECTION_TRACE_END
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter,
41 DOMEventTargetHelper)
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
45 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter,
46 DOMEventTargetHelper)
47 tmp->Unroot();
48 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
50 // QueryInterface implementation for BluetoothAdapter
51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
52 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
54 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper)
55 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper)
57 class GetDevicesTask : public BluetoothReplyRunnable
58 {
59 public:
60 GetDevicesTask(BluetoothAdapter* aAdapterPtr,
61 nsIDOMDOMRequest* aReq) :
62 BluetoothReplyRunnable(aReq),
63 mAdapterPtr(aAdapterPtr)
64 {
65 MOZ_ASSERT(aReq && aAdapterPtr);
66 }
68 virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
69 {
70 aValue.setUndefined();
72 const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
73 if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
74 BT_WARNING("Not a BluetoothNamedValue array!");
75 SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
76 return false;
77 }
79 const InfallibleTArray<BluetoothNamedValue>& values =
80 v.get_ArrayOfBluetoothNamedValue();
82 nsTArray<nsRefPtr<BluetoothDevice> > devices;
83 for (uint32_t i = 0; i < values.Length(); i++) {
84 const BluetoothValue properties = values[i].value();
85 if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
86 BT_WARNING("Not a BluetoothNamedValue array!");
87 SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
88 return false;
89 }
90 nsRefPtr<BluetoothDevice> d =
91 BluetoothDevice::Create(mAdapterPtr->GetOwner(),
92 mAdapterPtr->GetPath(),
93 properties);
94 devices.AppendElement(d);
95 }
97 nsresult rv;
98 nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
99 if (!sc) {
100 BT_WARNING("Cannot create script context!");
101 SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
102 return false;
103 }
105 AutoPushJSContext cx(sc->GetNativeContext());
106 JSObject* JsDevices = nullptr;
107 rv = nsTArrayToJSArray(cx, devices, &JsDevices);
108 if (!JsDevices) {
109 BT_WARNING("Cannot create JS array!");
110 SetError(NS_LITERAL_STRING("BluetoothError"));
111 return false;
112 }
114 aValue.setObject(*JsDevices);
115 return true;
116 }
118 void
119 ReleaseMembers()
120 {
121 BluetoothReplyRunnable::ReleaseMembers();
122 mAdapterPtr = nullptr;
123 }
124 private:
125 nsRefPtr<BluetoothAdapter> mAdapterPtr;
126 };
128 class GetScoConnectionStatusTask : public BluetoothReplyRunnable
129 {
130 public:
131 GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) :
132 BluetoothReplyRunnable(aReq)
133 {
134 MOZ_ASSERT(aReq);
135 }
137 virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
138 {
139 aValue.setUndefined();
141 const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
142 if (v.type() != BluetoothValue::Tbool) {
143 BT_WARNING("Not a boolean!");
144 SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
145 return false;
146 }
148 aValue.setBoolean(v.get_bool());
149 return true;
150 }
152 void
153 ReleaseMembers()
154 {
155 BluetoothReplyRunnable::ReleaseMembers();
156 }
157 };
159 static int kCreatePairedDeviceTimeout = 50000; // unit: msec
161 BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
162 const BluetoothValue& aValue)
163 : DOMEventTargetHelper(aWindow)
164 , BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
165 , mJsUuids(nullptr)
166 , mJsDeviceAddresses(nullptr)
167 , mDiscoverable(false)
168 , mDiscovering(false)
169 , mPairable(false)
170 , mPowered(false)
171 , mIsRooted(false)
172 {
173 MOZ_ASSERT(aWindow);
174 MOZ_ASSERT(IsDOMBinding());
176 const InfallibleTArray<BluetoothNamedValue>& values =
177 aValue.get_ArrayOfBluetoothNamedValue();
178 for (uint32_t i = 0; i < values.Length(); ++i) {
179 SetPropertyByValue(values[i]);
180 }
182 BluetoothService* bs = BluetoothService::Get();
183 NS_ENSURE_TRUE_VOID(bs);
184 bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
185 }
187 BluetoothAdapter::~BluetoothAdapter()
188 {
189 Unroot();
190 BluetoothService* bs = BluetoothService::Get();
191 // We can be null on shutdown, where this might happen
192 NS_ENSURE_TRUE_VOID(bs);
193 bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
194 }
196 void
197 BluetoothAdapter::DisconnectFromOwner()
198 {
199 DOMEventTargetHelper::DisconnectFromOwner();
201 BluetoothService* bs = BluetoothService::Get();
202 NS_ENSURE_TRUE_VOID(bs);
203 bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
204 }
206 void
207 BluetoothAdapter::Unroot()
208 {
209 if (!mIsRooted) {
210 return;
211 }
212 mJsUuids = nullptr;
213 mJsDeviceAddresses = nullptr;
214 mozilla::DropJSObjects(this);
215 mIsRooted = false;
216 }
218 void
219 BluetoothAdapter::Root()
220 {
221 if (mIsRooted) {
222 return;
223 }
224 mozilla::HoldJSObjects(this);
225 mIsRooted = true;
226 }
228 void
229 BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
230 {
231 const nsString& name = aValue.name();
232 const BluetoothValue& value = aValue.value();
233 if (name.EqualsLiteral("Name")) {
234 mName = value.get_nsString();
235 } else if (name.EqualsLiteral("Address")) {
236 mAddress = value.get_nsString();
237 } else if (name.EqualsLiteral("Path")) {
238 mPath = value.get_nsString();
239 } else if (name.EqualsLiteral("Discoverable")) {
240 mDiscoverable = value.get_bool();
241 } else if (name.EqualsLiteral("Discovering")) {
242 mDiscovering = value.get_bool();
243 } else if (name.EqualsLiteral("Pairable")) {
244 mPairable = value.get_bool();
245 } else if (name.EqualsLiteral("Powered")) {
246 mPowered = value.get_bool();
247 } else if (name.EqualsLiteral("PairableTimeout")) {
248 mPairableTimeout = value.get_uint32_t();
249 } else if (name.EqualsLiteral("DiscoverableTimeout")) {
250 mDiscoverableTimeout = value.get_uint32_t();
251 } else if (name.EqualsLiteral("Class")) {
252 mClass = value.get_uint32_t();
253 } else if (name.EqualsLiteral("UUIDs")) {
254 mUuids = value.get_ArrayOfnsString();
255 nsresult rv;
256 nsIScriptContext* sc = GetContextForEventHandlers(&rv);
257 NS_ENSURE_SUCCESS_VOID(rv);
258 NS_ENSURE_TRUE_VOID(sc);
260 AutoPushJSContext cx(sc->GetNativeContext());
261 JS::Rooted<JSObject*> uuids(cx);
262 if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
263 BT_WARNING("Cannot set JS UUIDs object!");
264 return;
265 }
266 mJsUuids = uuids;
267 Root();
268 } else if (name.EqualsLiteral("Devices")) {
269 mDeviceAddresses = value.get_ArrayOfnsString();
271 nsresult rv;
272 nsIScriptContext* sc = GetContextForEventHandlers(&rv);
273 NS_ENSURE_SUCCESS_VOID(rv);
274 NS_ENSURE_TRUE_VOID(sc);
276 AutoPushJSContext cx(sc->GetNativeContext());
277 JS::Rooted<JSObject*> deviceAddresses(cx);
278 if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses,
279 deviceAddresses.address()))) {
280 BT_WARNING("Cannot set JS Devices object!");
281 return;
282 }
283 mJsDeviceAddresses = deviceAddresses;
284 Root();
285 } else {
286 #ifdef DEBUG
287 nsCString warningMsg;
288 warningMsg.AssignLiteral("Not handling adapter property: ");
289 warningMsg.Append(NS_ConvertUTF16toUTF8(name));
290 BT_WARNING(warningMsg.get());
291 #endif
292 }
293 }
295 // static
296 already_AddRefed<BluetoothAdapter>
297 BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue)
298 {
299 MOZ_ASSERT(NS_IsMainThread());
300 MOZ_ASSERT(aWindow);
302 nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aWindow, aValue);
303 return adapter.forget();
304 }
306 void
307 BluetoothAdapter::Notify(const BluetoothSignal& aData)
308 {
309 InfallibleTArray<BluetoothNamedValue> arr;
311 BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
313 BluetoothValue v = aData.value();
314 if (aData.name().EqualsLiteral("DeviceFound")) {
315 nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
317 BluetoothDeviceEventInit init;
318 init.mBubbles = false;
319 init.mCancelable = false;
320 init.mDevice = device;
321 nsRefPtr<BluetoothDeviceEvent> event =
322 BluetoothDeviceEvent::Constructor(this, NS_LITERAL_STRING("devicefound"), init);
323 DispatchTrustedEvent(event);
324 } else if (aData.name().EqualsLiteral("PropertyChanged")) {
325 MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
327 const InfallibleTArray<BluetoothNamedValue>& arr =
328 v.get_ArrayOfBluetoothNamedValue();
330 for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) {
331 SetPropertyByValue(arr[i]);
332 }
333 } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
334 aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
335 aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
336 aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
337 MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
338 const InfallibleTArray<BluetoothNamedValue>& arr =
339 v.get_ArrayOfBluetoothNamedValue();
341 MOZ_ASSERT(arr.Length() == 2 &&
342 arr[0].value().type() == BluetoothValue::TnsString &&
343 arr[1].value().type() == BluetoothValue::Tbool);
344 nsString address = arr[0].value().get_nsString();
345 bool status = arr[1].value().get_bool();
347 BluetoothStatusChangedEventInit init;
348 init.mBubbles = false;
349 init.mCancelable = false;
350 init.mAddress = address;
351 init.mStatus = status;
352 nsRefPtr<BluetoothStatusChangedEvent> event =
353 BluetoothStatusChangedEvent::Constructor(this, aData.name(), init);
354 DispatchTrustedEvent(event);
355 } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) {
356 nsCOMPtr<nsIDOMEvent> event;
357 nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
358 NS_ENSURE_SUCCESS_VOID(rv);
360 rv = event->InitEvent(aData.name(), false, false);
361 NS_ENSURE_SUCCESS_VOID(rv);
363 DispatchTrustedEvent(event);
364 } else {
365 #ifdef DEBUG
366 nsCString warningMsg;
367 warningMsg.AssignLiteral("Not handling adapter signal: ");
368 warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
369 BT_WARNING(warningMsg.get());
370 #endif
371 }
372 }
374 already_AddRefed<DOMRequest>
375 BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
376 {
377 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
378 if (!win) {
379 aRv.Throw(NS_ERROR_FAILURE);
380 return nullptr;
381 }
383 nsRefPtr<DOMRequest> request = new DOMRequest(win);
384 nsRefPtr<BluetoothVoidReplyRunnable> results =
385 new BluetoothVoidReplyRunnable(request);
387 BluetoothService* bs = BluetoothService::Get();
388 if (!bs) {
389 aRv.Throw(NS_ERROR_FAILURE);
390 return nullptr;
391 }
392 nsresult rv;
393 if (aStart) {
394 rv = bs->StartDiscoveryInternal(results);
395 } else {
396 rv = bs->StopDiscoveryInternal(results);
397 }
398 if (NS_FAILED(rv)) {
399 BT_WARNING("Start/Stop Discovery failed!");
400 aRv.Throw(rv);
401 return nullptr;
402 }
404 // mDiscovering is not set here, we'll get a Property update from our external
405 // protocol to tell us that it's been set.
407 return request.forget();
408 }
410 already_AddRefed<DOMRequest>
411 BluetoothAdapter::StartDiscovery(ErrorResult& aRv)
412 {
413 return StartStopDiscovery(true, aRv);
414 }
416 already_AddRefed<DOMRequest>
417 BluetoothAdapter::StopDiscovery(ErrorResult& aRv)
418 {
419 return StartStopDiscovery(false, aRv);
420 }
422 void
423 BluetoothAdapter::GetDevices(JSContext* aContext,
424 JS::MutableHandle<JS::Value> aDevices,
425 ErrorResult& aRv)
426 {
427 if (!mJsDeviceAddresses) {
428 BT_WARNING("Devices not yet set!\n");
429 aRv.Throw(NS_ERROR_FAILURE);
430 return;
431 }
433 JS::ExposeObjectToActiveJS(mJsDeviceAddresses);
434 aDevices.setObject(*mJsDeviceAddresses);
435 }
437 void
438 BluetoothAdapter::GetUuids(JSContext* aContext,
439 JS::MutableHandle<JS::Value> aUuids,
440 ErrorResult& aRv)
441 {
442 if (!mJsUuids) {
443 BT_WARNING("UUIDs not yet set!\n");
444 aRv.Throw(NS_ERROR_FAILURE);
445 return;
446 }
448 JS::ExposeObjectToActiveJS(mJsUuids);
449 aUuids.setObject(*mJsUuids);
450 }
452 already_AddRefed<DOMRequest>
453 BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv)
454 {
455 if (mName.Equals(aName)) {
456 return FirePropertyAlreadySet(GetOwner(), aRv);
457 }
458 nsString name(aName);
459 BluetoothValue value(name);
460 BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value);
461 return SetProperty(GetOwner(), property, aRv);
462 }
464 already_AddRefed<DOMRequest>
465 BluetoothAdapter::SetDiscoverable(bool aDiscoverable, ErrorResult& aRv)
466 {
467 if (aDiscoverable == mDiscoverable) {
468 return FirePropertyAlreadySet(GetOwner(), aRv);
469 }
470 BluetoothValue value(aDiscoverable);
471 BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value);
472 return SetProperty(GetOwner(), property, aRv);
473 }
475 already_AddRefed<DOMRequest>
476 BluetoothAdapter::SetDiscoverableTimeout(uint32_t aDiscoverableTimeout, ErrorResult& aRv)
477 {
478 if (aDiscoverableTimeout == mDiscoverableTimeout) {
479 return FirePropertyAlreadySet(GetOwner(), aRv);
480 }
481 BluetoothValue value(aDiscoverableTimeout);
482 BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value);
483 return SetProperty(GetOwner(), property, aRv);
484 }
486 already_AddRefed<DOMRequest>
487 BluetoothAdapter::GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv)
488 {
489 MOZ_ASSERT(NS_IsMainThread());
491 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
492 if (!win) {
493 aRv.Throw(NS_ERROR_FAILURE);
494 return nullptr;
495 }
497 nsRefPtr<DOMRequest> request = new DOMRequest(win);
498 nsRefPtr<BluetoothReplyRunnable> results =
499 new GetDevicesTask(this, request);
501 BluetoothService* bs = BluetoothService::Get();
502 if (!bs) {
503 aRv.Throw(NS_ERROR_FAILURE);
504 return nullptr;
505 }
506 nsresult rv = bs->GetConnectedDevicePropertiesInternal(aServiceUuid, results);
507 if (NS_FAILED(rv)) {
508 aRv.Throw(rv);
509 return nullptr;
510 }
512 return request.forget();
513 }
515 already_AddRefed<DOMRequest>
516 BluetoothAdapter::GetPairedDevices(ErrorResult& aRv)
517 {
518 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
519 if (!win) {
520 aRv.Throw(NS_ERROR_FAILURE);
521 return nullptr;
522 }
524 nsRefPtr<DOMRequest> request = new DOMRequest(win);
525 nsRefPtr<BluetoothReplyRunnable> results =
526 new GetDevicesTask(this, request);
528 BluetoothService* bs = BluetoothService::Get();
529 if (!bs) {
530 aRv.Throw(NS_ERROR_FAILURE);
531 return nullptr;
532 }
533 nsresult rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results);
534 if (NS_FAILED(rv)) {
535 aRv.Throw(rv);
536 return nullptr;
537 }
539 return request.forget();
540 }
542 already_AddRefed<DOMRequest>
543 BluetoothAdapter::PairUnpair(bool aPair, const nsAString& aDeviceAddress,
544 ErrorResult& aRv)
545 {
546 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
547 if (!win) {
548 aRv.Throw(NS_ERROR_FAILURE);
549 return nullptr;
550 }
552 nsRefPtr<DOMRequest> request = new DOMRequest(win);
553 nsRefPtr<BluetoothVoidReplyRunnable> results =
554 new BluetoothVoidReplyRunnable(request);
556 BluetoothService* bs = BluetoothService::Get();
557 if (!bs) {
558 aRv.Throw(NS_ERROR_FAILURE);
559 return nullptr;
560 }
561 nsresult rv;
562 if (aPair) {
563 rv = bs->CreatePairedDeviceInternal(aDeviceAddress,
564 kCreatePairedDeviceTimeout,
565 results);
566 } else {
567 rv = bs->RemoveDeviceInternal(aDeviceAddress, results);
568 }
569 if (NS_FAILED(rv)) {
570 BT_WARNING("Pair/Unpair failed!");
571 aRv.Throw(rv);
572 return nullptr;
573 }
575 return request.forget();
576 }
578 already_AddRefed<DOMRequest>
579 BluetoothAdapter::Pair(const nsAString& aDeviceAddress, ErrorResult& aRv)
580 {
581 return PairUnpair(true, aDeviceAddress, aRv);
582 }
584 already_AddRefed<DOMRequest>
585 BluetoothAdapter::Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv)
586 {
587 return PairUnpair(false, aDeviceAddress, aRv);
588 }
590 already_AddRefed<DOMRequest>
591 BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
592 const nsAString& aPinCode, ErrorResult& aRv)
593 {
594 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
595 if (!win) {
596 aRv.Throw(NS_ERROR_FAILURE);
597 return nullptr;
598 }
600 nsRefPtr<DOMRequest> request = new DOMRequest(win);
601 nsRefPtr<BluetoothVoidReplyRunnable> results =
602 new BluetoothVoidReplyRunnable(request);
604 BluetoothService* bs = BluetoothService::Get();
605 if (!bs) {
606 aRv.Throw(NS_ERROR_FAILURE);
607 return nullptr;
608 }
609 if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
610 BT_WARNING("SetPinCode failed!");
611 aRv.Throw(NS_ERROR_FAILURE);
612 return nullptr;
613 }
615 return request.forget();
616 }
618 already_AddRefed<DOMRequest>
619 BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
620 ErrorResult& aRv)
621 {
622 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
623 if (!win) {
624 aRv.Throw(NS_ERROR_FAILURE);
625 return nullptr;
626 }
628 nsRefPtr<DOMRequest> request = new DOMRequest(win);
629 nsRefPtr<BluetoothVoidReplyRunnable> results =
630 new BluetoothVoidReplyRunnable(request);
632 BluetoothService* bs = BluetoothService::Get();
633 if (!bs) {
634 aRv.Throw(NS_ERROR_FAILURE);
635 return nullptr;
636 }
637 if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
638 BT_WARNING("SetPasskeyInternal failed!");
639 aRv.Throw(NS_ERROR_FAILURE);
640 return nullptr;
641 }
643 return request.forget();
644 }
646 already_AddRefed<DOMRequest>
647 BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
648 bool aConfirmation, ErrorResult& aRv)
649 {
650 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
651 if (!win) {
652 aRv.Throw(NS_ERROR_FAILURE);
653 return nullptr;
654 }
656 nsRefPtr<DOMRequest> request = new DOMRequest(win);
657 nsRefPtr<BluetoothVoidReplyRunnable> results =
658 new BluetoothVoidReplyRunnable(request);
660 BluetoothService* bs = BluetoothService::Get();
661 if (!bs) {
662 aRv.Throw(NS_ERROR_FAILURE);
663 return nullptr;
664 }
665 if (!bs->SetPairingConfirmationInternal(aDeviceAddress,
666 aConfirmation,
667 results)) {
668 BT_WARNING("SetPairingConfirmation failed!");
669 aRv.Throw(NS_ERROR_FAILURE);
670 return nullptr;
671 }
673 return request.forget();
674 }
676 already_AddRefed<DOMRequest>
677 BluetoothAdapter::Connect(BluetoothDevice& aDevice,
678 const Optional<short unsigned int>& aServiceUuid,
679 ErrorResult& aRv)
680 {
681 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
682 if (!win) {
683 aRv.Throw(NS_ERROR_FAILURE);
684 return nullptr;
685 }
687 nsRefPtr<DOMRequest> request = new DOMRequest(win);
688 nsRefPtr<BluetoothVoidReplyRunnable> results =
689 new BluetoothVoidReplyRunnable(request);
691 nsAutoString address;
692 aDevice.GetAddress(address);
693 uint32_t deviceClass = aDevice.Class();
694 uint16_t serviceUuid = 0;
695 if (aServiceUuid.WasPassed()) {
696 serviceUuid = aServiceUuid.Value();
697 }
699 BluetoothService* bs = BluetoothService::Get();
700 if (!bs) {
701 aRv.Throw(NS_ERROR_FAILURE);
702 return nullptr;
703 }
704 bs->Connect(address, deviceClass, serviceUuid, results);
706 return request.forget();
707 }
709 already_AddRefed<DOMRequest>
710 BluetoothAdapter::Disconnect(BluetoothDevice& aDevice,
711 const Optional<short unsigned int>& aServiceUuid,
712 ErrorResult& aRv)
713 {
714 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
715 if (!win) {
716 aRv.Throw(NS_ERROR_FAILURE);
717 return nullptr;
718 }
720 nsRefPtr<DOMRequest> request = new DOMRequest(win);
721 nsRefPtr<BluetoothVoidReplyRunnable> results =
722 new BluetoothVoidReplyRunnable(request);
724 nsAutoString address;
725 aDevice.GetAddress(address);
726 uint16_t serviceUuid = 0;
727 if (aServiceUuid.WasPassed()) {
728 serviceUuid = aServiceUuid.Value();
729 }
731 BluetoothService* bs = BluetoothService::Get();
732 if (!bs) {
733 aRv.Throw(NS_ERROR_FAILURE);
734 return nullptr;
735 }
736 bs->Disconnect(address, serviceUuid, results);
738 return request.forget();
739 }
741 already_AddRefed<DOMRequest>
742 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
743 nsIDOMBlob* aBlob, ErrorResult& aRv)
744 {
745 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
746 if (!win) {
747 aRv.Throw(NS_ERROR_FAILURE);
748 return nullptr;
749 }
751 nsRefPtr<DOMRequest> request = new DOMRequest(win);
752 nsRefPtr<BluetoothVoidReplyRunnable> results =
753 new BluetoothVoidReplyRunnable(request);
755 BluetoothService* bs = BluetoothService::Get();
756 if (!bs) {
757 aRv.Throw(NS_ERROR_FAILURE);
758 return nullptr;
759 }
761 if (XRE_GetProcessType() == GeckoProcessType_Default) {
762 // In-process transfer
763 bs->SendFile(aDeviceAddress, aBlob, results);
764 } else {
765 ContentChild *cc = ContentChild::GetSingleton();
766 if (!cc) {
767 aRv.Throw(NS_ERROR_FAILURE);
768 return nullptr;
769 }
771 BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob);
772 if (!actor) {
773 aRv.Throw(NS_ERROR_FAILURE);
774 return nullptr;
775 }
777 bs->SendFile(aDeviceAddress, nullptr, actor, results);
778 }
780 return request.forget();
781 }
783 already_AddRefed<DOMRequest>
784 BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv)
785 {
786 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
787 if (!win) {
788 aRv.Throw(NS_ERROR_FAILURE);
789 return nullptr;
790 }
792 nsRefPtr<DOMRequest> request = new DOMRequest(win);
793 nsRefPtr<BluetoothVoidReplyRunnable> results =
794 new BluetoothVoidReplyRunnable(request);
796 BluetoothService* bs = BluetoothService::Get();
797 if (!bs) {
798 aRv.Throw(NS_ERROR_FAILURE);
799 return nullptr;
800 }
801 bs->StopSendingFile(aDeviceAddress, results);
803 return request.forget();
804 }
806 already_AddRefed<DOMRequest>
807 BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
808 bool aConfirmation, ErrorResult& aRv)
809 {
810 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
811 if (!win) {
812 aRv.Throw(NS_ERROR_FAILURE);
813 return nullptr;
814 }
816 nsRefPtr<DOMRequest> request = new DOMRequest(win);
817 nsRefPtr<BluetoothVoidReplyRunnable> results =
818 new BluetoothVoidReplyRunnable(request);
820 BluetoothService* bs = BluetoothService::Get();
821 if (!bs) {
822 aRv.Throw(NS_ERROR_FAILURE);
823 return nullptr;
824 }
825 bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results);
827 return request.forget();
828 }
830 already_AddRefed<DOMRequest>
831 BluetoothAdapter::ConnectSco(ErrorResult& aRv)
832 {
833 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
834 if (!win) {
835 aRv.Throw(NS_ERROR_FAILURE);
836 return nullptr;
837 }
839 nsRefPtr<DOMRequest> request = new DOMRequest(win);
840 nsRefPtr<BluetoothVoidReplyRunnable> results =
841 new BluetoothVoidReplyRunnable(request);
843 BluetoothService* bs = BluetoothService::Get();
844 if (!bs) {
845 aRv.Throw(NS_ERROR_FAILURE);
846 return nullptr;
847 }
848 bs->ConnectSco(results);
850 return request.forget();
851 }
853 already_AddRefed<DOMRequest>
854 BluetoothAdapter::DisconnectSco(ErrorResult& aRv)
855 {
856 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
857 if (!win) {
858 aRv.Throw(NS_ERROR_FAILURE);
859 return nullptr;
860 }
862 nsRefPtr<DOMRequest> request = new DOMRequest(win);
863 nsRefPtr<BluetoothVoidReplyRunnable> results =
864 new BluetoothVoidReplyRunnable(request);
866 BluetoothService* bs = BluetoothService::Get();
867 if (!bs) {
868 aRv.Throw(NS_ERROR_FAILURE);
869 return nullptr;
870 }
871 bs->DisconnectSco(results);
873 return request.forget();
874 }
876 already_AddRefed<DOMRequest>
877 BluetoothAdapter::IsScoConnected(ErrorResult& aRv)
878 {
879 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
880 if (!win) {
881 aRv.Throw(NS_ERROR_FAILURE);
882 return nullptr;
883 }
885 nsRefPtr<DOMRequest> request = new DOMRequest(win);
886 nsRefPtr<BluetoothReplyRunnable> results =
887 new GetScoConnectionStatusTask(request);
889 BluetoothService* bs = BluetoothService::Get();
890 if (!bs) {
891 aRv.Throw(NS_ERROR_FAILURE);
892 return nullptr;
893 }
894 bs->IsScoConnected(results);
896 return request.forget();
897 }
899 already_AddRefed<DOMRequest>
900 BluetoothAdapter::AnswerWaitingCall(ErrorResult& aRv)
901 {
902 #ifdef MOZ_B2G_RIL
903 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
904 if (!win) {
905 aRv.Throw(NS_ERROR_FAILURE);
906 return nullptr;
907 }
909 nsRefPtr<DOMRequest> request = new DOMRequest(win);
910 nsRefPtr<BluetoothVoidReplyRunnable> results =
911 new BluetoothVoidReplyRunnable(request);
913 BluetoothService* bs = BluetoothService::Get();
914 if (!bs) {
915 aRv.Throw(NS_ERROR_FAILURE);
916 return nullptr;
917 }
918 bs->AnswerWaitingCall(results);
920 return request.forget();
921 #else
922 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
923 return nullptr;
924 #endif // MOZ_B2G_RIL
925 }
927 already_AddRefed<DOMRequest>
928 BluetoothAdapter::IgnoreWaitingCall(ErrorResult& aRv)
929 {
930 #ifdef MOZ_B2G_RIL
931 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
932 if (!win) {
933 aRv.Throw(NS_ERROR_FAILURE);
934 return nullptr;
935 }
937 nsRefPtr<DOMRequest> request = new DOMRequest(win);
938 nsRefPtr<BluetoothVoidReplyRunnable> results =
939 new BluetoothVoidReplyRunnable(request);
941 BluetoothService* bs = BluetoothService::Get();
942 if (!bs) {
943 aRv.Throw(NS_ERROR_FAILURE);
944 return nullptr;
945 }
946 bs->IgnoreWaitingCall(results);
948 return request.forget();
949 #else
950 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
951 return nullptr;
952 #endif // MOZ_B2G_RIL
953 }
955 already_AddRefed<DOMRequest>
956 BluetoothAdapter::ToggleCalls(ErrorResult& aRv)
957 {
958 #ifdef MOZ_B2G_RIL
959 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
960 if (!win) {
961 aRv.Throw(NS_ERROR_FAILURE);
962 return nullptr;
963 }
965 nsRefPtr<DOMRequest> request = new DOMRequest(win);
966 nsRefPtr<BluetoothVoidReplyRunnable> results =
967 new BluetoothVoidReplyRunnable(request);
969 BluetoothService* bs = BluetoothService::Get();
970 if (!bs) {
971 aRv.Throw(NS_ERROR_FAILURE);
972 return nullptr;
973 }
974 bs->ToggleCalls(results);
976 return request.forget();
977 #else
978 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
979 return nullptr;
980 #endif // MOZ_B2G_RIL
981 }
983 already_AddRefed<DOMRequest>
984 BluetoothAdapter::SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv)
985 {
986 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
987 if (!win) {
988 aRv.Throw(NS_ERROR_FAILURE);
989 return nullptr;
990 }
992 nsRefPtr<DOMRequest> request = new DOMRequest(win);
993 nsRefPtr<BluetoothReplyRunnable> results =
994 new BluetoothVoidReplyRunnable(request);
996 BluetoothService* bs = BluetoothService::Get();
997 if (!bs) {
998 aRv.Throw(NS_ERROR_FAILURE);
999 return nullptr;
1000 }
1001 bs->SendMetaData(aMediaMetaData.mTitle,
1002 aMediaMetaData.mArtist,
1003 aMediaMetaData.mAlbum,
1004 aMediaMetaData.mMediaNumber,
1005 aMediaMetaData.mTotalMediaCount,
1006 aMediaMetaData.mDuration,
1007 results);
1009 return request.forget();
1010 }
1012 already_AddRefed<DOMRequest>
1013 BluetoothAdapter::SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv)
1014 {
1015 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
1016 if (!win) {
1017 aRv.Throw(NS_ERROR_FAILURE);
1018 return nullptr;
1019 }
1021 nsRefPtr<DOMRequest> request = new DOMRequest(win);
1022 nsRefPtr<BluetoothReplyRunnable> results =
1023 new BluetoothVoidReplyRunnable(request);
1025 BluetoothService* bs = BluetoothService::Get();
1026 if (!bs) {
1027 aRv.Throw(NS_ERROR_FAILURE);
1028 return nullptr;
1029 }
1030 bs->SendPlayStatus(aMediaPlayStatus.mDuration,
1031 aMediaPlayStatus.mPosition,
1032 aMediaPlayStatus.mPlayStatus,
1033 results);
1035 return request.forget();
1036 }
1038 JSObject*
1039 BluetoothAdapter::WrapObject(JSContext* aCx)
1040 {
1041 return BluetoothAdapterBinding::Wrap(aCx, this);
1042 }