|
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/. */ |
|
6 |
|
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" |
|
13 |
|
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" |
|
20 |
|
21 #include "BluetoothAdapter.h" |
|
22 #include "BluetoothDevice.h" |
|
23 #include "BluetoothReplyRunnable.h" |
|
24 #include "BluetoothService.h" |
|
25 #include "BluetoothUtils.h" |
|
26 |
|
27 using namespace mozilla; |
|
28 using namespace mozilla::dom; |
|
29 |
|
30 USING_BLUETOOTH_NAMESPACE |
|
31 |
|
32 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter) |
|
33 |
|
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 |
|
39 |
|
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 |
|
44 |
|
45 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, |
|
46 DOMEventTargetHelper) |
|
47 tmp->Unroot(); |
|
48 NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
|
49 |
|
50 // QueryInterface implementation for BluetoothAdapter |
|
51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) |
|
52 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
|
53 |
|
54 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper) |
|
55 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper) |
|
56 |
|
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 } |
|
67 |
|
68 virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) |
|
69 { |
|
70 aValue.setUndefined(); |
|
71 |
|
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 } |
|
78 |
|
79 const InfallibleTArray<BluetoothNamedValue>& values = |
|
80 v.get_ArrayOfBluetoothNamedValue(); |
|
81 |
|
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 } |
|
96 |
|
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 } |
|
104 |
|
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 } |
|
113 |
|
114 aValue.setObject(*JsDevices); |
|
115 return true; |
|
116 } |
|
117 |
|
118 void |
|
119 ReleaseMembers() |
|
120 { |
|
121 BluetoothReplyRunnable::ReleaseMembers(); |
|
122 mAdapterPtr = nullptr; |
|
123 } |
|
124 private: |
|
125 nsRefPtr<BluetoothAdapter> mAdapterPtr; |
|
126 }; |
|
127 |
|
128 class GetScoConnectionStatusTask : public BluetoothReplyRunnable |
|
129 { |
|
130 public: |
|
131 GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) : |
|
132 BluetoothReplyRunnable(aReq) |
|
133 { |
|
134 MOZ_ASSERT(aReq); |
|
135 } |
|
136 |
|
137 virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) |
|
138 { |
|
139 aValue.setUndefined(); |
|
140 |
|
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 } |
|
147 |
|
148 aValue.setBoolean(v.get_bool()); |
|
149 return true; |
|
150 } |
|
151 |
|
152 void |
|
153 ReleaseMembers() |
|
154 { |
|
155 BluetoothReplyRunnable::ReleaseMembers(); |
|
156 } |
|
157 }; |
|
158 |
|
159 static int kCreatePairedDeviceTimeout = 50000; // unit: msec |
|
160 |
|
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()); |
|
175 |
|
176 const InfallibleTArray<BluetoothNamedValue>& values = |
|
177 aValue.get_ArrayOfBluetoothNamedValue(); |
|
178 for (uint32_t i = 0; i < values.Length(); ++i) { |
|
179 SetPropertyByValue(values[i]); |
|
180 } |
|
181 |
|
182 BluetoothService* bs = BluetoothService::Get(); |
|
183 NS_ENSURE_TRUE_VOID(bs); |
|
184 bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); |
|
185 } |
|
186 |
|
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 } |
|
195 |
|
196 void |
|
197 BluetoothAdapter::DisconnectFromOwner() |
|
198 { |
|
199 DOMEventTargetHelper::DisconnectFromOwner(); |
|
200 |
|
201 BluetoothService* bs = BluetoothService::Get(); |
|
202 NS_ENSURE_TRUE_VOID(bs); |
|
203 bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); |
|
204 } |
|
205 |
|
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 } |
|
217 |
|
218 void |
|
219 BluetoothAdapter::Root() |
|
220 { |
|
221 if (mIsRooted) { |
|
222 return; |
|
223 } |
|
224 mozilla::HoldJSObjects(this); |
|
225 mIsRooted = true; |
|
226 } |
|
227 |
|
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); |
|
259 |
|
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(); |
|
270 |
|
271 nsresult rv; |
|
272 nsIScriptContext* sc = GetContextForEventHandlers(&rv); |
|
273 NS_ENSURE_SUCCESS_VOID(rv); |
|
274 NS_ENSURE_TRUE_VOID(sc); |
|
275 |
|
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 } |
|
294 |
|
295 // static |
|
296 already_AddRefed<BluetoothAdapter> |
|
297 BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue) |
|
298 { |
|
299 MOZ_ASSERT(NS_IsMainThread()); |
|
300 MOZ_ASSERT(aWindow); |
|
301 |
|
302 nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aWindow, aValue); |
|
303 return adapter.forget(); |
|
304 } |
|
305 |
|
306 void |
|
307 BluetoothAdapter::Notify(const BluetoothSignal& aData) |
|
308 { |
|
309 InfallibleTArray<BluetoothNamedValue> arr; |
|
310 |
|
311 BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get()); |
|
312 |
|
313 BluetoothValue v = aData.value(); |
|
314 if (aData.name().EqualsLiteral("DeviceFound")) { |
|
315 nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value()); |
|
316 |
|
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); |
|
326 |
|
327 const InfallibleTArray<BluetoothNamedValue>& arr = |
|
328 v.get_ArrayOfBluetoothNamedValue(); |
|
329 |
|
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(); |
|
340 |
|
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(); |
|
346 |
|
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); |
|
359 |
|
360 rv = event->InitEvent(aData.name(), false, false); |
|
361 NS_ENSURE_SUCCESS_VOID(rv); |
|
362 |
|
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 } |
|
373 |
|
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 } |
|
382 |
|
383 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
384 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
385 new BluetoothVoidReplyRunnable(request); |
|
386 |
|
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 } |
|
403 |
|
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. |
|
406 |
|
407 return request.forget(); |
|
408 } |
|
409 |
|
410 already_AddRefed<DOMRequest> |
|
411 BluetoothAdapter::StartDiscovery(ErrorResult& aRv) |
|
412 { |
|
413 return StartStopDiscovery(true, aRv); |
|
414 } |
|
415 |
|
416 already_AddRefed<DOMRequest> |
|
417 BluetoothAdapter::StopDiscovery(ErrorResult& aRv) |
|
418 { |
|
419 return StartStopDiscovery(false, aRv); |
|
420 } |
|
421 |
|
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 } |
|
432 |
|
433 JS::ExposeObjectToActiveJS(mJsDeviceAddresses); |
|
434 aDevices.setObject(*mJsDeviceAddresses); |
|
435 } |
|
436 |
|
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 } |
|
447 |
|
448 JS::ExposeObjectToActiveJS(mJsUuids); |
|
449 aUuids.setObject(*mJsUuids); |
|
450 } |
|
451 |
|
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 } |
|
463 |
|
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 } |
|
474 |
|
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 } |
|
485 |
|
486 already_AddRefed<DOMRequest> |
|
487 BluetoothAdapter::GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv) |
|
488 { |
|
489 MOZ_ASSERT(NS_IsMainThread()); |
|
490 |
|
491 nsCOMPtr<nsPIDOMWindow> win = GetOwner(); |
|
492 if (!win) { |
|
493 aRv.Throw(NS_ERROR_FAILURE); |
|
494 return nullptr; |
|
495 } |
|
496 |
|
497 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
498 nsRefPtr<BluetoothReplyRunnable> results = |
|
499 new GetDevicesTask(this, request); |
|
500 |
|
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 } |
|
511 |
|
512 return request.forget(); |
|
513 } |
|
514 |
|
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 } |
|
523 |
|
524 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
525 nsRefPtr<BluetoothReplyRunnable> results = |
|
526 new GetDevicesTask(this, request); |
|
527 |
|
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 } |
|
538 |
|
539 return request.forget(); |
|
540 } |
|
541 |
|
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 } |
|
551 |
|
552 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
553 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
554 new BluetoothVoidReplyRunnable(request); |
|
555 |
|
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 } |
|
574 |
|
575 return request.forget(); |
|
576 } |
|
577 |
|
578 already_AddRefed<DOMRequest> |
|
579 BluetoothAdapter::Pair(const nsAString& aDeviceAddress, ErrorResult& aRv) |
|
580 { |
|
581 return PairUnpair(true, aDeviceAddress, aRv); |
|
582 } |
|
583 |
|
584 already_AddRefed<DOMRequest> |
|
585 BluetoothAdapter::Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv) |
|
586 { |
|
587 return PairUnpair(false, aDeviceAddress, aRv); |
|
588 } |
|
589 |
|
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 } |
|
599 |
|
600 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
601 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
602 new BluetoothVoidReplyRunnable(request); |
|
603 |
|
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 } |
|
614 |
|
615 return request.forget(); |
|
616 } |
|
617 |
|
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 } |
|
627 |
|
628 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
629 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
630 new BluetoothVoidReplyRunnable(request); |
|
631 |
|
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 } |
|
642 |
|
643 return request.forget(); |
|
644 } |
|
645 |
|
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 } |
|
655 |
|
656 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
657 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
658 new BluetoothVoidReplyRunnable(request); |
|
659 |
|
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 } |
|
672 |
|
673 return request.forget(); |
|
674 } |
|
675 |
|
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 } |
|
686 |
|
687 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
688 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
689 new BluetoothVoidReplyRunnable(request); |
|
690 |
|
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 } |
|
698 |
|
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); |
|
705 |
|
706 return request.forget(); |
|
707 } |
|
708 |
|
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 } |
|
719 |
|
720 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
721 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
722 new BluetoothVoidReplyRunnable(request); |
|
723 |
|
724 nsAutoString address; |
|
725 aDevice.GetAddress(address); |
|
726 uint16_t serviceUuid = 0; |
|
727 if (aServiceUuid.WasPassed()) { |
|
728 serviceUuid = aServiceUuid.Value(); |
|
729 } |
|
730 |
|
731 BluetoothService* bs = BluetoothService::Get(); |
|
732 if (!bs) { |
|
733 aRv.Throw(NS_ERROR_FAILURE); |
|
734 return nullptr; |
|
735 } |
|
736 bs->Disconnect(address, serviceUuid, results); |
|
737 |
|
738 return request.forget(); |
|
739 } |
|
740 |
|
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 } |
|
750 |
|
751 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
752 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
753 new BluetoothVoidReplyRunnable(request); |
|
754 |
|
755 BluetoothService* bs = BluetoothService::Get(); |
|
756 if (!bs) { |
|
757 aRv.Throw(NS_ERROR_FAILURE); |
|
758 return nullptr; |
|
759 } |
|
760 |
|
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 } |
|
770 |
|
771 BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob); |
|
772 if (!actor) { |
|
773 aRv.Throw(NS_ERROR_FAILURE); |
|
774 return nullptr; |
|
775 } |
|
776 |
|
777 bs->SendFile(aDeviceAddress, nullptr, actor, results); |
|
778 } |
|
779 |
|
780 return request.forget(); |
|
781 } |
|
782 |
|
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 } |
|
791 |
|
792 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
793 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
794 new BluetoothVoidReplyRunnable(request); |
|
795 |
|
796 BluetoothService* bs = BluetoothService::Get(); |
|
797 if (!bs) { |
|
798 aRv.Throw(NS_ERROR_FAILURE); |
|
799 return nullptr; |
|
800 } |
|
801 bs->StopSendingFile(aDeviceAddress, results); |
|
802 |
|
803 return request.forget(); |
|
804 } |
|
805 |
|
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 } |
|
815 |
|
816 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
817 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
818 new BluetoothVoidReplyRunnable(request); |
|
819 |
|
820 BluetoothService* bs = BluetoothService::Get(); |
|
821 if (!bs) { |
|
822 aRv.Throw(NS_ERROR_FAILURE); |
|
823 return nullptr; |
|
824 } |
|
825 bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results); |
|
826 |
|
827 return request.forget(); |
|
828 } |
|
829 |
|
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 } |
|
838 |
|
839 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
840 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
841 new BluetoothVoidReplyRunnable(request); |
|
842 |
|
843 BluetoothService* bs = BluetoothService::Get(); |
|
844 if (!bs) { |
|
845 aRv.Throw(NS_ERROR_FAILURE); |
|
846 return nullptr; |
|
847 } |
|
848 bs->ConnectSco(results); |
|
849 |
|
850 return request.forget(); |
|
851 } |
|
852 |
|
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 } |
|
861 |
|
862 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
863 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
864 new BluetoothVoidReplyRunnable(request); |
|
865 |
|
866 BluetoothService* bs = BluetoothService::Get(); |
|
867 if (!bs) { |
|
868 aRv.Throw(NS_ERROR_FAILURE); |
|
869 return nullptr; |
|
870 } |
|
871 bs->DisconnectSco(results); |
|
872 |
|
873 return request.forget(); |
|
874 } |
|
875 |
|
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 } |
|
884 |
|
885 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
886 nsRefPtr<BluetoothReplyRunnable> results = |
|
887 new GetScoConnectionStatusTask(request); |
|
888 |
|
889 BluetoothService* bs = BluetoothService::Get(); |
|
890 if (!bs) { |
|
891 aRv.Throw(NS_ERROR_FAILURE); |
|
892 return nullptr; |
|
893 } |
|
894 bs->IsScoConnected(results); |
|
895 |
|
896 return request.forget(); |
|
897 } |
|
898 |
|
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 } |
|
908 |
|
909 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
910 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
911 new BluetoothVoidReplyRunnable(request); |
|
912 |
|
913 BluetoothService* bs = BluetoothService::Get(); |
|
914 if (!bs) { |
|
915 aRv.Throw(NS_ERROR_FAILURE); |
|
916 return nullptr; |
|
917 } |
|
918 bs->AnswerWaitingCall(results); |
|
919 |
|
920 return request.forget(); |
|
921 #else |
|
922 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
|
923 return nullptr; |
|
924 #endif // MOZ_B2G_RIL |
|
925 } |
|
926 |
|
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 } |
|
936 |
|
937 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
938 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
939 new BluetoothVoidReplyRunnable(request); |
|
940 |
|
941 BluetoothService* bs = BluetoothService::Get(); |
|
942 if (!bs) { |
|
943 aRv.Throw(NS_ERROR_FAILURE); |
|
944 return nullptr; |
|
945 } |
|
946 bs->IgnoreWaitingCall(results); |
|
947 |
|
948 return request.forget(); |
|
949 #else |
|
950 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
|
951 return nullptr; |
|
952 #endif // MOZ_B2G_RIL |
|
953 } |
|
954 |
|
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 } |
|
964 |
|
965 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
966 nsRefPtr<BluetoothVoidReplyRunnable> results = |
|
967 new BluetoothVoidReplyRunnable(request); |
|
968 |
|
969 BluetoothService* bs = BluetoothService::Get(); |
|
970 if (!bs) { |
|
971 aRv.Throw(NS_ERROR_FAILURE); |
|
972 return nullptr; |
|
973 } |
|
974 bs->ToggleCalls(results); |
|
975 |
|
976 return request.forget(); |
|
977 #else |
|
978 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); |
|
979 return nullptr; |
|
980 #endif // MOZ_B2G_RIL |
|
981 } |
|
982 |
|
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 } |
|
991 |
|
992 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
993 nsRefPtr<BluetoothReplyRunnable> results = |
|
994 new BluetoothVoidReplyRunnable(request); |
|
995 |
|
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); |
|
1008 |
|
1009 return request.forget(); |
|
1010 } |
|
1011 |
|
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 } |
|
1020 |
|
1021 nsRefPtr<DOMRequest> request = new DOMRequest(win); |
|
1022 nsRefPtr<BluetoothReplyRunnable> results = |
|
1023 new BluetoothVoidReplyRunnable(request); |
|
1024 |
|
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); |
|
1034 |
|
1035 return request.forget(); |
|
1036 } |
|
1037 |
|
1038 JSObject* |
|
1039 BluetoothAdapter::WrapObject(JSContext* aCx) |
|
1040 { |
|
1041 return BluetoothAdapterBinding::Wrap(aCx, this); |
|
1042 } |