1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/BluetoothAdapter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1042 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "base/basictypes.h" 1.11 +#include "nsCxPusher.h" 1.12 +#include "nsDOMClassInfo.h" 1.13 +#include "nsTArrayHelpers.h" 1.14 +#include "DOMRequest.h" 1.15 +#include "nsThreadUtils.h" 1.16 + 1.17 +#include "mozilla/dom/bluetooth/BluetoothTypes.h" 1.18 +#include "mozilla/dom/BluetoothAdapterBinding.h" 1.19 +#include "mozilla/dom/BluetoothDeviceEvent.h" 1.20 +#include "mozilla/dom/BluetoothStatusChangedEvent.h" 1.21 +#include "mozilla/dom/ContentChild.h" 1.22 +#include "mozilla/LazyIdleThread.h" 1.23 + 1.24 +#include "BluetoothAdapter.h" 1.25 +#include "BluetoothDevice.h" 1.26 +#include "BluetoothReplyRunnable.h" 1.27 +#include "BluetoothService.h" 1.28 +#include "BluetoothUtils.h" 1.29 + 1.30 +using namespace mozilla; 1.31 +using namespace mozilla::dom; 1.32 + 1.33 +USING_BLUETOOTH_NAMESPACE 1.34 + 1.35 +NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter) 1.36 + 1.37 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter, 1.38 + DOMEventTargetHelper) 1.39 + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids) 1.40 + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsDeviceAddresses) 1.41 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.42 + 1.43 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 1.44 + DOMEventTargetHelper) 1.45 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.46 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.47 + 1.48 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, 1.49 + DOMEventTargetHelper) 1.50 + tmp->Unroot(); 1.51 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.52 + 1.53 +// QueryInterface implementation for BluetoothAdapter 1.54 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) 1.55 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.56 + 1.57 +NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper) 1.58 +NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper) 1.59 + 1.60 +class GetDevicesTask : public BluetoothReplyRunnable 1.61 +{ 1.62 +public: 1.63 + GetDevicesTask(BluetoothAdapter* aAdapterPtr, 1.64 + nsIDOMDOMRequest* aReq) : 1.65 + BluetoothReplyRunnable(aReq), 1.66 + mAdapterPtr(aAdapterPtr) 1.67 + { 1.68 + MOZ_ASSERT(aReq && aAdapterPtr); 1.69 + } 1.70 + 1.71 + virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) 1.72 + { 1.73 + aValue.setUndefined(); 1.74 + 1.75 + const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); 1.76 + if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) { 1.77 + BT_WARNING("Not a BluetoothNamedValue array!"); 1.78 + SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); 1.79 + return false; 1.80 + } 1.81 + 1.82 + const InfallibleTArray<BluetoothNamedValue>& values = 1.83 + v.get_ArrayOfBluetoothNamedValue(); 1.84 + 1.85 + nsTArray<nsRefPtr<BluetoothDevice> > devices; 1.86 + for (uint32_t i = 0; i < values.Length(); i++) { 1.87 + const BluetoothValue properties = values[i].value(); 1.88 + if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) { 1.89 + BT_WARNING("Not a BluetoothNamedValue array!"); 1.90 + SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); 1.91 + return false; 1.92 + } 1.93 + nsRefPtr<BluetoothDevice> d = 1.94 + BluetoothDevice::Create(mAdapterPtr->GetOwner(), 1.95 + mAdapterPtr->GetPath(), 1.96 + properties); 1.97 + devices.AppendElement(d); 1.98 + } 1.99 + 1.100 + nsresult rv; 1.101 + nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv); 1.102 + if (!sc) { 1.103 + BT_WARNING("Cannot create script context!"); 1.104 + SetError(NS_LITERAL_STRING("BluetoothScriptContextError")); 1.105 + return false; 1.106 + } 1.107 + 1.108 + AutoPushJSContext cx(sc->GetNativeContext()); 1.109 + JSObject* JsDevices = nullptr; 1.110 + rv = nsTArrayToJSArray(cx, devices, &JsDevices); 1.111 + if (!JsDevices) { 1.112 + BT_WARNING("Cannot create JS array!"); 1.113 + SetError(NS_LITERAL_STRING("BluetoothError")); 1.114 + return false; 1.115 + } 1.116 + 1.117 + aValue.setObject(*JsDevices); 1.118 + return true; 1.119 + } 1.120 + 1.121 + void 1.122 + ReleaseMembers() 1.123 + { 1.124 + BluetoothReplyRunnable::ReleaseMembers(); 1.125 + mAdapterPtr = nullptr; 1.126 + } 1.127 +private: 1.128 + nsRefPtr<BluetoothAdapter> mAdapterPtr; 1.129 +}; 1.130 + 1.131 +class GetScoConnectionStatusTask : public BluetoothReplyRunnable 1.132 +{ 1.133 +public: 1.134 + GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) : 1.135 + BluetoothReplyRunnable(aReq) 1.136 + { 1.137 + MOZ_ASSERT(aReq); 1.138 + } 1.139 + 1.140 + virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) 1.141 + { 1.142 + aValue.setUndefined(); 1.143 + 1.144 + const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); 1.145 + if (v.type() != BluetoothValue::Tbool) { 1.146 + BT_WARNING("Not a boolean!"); 1.147 + SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); 1.148 + return false; 1.149 + } 1.150 + 1.151 + aValue.setBoolean(v.get_bool()); 1.152 + return true; 1.153 + } 1.154 + 1.155 + void 1.156 + ReleaseMembers() 1.157 + { 1.158 + BluetoothReplyRunnable::ReleaseMembers(); 1.159 + } 1.160 +}; 1.161 + 1.162 +static int kCreatePairedDeviceTimeout = 50000; // unit: msec 1.163 + 1.164 +BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow, 1.165 + const BluetoothValue& aValue) 1.166 + : DOMEventTargetHelper(aWindow) 1.167 + , BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER) 1.168 + , mJsUuids(nullptr) 1.169 + , mJsDeviceAddresses(nullptr) 1.170 + , mDiscoverable(false) 1.171 + , mDiscovering(false) 1.172 + , mPairable(false) 1.173 + , mPowered(false) 1.174 + , mIsRooted(false) 1.175 +{ 1.176 + MOZ_ASSERT(aWindow); 1.177 + MOZ_ASSERT(IsDOMBinding()); 1.178 + 1.179 + const InfallibleTArray<BluetoothNamedValue>& values = 1.180 + aValue.get_ArrayOfBluetoothNamedValue(); 1.181 + for (uint32_t i = 0; i < values.Length(); ++i) { 1.182 + SetPropertyByValue(values[i]); 1.183 + } 1.184 + 1.185 + BluetoothService* bs = BluetoothService::Get(); 1.186 + NS_ENSURE_TRUE_VOID(bs); 1.187 + bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); 1.188 +} 1.189 + 1.190 +BluetoothAdapter::~BluetoothAdapter() 1.191 +{ 1.192 + Unroot(); 1.193 + BluetoothService* bs = BluetoothService::Get(); 1.194 + // We can be null on shutdown, where this might happen 1.195 + NS_ENSURE_TRUE_VOID(bs); 1.196 + bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); 1.197 +} 1.198 + 1.199 +void 1.200 +BluetoothAdapter::DisconnectFromOwner() 1.201 +{ 1.202 + DOMEventTargetHelper::DisconnectFromOwner(); 1.203 + 1.204 + BluetoothService* bs = BluetoothService::Get(); 1.205 + NS_ENSURE_TRUE_VOID(bs); 1.206 + bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); 1.207 +} 1.208 + 1.209 +void 1.210 +BluetoothAdapter::Unroot() 1.211 +{ 1.212 + if (!mIsRooted) { 1.213 + return; 1.214 + } 1.215 + mJsUuids = nullptr; 1.216 + mJsDeviceAddresses = nullptr; 1.217 + mozilla::DropJSObjects(this); 1.218 + mIsRooted = false; 1.219 +} 1.220 + 1.221 +void 1.222 +BluetoothAdapter::Root() 1.223 +{ 1.224 + if (mIsRooted) { 1.225 + return; 1.226 + } 1.227 + mozilla::HoldJSObjects(this); 1.228 + mIsRooted = true; 1.229 +} 1.230 + 1.231 +void 1.232 +BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue) 1.233 +{ 1.234 + const nsString& name = aValue.name(); 1.235 + const BluetoothValue& value = aValue.value(); 1.236 + if (name.EqualsLiteral("Name")) { 1.237 + mName = value.get_nsString(); 1.238 + } else if (name.EqualsLiteral("Address")) { 1.239 + mAddress = value.get_nsString(); 1.240 + } else if (name.EqualsLiteral("Path")) { 1.241 + mPath = value.get_nsString(); 1.242 + } else if (name.EqualsLiteral("Discoverable")) { 1.243 + mDiscoverable = value.get_bool(); 1.244 + } else if (name.EqualsLiteral("Discovering")) { 1.245 + mDiscovering = value.get_bool(); 1.246 + } else if (name.EqualsLiteral("Pairable")) { 1.247 + mPairable = value.get_bool(); 1.248 + } else if (name.EqualsLiteral("Powered")) { 1.249 + mPowered = value.get_bool(); 1.250 + } else if (name.EqualsLiteral("PairableTimeout")) { 1.251 + mPairableTimeout = value.get_uint32_t(); 1.252 + } else if (name.EqualsLiteral("DiscoverableTimeout")) { 1.253 + mDiscoverableTimeout = value.get_uint32_t(); 1.254 + } else if (name.EqualsLiteral("Class")) { 1.255 + mClass = value.get_uint32_t(); 1.256 + } else if (name.EqualsLiteral("UUIDs")) { 1.257 + mUuids = value.get_ArrayOfnsString(); 1.258 + nsresult rv; 1.259 + nsIScriptContext* sc = GetContextForEventHandlers(&rv); 1.260 + NS_ENSURE_SUCCESS_VOID(rv); 1.261 + NS_ENSURE_TRUE_VOID(sc); 1.262 + 1.263 + AutoPushJSContext cx(sc->GetNativeContext()); 1.264 + JS::Rooted<JSObject*> uuids(cx); 1.265 + if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) { 1.266 + BT_WARNING("Cannot set JS UUIDs object!"); 1.267 + return; 1.268 + } 1.269 + mJsUuids = uuids; 1.270 + Root(); 1.271 + } else if (name.EqualsLiteral("Devices")) { 1.272 + mDeviceAddresses = value.get_ArrayOfnsString(); 1.273 + 1.274 + nsresult rv; 1.275 + nsIScriptContext* sc = GetContextForEventHandlers(&rv); 1.276 + NS_ENSURE_SUCCESS_VOID(rv); 1.277 + NS_ENSURE_TRUE_VOID(sc); 1.278 + 1.279 + AutoPushJSContext cx(sc->GetNativeContext()); 1.280 + JS::Rooted<JSObject*> deviceAddresses(cx); 1.281 + if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses, 1.282 + deviceAddresses.address()))) { 1.283 + BT_WARNING("Cannot set JS Devices object!"); 1.284 + return; 1.285 + } 1.286 + mJsDeviceAddresses = deviceAddresses; 1.287 + Root(); 1.288 + } else { 1.289 +#ifdef DEBUG 1.290 + nsCString warningMsg; 1.291 + warningMsg.AssignLiteral("Not handling adapter property: "); 1.292 + warningMsg.Append(NS_ConvertUTF16toUTF8(name)); 1.293 + BT_WARNING(warningMsg.get()); 1.294 +#endif 1.295 + } 1.296 +} 1.297 + 1.298 +// static 1.299 +already_AddRefed<BluetoothAdapter> 1.300 +BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue) 1.301 +{ 1.302 + MOZ_ASSERT(NS_IsMainThread()); 1.303 + MOZ_ASSERT(aWindow); 1.304 + 1.305 + nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aWindow, aValue); 1.306 + return adapter.forget(); 1.307 +} 1.308 + 1.309 +void 1.310 +BluetoothAdapter::Notify(const BluetoothSignal& aData) 1.311 +{ 1.312 + InfallibleTArray<BluetoothNamedValue> arr; 1.313 + 1.314 + BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get()); 1.315 + 1.316 + BluetoothValue v = aData.value(); 1.317 + if (aData.name().EqualsLiteral("DeviceFound")) { 1.318 + nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value()); 1.319 + 1.320 + BluetoothDeviceEventInit init; 1.321 + init.mBubbles = false; 1.322 + init.mCancelable = false; 1.323 + init.mDevice = device; 1.324 + nsRefPtr<BluetoothDeviceEvent> event = 1.325 + BluetoothDeviceEvent::Constructor(this, NS_LITERAL_STRING("devicefound"), init); 1.326 + DispatchTrustedEvent(event); 1.327 + } else if (aData.name().EqualsLiteral("PropertyChanged")) { 1.328 + MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); 1.329 + 1.330 + const InfallibleTArray<BluetoothNamedValue>& arr = 1.331 + v.get_ArrayOfBluetoothNamedValue(); 1.332 + 1.333 + for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) { 1.334 + SetPropertyByValue(arr[i]); 1.335 + } 1.336 + } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) || 1.337 + aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) || 1.338 + aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) || 1.339 + aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) { 1.340 + MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); 1.341 + const InfallibleTArray<BluetoothNamedValue>& arr = 1.342 + v.get_ArrayOfBluetoothNamedValue(); 1.343 + 1.344 + MOZ_ASSERT(arr.Length() == 2 && 1.345 + arr[0].value().type() == BluetoothValue::TnsString && 1.346 + arr[1].value().type() == BluetoothValue::Tbool); 1.347 + nsString address = arr[0].value().get_nsString(); 1.348 + bool status = arr[1].value().get_bool(); 1.349 + 1.350 + BluetoothStatusChangedEventInit init; 1.351 + init.mBubbles = false; 1.352 + init.mCancelable = false; 1.353 + init.mAddress = address; 1.354 + init.mStatus = status; 1.355 + nsRefPtr<BluetoothStatusChangedEvent> event = 1.356 + BluetoothStatusChangedEvent::Constructor(this, aData.name(), init); 1.357 + DispatchTrustedEvent(event); 1.358 + } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) { 1.359 + nsCOMPtr<nsIDOMEvent> event; 1.360 + nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); 1.361 + NS_ENSURE_SUCCESS_VOID(rv); 1.362 + 1.363 + rv = event->InitEvent(aData.name(), false, false); 1.364 + NS_ENSURE_SUCCESS_VOID(rv); 1.365 + 1.366 + DispatchTrustedEvent(event); 1.367 + } else { 1.368 +#ifdef DEBUG 1.369 + nsCString warningMsg; 1.370 + warningMsg.AssignLiteral("Not handling adapter signal: "); 1.371 + warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name())); 1.372 + BT_WARNING(warningMsg.get()); 1.373 +#endif 1.374 + } 1.375 +} 1.376 + 1.377 +already_AddRefed<DOMRequest> 1.378 +BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv) 1.379 +{ 1.380 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.381 + if (!win) { 1.382 + aRv.Throw(NS_ERROR_FAILURE); 1.383 + return nullptr; 1.384 + } 1.385 + 1.386 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.387 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.388 + new BluetoothVoidReplyRunnable(request); 1.389 + 1.390 + BluetoothService* bs = BluetoothService::Get(); 1.391 + if (!bs) { 1.392 + aRv.Throw(NS_ERROR_FAILURE); 1.393 + return nullptr; 1.394 + } 1.395 + nsresult rv; 1.396 + if (aStart) { 1.397 + rv = bs->StartDiscoveryInternal(results); 1.398 + } else { 1.399 + rv = bs->StopDiscoveryInternal(results); 1.400 + } 1.401 + if (NS_FAILED(rv)) { 1.402 + BT_WARNING("Start/Stop Discovery failed!"); 1.403 + aRv.Throw(rv); 1.404 + return nullptr; 1.405 + } 1.406 + 1.407 + // mDiscovering is not set here, we'll get a Property update from our external 1.408 + // protocol to tell us that it's been set. 1.409 + 1.410 + return request.forget(); 1.411 +} 1.412 + 1.413 +already_AddRefed<DOMRequest> 1.414 +BluetoothAdapter::StartDiscovery(ErrorResult& aRv) 1.415 +{ 1.416 + return StartStopDiscovery(true, aRv); 1.417 +} 1.418 + 1.419 +already_AddRefed<DOMRequest> 1.420 +BluetoothAdapter::StopDiscovery(ErrorResult& aRv) 1.421 +{ 1.422 + return StartStopDiscovery(false, aRv); 1.423 +} 1.424 + 1.425 +void 1.426 +BluetoothAdapter::GetDevices(JSContext* aContext, 1.427 + JS::MutableHandle<JS::Value> aDevices, 1.428 + ErrorResult& aRv) 1.429 +{ 1.430 + if (!mJsDeviceAddresses) { 1.431 + BT_WARNING("Devices not yet set!\n"); 1.432 + aRv.Throw(NS_ERROR_FAILURE); 1.433 + return; 1.434 + } 1.435 + 1.436 + JS::ExposeObjectToActiveJS(mJsDeviceAddresses); 1.437 + aDevices.setObject(*mJsDeviceAddresses); 1.438 +} 1.439 + 1.440 +void 1.441 +BluetoothAdapter::GetUuids(JSContext* aContext, 1.442 + JS::MutableHandle<JS::Value> aUuids, 1.443 + ErrorResult& aRv) 1.444 +{ 1.445 + if (!mJsUuids) { 1.446 + BT_WARNING("UUIDs not yet set!\n"); 1.447 + aRv.Throw(NS_ERROR_FAILURE); 1.448 + return; 1.449 + } 1.450 + 1.451 + JS::ExposeObjectToActiveJS(mJsUuids); 1.452 + aUuids.setObject(*mJsUuids); 1.453 +} 1.454 + 1.455 +already_AddRefed<DOMRequest> 1.456 +BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv) 1.457 +{ 1.458 + if (mName.Equals(aName)) { 1.459 + return FirePropertyAlreadySet(GetOwner(), aRv); 1.460 + } 1.461 + nsString name(aName); 1.462 + BluetoothValue value(name); 1.463 + BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value); 1.464 + return SetProperty(GetOwner(), property, aRv); 1.465 +} 1.466 + 1.467 +already_AddRefed<DOMRequest> 1.468 +BluetoothAdapter::SetDiscoverable(bool aDiscoverable, ErrorResult& aRv) 1.469 +{ 1.470 + if (aDiscoverable == mDiscoverable) { 1.471 + return FirePropertyAlreadySet(GetOwner(), aRv); 1.472 + } 1.473 + BluetoothValue value(aDiscoverable); 1.474 + BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value); 1.475 + return SetProperty(GetOwner(), property, aRv); 1.476 +} 1.477 + 1.478 +already_AddRefed<DOMRequest> 1.479 +BluetoothAdapter::SetDiscoverableTimeout(uint32_t aDiscoverableTimeout, ErrorResult& aRv) 1.480 +{ 1.481 + if (aDiscoverableTimeout == mDiscoverableTimeout) { 1.482 + return FirePropertyAlreadySet(GetOwner(), aRv); 1.483 + } 1.484 + BluetoothValue value(aDiscoverableTimeout); 1.485 + BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value); 1.486 + return SetProperty(GetOwner(), property, aRv); 1.487 +} 1.488 + 1.489 +already_AddRefed<DOMRequest> 1.490 +BluetoothAdapter::GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv) 1.491 +{ 1.492 + MOZ_ASSERT(NS_IsMainThread()); 1.493 + 1.494 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.495 + if (!win) { 1.496 + aRv.Throw(NS_ERROR_FAILURE); 1.497 + return nullptr; 1.498 + } 1.499 + 1.500 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.501 + nsRefPtr<BluetoothReplyRunnable> results = 1.502 + new GetDevicesTask(this, request); 1.503 + 1.504 + BluetoothService* bs = BluetoothService::Get(); 1.505 + if (!bs) { 1.506 + aRv.Throw(NS_ERROR_FAILURE); 1.507 + return nullptr; 1.508 + } 1.509 + nsresult rv = bs->GetConnectedDevicePropertiesInternal(aServiceUuid, results); 1.510 + if (NS_FAILED(rv)) { 1.511 + aRv.Throw(rv); 1.512 + return nullptr; 1.513 + } 1.514 + 1.515 + return request.forget(); 1.516 +} 1.517 + 1.518 +already_AddRefed<DOMRequest> 1.519 +BluetoothAdapter::GetPairedDevices(ErrorResult& aRv) 1.520 +{ 1.521 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.522 + if (!win) { 1.523 + aRv.Throw(NS_ERROR_FAILURE); 1.524 + return nullptr; 1.525 + } 1.526 + 1.527 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.528 + nsRefPtr<BluetoothReplyRunnable> results = 1.529 + new GetDevicesTask(this, request); 1.530 + 1.531 + BluetoothService* bs = BluetoothService::Get(); 1.532 + if (!bs) { 1.533 + aRv.Throw(NS_ERROR_FAILURE); 1.534 + return nullptr; 1.535 + } 1.536 + nsresult rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results); 1.537 + if (NS_FAILED(rv)) { 1.538 + aRv.Throw(rv); 1.539 + return nullptr; 1.540 + } 1.541 + 1.542 + return request.forget(); 1.543 +} 1.544 + 1.545 +already_AddRefed<DOMRequest> 1.546 +BluetoothAdapter::PairUnpair(bool aPair, const nsAString& aDeviceAddress, 1.547 + ErrorResult& aRv) 1.548 +{ 1.549 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.550 + if (!win) { 1.551 + aRv.Throw(NS_ERROR_FAILURE); 1.552 + return nullptr; 1.553 + } 1.554 + 1.555 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.556 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.557 + new BluetoothVoidReplyRunnable(request); 1.558 + 1.559 + BluetoothService* bs = BluetoothService::Get(); 1.560 + if (!bs) { 1.561 + aRv.Throw(NS_ERROR_FAILURE); 1.562 + return nullptr; 1.563 + } 1.564 + nsresult rv; 1.565 + if (aPair) { 1.566 + rv = bs->CreatePairedDeviceInternal(aDeviceAddress, 1.567 + kCreatePairedDeviceTimeout, 1.568 + results); 1.569 + } else { 1.570 + rv = bs->RemoveDeviceInternal(aDeviceAddress, results); 1.571 + } 1.572 + if (NS_FAILED(rv)) { 1.573 + BT_WARNING("Pair/Unpair failed!"); 1.574 + aRv.Throw(rv); 1.575 + return nullptr; 1.576 + } 1.577 + 1.578 + return request.forget(); 1.579 +} 1.580 + 1.581 +already_AddRefed<DOMRequest> 1.582 +BluetoothAdapter::Pair(const nsAString& aDeviceAddress, ErrorResult& aRv) 1.583 +{ 1.584 + return PairUnpair(true, aDeviceAddress, aRv); 1.585 +} 1.586 + 1.587 +already_AddRefed<DOMRequest> 1.588 +BluetoothAdapter::Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv) 1.589 +{ 1.590 + return PairUnpair(false, aDeviceAddress, aRv); 1.591 +} 1.592 + 1.593 +already_AddRefed<DOMRequest> 1.594 +BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress, 1.595 + const nsAString& aPinCode, ErrorResult& aRv) 1.596 +{ 1.597 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.598 + if (!win) { 1.599 + aRv.Throw(NS_ERROR_FAILURE); 1.600 + return nullptr; 1.601 + } 1.602 + 1.603 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.604 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.605 + new BluetoothVoidReplyRunnable(request); 1.606 + 1.607 + BluetoothService* bs = BluetoothService::Get(); 1.608 + if (!bs) { 1.609 + aRv.Throw(NS_ERROR_FAILURE); 1.610 + return nullptr; 1.611 + } 1.612 + if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) { 1.613 + BT_WARNING("SetPinCode failed!"); 1.614 + aRv.Throw(NS_ERROR_FAILURE); 1.615 + return nullptr; 1.616 + } 1.617 + 1.618 + return request.forget(); 1.619 +} 1.620 + 1.621 +already_AddRefed<DOMRequest> 1.622 +BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey, 1.623 + ErrorResult& aRv) 1.624 +{ 1.625 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.626 + if (!win) { 1.627 + aRv.Throw(NS_ERROR_FAILURE); 1.628 + return nullptr; 1.629 + } 1.630 + 1.631 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.632 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.633 + new BluetoothVoidReplyRunnable(request); 1.634 + 1.635 + BluetoothService* bs = BluetoothService::Get(); 1.636 + if (!bs) { 1.637 + aRv.Throw(NS_ERROR_FAILURE); 1.638 + return nullptr; 1.639 + } 1.640 + if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) { 1.641 + BT_WARNING("SetPasskeyInternal failed!"); 1.642 + aRv.Throw(NS_ERROR_FAILURE); 1.643 + return nullptr; 1.644 + } 1.645 + 1.646 + return request.forget(); 1.647 +} 1.648 + 1.649 +already_AddRefed<DOMRequest> 1.650 +BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress, 1.651 + bool aConfirmation, ErrorResult& aRv) 1.652 +{ 1.653 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.654 + if (!win) { 1.655 + aRv.Throw(NS_ERROR_FAILURE); 1.656 + return nullptr; 1.657 + } 1.658 + 1.659 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.660 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.661 + new BluetoothVoidReplyRunnable(request); 1.662 + 1.663 + BluetoothService* bs = BluetoothService::Get(); 1.664 + if (!bs) { 1.665 + aRv.Throw(NS_ERROR_FAILURE); 1.666 + return nullptr; 1.667 + } 1.668 + if (!bs->SetPairingConfirmationInternal(aDeviceAddress, 1.669 + aConfirmation, 1.670 + results)) { 1.671 + BT_WARNING("SetPairingConfirmation failed!"); 1.672 + aRv.Throw(NS_ERROR_FAILURE); 1.673 + return nullptr; 1.674 + } 1.675 + 1.676 + return request.forget(); 1.677 +} 1.678 + 1.679 +already_AddRefed<DOMRequest> 1.680 +BluetoothAdapter::Connect(BluetoothDevice& aDevice, 1.681 + const Optional<short unsigned int>& aServiceUuid, 1.682 + ErrorResult& aRv) 1.683 +{ 1.684 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.685 + if (!win) { 1.686 + aRv.Throw(NS_ERROR_FAILURE); 1.687 + return nullptr; 1.688 + } 1.689 + 1.690 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.691 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.692 + new BluetoothVoidReplyRunnable(request); 1.693 + 1.694 + nsAutoString address; 1.695 + aDevice.GetAddress(address); 1.696 + uint32_t deviceClass = aDevice.Class(); 1.697 + uint16_t serviceUuid = 0; 1.698 + if (aServiceUuid.WasPassed()) { 1.699 + serviceUuid = aServiceUuid.Value(); 1.700 + } 1.701 + 1.702 + BluetoothService* bs = BluetoothService::Get(); 1.703 + if (!bs) { 1.704 + aRv.Throw(NS_ERROR_FAILURE); 1.705 + return nullptr; 1.706 + } 1.707 + bs->Connect(address, deviceClass, serviceUuid, results); 1.708 + 1.709 + return request.forget(); 1.710 +} 1.711 + 1.712 +already_AddRefed<DOMRequest> 1.713 +BluetoothAdapter::Disconnect(BluetoothDevice& aDevice, 1.714 + const Optional<short unsigned int>& aServiceUuid, 1.715 + ErrorResult& aRv) 1.716 +{ 1.717 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.718 + if (!win) { 1.719 + aRv.Throw(NS_ERROR_FAILURE); 1.720 + return nullptr; 1.721 + } 1.722 + 1.723 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.724 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.725 + new BluetoothVoidReplyRunnable(request); 1.726 + 1.727 + nsAutoString address; 1.728 + aDevice.GetAddress(address); 1.729 + uint16_t serviceUuid = 0; 1.730 + if (aServiceUuid.WasPassed()) { 1.731 + serviceUuid = aServiceUuid.Value(); 1.732 + } 1.733 + 1.734 + BluetoothService* bs = BluetoothService::Get(); 1.735 + if (!bs) { 1.736 + aRv.Throw(NS_ERROR_FAILURE); 1.737 + return nullptr; 1.738 + } 1.739 + bs->Disconnect(address, serviceUuid, results); 1.740 + 1.741 + return request.forget(); 1.742 +} 1.743 + 1.744 +already_AddRefed<DOMRequest> 1.745 +BluetoothAdapter::SendFile(const nsAString& aDeviceAddress, 1.746 + nsIDOMBlob* aBlob, ErrorResult& aRv) 1.747 +{ 1.748 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.749 + if (!win) { 1.750 + aRv.Throw(NS_ERROR_FAILURE); 1.751 + return nullptr; 1.752 + } 1.753 + 1.754 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.755 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.756 + new BluetoothVoidReplyRunnable(request); 1.757 + 1.758 + BluetoothService* bs = BluetoothService::Get(); 1.759 + if (!bs) { 1.760 + aRv.Throw(NS_ERROR_FAILURE); 1.761 + return nullptr; 1.762 + } 1.763 + 1.764 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.765 + // In-process transfer 1.766 + bs->SendFile(aDeviceAddress, aBlob, results); 1.767 + } else { 1.768 + ContentChild *cc = ContentChild::GetSingleton(); 1.769 + if (!cc) { 1.770 + aRv.Throw(NS_ERROR_FAILURE); 1.771 + return nullptr; 1.772 + } 1.773 + 1.774 + BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob); 1.775 + if (!actor) { 1.776 + aRv.Throw(NS_ERROR_FAILURE); 1.777 + return nullptr; 1.778 + } 1.779 + 1.780 + bs->SendFile(aDeviceAddress, nullptr, actor, results); 1.781 + } 1.782 + 1.783 + return request.forget(); 1.784 +} 1.785 + 1.786 +already_AddRefed<DOMRequest> 1.787 +BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv) 1.788 +{ 1.789 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.790 + if (!win) { 1.791 + aRv.Throw(NS_ERROR_FAILURE); 1.792 + return nullptr; 1.793 + } 1.794 + 1.795 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.796 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.797 + new BluetoothVoidReplyRunnable(request); 1.798 + 1.799 + BluetoothService* bs = BluetoothService::Get(); 1.800 + if (!bs) { 1.801 + aRv.Throw(NS_ERROR_FAILURE); 1.802 + return nullptr; 1.803 + } 1.804 + bs->StopSendingFile(aDeviceAddress, results); 1.805 + 1.806 + return request.forget(); 1.807 +} 1.808 + 1.809 +already_AddRefed<DOMRequest> 1.810 +BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress, 1.811 + bool aConfirmation, ErrorResult& aRv) 1.812 +{ 1.813 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.814 + if (!win) { 1.815 + aRv.Throw(NS_ERROR_FAILURE); 1.816 + return nullptr; 1.817 + } 1.818 + 1.819 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.820 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.821 + new BluetoothVoidReplyRunnable(request); 1.822 + 1.823 + BluetoothService* bs = BluetoothService::Get(); 1.824 + if (!bs) { 1.825 + aRv.Throw(NS_ERROR_FAILURE); 1.826 + return nullptr; 1.827 + } 1.828 + bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results); 1.829 + 1.830 + return request.forget(); 1.831 +} 1.832 + 1.833 +already_AddRefed<DOMRequest> 1.834 +BluetoothAdapter::ConnectSco(ErrorResult& aRv) 1.835 +{ 1.836 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.837 + if (!win) { 1.838 + aRv.Throw(NS_ERROR_FAILURE); 1.839 + return nullptr; 1.840 + } 1.841 + 1.842 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.843 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.844 + new BluetoothVoidReplyRunnable(request); 1.845 + 1.846 + BluetoothService* bs = BluetoothService::Get(); 1.847 + if (!bs) { 1.848 + aRv.Throw(NS_ERROR_FAILURE); 1.849 + return nullptr; 1.850 + } 1.851 + bs->ConnectSco(results); 1.852 + 1.853 + return request.forget(); 1.854 +} 1.855 + 1.856 +already_AddRefed<DOMRequest> 1.857 +BluetoothAdapter::DisconnectSco(ErrorResult& aRv) 1.858 +{ 1.859 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.860 + if (!win) { 1.861 + aRv.Throw(NS_ERROR_FAILURE); 1.862 + return nullptr; 1.863 + } 1.864 + 1.865 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.866 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.867 + new BluetoothVoidReplyRunnable(request); 1.868 + 1.869 + BluetoothService* bs = BluetoothService::Get(); 1.870 + if (!bs) { 1.871 + aRv.Throw(NS_ERROR_FAILURE); 1.872 + return nullptr; 1.873 + } 1.874 + bs->DisconnectSco(results); 1.875 + 1.876 + return request.forget(); 1.877 +} 1.878 + 1.879 +already_AddRefed<DOMRequest> 1.880 +BluetoothAdapter::IsScoConnected(ErrorResult& aRv) 1.881 +{ 1.882 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.883 + if (!win) { 1.884 + aRv.Throw(NS_ERROR_FAILURE); 1.885 + return nullptr; 1.886 + } 1.887 + 1.888 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.889 + nsRefPtr<BluetoothReplyRunnable> results = 1.890 + new GetScoConnectionStatusTask(request); 1.891 + 1.892 + BluetoothService* bs = BluetoothService::Get(); 1.893 + if (!bs) { 1.894 + aRv.Throw(NS_ERROR_FAILURE); 1.895 + return nullptr; 1.896 + } 1.897 + bs->IsScoConnected(results); 1.898 + 1.899 + return request.forget(); 1.900 +} 1.901 + 1.902 +already_AddRefed<DOMRequest> 1.903 +BluetoothAdapter::AnswerWaitingCall(ErrorResult& aRv) 1.904 +{ 1.905 +#ifdef MOZ_B2G_RIL 1.906 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.907 + if (!win) { 1.908 + aRv.Throw(NS_ERROR_FAILURE); 1.909 + return nullptr; 1.910 + } 1.911 + 1.912 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.913 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.914 + new BluetoothVoidReplyRunnable(request); 1.915 + 1.916 + BluetoothService* bs = BluetoothService::Get(); 1.917 + if (!bs) { 1.918 + aRv.Throw(NS_ERROR_FAILURE); 1.919 + return nullptr; 1.920 + } 1.921 + bs->AnswerWaitingCall(results); 1.922 + 1.923 + return request.forget(); 1.924 +#else 1.925 + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 1.926 + return nullptr; 1.927 +#endif // MOZ_B2G_RIL 1.928 +} 1.929 + 1.930 +already_AddRefed<DOMRequest> 1.931 +BluetoothAdapter::IgnoreWaitingCall(ErrorResult& aRv) 1.932 +{ 1.933 +#ifdef MOZ_B2G_RIL 1.934 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.935 + if (!win) { 1.936 + aRv.Throw(NS_ERROR_FAILURE); 1.937 + return nullptr; 1.938 + } 1.939 + 1.940 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.941 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.942 + new BluetoothVoidReplyRunnable(request); 1.943 + 1.944 + BluetoothService* bs = BluetoothService::Get(); 1.945 + if (!bs) { 1.946 + aRv.Throw(NS_ERROR_FAILURE); 1.947 + return nullptr; 1.948 + } 1.949 + bs->IgnoreWaitingCall(results); 1.950 + 1.951 + return request.forget(); 1.952 +#else 1.953 + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 1.954 + return nullptr; 1.955 +#endif // MOZ_B2G_RIL 1.956 +} 1.957 + 1.958 +already_AddRefed<DOMRequest> 1.959 +BluetoothAdapter::ToggleCalls(ErrorResult& aRv) 1.960 +{ 1.961 +#ifdef MOZ_B2G_RIL 1.962 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.963 + if (!win) { 1.964 + aRv.Throw(NS_ERROR_FAILURE); 1.965 + return nullptr; 1.966 + } 1.967 + 1.968 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.969 + nsRefPtr<BluetoothVoidReplyRunnable> results = 1.970 + new BluetoothVoidReplyRunnable(request); 1.971 + 1.972 + BluetoothService* bs = BluetoothService::Get(); 1.973 + if (!bs) { 1.974 + aRv.Throw(NS_ERROR_FAILURE); 1.975 + return nullptr; 1.976 + } 1.977 + bs->ToggleCalls(results); 1.978 + 1.979 + return request.forget(); 1.980 +#else 1.981 + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 1.982 + return nullptr; 1.983 +#endif // MOZ_B2G_RIL 1.984 +} 1.985 + 1.986 +already_AddRefed<DOMRequest> 1.987 +BluetoothAdapter::SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv) 1.988 +{ 1.989 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.990 + if (!win) { 1.991 + aRv.Throw(NS_ERROR_FAILURE); 1.992 + return nullptr; 1.993 + } 1.994 + 1.995 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.996 + nsRefPtr<BluetoothReplyRunnable> results = 1.997 + new BluetoothVoidReplyRunnable(request); 1.998 + 1.999 + BluetoothService* bs = BluetoothService::Get(); 1.1000 + if (!bs) { 1.1001 + aRv.Throw(NS_ERROR_FAILURE); 1.1002 + return nullptr; 1.1003 + } 1.1004 + bs->SendMetaData(aMediaMetaData.mTitle, 1.1005 + aMediaMetaData.mArtist, 1.1006 + aMediaMetaData.mAlbum, 1.1007 + aMediaMetaData.mMediaNumber, 1.1008 + aMediaMetaData.mTotalMediaCount, 1.1009 + aMediaMetaData.mDuration, 1.1010 + results); 1.1011 + 1.1012 + return request.forget(); 1.1013 +} 1.1014 + 1.1015 +already_AddRefed<DOMRequest> 1.1016 +BluetoothAdapter::SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv) 1.1017 +{ 1.1018 + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); 1.1019 + if (!win) { 1.1020 + aRv.Throw(NS_ERROR_FAILURE); 1.1021 + return nullptr; 1.1022 + } 1.1023 + 1.1024 + nsRefPtr<DOMRequest> request = new DOMRequest(win); 1.1025 + nsRefPtr<BluetoothReplyRunnable> results = 1.1026 + new BluetoothVoidReplyRunnable(request); 1.1027 + 1.1028 + BluetoothService* bs = BluetoothService::Get(); 1.1029 + if (!bs) { 1.1030 + aRv.Throw(NS_ERROR_FAILURE); 1.1031 + return nullptr; 1.1032 + } 1.1033 + bs->SendPlayStatus(aMediaPlayStatus.mDuration, 1.1034 + aMediaPlayStatus.mPosition, 1.1035 + aMediaPlayStatus.mPlayStatus, 1.1036 + results); 1.1037 + 1.1038 + return request.forget(); 1.1039 +} 1.1040 + 1.1041 +JSObject* 1.1042 +BluetoothAdapter::WrapObject(JSContext* aCx) 1.1043 +{ 1.1044 + return BluetoothAdapterBinding::Wrap(aCx, this); 1.1045 +}