michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "nsCxPusher.h" michael@0: #include "nsDOMClassInfo.h" michael@0: #include "nsTArrayHelpers.h" michael@0: #include "DOMRequest.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #include "mozilla/dom/bluetooth/BluetoothTypes.h" michael@0: #include "mozilla/dom/BluetoothAdapterBinding.h" michael@0: #include "mozilla/dom/BluetoothDeviceEvent.h" michael@0: #include "mozilla/dom/BluetoothStatusChangedEvent.h" michael@0: #include "mozilla/dom/ContentChild.h" michael@0: #include "mozilla/LazyIdleThread.h" michael@0: michael@0: #include "BluetoothAdapter.h" michael@0: #include "BluetoothDevice.h" michael@0: #include "BluetoothReplyRunnable.h" michael@0: #include "BluetoothService.h" michael@0: #include "BluetoothUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: USING_BLUETOOTH_NAMESPACE michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter, michael@0: DOMEventTargetHelper) michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids) michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsDeviceAddresses) michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, michael@0: DOMEventTargetHelper) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, michael@0: DOMEventTargetHelper) michael@0: tmp->Unroot(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: // QueryInterface implementation for BluetoothAdapter michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper) michael@0: NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper) michael@0: michael@0: class GetDevicesTask : public BluetoothReplyRunnable michael@0: { michael@0: public: michael@0: GetDevicesTask(BluetoothAdapter* aAdapterPtr, michael@0: nsIDOMDOMRequest* aReq) : michael@0: BluetoothReplyRunnable(aReq), michael@0: mAdapterPtr(aAdapterPtr) michael@0: { michael@0: MOZ_ASSERT(aReq && aAdapterPtr); michael@0: } michael@0: michael@0: virtual bool ParseSuccessfulReply(JS::MutableHandle aValue) michael@0: { michael@0: aValue.setUndefined(); michael@0: michael@0: const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); michael@0: if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) { michael@0: BT_WARNING("Not a BluetoothNamedValue array!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); michael@0: return false; michael@0: } michael@0: michael@0: const InfallibleTArray& values = michael@0: v.get_ArrayOfBluetoothNamedValue(); michael@0: michael@0: nsTArray > devices; michael@0: for (uint32_t i = 0; i < values.Length(); i++) { michael@0: const BluetoothValue properties = values[i].value(); michael@0: if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) { michael@0: BT_WARNING("Not a BluetoothNamedValue array!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); michael@0: return false; michael@0: } michael@0: nsRefPtr d = michael@0: BluetoothDevice::Create(mAdapterPtr->GetOwner(), michael@0: mAdapterPtr->GetPath(), michael@0: properties); michael@0: devices.AppendElement(d); michael@0: } michael@0: michael@0: nsresult rv; michael@0: nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv); michael@0: if (!sc) { michael@0: BT_WARNING("Cannot create script context!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothScriptContextError")); michael@0: return false; michael@0: } michael@0: michael@0: AutoPushJSContext cx(sc->GetNativeContext()); michael@0: JSObject* JsDevices = nullptr; michael@0: rv = nsTArrayToJSArray(cx, devices, &JsDevices); michael@0: if (!JsDevices) { michael@0: BT_WARNING("Cannot create JS array!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothError")); michael@0: return false; michael@0: } michael@0: michael@0: aValue.setObject(*JsDevices); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: ReleaseMembers() michael@0: { michael@0: BluetoothReplyRunnable::ReleaseMembers(); michael@0: mAdapterPtr = nullptr; michael@0: } michael@0: private: michael@0: nsRefPtr mAdapterPtr; michael@0: }; michael@0: michael@0: class GetScoConnectionStatusTask : public BluetoothReplyRunnable michael@0: { michael@0: public: michael@0: GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) : michael@0: BluetoothReplyRunnable(aReq) michael@0: { michael@0: MOZ_ASSERT(aReq); michael@0: } michael@0: michael@0: virtual bool ParseSuccessfulReply(JS::MutableHandle aValue) michael@0: { michael@0: aValue.setUndefined(); michael@0: michael@0: const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); michael@0: if (v.type() != BluetoothValue::Tbool) { michael@0: BT_WARNING("Not a boolean!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); michael@0: return false; michael@0: } michael@0: michael@0: aValue.setBoolean(v.get_bool()); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: ReleaseMembers() michael@0: { michael@0: BluetoothReplyRunnable::ReleaseMembers(); michael@0: } michael@0: }; michael@0: michael@0: static int kCreatePairedDeviceTimeout = 50000; // unit: msec michael@0: michael@0: BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow, michael@0: const BluetoothValue& aValue) michael@0: : DOMEventTargetHelper(aWindow) michael@0: , BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER) michael@0: , mJsUuids(nullptr) michael@0: , mJsDeviceAddresses(nullptr) michael@0: , mDiscoverable(false) michael@0: , mDiscovering(false) michael@0: , mPairable(false) michael@0: , mPowered(false) michael@0: , mIsRooted(false) michael@0: { michael@0: MOZ_ASSERT(aWindow); michael@0: MOZ_ASSERT(IsDOMBinding()); michael@0: michael@0: const InfallibleTArray& values = michael@0: aValue.get_ArrayOfBluetoothNamedValue(); michael@0: for (uint32_t i = 0; i < values.Length(); ++i) { michael@0: SetPropertyByValue(values[i]); michael@0: } michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); michael@0: } michael@0: michael@0: BluetoothAdapter::~BluetoothAdapter() michael@0: { michael@0: Unroot(); michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: // We can be null on shutdown, where this might happen michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::DisconnectFromOwner() michael@0: { michael@0: DOMEventTargetHelper::DisconnectFromOwner(); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this); michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::Unroot() michael@0: { michael@0: if (!mIsRooted) { michael@0: return; michael@0: } michael@0: mJsUuids = nullptr; michael@0: mJsDeviceAddresses = nullptr; michael@0: mozilla::DropJSObjects(this); michael@0: mIsRooted = false; michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::Root() michael@0: { michael@0: if (mIsRooted) { michael@0: return; michael@0: } michael@0: mozilla::HoldJSObjects(this); michael@0: mIsRooted = true; michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue) michael@0: { michael@0: const nsString& name = aValue.name(); michael@0: const BluetoothValue& value = aValue.value(); michael@0: if (name.EqualsLiteral("Name")) { michael@0: mName = value.get_nsString(); michael@0: } else if (name.EqualsLiteral("Address")) { michael@0: mAddress = value.get_nsString(); michael@0: } else if (name.EqualsLiteral("Path")) { michael@0: mPath = value.get_nsString(); michael@0: } else if (name.EqualsLiteral("Discoverable")) { michael@0: mDiscoverable = value.get_bool(); michael@0: } else if (name.EqualsLiteral("Discovering")) { michael@0: mDiscovering = value.get_bool(); michael@0: } else if (name.EqualsLiteral("Pairable")) { michael@0: mPairable = value.get_bool(); michael@0: } else if (name.EqualsLiteral("Powered")) { michael@0: mPowered = value.get_bool(); michael@0: } else if (name.EqualsLiteral("PairableTimeout")) { michael@0: mPairableTimeout = value.get_uint32_t(); michael@0: } else if (name.EqualsLiteral("DiscoverableTimeout")) { michael@0: mDiscoverableTimeout = value.get_uint32_t(); michael@0: } else if (name.EqualsLiteral("Class")) { michael@0: mClass = value.get_uint32_t(); michael@0: } else if (name.EqualsLiteral("UUIDs")) { michael@0: mUuids = value.get_ArrayOfnsString(); michael@0: nsresult rv; michael@0: nsIScriptContext* sc = GetContextForEventHandlers(&rv); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: NS_ENSURE_TRUE_VOID(sc); michael@0: michael@0: AutoPushJSContext cx(sc->GetNativeContext()); michael@0: JS::Rooted uuids(cx); michael@0: if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) { michael@0: BT_WARNING("Cannot set JS UUIDs object!"); michael@0: return; michael@0: } michael@0: mJsUuids = uuids; michael@0: Root(); michael@0: } else if (name.EqualsLiteral("Devices")) { michael@0: mDeviceAddresses = value.get_ArrayOfnsString(); michael@0: michael@0: nsresult rv; michael@0: nsIScriptContext* sc = GetContextForEventHandlers(&rv); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: NS_ENSURE_TRUE_VOID(sc); michael@0: michael@0: AutoPushJSContext cx(sc->GetNativeContext()); michael@0: JS::Rooted deviceAddresses(cx); michael@0: if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses, michael@0: deviceAddresses.address()))) { michael@0: BT_WARNING("Cannot set JS Devices object!"); michael@0: return; michael@0: } michael@0: mJsDeviceAddresses = deviceAddresses; michael@0: Root(); michael@0: } else { michael@0: #ifdef DEBUG michael@0: nsCString warningMsg; michael@0: warningMsg.AssignLiteral("Not handling adapter property: "); michael@0: warningMsg.Append(NS_ConvertUTF16toUTF8(name)); michael@0: BT_WARNING(warningMsg.get()); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: // static michael@0: already_AddRefed michael@0: BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(aWindow); michael@0: michael@0: nsRefPtr adapter = new BluetoothAdapter(aWindow, aValue); michael@0: return adapter.forget(); michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::Notify(const BluetoothSignal& aData) michael@0: { michael@0: InfallibleTArray arr; michael@0: michael@0: BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get()); michael@0: michael@0: BluetoothValue v = aData.value(); michael@0: if (aData.name().EqualsLiteral("DeviceFound")) { michael@0: nsRefPtr device = BluetoothDevice::Create(GetOwner(), mPath, aData.value()); michael@0: michael@0: BluetoothDeviceEventInit init; michael@0: init.mBubbles = false; michael@0: init.mCancelable = false; michael@0: init.mDevice = device; michael@0: nsRefPtr event = michael@0: BluetoothDeviceEvent::Constructor(this, NS_LITERAL_STRING("devicefound"), init); michael@0: DispatchTrustedEvent(event); michael@0: } else if (aData.name().EqualsLiteral("PropertyChanged")) { michael@0: MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); michael@0: michael@0: const InfallibleTArray& arr = michael@0: v.get_ArrayOfBluetoothNamedValue(); michael@0: michael@0: for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) { michael@0: SetPropertyByValue(arr[i]); michael@0: } michael@0: } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) || michael@0: aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) || michael@0: aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) || michael@0: aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) { michael@0: MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); michael@0: const InfallibleTArray& arr = michael@0: v.get_ArrayOfBluetoothNamedValue(); michael@0: michael@0: MOZ_ASSERT(arr.Length() == 2 && michael@0: arr[0].value().type() == BluetoothValue::TnsString && michael@0: arr[1].value().type() == BluetoothValue::Tbool); michael@0: nsString address = arr[0].value().get_nsString(); michael@0: bool status = arr[1].value().get_bool(); michael@0: michael@0: BluetoothStatusChangedEventInit init; michael@0: init.mBubbles = false; michael@0: init.mCancelable = false; michael@0: init.mAddress = address; michael@0: init.mStatus = status; michael@0: nsRefPtr event = michael@0: BluetoothStatusChangedEvent::Constructor(this, aData.name(), init); michael@0: DispatchTrustedEvent(event); michael@0: } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) { michael@0: nsCOMPtr event; michael@0: nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: rv = event->InitEvent(aData.name(), false, false); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: DispatchTrustedEvent(event); michael@0: } else { michael@0: #ifdef DEBUG michael@0: nsCString warningMsg; michael@0: warningMsg.AssignLiteral("Not handling adapter signal: "); michael@0: warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name())); michael@0: BT_WARNING(warningMsg.get()); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: nsresult rv; michael@0: if (aStart) { michael@0: rv = bs->StartDiscoveryInternal(results); michael@0: } else { michael@0: rv = bs->StopDiscoveryInternal(results); michael@0: } michael@0: if (NS_FAILED(rv)) { michael@0: BT_WARNING("Start/Stop Discovery failed!"); michael@0: aRv.Throw(rv); michael@0: return nullptr; michael@0: } michael@0: michael@0: // mDiscovering is not set here, we'll get a Property update from our external michael@0: // protocol to tell us that it's been set. michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::StartDiscovery(ErrorResult& aRv) michael@0: { michael@0: return StartStopDiscovery(true, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::StopDiscovery(ErrorResult& aRv) michael@0: { michael@0: return StartStopDiscovery(false, aRv); michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::GetDevices(JSContext* aContext, michael@0: JS::MutableHandle aDevices, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mJsDeviceAddresses) { michael@0: BT_WARNING("Devices not yet set!\n"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return; michael@0: } michael@0: michael@0: JS::ExposeObjectToActiveJS(mJsDeviceAddresses); michael@0: aDevices.setObject(*mJsDeviceAddresses); michael@0: } michael@0: michael@0: void michael@0: BluetoothAdapter::GetUuids(JSContext* aContext, michael@0: JS::MutableHandle aUuids, michael@0: ErrorResult& aRv) michael@0: { michael@0: if (!mJsUuids) { michael@0: BT_WARNING("UUIDs not yet set!\n"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return; michael@0: } michael@0: michael@0: JS::ExposeObjectToActiveJS(mJsUuids); michael@0: aUuids.setObject(*mJsUuids); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv) michael@0: { michael@0: if (mName.Equals(aName)) { michael@0: return FirePropertyAlreadySet(GetOwner(), aRv); michael@0: } michael@0: nsString name(aName); michael@0: BluetoothValue value(name); michael@0: BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value); michael@0: return SetProperty(GetOwner(), property, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetDiscoverable(bool aDiscoverable, ErrorResult& aRv) michael@0: { michael@0: if (aDiscoverable == mDiscoverable) { michael@0: return FirePropertyAlreadySet(GetOwner(), aRv); michael@0: } michael@0: BluetoothValue value(aDiscoverable); michael@0: BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value); michael@0: return SetProperty(GetOwner(), property, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetDiscoverableTimeout(uint32_t aDiscoverableTimeout, ErrorResult& aRv) michael@0: { michael@0: if (aDiscoverableTimeout == mDiscoverableTimeout) { michael@0: return FirePropertyAlreadySet(GetOwner(), aRv); michael@0: } michael@0: BluetoothValue value(aDiscoverableTimeout); michael@0: BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value); michael@0: return SetProperty(GetOwner(), property, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new GetDevicesTask(this, request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: nsresult rv = bs->GetConnectedDevicePropertiesInternal(aServiceUuid, results); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::GetPairedDevices(ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new GetDevicesTask(this, request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: nsresult rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::PairUnpair(bool aPair, const nsAString& aDeviceAddress, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: nsresult rv; michael@0: if (aPair) { michael@0: rv = bs->CreatePairedDeviceInternal(aDeviceAddress, michael@0: kCreatePairedDeviceTimeout, michael@0: results); michael@0: } else { michael@0: rv = bs->RemoveDeviceInternal(aDeviceAddress, results); michael@0: } michael@0: if (NS_FAILED(rv)) { michael@0: BT_WARNING("Pair/Unpair failed!"); michael@0: aRv.Throw(rv); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::Pair(const nsAString& aDeviceAddress, ErrorResult& aRv) michael@0: { michael@0: return PairUnpair(true, aDeviceAddress, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::Unpair(const nsAString& aDeviceAddress, ErrorResult& aRv) michael@0: { michael@0: return PairUnpair(false, aDeviceAddress, aRv); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress, michael@0: const nsAString& aPinCode, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) { michael@0: BT_WARNING("SetPinCode failed!"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) { michael@0: BT_WARNING("SetPasskeyInternal failed!"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress, michael@0: bool aConfirmation, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: if (!bs->SetPairingConfirmationInternal(aDeviceAddress, michael@0: aConfirmation, michael@0: results)) { michael@0: BT_WARNING("SetPairingConfirmation failed!"); michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::Connect(BluetoothDevice& aDevice, michael@0: const Optional& aServiceUuid, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: nsAutoString address; michael@0: aDevice.GetAddress(address); michael@0: uint32_t deviceClass = aDevice.Class(); michael@0: uint16_t serviceUuid = 0; michael@0: if (aServiceUuid.WasPassed()) { michael@0: serviceUuid = aServiceUuid.Value(); michael@0: } michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->Connect(address, deviceClass, serviceUuid, results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::Disconnect(BluetoothDevice& aDevice, michael@0: const Optional& aServiceUuid, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: nsAutoString address; michael@0: aDevice.GetAddress(address); michael@0: uint16_t serviceUuid = 0; michael@0: if (aServiceUuid.WasPassed()) { michael@0: serviceUuid = aServiceUuid.Value(); michael@0: } michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->Disconnect(address, serviceUuid, results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SendFile(const nsAString& aDeviceAddress, michael@0: nsIDOMBlob* aBlob, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: if (XRE_GetProcessType() == GeckoProcessType_Default) { michael@0: // In-process transfer michael@0: bs->SendFile(aDeviceAddress, aBlob, results); michael@0: } else { michael@0: ContentChild *cc = ContentChild::GetSingleton(); michael@0: if (!cc) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob); michael@0: if (!actor) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: bs->SendFile(aDeviceAddress, nullptr, actor, results); michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->StopSendingFile(aDeviceAddress, results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress, michael@0: bool aConfirmation, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::ConnectSco(ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->ConnectSco(results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::DisconnectSco(ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->DisconnectSco(results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::IsScoConnected(ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new GetScoConnectionStatusTask(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->IsScoConnected(results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::AnswerWaitingCall(ErrorResult& aRv) michael@0: { michael@0: #ifdef MOZ_B2G_RIL michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->AnswerWaitingCall(results); michael@0: michael@0: return request.forget(); michael@0: #else michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: return nullptr; michael@0: #endif // MOZ_B2G_RIL michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::IgnoreWaitingCall(ErrorResult& aRv) michael@0: { michael@0: #ifdef MOZ_B2G_RIL michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->IgnoreWaitingCall(results); michael@0: michael@0: return request.forget(); michael@0: #else michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: return nullptr; michael@0: #endif // MOZ_B2G_RIL michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::ToggleCalls(ErrorResult& aRv) michael@0: { michael@0: #ifdef MOZ_B2G_RIL michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->ToggleCalls(results); michael@0: michael@0: return request.forget(); michael@0: #else michael@0: aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); michael@0: return nullptr; michael@0: #endif // MOZ_B2G_RIL michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->SendMetaData(aMediaMetaData.mTitle, michael@0: aMediaMetaData.mArtist, michael@0: aMediaMetaData.mAlbum, michael@0: aMediaMetaData.mMediaNumber, michael@0: aMediaMetaData.mTotalMediaCount, michael@0: aMediaMetaData.mDuration, michael@0: results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothAdapter::SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new BluetoothVoidReplyRunnable(request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: bs->SendPlayStatus(aMediaPlayStatus.mDuration, michael@0: aMediaPlayStatus.mPosition, michael@0: aMediaPlayStatus.mPlayStatus, michael@0: results); michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: JSObject* michael@0: BluetoothAdapter::WrapObject(JSContext* aCx) michael@0: { michael@0: return BluetoothAdapterBinding::Wrap(aCx, this); michael@0: }